summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRoman Shevchenko <roman.shevchenko@jetbrains.com>2014-08-28 21:34:14 +0400
committerRoman Shevchenko <roman.shevchenko@jetbrains.com>2014-08-28 21:34:19 +0400
commit076e4393f25bf1ad1ff1bd2853153e2b595dd90b (patch)
treef1a17a12ea762525b5efbc0778b0945d906c68c9 /src
parent663631f0456fcc245dd835889f86541d75161c53 (diff)
downloadfernflower-076e4393f25bf1ad1ff1bd2853153e2b595dd90b.tar
fernflower-076e4393f25bf1ad1ff1bd2853153e2b595dd90b.tar.gz
fernflower-076e4393f25bf1ad1ff1bd2853153e2b595dd90b.tar.lz
fernflower-076e4393f25bf1ad1ff1bd2853153e2b595dd90b.tar.xz
fernflower-076e4393f25bf1ad1ff1bd2853153e2b595dd90b.zip
java-decompiler: post-import cleanup (formatting and copyright)
Diffstat (limited to 'src')
-rw-r--r--src/org/jetbrains/java/decompiler/code/CodeConstants.java703
-rw-r--r--src/org/jetbrains/java/decompiler/code/ConstantsUtil.java969
-rw-r--r--src/org/jetbrains/java/decompiler/code/ExceptionHandler.java99
-rw-r--r--src/org/jetbrains/java/decompiler/code/ExceptionTable.java89
-rw-r--r--src/org/jetbrains/java/decompiler/code/FullInstructionSequence.java48
-rw-r--r--src/org/jetbrains/java/decompiler/code/IfInstruction.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/Instruction.java224
-rw-r--r--src/org/jetbrains/java/decompiler/code/InstructionSequence.java412
-rw-r--r--src/org/jetbrains/java/decompiler/code/JumpInstruction.java49
-rw-r--r--src/org/jetbrains/java/decompiler/code/SimpleInstructionSequence.java50
-rw-r--r--src/org/jetbrains/java/decompiler/code/SwitchInstruction.java162
-rw-r--r--src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java499
-rw-r--r--src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java1722
-rw-r--r--src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java229
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/AALOAD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/AASTORE.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ACONST_NULL.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ALOAD.java85
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ANEWARRAY.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ARETURN.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ARRAYLENGTH.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ASTORE.java86
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ATHROW.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/BALOAD.java17
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/BASTORE.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/BIPUSH.java62
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/CALOAD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/CASTORE.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/CHECKCAST.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/D2F.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/D2I.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/D2L.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DADD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DALOAD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DASTORE.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DCMPG.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DCMPL.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DCONST_0.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DCONST_1.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DDIV.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DLOAD.java86
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DMUL.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DNEG.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DREM.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DRETURN.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DSTORE.java85
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DSUB.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DUP.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DUP2.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DUP2_X1.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DUP2_X2.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DUP_X1.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/DUP_X2.java17
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/F2D.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/F2I.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/F2L.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FADD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FALOAD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FASTORE.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FCMPG.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FCMPL.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FCONST_0.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FCONST_1.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FCONST_2.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FDIV.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FLOAD.java86
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FMUL.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FNEG.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FREM.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FRETURN.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FSTORE.java85
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/FSUB.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/GETFIELD.java37
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/GETSTATIC.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/GOTO.java60
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/GOTO_W.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/I2B.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/I2C.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/I2D.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/I2F.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/I2L.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/I2S.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IADD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IALOAD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IAND.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IASTORE.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IDIV.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IFEQ.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IFGE.java34
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IFGT.java34
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IFLE.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IFLT.java34
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IFNE.java34
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IFNONNULL.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IFNULL.java34
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IF_ACMPEQ.java34
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IF_ACMPNE.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPEQ.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPGE.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPGT.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPLE.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPLT.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPNE.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IINC.java55
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ILOAD.java77
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IMUL.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/INEG.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/INSTANCEOF.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/INVOKEINTERFACE.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/INVOKESPECIAL.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/INVOKESTATIC.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/INVOKEVIRTUAL.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IOR.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IREM.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IRETURN.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ISHL.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ISHR.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ISTORE.java77
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/ISUB.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IUSHR.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/IXOR.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/JSR.java60
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/JSR_W.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/L2D.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/L2F.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/L2I.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LADD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LALOAD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LAND.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LASTORE.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LCMP.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LCONST_0.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LCONST_1.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LDC.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LDC2_W.java34
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LDC_W.java34
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LDIV.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LLOAD.java75
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LMUL.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LNEG.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LOOKUPSWITCH.java54
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LOR.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LREM.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LRETURN.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LSHL.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LSHR.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LSTORE.java77
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LSUB.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LUSHR.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/LXOR.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/MONITORENTER.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/MONITOREXIT.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/MULTIANEWARRAY.java38
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/NEW.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/NEWARRAY.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/NOP.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/POP.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/POP2.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/PUTFIELD.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/PUTSTATIC.java36
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/RET.java51
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/RETURN.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/SALOAD.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/SASTORE.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/SIPUSH.java34
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/SWAP.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/TABLESWITCH.java55
-rw-r--r--src/org/jetbrains/java/decompiler/code/instructions/XXXUNUSEDXXX.java15
-rw-r--r--src/org/jetbrains/java/decompiler/code/interpreter/InstructionImpact.java955
-rw-r--r--src/org/jetbrains/java/decompiler/code/interpreter/Util.java517
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/ALOAD.java90
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/ANEWARRAY.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/ASTORE.java90
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/BIPUSH.java66
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/CHECKCAST.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/DLOAD.java90
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/DSTORE.java89
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/FLOAD.java90
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/FSTORE.java89
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/GETFIELD.java41
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/GETSTATIC.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/GOTO.java64
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/GOTO_W.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/IINC.java59
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/ILOAD.java81
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/INSTANCEOF.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEDYNAMIC.java39
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEINTERFACE.java44
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESPECIAL.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESTATIC.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEVIRTUAL.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/ISTORE.java81
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/JSR.java64
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/JSR_W.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/LDC.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/LDC2_W.java38
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/LDC_W.java38
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/LLOAD.java79
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/LOOKUPSWITCH.java58
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/LSTORE.java81
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/MULTIANEWARRAY.java42
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/NEW.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/NEWARRAY.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/PUTFIELD.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/PUTSTATIC.java40
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/RET.java55
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/SIPUSH.java38
-rw-r--r--src/org/jetbrains/java/decompiler/code/optinstructions/TABLESWITCH.java59
-rw-r--r--src/org/jetbrains/java/decompiler/main/AssertProcessor.java590
-rw-r--r--src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java561
-rw-r--r--src/org/jetbrains/java/decompiler/main/ClassWriter.java2161
-rw-r--r--src/org/jetbrains/java/decompiler/main/ClassesProcessor.java834
-rw-r--r--src/org/jetbrains/java/decompiler/main/DecompilerContext.java359
-rw-r--r--src/org/jetbrains/java/decompiler/main/EnumProcessor.java261
-rw-r--r--src/org/jetbrains/java/decompiler/main/Fernflower.java171
-rw-r--r--src/org/jetbrains/java/decompiler/main/InitializerProcessor.java598
-rw-r--r--src/org/jetbrains/java/decompiler/main/collectors/CounterContainer.java50
-rw-r--r--src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java279
-rw-r--r--src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java77
-rw-r--r--src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java608
-rw-r--r--src/org/jetbrains/java/decompiler/main/decompiler/IdeDecompiler.java46
-rw-r--r--src/org/jetbrains/java/decompiler/main/decompiler/WebDecompiler.java124
-rw-r--r--src/org/jetbrains/java/decompiler/main/decompiler/helper/PrintStreamLogger.java141
-rw-r--r--src/org/jetbrains/java/decompiler/main/extern/IBytecodeProvider.java22
-rw-r--r--src/org/jetbrains/java/decompiler/main/extern/IDecompilatSaver.java44
-rw-r--r--src/org/jetbrains/java/decompiler/main/extern/IFernflowerLogger.java89
-rw-r--r--src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java91
-rw-r--r--src/org/jetbrains/java/decompiler/main/extern/IIdentifierRenamer.java39
-rw-r--r--src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java380
-rw-r--r--src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java247
-rw-r--r--src/org/jetbrains/java/decompiler/main/rels/MethodProcessorThread.java488
-rw-r--r--src/org/jetbrains/java/decompiler/main/rels/MethodWrapper.java86
-rw-r--r--src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java1992
-rw-r--r--src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java869
-rw-r--r--src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java839
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/ClearStructHelper.java53
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java396
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java412
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java1391
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java398
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java655
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java1719
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/ExprentStack.java69
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java2031
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java614
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java1444
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java415
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java1008
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java381
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java389
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java805
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java267
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/PrimitiveExprsList.java70
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java822
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java613
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java1672
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java1401
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java183
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/StrongConnectivityHelper.java305
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorEngine.java227
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java344
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java687
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/decompose/GenericDominatorEngine.java276
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraph.java26
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraphNode.java22
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java600
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/IrreducibleCFGDeobfuscator.java455
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java187
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java209
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java78
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java350
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java715
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java254
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java233
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java341
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java1157
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java257
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java950
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java127
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java981
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java197
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java354
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java240
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectNode.java107
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java1097
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java942
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java1634
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java157
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java428
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java375
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java410
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java121
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java782
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java71
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java254
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java1705
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java689
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java271
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java88
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java668
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java227
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java507
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionEdge.java92
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionNode.java132
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionPaar.java104
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java307
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java628
-rw-r--r--src/org/jetbrains/java/decompiler/modules/renamer/ClassWrapperNode.java78
-rw-r--r--src/org/jetbrains/java/decompiler/modules/renamer/ConverterHelper.java256
-rw-r--r--src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java875
-rw-r--r--src/org/jetbrains/java/decompiler/modules/renamer/PoolInterceptor.java72
-rw-r--r--src/org/jetbrains/java/decompiler/struct/ContextUnit.java390
-rw-r--r--src/org/jetbrains/java/decompiler/struct/IDecompiledData.java24
-rw-r--r--src/org/jetbrains/java/decompiler/struct/ISaveClass.java28
-rw-r--r--src/org/jetbrains/java/decompiler/struct/StructClass.java618
-rw-r--r--src/org/jetbrains/java/decompiler/struct/StructContext.java387
-rw-r--r--src/org/jetbrains/java/decompiler/struct/StructField.java173
-rw-r--r--src/org/jetbrains/java/decompiler/struct/StructMethod.java1068
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java52
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java337
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java83
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationTypeAttribute.java369
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java117
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java39
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java87
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java122
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java252
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java39
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java117
-rw-r--r--src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java71
-rw-r--r--src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java602
-rw-r--r--src/org/jetbrains/java/decompiler/struct/consts/LinkConstant.java283
-rw-r--r--src/org/jetbrains/java/decompiler/struct/consts/PooledConstant.java189
-rw-r--r--src/org/jetbrains/java/decompiler/struct/consts/PrimitiveConstant.java218
-rw-r--r--src/org/jetbrains/java/decompiler/struct/consts/VariableTypeEnum.java74
-rw-r--r--src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java170
-rw-r--r--src/org/jetbrains/java/decompiler/struct/gen/FieldDescriptor.java89
-rw-r--r--src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java160
-rw-r--r--src/org/jetbrains/java/decompiler/struct/gen/VarType.java808
-rw-r--r--src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java32
-rw-r--r--src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java22
-rw-r--r--src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java436
-rw-r--r--src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java34
-rw-r--r--src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java514
-rw-r--r--src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java340
-rw-r--r--src/org/jetbrains/java/decompiler/util/DataInputFullStream.java70
-rw-r--r--src/org/jetbrains/java/decompiler/util/FastFixedSetFactory.java699
-rw-r--r--src/org/jetbrains/java/decompiler/util/FastSetFactory.java943
-rw-r--r--src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java1071
-rw-r--r--src/org/jetbrains/java/decompiler/util/InterpreterUtil.java272
-rw-r--r--src/org/jetbrains/java/decompiler/util/ListStack.java178
-rw-r--r--src/org/jetbrains/java/decompiler/util/SFormsFastMap.java465
-rw-r--r--src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java796
-rw-r--r--src/org/jetbrains/java/decompiler/util/SFormsFastMapOld.java542
-rw-r--r--src/org/jetbrains/java/decompiler/util/VBStyleCollection.java380
355 files changed, 40736 insertions, 37835 deletions
diff --git a/src/org/jetbrains/java/decompiler/code/CodeConstants.java b/src/org/jetbrains/java/decompiler/code/CodeConstants.java
index 78cbcf0..de5198b 100644
--- a/src/org/jetbrains/java/decompiler/code/CodeConstants.java
+++ b/src/org/jetbrains/java/decompiler/code/CodeConstants.java
@@ -1,371 +1,370 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
public interface CodeConstants {
- // ----------------------------------------------------------------------
- // BYTECODE VERSIONS
- // ----------------------------------------------------------------------
-
- public final static int BYTECODE_JAVA_LE_4 = 1;
- public final static int BYTECODE_JAVA_5 = 2;
- public final static int BYTECODE_JAVA_6 = 3;
- public final static int BYTECODE_JAVA_7 = 4;
- public final static int BYTECODE_JAVA_8 = 5;
-
- // ----------------------------------------------------------------------
- // VARIABLE TYPES
- // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
+ // BYTECODE VERSIONS
+ // ----------------------------------------------------------------------
+
+ public final static int BYTECODE_JAVA_LE_4 = 1;
+ public final static int BYTECODE_JAVA_5 = 2;
+ public final static int BYTECODE_JAVA_6 = 3;
+ public final static int BYTECODE_JAVA_7 = 4;
+ public final static int BYTECODE_JAVA_8 = 5;
+
+ // ----------------------------------------------------------------------
+ // VARIABLE TYPES
+ // ----------------------------------------------------------------------
+
+ public final static int TYPE_BYTE = 0;
+ public final static int TYPE_CHAR = 1;
+ public final static int TYPE_DOUBLE = 2;
+ public final static int TYPE_FLOAT = 3;
+ public final static int TYPE_INT = 4;
+ public final static int TYPE_LONG = 5;
+ public final static int TYPE_SHORT = 6;
+ public final static int TYPE_BOOLEAN = 7;
+ public final static int TYPE_OBJECT = 8;
+ public final static int TYPE_ADDRESS = 9;
+ public final static int TYPE_VOID = 10;
+ public final static int TYPE_ANY = 11;
+ public final static int TYPE_GROUP2EMPTY = 12;
+ public final static int TYPE_NULL = 13;
+ public final static int TYPE_NOTINITIALIZED = 14;
+ public final static int TYPE_BYTECHAR = 15;
+ public final static int TYPE_SHORTCHAR = 16;
+ public final static int TYPE_UNKNOWN = 17;
+ public final static int TYPE_GENVAR = 18;
+
+ // ----------------------------------------------------------------------
+ // VARIABLE TYPE FAMILIES
+ // ----------------------------------------------------------------------
+
+ public final static int TYPE_FAMILY_UNKNOWN = 0;
+ public final static int TYPE_FAMILY_BOOLEAN = 1;
+ public final static int TYPE_FAMILY_INTEGER = 2;
+ public final static int TYPE_FAMILY_FLOAT = 3;
+ public final static int TYPE_FAMILY_LONG = 4;
+ public final static int TYPE_FAMILY_DOUBLE = 5;
+ public final static int TYPE_FAMILY_OBJECT = 6;
+
+ // ----------------------------------------------------------------------
+ // MODULE CONSTANTS
+ // ----------------------------------------------------------------------
+
+ public final static int STACKSIZE_SIMPLE = 1;
+ public final static int STACKSIZE_DOUBLE = 2;
+
+ public final static int VAR_LOCAL = 0;
+ public final static int VAR_STACK = 1;
+
+ public final static int VAR_WRITE = 0;
+ public final static int VAR_READ = 1;
+
+
+ // ----------------------------------------------------------------------
+ // ACCESS FLAGS
+ // ----------------------------------------------------------------------
+
+ public final static int ACC_PUBLIC = 0x0001;
+ public final static int ACC_PRIVATE = 0x0002;
+ public final static int ACC_PROTECTED = 0x0004;
+ public final static int ACC_STATIC = 0x0008;
+ public final static int ACC_FINAL = 0x0010;
+ public final static int ACC_SYNCHRONIZED = 0x0020;
+ public final static int ACC_NATIVE = 0x0100;
+ public final static int ACC_ABSTRACT = 0x0400;
+ public final static int ACC_STRICT = 0x0800;
+ public final static int ACC_VOLATILE = 0x0040;
+ public final static int ACC_BRIDGE = 0x0040;
+ public final static int ACC_TRANSIENT = 0x0080;
+ public final static int ACC_VARARGS = 0x0080;
+ public final static int ACC_SYNTHETIC = 0x1000;
+ public final static int ACC_ANNOTATION = 0x2000;
+ public final static int ACC_ENUM = 0x4000;
+
+ // ----------------------------------------------------------------------
+ // CLASS FLAGS
+ // ----------------------------------------------------------------------
+
+ public final static int ACC_SUPER = 0x0020;
+ public final static int ACC_INTERFACE = 0x0200;
+
+
+ // ----------------------------------------------------------------------
+ // DEPENDENCY CONSTANTS
+ // ----------------------------------------------------------------------
- public final static int TYPE_BYTE = 0;
- public final static int TYPE_CHAR = 1;
- public final static int TYPE_DOUBLE = 2;
- public final static int TYPE_FLOAT = 3;
- public final static int TYPE_INT = 4;
- public final static int TYPE_LONG = 5;
- public final static int TYPE_SHORT = 6;
- public final static int TYPE_BOOLEAN = 7;
- public final static int TYPE_OBJECT = 8;
- public final static int TYPE_ADDRESS = 9;
- public final static int TYPE_VOID = 10;
- public final static int TYPE_ANY = 11;
- public final static int TYPE_GROUP2EMPTY = 12;
- public final static int TYPE_NULL = 13;
- public final static int TYPE_NOTINITIALIZED = 14;
- public final static int TYPE_BYTECHAR = 15;
- public final static int TYPE_SHORTCHAR = 16;
- public final static int TYPE_UNKNOWN = 17;
- public final static int TYPE_GENVAR = 18;
+ public final static int DEP_CONSTANT = 0;
+ public final static int DEP_UNKNOWN = 1;
+ public final static int DEP_GENERAL = 2;
+ public final static int DEP_PARAMS = 4;
+ public final static int DEP_STATIC = 8;
- // ----------------------------------------------------------------------
- // VARIABLE TYPE FAMILIES
- // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
+ // INSTRUCTION GROUPS
+ // ----------------------------------------------------------------------
- public final static int TYPE_FAMILY_UNKNOWN = 0;
- public final static int TYPE_FAMILY_BOOLEAN = 1;
- public final static int TYPE_FAMILY_INTEGER = 2;
- public final static int TYPE_FAMILY_FLOAT = 3;
- public final static int TYPE_FAMILY_LONG = 4;
- public final static int TYPE_FAMILY_DOUBLE = 5;
- public final static int TYPE_FAMILY_OBJECT = 6;
-
- // ----------------------------------------------------------------------
- // MODULE CONSTANTS
- // ----------------------------------------------------------------------
+ public final static int GROUP_GENERAL = 1;
+ public final static int GROUP_JUMP = 2;
+ public final static int GROUP_SWITCH = 3;
+ public final static int GROUP_INVOCATION = 4;
+ public final static int GROUP_FIELDACCESS = 5;
+ public final static int GROUP_RETURN = 6;
- public final static int STACKSIZE_SIMPLE = 1;
- public final static int STACKSIZE_DOUBLE = 2;
-
- public final static int VAR_LOCAL = 0;
- public final static int VAR_STACK = 1;
-
- public final static int VAR_WRITE = 0;
- public final static int VAR_READ = 1;
-
-
- // ----------------------------------------------------------------------
- // ACCESS FLAGS
- // ----------------------------------------------------------------------
-
- public final static int ACC_PUBLIC = 0x0001;
- public final static int ACC_PRIVATE = 0x0002;
- public final static int ACC_PROTECTED = 0x0004;
- public final static int ACC_STATIC = 0x0008;
- public final static int ACC_FINAL = 0x0010;
- public final static int ACC_SYNCHRONIZED = 0x0020;
- public final static int ACC_NATIVE = 0x0100;
- public final static int ACC_ABSTRACT = 0x0400;
- public final static int ACC_STRICT = 0x0800;
- public final static int ACC_VOLATILE = 0x0040;
- public final static int ACC_BRIDGE = 0x0040;
- public final static int ACC_TRANSIENT = 0x0080;
- public final static int ACC_VARARGS = 0x0080;
- public final static int ACC_SYNTHETIC = 0x1000;
- public final static int ACC_ANNOTATION = 0x2000;
- public final static int ACC_ENUM = 0x4000;
+ // ----------------------------------------------------------------------
+ // POOL CONSTANTS
+ // ----------------------------------------------------------------------
- // ----------------------------------------------------------------------
- // CLASS FLAGS
- // ----------------------------------------------------------------------
-
- public final static int ACC_SUPER = 0x0020;
- public final static int ACC_INTERFACE = 0x0200;
-
+ public final static int CONSTANT_Utf8 = 1;
+ public final static int CONSTANT_Integer = 3;
+ public final static int CONSTANT_Float = 4;
+ public final static int CONSTANT_Long = 5;
+ public final static int CONSTANT_Double = 6;
+ public final static int CONSTANT_Class = 7;
+ public final static int CONSTANT_String = 8;
+ public final static int CONSTANT_Fieldref = 9;
+ public final static int CONSTANT_Methodref = 10;
+ public final static int CONSTANT_InterfaceMethodref = 11;
+ public final static int CONSTANT_NameAndType = 12;
+ public final static int CONSTANT_MethodHandle = 15;
+ public final static int CONSTANT_MethodType = 16;
+ public final static int CONSTANT_InvokeDynamic = 18;
- // ----------------------------------------------------------------------
- // DEPENDENCY CONSTANTS
- // ----------------------------------------------------------------------
-
- public final static int DEP_CONSTANT = 0;
- public final static int DEP_UNKNOWN = 1;
- public final static int DEP_GENERAL = 2;
- public final static int DEP_PARAMS = 4;
- public final static int DEP_STATIC = 8;
+ // ----------------------------------------------------------------------
+ // MethodHandle reference_kind values
+ // ----------------------------------------------------------------------
- // ----------------------------------------------------------------------
- // INSTRUCTION GROUPS
- // ----------------------------------------------------------------------
-
- public final static int GROUP_GENERAL = 1;
- public final static int GROUP_JUMP = 2;
- public final static int GROUP_SWITCH = 3;
- public final static int GROUP_INVOCATION = 4;
- public final static int GROUP_FIELDACCESS = 5;
- public final static int GROUP_RETURN = 6;
-
- // ----------------------------------------------------------------------
- // POOL CONSTANTS
- // ----------------------------------------------------------------------
-
- public final static int CONSTANT_Utf8 = 1;
- public final static int CONSTANT_Integer = 3;
- public final static int CONSTANT_Float = 4;
- public final static int CONSTANT_Long = 5;
- public final static int CONSTANT_Double = 6;
- public final static int CONSTANT_Class = 7;
- public final static int CONSTANT_String = 8;
- public final static int CONSTANT_Fieldref = 9;
- public final static int CONSTANT_Methodref = 10;
- public final static int CONSTANT_InterfaceMethodref = 11;
- public final static int CONSTANT_NameAndType = 12;
- public final static int CONSTANT_MethodHandle = 15;
- public final static int CONSTANT_MethodType = 16;
- public final static int CONSTANT_InvokeDynamic = 18;
-
- // ----------------------------------------------------------------------
- // MethodHandle reference_kind values
- // ----------------------------------------------------------------------
+ public final static int CONSTANT_MethodHandle_REF_getField = 1;
+ public final static int CONSTANT_MethodHandle_REF_getStatic = 2;
+ public final static int CONSTANT_MethodHandle_REF_putField = 3;
+ public final static int CONSTANT_MethodHandle_REF_putStatic = 4;
+ public final static int CONSTANT_MethodHandle_REF_invokeVirtual = 5;
+ public final static int CONSTANT_MethodHandle_REF_invokeStatic = 6;
+ public final static int CONSTANT_MethodHandle_REF_invokeSpecial = 7;
+ public final static int CONSTANT_MethodHandle_REF_newInvokeSpecial = 8;
+ public final static int CONSTANT_MethodHandle_REF_invokeInterface = 9;
- public final static int CONSTANT_MethodHandle_REF_getField = 1;
- public final static int CONSTANT_MethodHandle_REF_getStatic = 2;
- public final static int CONSTANT_MethodHandle_REF_putField = 3;
- public final static int CONSTANT_MethodHandle_REF_putStatic = 4;
- public final static int CONSTANT_MethodHandle_REF_invokeVirtual = 5;
- public final static int CONSTANT_MethodHandle_REF_invokeStatic = 6;
- public final static int CONSTANT_MethodHandle_REF_invokeSpecial = 7;
- public final static int CONSTANT_MethodHandle_REF_newInvokeSpecial = 8;
- public final static int CONSTANT_MethodHandle_REF_invokeInterface = 9;
-
- // ----------------------------------------------------------------------
- // VM OPCODES
- // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
+ // VM OPCODES
+ // ----------------------------------------------------------------------
- public final static int opc_nop = 0;
- public final static int opc_aconst_null = 1;
- public final static int opc_iconst_m1 = 2;
- public final static int opc_iconst_0 = 3;
- public final static int opc_iconst_1 = 4;
- public final static int opc_iconst_2 = 5;
- public final static int opc_iconst_3 = 6;
- public final static int opc_iconst_4 = 7;
- public final static int opc_iconst_5 = 8;
- public final static int opc_lconst_0 = 9;
- public final static int opc_lconst_1 = 10;
- public final static int opc_fconst_0 = 11;
- public final static int opc_fconst_1 = 12;
- public final static int opc_fconst_2 = 13;
- public final static int opc_dconst_0 = 14;
- public final static int opc_dconst_1 = 15;
- public final static int opc_bipush = 16;
- public final static int opc_sipush = 17;
- public final static int opc_ldc = 18;
- public final static int opc_ldc_w = 19;
- public final static int opc_ldc2_w = 20;
- public final static int opc_iload = 21;
- public final static int opc_lload = 22;
- public final static int opc_fload = 23;
- public final static int opc_dload = 24;
- public final static int opc_aload = 25;
- public final static int opc_iload_0 = 26;
- public final static int opc_iload_1 = 27;
- public final static int opc_iload_2 = 28;
- public final static int opc_iload_3 = 29;
- public final static int opc_lload_0 = 30;
- public final static int opc_lload_1 = 31;
- public final static int opc_lload_2 = 32;
- public final static int opc_lload_3 = 33;
- public final static int opc_fload_0 = 34;
- public final static int opc_fload_1 = 35;
- public final static int opc_fload_2 = 36;
- public final static int opc_fload_3 = 37;
- public final static int opc_dload_0 = 38;
- public final static int opc_dload_1 = 39;
- public final static int opc_dload_2 = 40;
- public final static int opc_dload_3 = 41;
- public final static int opc_aload_0 = 42;
- public final static int opc_aload_1 = 43;
- public final static int opc_aload_2 = 44;
- public final static int opc_aload_3 = 45;
- public final static int opc_iaload = 46;
- public final static int opc_laload = 47;
- public final static int opc_faload = 48;
- public final static int opc_daload = 49;
- public final static int opc_aaload = 50;
- public final static int opc_baload = 51;
- public final static int opc_caload = 52;
- public final static int opc_saload = 53;
- public final static int opc_istore = 54;
- public final static int opc_lstore = 55;
- public final static int opc_fstore = 56;
- public final static int opc_dstore = 57;
- public final static int opc_astore = 58;
- public final static int opc_istore_0 = 59;
- public final static int opc_istore_1 = 60;
- public final static int opc_istore_2 = 61;
- public final static int opc_istore_3 = 62;
- public final static int opc_lstore_0 = 63;
- public final static int opc_lstore_1 = 64;
- public final static int opc_lstore_2 = 65;
- public final static int opc_lstore_3 = 66;
- public final static int opc_fstore_0 = 67;
- public final static int opc_fstore_1 = 68;
- public final static int opc_fstore_2 = 69;
- public final static int opc_fstore_3 = 70;
- public final static int opc_dstore_0 = 71;
- public final static int opc_dstore_1 = 72;
- public final static int opc_dstore_2 = 73;
- public final static int opc_dstore_3 = 74;
- public final static int opc_astore_0 = 75;
- public final static int opc_astore_1 = 76;
- public final static int opc_astore_2 = 77;
- public final static int opc_astore_3 = 78;
- public final static int opc_iastore = 79;
- public final static int opc_lastore = 80;
- public final static int opc_fastore = 81;
- public final static int opc_dastore = 82;
- public final static int opc_aastore = 83;
- public final static int opc_bastore = 84;
- public final static int opc_castore = 85;
- public final static int opc_sastore = 86;
- public final static int opc_pop = 87;
- public final static int opc_pop2 = 88;
- public final static int opc_dup = 89;
- public final static int opc_dup_x1 = 90;
- public final static int opc_dup_x2 = 91;
- public final static int opc_dup2 = 92;
- public final static int opc_dup2_x1 = 93;
- public final static int opc_dup2_x2 = 94;
- public final static int opc_swap = 95;
- public final static int opc_iadd = 96;
- public final static int opc_ladd = 97;
- public final static int opc_fadd = 98;
- public final static int opc_dadd = 99;
- public final static int opc_isub = 100;
- public final static int opc_lsub = 101;
- public final static int opc_fsub = 102;
- public final static int opc_dsub = 103;
- public final static int opc_imul = 104;
- public final static int opc_lmul = 105;
- public final static int opc_fmul = 106;
- public final static int opc_dmul = 107;
- public final static int opc_idiv = 108;
- public final static int opc_ldiv = 109;
- public final static int opc_fdiv = 110;
- public final static int opc_ddiv = 111;
- public final static int opc_irem = 112;
- public final static int opc_lrem = 113;
- public final static int opc_frem = 114;
- public final static int opc_drem = 115;
- public final static int opc_ineg = 116;
- public final static int opc_lneg = 117;
- public final static int opc_fneg = 118;
- public final static int opc_dneg = 119;
- public final static int opc_ishl = 120;
- public final static int opc_lshl = 121;
- public final static int opc_ishr = 122;
- public final static int opc_lshr = 123;
- public final static int opc_iushr = 124;
- public final static int opc_lushr = 125;
- public final static int opc_iand = 126;
- public final static int opc_land = 127;
- public final static int opc_ior = 128;
- public final static int opc_lor = 129;
- public final static int opc_ixor = 130;
- public final static int opc_lxor = 131;
- public final static int opc_iinc = 132;
- public final static int opc_i2l = 133;
- public final static int opc_i2f = 134;
- public final static int opc_i2d = 135;
- public final static int opc_l2i = 136;
- public final static int opc_l2f = 137;
- public final static int opc_l2d = 138;
- public final static int opc_f2i = 139;
- public final static int opc_f2l = 140;
- public final static int opc_f2d = 141;
- public final static int opc_d2i = 142;
- public final static int opc_d2l = 143;
- public final static int opc_d2f = 144;
- public final static int opc_i2b = 145;
- public final static int opc_i2c = 146;
- public final static int opc_i2s = 147;
- public final static int opc_lcmp = 148;
- public final static int opc_fcmpl = 149;
- public final static int opc_fcmpg = 150;
- public final static int opc_dcmpl = 151;
- public final static int opc_dcmpg = 152;
- public final static int opc_ifeq = 153;
- public final static int opc_ifne = 154;
- public final static int opc_iflt = 155;
- public final static int opc_ifge = 156;
- public final static int opc_ifgt = 157;
- public final static int opc_ifle = 158;
- public final static int opc_if_icmpeq = 159;
- public final static int opc_if_icmpne = 160;
- public final static int opc_if_icmplt = 161;
- public final static int opc_if_icmpge = 162;
- public final static int opc_if_icmpgt = 163;
- public final static int opc_if_icmple = 164;
- public final static int opc_if_acmpeq = 165;
- public final static int opc_if_acmpne = 166;
- public final static int opc_goto = 167;
- public final static int opc_jsr = 168;
- public final static int opc_ret = 169;
- public final static int opc_tableswitch = 170;
- public final static int opc_lookupswitch = 171;
- public final static int opc_ireturn = 172;
- public final static int opc_lreturn = 173;
- public final static int opc_freturn = 174;
- public final static int opc_dreturn = 175;
- public final static int opc_areturn = 176;
- public final static int opc_return = 177;
- public final static int opc_getstatic = 178;
- public final static int opc_putstatic = 179;
- public final static int opc_getfield = 180;
- public final static int opc_putfield = 181;
- public final static int opc_invokevirtual = 182;
- public final static int opc_invokespecial = 183;
- public final static int opc_invokestatic = 184;
- public final static int opc_invokeinterface = 185;
- public final static int opc_invokedynamic = 186;
- public final static int opc_xxxunusedxxx = 186;
- public final static int opc_new = 187;
- public final static int opc_newarray = 188;
- public final static int opc_anewarray = 189;
- public final static int opc_arraylength = 190;
- public final static int opc_athrow = 191;
- public final static int opc_checkcast = 192;
- public final static int opc_instanceof = 193;
- public final static int opc_monitorenter = 194;
- public final static int opc_monitorexit = 195;
- public final static int opc_wide = 196;
- public final static int opc_multianewarray = 197;
- public final static int opc_ifnull = 198;
- public final static int opc_ifnonnull = 199;
- public final static int opc_goto_w = 200;
- public final static int opc_jsr_w = 201;
-
-
+ public final static int opc_nop = 0;
+ public final static int opc_aconst_null = 1;
+ public final static int opc_iconst_m1 = 2;
+ public final static int opc_iconst_0 = 3;
+ public final static int opc_iconst_1 = 4;
+ public final static int opc_iconst_2 = 5;
+ public final static int opc_iconst_3 = 6;
+ public final static int opc_iconst_4 = 7;
+ public final static int opc_iconst_5 = 8;
+ public final static int opc_lconst_0 = 9;
+ public final static int opc_lconst_1 = 10;
+ public final static int opc_fconst_0 = 11;
+ public final static int opc_fconst_1 = 12;
+ public final static int opc_fconst_2 = 13;
+ public final static int opc_dconst_0 = 14;
+ public final static int opc_dconst_1 = 15;
+ public final static int opc_bipush = 16;
+ public final static int opc_sipush = 17;
+ public final static int opc_ldc = 18;
+ public final static int opc_ldc_w = 19;
+ public final static int opc_ldc2_w = 20;
+ public final static int opc_iload = 21;
+ public final static int opc_lload = 22;
+ public final static int opc_fload = 23;
+ public final static int opc_dload = 24;
+ public final static int opc_aload = 25;
+ public final static int opc_iload_0 = 26;
+ public final static int opc_iload_1 = 27;
+ public final static int opc_iload_2 = 28;
+ public final static int opc_iload_3 = 29;
+ public final static int opc_lload_0 = 30;
+ public final static int opc_lload_1 = 31;
+ public final static int opc_lload_2 = 32;
+ public final static int opc_lload_3 = 33;
+ public final static int opc_fload_0 = 34;
+ public final static int opc_fload_1 = 35;
+ public final static int opc_fload_2 = 36;
+ public final static int opc_fload_3 = 37;
+ public final static int opc_dload_0 = 38;
+ public final static int opc_dload_1 = 39;
+ public final static int opc_dload_2 = 40;
+ public final static int opc_dload_3 = 41;
+ public final static int opc_aload_0 = 42;
+ public final static int opc_aload_1 = 43;
+ public final static int opc_aload_2 = 44;
+ public final static int opc_aload_3 = 45;
+ public final static int opc_iaload = 46;
+ public final static int opc_laload = 47;
+ public final static int opc_faload = 48;
+ public final static int opc_daload = 49;
+ public final static int opc_aaload = 50;
+ public final static int opc_baload = 51;
+ public final static int opc_caload = 52;
+ public final static int opc_saload = 53;
+ public final static int opc_istore = 54;
+ public final static int opc_lstore = 55;
+ public final static int opc_fstore = 56;
+ public final static int opc_dstore = 57;
+ public final static int opc_astore = 58;
+ public final static int opc_istore_0 = 59;
+ public final static int opc_istore_1 = 60;
+ public final static int opc_istore_2 = 61;
+ public final static int opc_istore_3 = 62;
+ public final static int opc_lstore_0 = 63;
+ public final static int opc_lstore_1 = 64;
+ public final static int opc_lstore_2 = 65;
+ public final static int opc_lstore_3 = 66;
+ public final static int opc_fstore_0 = 67;
+ public final static int opc_fstore_1 = 68;
+ public final static int opc_fstore_2 = 69;
+ public final static int opc_fstore_3 = 70;
+ public final static int opc_dstore_0 = 71;
+ public final static int opc_dstore_1 = 72;
+ public final static int opc_dstore_2 = 73;
+ public final static int opc_dstore_3 = 74;
+ public final static int opc_astore_0 = 75;
+ public final static int opc_astore_1 = 76;
+ public final static int opc_astore_2 = 77;
+ public final static int opc_astore_3 = 78;
+ public final static int opc_iastore = 79;
+ public final static int opc_lastore = 80;
+ public final static int opc_fastore = 81;
+ public final static int opc_dastore = 82;
+ public final static int opc_aastore = 83;
+ public final static int opc_bastore = 84;
+ public final static int opc_castore = 85;
+ public final static int opc_sastore = 86;
+ public final static int opc_pop = 87;
+ public final static int opc_pop2 = 88;
+ public final static int opc_dup = 89;
+ public final static int opc_dup_x1 = 90;
+ public final static int opc_dup_x2 = 91;
+ public final static int opc_dup2 = 92;
+ public final static int opc_dup2_x1 = 93;
+ public final static int opc_dup2_x2 = 94;
+ public final static int opc_swap = 95;
+ public final static int opc_iadd = 96;
+ public final static int opc_ladd = 97;
+ public final static int opc_fadd = 98;
+ public final static int opc_dadd = 99;
+ public final static int opc_isub = 100;
+ public final static int opc_lsub = 101;
+ public final static int opc_fsub = 102;
+ public final static int opc_dsub = 103;
+ public final static int opc_imul = 104;
+ public final static int opc_lmul = 105;
+ public final static int opc_fmul = 106;
+ public final static int opc_dmul = 107;
+ public final static int opc_idiv = 108;
+ public final static int opc_ldiv = 109;
+ public final static int opc_fdiv = 110;
+ public final static int opc_ddiv = 111;
+ public final static int opc_irem = 112;
+ public final static int opc_lrem = 113;
+ public final static int opc_frem = 114;
+ public final static int opc_drem = 115;
+ public final static int opc_ineg = 116;
+ public final static int opc_lneg = 117;
+ public final static int opc_fneg = 118;
+ public final static int opc_dneg = 119;
+ public final static int opc_ishl = 120;
+ public final static int opc_lshl = 121;
+ public final static int opc_ishr = 122;
+ public final static int opc_lshr = 123;
+ public final static int opc_iushr = 124;
+ public final static int opc_lushr = 125;
+ public final static int opc_iand = 126;
+ public final static int opc_land = 127;
+ public final static int opc_ior = 128;
+ public final static int opc_lor = 129;
+ public final static int opc_ixor = 130;
+ public final static int opc_lxor = 131;
+ public final static int opc_iinc = 132;
+ public final static int opc_i2l = 133;
+ public final static int opc_i2f = 134;
+ public final static int opc_i2d = 135;
+ public final static int opc_l2i = 136;
+ public final static int opc_l2f = 137;
+ public final static int opc_l2d = 138;
+ public final static int opc_f2i = 139;
+ public final static int opc_f2l = 140;
+ public final static int opc_f2d = 141;
+ public final static int opc_d2i = 142;
+ public final static int opc_d2l = 143;
+ public final static int opc_d2f = 144;
+ public final static int opc_i2b = 145;
+ public final static int opc_i2c = 146;
+ public final static int opc_i2s = 147;
+ public final static int opc_lcmp = 148;
+ public final static int opc_fcmpl = 149;
+ public final static int opc_fcmpg = 150;
+ public final static int opc_dcmpl = 151;
+ public final static int opc_dcmpg = 152;
+ public final static int opc_ifeq = 153;
+ public final static int opc_ifne = 154;
+ public final static int opc_iflt = 155;
+ public final static int opc_ifge = 156;
+ public final static int opc_ifgt = 157;
+ public final static int opc_ifle = 158;
+ public final static int opc_if_icmpeq = 159;
+ public final static int opc_if_icmpne = 160;
+ public final static int opc_if_icmplt = 161;
+ public final static int opc_if_icmpge = 162;
+ public final static int opc_if_icmpgt = 163;
+ public final static int opc_if_icmple = 164;
+ public final static int opc_if_acmpeq = 165;
+ public final static int opc_if_acmpne = 166;
+ public final static int opc_goto = 167;
+ public final static int opc_jsr = 168;
+ public final static int opc_ret = 169;
+ public final static int opc_tableswitch = 170;
+ public final static int opc_lookupswitch = 171;
+ public final static int opc_ireturn = 172;
+ public final static int opc_lreturn = 173;
+ public final static int opc_freturn = 174;
+ public final static int opc_dreturn = 175;
+ public final static int opc_areturn = 176;
+ public final static int opc_return = 177;
+ public final static int opc_getstatic = 178;
+ public final static int opc_putstatic = 179;
+ public final static int opc_getfield = 180;
+ public final static int opc_putfield = 181;
+ public final static int opc_invokevirtual = 182;
+ public final static int opc_invokespecial = 183;
+ public final static int opc_invokestatic = 184;
+ public final static int opc_invokeinterface = 185;
+ public final static int opc_invokedynamic = 186;
+ public final static int opc_xxxunusedxxx = 186;
+ public final static int opc_new = 187;
+ public final static int opc_newarray = 188;
+ public final static int opc_anewarray = 189;
+ public final static int opc_arraylength = 190;
+ public final static int opc_athrow = 191;
+ public final static int opc_checkcast = 192;
+ public final static int opc_instanceof = 193;
+ public final static int opc_monitorenter = 194;
+ public final static int opc_monitorexit = 195;
+ public final static int opc_wide = 196;
+ public final static int opc_multianewarray = 197;
+ public final static int opc_ifnull = 198;
+ public final static int opc_ifnonnull = 199;
+ public final static int opc_goto_w = 200;
+ public final static int opc_jsr_w = 201;
}
diff --git a/src/org/jetbrains/java/decompiler/code/ConstantsUtil.java b/src/org/jetbrains/java/decompiler/code/ConstantsUtil.java
index dcaea77..79eecdf 100644
--- a/src/org/jetbrains/java/decompiler/code/ConstantsUtil.java
+++ b/src/org/jetbrains/java/decompiler/code/ConstantsUtil.java
@@ -1,519 +1,482 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
-import org.jetbrains.java.decompiler.code.optinstructions.ALOAD;
-import org.jetbrains.java.decompiler.code.optinstructions.ANEWARRAY;
-import org.jetbrains.java.decompiler.code.optinstructions.ASTORE;
-import org.jetbrains.java.decompiler.code.optinstructions.BIPUSH;
-import org.jetbrains.java.decompiler.code.optinstructions.CHECKCAST;
-import org.jetbrains.java.decompiler.code.optinstructions.DLOAD;
-import org.jetbrains.java.decompiler.code.optinstructions.DSTORE;
-import org.jetbrains.java.decompiler.code.optinstructions.FLOAD;
-import org.jetbrains.java.decompiler.code.optinstructions.FSTORE;
-import org.jetbrains.java.decompiler.code.optinstructions.GETFIELD;
-import org.jetbrains.java.decompiler.code.optinstructions.GETSTATIC;
-import org.jetbrains.java.decompiler.code.optinstructions.GOTO;
-import org.jetbrains.java.decompiler.code.optinstructions.GOTO_W;
-import org.jetbrains.java.decompiler.code.optinstructions.IINC;
-import org.jetbrains.java.decompiler.code.optinstructions.ILOAD;
-import org.jetbrains.java.decompiler.code.optinstructions.INSTANCEOF;
-import org.jetbrains.java.decompiler.code.optinstructions.INVOKEDYNAMIC;
-import org.jetbrains.java.decompiler.code.optinstructions.INVOKEINTERFACE;
-import org.jetbrains.java.decompiler.code.optinstructions.INVOKESPECIAL;
-import org.jetbrains.java.decompiler.code.optinstructions.INVOKESTATIC;
-import org.jetbrains.java.decompiler.code.optinstructions.INVOKEVIRTUAL;
-import org.jetbrains.java.decompiler.code.optinstructions.ISTORE;
-import org.jetbrains.java.decompiler.code.optinstructions.JSR;
-import org.jetbrains.java.decompiler.code.optinstructions.JSR_W;
-import org.jetbrains.java.decompiler.code.optinstructions.LDC;
-import org.jetbrains.java.decompiler.code.optinstructions.LDC2_W;
-import org.jetbrains.java.decompiler.code.optinstructions.LDC_W;
-import org.jetbrains.java.decompiler.code.optinstructions.LLOAD;
-import org.jetbrains.java.decompiler.code.optinstructions.LOOKUPSWITCH;
-import org.jetbrains.java.decompiler.code.optinstructions.LSTORE;
-import org.jetbrains.java.decompiler.code.optinstructions.MULTIANEWARRAY;
-import org.jetbrains.java.decompiler.code.optinstructions.NEW;
-import org.jetbrains.java.decompiler.code.optinstructions.NEWARRAY;
-import org.jetbrains.java.decompiler.code.optinstructions.PUTFIELD;
-import org.jetbrains.java.decompiler.code.optinstructions.PUTSTATIC;
-import org.jetbrains.java.decompiler.code.optinstructions.RET;
-import org.jetbrains.java.decompiler.code.optinstructions.SIPUSH;
-import org.jetbrains.java.decompiler.code.optinstructions.TABLESWITCH;
+import org.jetbrains.java.decompiler.code.optinstructions.*;
public class ConstantsUtil {
-
- public static String getName(int opcode) {
- return opcodeNames[opcode];
- }
- public static Instruction getInstructionInstance(int opcode, boolean wide, int group, int bytecode_version, int[] operands) {
+ public static String getName(int opcode) {
+ return opcodeNames[opcode];
+ }
+
+ public static Instruction getInstructionInstance(int opcode, boolean wide, int group, int bytecode_version, int[] operands) {
+
+ Instruction instr = getInstructionInstance(opcode, bytecode_version);
+ instr.wide = wide;
+ instr.group = group;
+ instr.bytecode_version = bytecode_version;
+ instr.setOperands(operands);
+
+ return instr;
+ }
+
+ private static Instruction getInstructionInstance(int opcode, int bytecode_version) {
+ try {
+ Instruction instr;
+
+ if ((opcode >= CodeConstants.opc_ifeq &&
+ opcode <= CodeConstants.opc_if_acmpne) ||
+ opcode == CodeConstants.opc_ifnull ||
+ opcode == CodeConstants.opc_ifnonnull) {
+ instr = new IfInstruction();
+ }
+ else {
+
+ Class cl = opcodeClasses[opcode];
+
+ if (opcode == CodeConstants.opc_invokedynamic && bytecode_version < CodeConstants.BYTECODE_JAVA_7) {
+ cl = null; // instruction unused in Java 6 and before
+ }
- Instruction instr = getInstructionInstance(opcode, bytecode_version);
- instr.wide = wide;
- instr.group = group;
- instr.bytecode_version = bytecode_version;
- instr.setOperands(operands);
+ if (cl == null) {
+ instr = new Instruction();
+ }
+ else {
+ instr = (Instruction)cl.newInstance();
+ }
+ }
- return instr;
- }
-
- private static Instruction getInstructionInstance(int opcode, int bytecode_version) {
- try {
- Instruction instr;
-
- if((opcode >= CodeConstants.opc_ifeq &&
- opcode <= CodeConstants.opc_if_acmpne) ||
- opcode == CodeConstants.opc_ifnull ||
- opcode == CodeConstants.opc_ifnonnull) {
- instr = new IfInstruction();
- } else {
+ instr.opcode = opcode;
+ return instr;
+ }
+ catch (Exception ex) {
+ return null;
+ }
+ }
- Class cl = opcodeClasses[opcode];
-
- if(opcode == CodeConstants.opc_invokedynamic && bytecode_version < CodeConstants.BYTECODE_JAVA_7) {
- cl = null; // instruction unused in Java 6 and before
- }
-
- if(cl == null) {
- instr = new Instruction();
- } else {
- instr = (Instruction)cl.newInstance();
- }
- }
-
- instr.opcode = opcode;
- return instr;
- } catch (Exception ex) {
- return null;
- }
-
- }
-
- private static String[] opcodeNames = {
- "nop", // "nop",
- "aconst_null", // "aconst_null",
- "iconst_m1", // "iconst_m1",
- "iconst_0", // "iconst_0",
- "iconst_1", // "iconst_1",
- "iconst_2", // "iconst_2",
- "iconst_3", // "iconst_3",
- "iconst_4", // "iconst_4",
- "iconst_5", // "iconst_5",
- "lconst_0", // "lconst_0",
- "lconst_1", // "lconst_1",
- "fconst_0", // "fconst_0",
- "fconst_1", // "fconst_1",
- "fconst_2", // "fconst_2",
- "dconst_0", // "dconst_0",
- "dconst_1", // "dconst_1",
- "bipush", // "bipush",
- "sipush", // "sipush",
- "ldc", // "ldc",
- "ldc_w", // "ldc_w",
- "ldc2_w", // "ldc2_w",
- "iload", // "iload",
- "lload", // "lload",
- "fload", // "fload",
- "dload", // "dload",
- "aload", // "aload",
- "iload_0", // "iload_0",
- "iload_1", // "iload_1",
- "iload_2", // "iload_2",
- "iload_3", // "iload_3",
- "lload_0", // "lload_0",
- "lload_1", // "lload_1",
- "lload_2", // "lload_2",
- "lload_3", // "lload_3",
- "fload_0", // "fload_0",
- "fload_1", // "fload_1",
- "fload_2", // "fload_2",
- "fload_3", // "fload_3",
- "dload_0", // "dload_0",
- "dload_1", // "dload_1",
- "dload_2", // "dload_2",
- "dload_3", // "dload_3",
- "aload_0", // "aload_0",
- "aload_1", // "aload_1",
- "aload_2", // "aload_2",
- "aload_3", // "aload_3",
- "iaload", // "iaload",
- "laload", // "laload",
- "faload", // "faload",
- "daload", // "daload",
- "aaload", // "aaload",
- "baload", // "baload",
- "caload", // "caload",
- "saload", // "saload",
- "istore", // "istore",
- "lstore", // "lstore",
- "fstore", // "fstore",
- "dstore", // "dstore",
- "astore", // "astore",
- "istore_0", // "istore_0",
- "istore_1", // "istore_1",
- "istore_2", // "istore_2",
- "istore_3", // "istore_3",
- "lstore_0", // "lstore_0",
- "lstore_1", // "lstore_1",
- "lstore_2", // "lstore_2",
- "lstore_3", // "lstore_3",
- "fstore_0", // "fstore_0",
- "fstore_1", // "fstore_1",
- "fstore_2", // "fstore_2",
- "fstore_3", // "fstore_3",
- "dstore_0", // "dstore_0",
- "dstore_1", // "dstore_1",
- "dstore_2", // "dstore_2",
- "dstore_3", // "dstore_3",
- "astore_0", // "astore_0",
- "astore_1", // "astore_1",
- "astore_2", // "astore_2",
- "astore_3", // "astore_3",
- "iastore", // "iastore",
- "lastore", // "lastore",
- "fastore", // "fastore",
- "dastore", // "dastore",
- "aastore", // "aastore",
- "bastore", // "bastore",
- "castore", // "castore",
- "sastore", // "sastore",
- "pop", // "pop",
- "pop2", // "pop2",
- "dup", // "dup",
- "dup_x1", // "dup_x1",
- "dup_x2", // "dup_x2",
- "dup2", // "dup2",
- "dup2_x1", // "dup2_x1",
- "dup2_x2", // "dup2_x2",
- "swap", // "swap",
- "iadd", // "iadd",
- "ladd", // "ladd",
- "fadd", // "fadd",
- "dadd", // "dadd",
- "isub", // "isub",
- "lsub", // "lsub",
- "fsub", // "fsub",
- "dsub", // "dsub",
- "imul", // "imul",
- "lmul", // "lmul",
- "fmul", // "fmul",
- "dmul", // "dmul",
- "idiv", // "idiv",
- "ldiv", // "ldiv",
- "fdiv", // "fdiv",
- "ddiv", // "ddiv",
- "irem", // "irem",
- "lrem", // "lrem",
- "frem", // "frem",
- "drem", // "drem",
- "ineg", // "ineg",
- "lneg", // "lneg",
- "fneg", // "fneg",
- "dneg", // "dneg",
- "ishl", // "ishl",
- "lshl", // "lshl",
- "ishr", // "ishr",
- "lshr", // "lshr",
- "iushr", // "iushr",
- "lushr", // "lushr",
- "iand", // "iand",
- "land", // "land",
- "ior", // "ior",
- "lor", // "lor",
- "ixor", // "ixor",
- "lxor", // "lxor",
- "iinc", // "iinc",
- "i2l", // "i2l",
- "i2f", // "i2f",
- "i2d", // "i2d",
- "l2i", // "l2i",
- "l2f", // "l2f",
- "l2d", // "l2d",
- "f2i", // "f2i",
- "f2l", // "f2l",
- "f2d", // "f2d",
- "d2i", // "d2i",
- "d2l", // "d2l",
- "d2f", // "d2f",
- "i2b", // "i2b",
- "i2c", // "i2c",
- "i2s", // "i2s",
- "lcmp", // "lcmp",
- "fcmpl", // "fcmpl",
- "fcmpg", // "fcmpg",
- "dcmpl", // "dcmpl",
- "dcmpg", // "dcmpg",
- "ifeq", // "ifeq",
- "ifne", // "ifne",
- "iflt", // "iflt",
- "ifge", // "ifge",
- "ifgt", // "ifgt",
- "ifle", // "ifle",
- "if_icmpeq", // "if_icmpeq",
- "if_icmpne", // "if_icmpne",
- "if_icmplt", // "if_icmplt",
- "if_icmpge", // "if_icmpge",
- "if_icmpgt", // "if_icmpgt",
- "if_icmple", // "if_icmple",
- "if_acmpeq", // "if_acmpeq",
- "if_acmpne", // "if_acmpne",
- "goto", // "goto",
- "jsr", // "jsr",
- "ret", // "ret",
- "tableswitch", // "tableswitch",
- "lookupswitch", // "lookupswitch",
- "ireturn", // "ireturn",
- "lreturn", // "lreturn",
- "freturn", // "freturn",
- "dreturn", // "dreturn",
- "areturn", // "areturn",
- "return", // "return",
- "getstatic", // "getstatic",
- "putstatic", // "putstatic",
- "getfield", // "getfield",
- "putfield", // "putfield",
- "invokevirtual", // "invokevirtual",
- "invokespecial", // "invokespecial",
- "invokestatic", // "invokestatic",
- "invokeinterface", // "invokeinterface",
- //"xxxunusedxxx", // "xxxunusedxxx", Java 6 and before
- "invokedynamic", // "invokedynamic", Java 7 and later
- "new", // "new",
- "newarray", // "newarray",
- "anewarray", // "anewarray",
- "arraylength", // "arraylength",
- "athrow", // "athrow",
- "checkcast", // "checkcast",
- "instanceof", // "instanceof",
- "monitorenter", // "monitorenter",
- "monitorexit", // "monitorexit",
- "wide", // "wide",
- "multianewarray", // "multianewarray",
- "ifnull", // "ifnull",
- "ifnonnull", // "ifnonnull",
- "goto_w", // "goto_w",
- "jsr_w" // "jsr_w"
- };
+ private static String[] opcodeNames = {
+ "nop", // "nop",
+ "aconst_null", // "aconst_null",
+ "iconst_m1", // "iconst_m1",
+ "iconst_0", // "iconst_0",
+ "iconst_1", // "iconst_1",
+ "iconst_2", // "iconst_2",
+ "iconst_3", // "iconst_3",
+ "iconst_4", // "iconst_4",
+ "iconst_5", // "iconst_5",
+ "lconst_0", // "lconst_0",
+ "lconst_1", // "lconst_1",
+ "fconst_0", // "fconst_0",
+ "fconst_1", // "fconst_1",
+ "fconst_2", // "fconst_2",
+ "dconst_0", // "dconst_0",
+ "dconst_1", // "dconst_1",
+ "bipush", // "bipush",
+ "sipush", // "sipush",
+ "ldc", // "ldc",
+ "ldc_w", // "ldc_w",
+ "ldc2_w", // "ldc2_w",
+ "iload", // "iload",
+ "lload", // "lload",
+ "fload", // "fload",
+ "dload", // "dload",
+ "aload", // "aload",
+ "iload_0", // "iload_0",
+ "iload_1", // "iload_1",
+ "iload_2", // "iload_2",
+ "iload_3", // "iload_3",
+ "lload_0", // "lload_0",
+ "lload_1", // "lload_1",
+ "lload_2", // "lload_2",
+ "lload_3", // "lload_3",
+ "fload_0", // "fload_0",
+ "fload_1", // "fload_1",
+ "fload_2", // "fload_2",
+ "fload_3", // "fload_3",
+ "dload_0", // "dload_0",
+ "dload_1", // "dload_1",
+ "dload_2", // "dload_2",
+ "dload_3", // "dload_3",
+ "aload_0", // "aload_0",
+ "aload_1", // "aload_1",
+ "aload_2", // "aload_2",
+ "aload_3", // "aload_3",
+ "iaload", // "iaload",
+ "laload", // "laload",
+ "faload", // "faload",
+ "daload", // "daload",
+ "aaload", // "aaload",
+ "baload", // "baload",
+ "caload", // "caload",
+ "saload", // "saload",
+ "istore", // "istore",
+ "lstore", // "lstore",
+ "fstore", // "fstore",
+ "dstore", // "dstore",
+ "astore", // "astore",
+ "istore_0", // "istore_0",
+ "istore_1", // "istore_1",
+ "istore_2", // "istore_2",
+ "istore_3", // "istore_3",
+ "lstore_0", // "lstore_0",
+ "lstore_1", // "lstore_1",
+ "lstore_2", // "lstore_2",
+ "lstore_3", // "lstore_3",
+ "fstore_0", // "fstore_0",
+ "fstore_1", // "fstore_1",
+ "fstore_2", // "fstore_2",
+ "fstore_3", // "fstore_3",
+ "dstore_0", // "dstore_0",
+ "dstore_1", // "dstore_1",
+ "dstore_2", // "dstore_2",
+ "dstore_3", // "dstore_3",
+ "astore_0", // "astore_0",
+ "astore_1", // "astore_1",
+ "astore_2", // "astore_2",
+ "astore_3", // "astore_3",
+ "iastore", // "iastore",
+ "lastore", // "lastore",
+ "fastore", // "fastore",
+ "dastore", // "dastore",
+ "aastore", // "aastore",
+ "bastore", // "bastore",
+ "castore", // "castore",
+ "sastore", // "sastore",
+ "pop", // "pop",
+ "pop2", // "pop2",
+ "dup", // "dup",
+ "dup_x1", // "dup_x1",
+ "dup_x2", // "dup_x2",
+ "dup2", // "dup2",
+ "dup2_x1", // "dup2_x1",
+ "dup2_x2", // "dup2_x2",
+ "swap", // "swap",
+ "iadd", // "iadd",
+ "ladd", // "ladd",
+ "fadd", // "fadd",
+ "dadd", // "dadd",
+ "isub", // "isub",
+ "lsub", // "lsub",
+ "fsub", // "fsub",
+ "dsub", // "dsub",
+ "imul", // "imul",
+ "lmul", // "lmul",
+ "fmul", // "fmul",
+ "dmul", // "dmul",
+ "idiv", // "idiv",
+ "ldiv", // "ldiv",
+ "fdiv", // "fdiv",
+ "ddiv", // "ddiv",
+ "irem", // "irem",
+ "lrem", // "lrem",
+ "frem", // "frem",
+ "drem", // "drem",
+ "ineg", // "ineg",
+ "lneg", // "lneg",
+ "fneg", // "fneg",
+ "dneg", // "dneg",
+ "ishl", // "ishl",
+ "lshl", // "lshl",
+ "ishr", // "ishr",
+ "lshr", // "lshr",
+ "iushr", // "iushr",
+ "lushr", // "lushr",
+ "iand", // "iand",
+ "land", // "land",
+ "ior", // "ior",
+ "lor", // "lor",
+ "ixor", // "ixor",
+ "lxor", // "lxor",
+ "iinc", // "iinc",
+ "i2l", // "i2l",
+ "i2f", // "i2f",
+ "i2d", // "i2d",
+ "l2i", // "l2i",
+ "l2f", // "l2f",
+ "l2d", // "l2d",
+ "f2i", // "f2i",
+ "f2l", // "f2l",
+ "f2d", // "f2d",
+ "d2i", // "d2i",
+ "d2l", // "d2l",
+ "d2f", // "d2f",
+ "i2b", // "i2b",
+ "i2c", // "i2c",
+ "i2s", // "i2s",
+ "lcmp", // "lcmp",
+ "fcmpl", // "fcmpl",
+ "fcmpg", // "fcmpg",
+ "dcmpl", // "dcmpl",
+ "dcmpg", // "dcmpg",
+ "ifeq", // "ifeq",
+ "ifne", // "ifne",
+ "iflt", // "iflt",
+ "ifge", // "ifge",
+ "ifgt", // "ifgt",
+ "ifle", // "ifle",
+ "if_icmpeq", // "if_icmpeq",
+ "if_icmpne", // "if_icmpne",
+ "if_icmplt", // "if_icmplt",
+ "if_icmpge", // "if_icmpge",
+ "if_icmpgt", // "if_icmpgt",
+ "if_icmple", // "if_icmple",
+ "if_acmpeq", // "if_acmpeq",
+ "if_acmpne", // "if_acmpne",
+ "goto", // "goto",
+ "jsr", // "jsr",
+ "ret", // "ret",
+ "tableswitch", // "tableswitch",
+ "lookupswitch", // "lookupswitch",
+ "ireturn", // "ireturn",
+ "lreturn", // "lreturn",
+ "freturn", // "freturn",
+ "dreturn", // "dreturn",
+ "areturn", // "areturn",
+ "return", // "return",
+ "getstatic", // "getstatic",
+ "putstatic", // "putstatic",
+ "getfield", // "getfield",
+ "putfield", // "putfield",
+ "invokevirtual", // "invokevirtual",
+ "invokespecial", // "invokespecial",
+ "invokestatic", // "invokestatic",
+ "invokeinterface", // "invokeinterface",
+ //"xxxunusedxxx", // "xxxunusedxxx", Java 6 and before
+ "invokedynamic", // "invokedynamic", Java 7 and later
+ "new", // "new",
+ "newarray", // "newarray",
+ "anewarray", // "anewarray",
+ "arraylength", // "arraylength",
+ "athrow", // "athrow",
+ "checkcast", // "checkcast",
+ "instanceof", // "instanceof",
+ "monitorenter", // "monitorenter",
+ "monitorexit", // "monitorexit",
+ "wide", // "wide",
+ "multianewarray", // "multianewarray",
+ "ifnull", // "ifnull",
+ "ifnonnull", // "ifnonnull",
+ "goto_w", // "goto_w",
+ "jsr_w" // "jsr_w"
+ };
- private static Class[] opcodeClasses = {
- null, // "nop",
- null, // "aconst_null",
- null, // "iconst_m1",
- null, // "iconst_0",
- null, // "iconst_1",
- null, // "iconst_2",
- null, // "iconst_3",
- null, // "iconst_4",
- null, // "iconst_5",
- null, // "lconst_0",
- null, // "lconst_1",
- null, // "fconst_0",
- null, // "fconst_1",
- null, // "fconst_2",
- null, // "dconst_0",
- null, // "dconst_1",
- BIPUSH.class, // "bipush",
- SIPUSH.class, // "sipush",
- LDC.class, // "ldc",
- LDC_W.class, // "ldc_w",
- LDC2_W.class, // "ldc2_w",
- ILOAD.class, // "iload",
- LLOAD.class, // "lload",
- FLOAD.class, // "fload",
- DLOAD.class, // "dload",
- ALOAD.class, // "aload",
- null, // "iload_0",
- null, // "iload_1",
- null, // "iload_2",
- null, // "iload_3",
- null, // "lload_0",
- null, // "lload_1",
- null, // "lload_2",
- null, // "lload_3",
- null, // "fload_0",
- null, // "fload_1",
- null, // "fload_2",
- null, // "fload_3",
- null, // "dload_0",
- null, // "dload_1",
- null, // "dload_2",
- null, // "dload_3",
- null, // "aload_0",
- null, // "aload_1",
- null, // "aload_2",
- null, // "aload_3",
- null, // "iaload",
- null, // "laload",
- null, // "faload",
- null, // "daload",
- null, // "aaload",
- null, // "baload",
- null, // "caload",
- null, // "saload",
- ISTORE.class, // "istore",
- LSTORE.class, // "lstore",
- FSTORE.class, // "fstore",
- DSTORE.class, // "dstore",
- ASTORE.class, // "astore",
- null, // "istore_0",
- null, // "istore_1",
- null, // "istore_2",
- null, // "istore_3",
- null, // "lstore_0",
- null, // "lstore_1",
- null, // "lstore_2",
- null, // "lstore_3",
- null, // "fstore_0",
- null, // "fstore_1",
- null, // "fstore_2",
- null, // "fstore_3",
- null, // "dstore_0",
- null, // "dstore_1",
- null, // "dstore_2",
- null, // "dstore_3",
- null, // "astore_0",
- null, // "astore_1",
- null, // "astore_2",
- null, // "astore_3",
- null, // "iastore",
- null, // "lastore",
- null, // "fastore",
- null, // "dastore",
- null, // "aastore",
- null, // "bastore",
- null, // "castore",
- null, // "sastore",
- null, // "pop",
- null, // "pop2",
- null, // "dup",
- null, // "dup_x1",
- null, // "dup_x2",
- null, // "dup2",
- null, // "dup2_x1",
- null, // "dup2_x2",
- null, // "swap",
- null, // "iadd",
- null, // "ladd",
- null, // "fadd",
- null, // "dadd",
- null, // "isub",
- null, // "lsub",
- null, // "fsub",
- null, // "dsub",
- null, // "imul",
- null, // "lmul",
- null, // "fmul",
- null, // "dmul",
- null, // "idiv",
- null, // "ldiv",
- null, // "fdiv",
- null, // "ddiv",
- null, // "irem",
- null, // "lrem",
- null, // "frem",
- null, // "drem",
- null, // "ineg",
- null, // "lneg",
- null, // "fneg",
- null, // "dneg",
- null, // "ishl",
- null, // "lshl",
- null, // "ishr",
- null, // "lshr",
- null, // "iushr",
- null, // "lushr",
- null, // "iand",
- null, // "land",
- null, // "ior",
- null, // "lor",
- null, // "ixor",
- null, // "lxor",
- IINC.class, // "iinc",
- null, // "i2l",
- null, // "i2f",
- null, // "i2d",
- null, // "l2i",
- null, // "l2f",
- null, // "l2d",
- null, // "f2i",
- null, // "f2l",
- null, // "f2d",
- null, // "d2i",
- null, // "d2l",
- null, // "d2f",
- null, // "i2b",
- null, // "i2c",
- null, // "i2s",
- null, // "lcmp",
- null, // "fcmpl",
- null, // "fcmpg",
- null, // "dcmpl",
- null, // "dcmpg",
- null, // "ifeq",
- null, // "ifne",
- null, // "iflt",
- null, // "ifge",
- null, // "ifgt",
- null, // "ifle",
- null, // "if_icmpeq",
- null, // "if_icmpne",
- null, // "if_icmplt",
- null, // "if_icmpge",
- null, // "if_icmpgt",
- null, // "if_icmple",
- null, // "if_acmpeq",
- null, // "if_acmpne",
- GOTO.class, // "goto",
- JSR.class, // "jsr",
- RET.class, // "ret",
- TABLESWITCH.class, // "tableswitch",
- LOOKUPSWITCH.class, // "lookupswitch",
- null, // "ireturn",
- null, // "lreturn",
- null, // "freturn",
- null, // "dreturn",
- null, // "areturn",
- null, // "return",
- GETSTATIC.class, // "getstatic",
- PUTSTATIC.class, // "putstatic",
- GETFIELD.class, // "getfield",
- PUTFIELD.class, // "putfield",
- INVOKEVIRTUAL.class, // "invokevirtual",
- INVOKESPECIAL.class, // "invokespecial",
- INVOKESTATIC.class, // "invokestatic",
- INVOKEINTERFACE.class, // "invokeinterface",
- INVOKEDYNAMIC.class, // "xxxunusedxxx" Java 6 and before, "invokedynamic" Java 7 and later
- NEW.class, // "new",
- NEWARRAY.class, // "newarray",
- ANEWARRAY.class, // "anewarray",
- null, // "arraylength",
- null, // "athrow",
- CHECKCAST.class, // "checkcast",
- INSTANCEOF.class, // "instanceof",
- null, // "monitorenter",
- null, // "monitorexit",
- null, // "wide",
- MULTIANEWARRAY.class, // "multianewarray",
- null, // "ifnull",
- null, // "ifnonnull",
- GOTO_W.class, // "goto_w",
- JSR_W.class // "jsr_w"
- };
-
-
-
+ private static Class[] opcodeClasses = {
+ null, // "nop",
+ null, // "aconst_null",
+ null, // "iconst_m1",
+ null, // "iconst_0",
+ null, // "iconst_1",
+ null, // "iconst_2",
+ null, // "iconst_3",
+ null, // "iconst_4",
+ null, // "iconst_5",
+ null, // "lconst_0",
+ null, // "lconst_1",
+ null, // "fconst_0",
+ null, // "fconst_1",
+ null, // "fconst_2",
+ null, // "dconst_0",
+ null, // "dconst_1",
+ BIPUSH.class, // "bipush",
+ SIPUSH.class, // "sipush",
+ LDC.class, // "ldc",
+ LDC_W.class, // "ldc_w",
+ LDC2_W.class, // "ldc2_w",
+ ILOAD.class, // "iload",
+ LLOAD.class, // "lload",
+ FLOAD.class, // "fload",
+ DLOAD.class, // "dload",
+ ALOAD.class, // "aload",
+ null, // "iload_0",
+ null, // "iload_1",
+ null, // "iload_2",
+ null, // "iload_3",
+ null, // "lload_0",
+ null, // "lload_1",
+ null, // "lload_2",
+ null, // "lload_3",
+ null, // "fload_0",
+ null, // "fload_1",
+ null, // "fload_2",
+ null, // "fload_3",
+ null, // "dload_0",
+ null, // "dload_1",
+ null, // "dload_2",
+ null, // "dload_3",
+ null, // "aload_0",
+ null, // "aload_1",
+ null, // "aload_2",
+ null, // "aload_3",
+ null, // "iaload",
+ null, // "laload",
+ null, // "faload",
+ null, // "daload",
+ null, // "aaload",
+ null, // "baload",
+ null, // "caload",
+ null, // "saload",
+ ISTORE.class, // "istore",
+ LSTORE.class, // "lstore",
+ FSTORE.class, // "fstore",
+ DSTORE.class, // "dstore",
+ ASTORE.class, // "astore",
+ null, // "istore_0",
+ null, // "istore_1",
+ null, // "istore_2",
+ null, // "istore_3",
+ null, // "lstore_0",
+ null, // "lstore_1",
+ null, // "lstore_2",
+ null, // "lstore_3",
+ null, // "fstore_0",
+ null, // "fstore_1",
+ null, // "fstore_2",
+ null, // "fstore_3",
+ null, // "dstore_0",
+ null, // "dstore_1",
+ null, // "dstore_2",
+ null, // "dstore_3",
+ null, // "astore_0",
+ null, // "astore_1",
+ null, // "astore_2",
+ null, // "astore_3",
+ null, // "iastore",
+ null, // "lastore",
+ null, // "fastore",
+ null, // "dastore",
+ null, // "aastore",
+ null, // "bastore",
+ null, // "castore",
+ null, // "sastore",
+ null, // "pop",
+ null, // "pop2",
+ null, // "dup",
+ null, // "dup_x1",
+ null, // "dup_x2",
+ null, // "dup2",
+ null, // "dup2_x1",
+ null, // "dup2_x2",
+ null, // "swap",
+ null, // "iadd",
+ null, // "ladd",
+ null, // "fadd",
+ null, // "dadd",
+ null, // "isub",
+ null, // "lsub",
+ null, // "fsub",
+ null, // "dsub",
+ null, // "imul",
+ null, // "lmul",
+ null, // "fmul",
+ null, // "dmul",
+ null, // "idiv",
+ null, // "ldiv",
+ null, // "fdiv",
+ null, // "ddiv",
+ null, // "irem",
+ null, // "lrem",
+ null, // "frem",
+ null, // "drem",
+ null, // "ineg",
+ null, // "lneg",
+ null, // "fneg",
+ null, // "dneg",
+ null, // "ishl",
+ null, // "lshl",
+ null, // "ishr",
+ null, // "lshr",
+ null, // "iushr",
+ null, // "lushr",
+ null, // "iand",
+ null, // "land",
+ null, // "ior",
+ null, // "lor",
+ null, // "ixor",
+ null, // "lxor",
+ IINC.class, // "iinc",
+ null, // "i2l",
+ null, // "i2f",
+ null, // "i2d",
+ null, // "l2i",
+ null, // "l2f",
+ null, // "l2d",
+ null, // "f2i",
+ null, // "f2l",
+ null, // "f2d",
+ null, // "d2i",
+ null, // "d2l",
+ null, // "d2f",
+ null, // "i2b",
+ null, // "i2c",
+ null, // "i2s",
+ null, // "lcmp",
+ null, // "fcmpl",
+ null, // "fcmpg",
+ null, // "dcmpl",
+ null, // "dcmpg",
+ null, // "ifeq",
+ null, // "ifne",
+ null, // "iflt",
+ null, // "ifge",
+ null, // "ifgt",
+ null, // "ifle",
+ null, // "if_icmpeq",
+ null, // "if_icmpne",
+ null, // "if_icmplt",
+ null, // "if_icmpge",
+ null, // "if_icmpgt",
+ null, // "if_icmple",
+ null, // "if_acmpeq",
+ null, // "if_acmpne",
+ GOTO.class, // "goto",
+ JSR.class, // "jsr",
+ RET.class, // "ret",
+ TABLESWITCH.class, // "tableswitch",
+ LOOKUPSWITCH.class, // "lookupswitch",
+ null, // "ireturn",
+ null, // "lreturn",
+ null, // "freturn",
+ null, // "dreturn",
+ null, // "areturn",
+ null, // "return",
+ GETSTATIC.class, // "getstatic",
+ PUTSTATIC.class, // "putstatic",
+ GETFIELD.class, // "getfield",
+ PUTFIELD.class, // "putfield",
+ INVOKEVIRTUAL.class, // "invokevirtual",
+ INVOKESPECIAL.class, // "invokespecial",
+ INVOKESTATIC.class, // "invokestatic",
+ INVOKEINTERFACE.class, // "invokeinterface",
+ INVOKEDYNAMIC.class, // "xxxunusedxxx" Java 6 and before, "invokedynamic" Java 7 and later
+ NEW.class, // "new",
+ NEWARRAY.class, // "newarray",
+ ANEWARRAY.class, // "anewarray",
+ null, // "arraylength",
+ null, // "athrow",
+ CHECKCAST.class, // "checkcast",
+ INSTANCEOF.class, // "instanceof",
+ null, // "monitorenter",
+ null, // "monitorexit",
+ null, // "wide",
+ MULTIANEWARRAY.class, // "multianewarray",
+ null, // "ifnull",
+ null, // "ifnonnull",
+ GOTO_W.class, // "goto_w",
+ JSR_W.class // "jsr_w"
+ };
}
diff --git a/src/org/jetbrains/java/decompiler/code/ExceptionHandler.java b/src/org/jetbrains/java/decompiler/code/ExceptionHandler.java
index 87598ac..5c5b659 100644
--- a/src/org/jetbrains/java/decompiler/code/ExceptionHandler.java
+++ b/src/org/jetbrains/java/decompiler/code/ExceptionHandler.java
@@ -1,62 +1,63 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
-
public class ExceptionHandler {
- public int from = 0;
- public int to = 0;
- public int handler = 0;
-
- public int from_instr = 0;
- public int to_instr = 0;
- public int handler_instr = 0;
-
- public int class_index = 0;
- public String exceptionClass = null;
-
- public ExceptionHandler(){}
-
- public ExceptionHandler(int from_raw, int to_raw, int handler_raw, String exceptionClass) {
- this.from = from_raw;
- this.to = to_raw;
- this.handler = handler_raw;
- this.exceptionClass = exceptionClass;
- }
-
- public void writeToStream(DataOutputStream out) throws IOException {
- out.writeShort(from);
- out.writeShort(to);
- out.writeShort(handler);
- out.writeShort(class_index);
- }
-
- public String toString() {
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- StringBuffer buf = new StringBuffer();
- buf.append("from: "+from+" to: "+to+" handler: "+handler+new_line_separator);
- buf.append("from_instr: "+from_instr+" to_instr: "+to_instr+" handler_instr: "+handler_instr+new_line_separator);
- buf.append("exceptionClass: "+exceptionClass+new_line_separator);
- return buf.toString();
- }
-
+ public int from = 0;
+ public int to = 0;
+ public int handler = 0;
+
+ public int from_instr = 0;
+ public int to_instr = 0;
+ public int handler_instr = 0;
+
+ public int class_index = 0;
+ public String exceptionClass = null;
+
+ public ExceptionHandler() {
+ }
+
+ public ExceptionHandler(int from_raw, int to_raw, int handler_raw, String exceptionClass) {
+ this.from = from_raw;
+ this.to = to_raw;
+ this.handler = handler_raw;
+ this.exceptionClass = exceptionClass;
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+ out.writeShort(from);
+ out.writeShort(to);
+ out.writeShort(handler);
+ out.writeShort(class_index);
+ }
+
+ public String toString() {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuffer buf = new StringBuffer();
+ buf.append("from: " + from + " to: " + to + " handler: " + handler + new_line_separator);
+ buf.append("from_instr: " + from_instr + " to_instr: " + to_instr + " handler_instr: " + handler_instr + new_line_separator);
+ buf.append("exceptionClass: " + exceptionClass + new_line_separator);
+ return buf.toString();
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/ExceptionTable.java b/src/org/jetbrains/java/decompiler/code/ExceptionTable.java
index da8ec22..e828a7f 100644
--- a/src/org/jetbrains/java/decompiler/code/ExceptionTable.java
+++ b/src/org/jetbrains/java/decompiler/code/ExceptionTable.java
@@ -1,57 +1,58 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.interpreter.Util;
import org.jetbrains.java.decompiler.struct.StructContext;
+import java.util.ArrayList;
+import java.util.List;
+
public class ExceptionTable {
- private List<ExceptionHandler> handlers = new ArrayList<ExceptionHandler>();
-
- public ExceptionTable() {}
-
- public ExceptionTable(List<ExceptionHandler> handlers) {
- this.handlers = handlers;
- }
-
-
- public ExceptionHandler getHandlerByClass(StructContext context, int line, String valclass, boolean withany) {
-
- ExceptionHandler res = null; // no handler found
-
- for(ExceptionHandler handler : handlers) {
- if(handler.from<=line && handler.to>line) {
- String name = handler.exceptionClass;
-
- if((withany && name==null) || // any -> finally or synchronized handler
- (name!=null && Util.instanceOf(context, valclass, name))) {
- res = handler;
- break;
- }
- }
- }
-
- return res;
- }
-
- public List<ExceptionHandler> getHandlers() {
- return handlers;
- }
-
+ private List<ExceptionHandler> handlers = new ArrayList<ExceptionHandler>();
+
+ public ExceptionTable() {
+ }
+
+ public ExceptionTable(List<ExceptionHandler> handlers) {
+ this.handlers = handlers;
+ }
+
+
+ public ExceptionHandler getHandlerByClass(StructContext context, int line, String valclass, boolean withany) {
+
+ ExceptionHandler res = null; // no handler found
+
+ for (ExceptionHandler handler : handlers) {
+ if (handler.from <= line && handler.to > line) {
+ String name = handler.exceptionClass;
+
+ if ((withany && name == null) || // any -> finally or synchronized handler
+ (name != null && Util.instanceOf(context, valclass, name))) {
+ res = handler;
+ break;
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public List<ExceptionHandler> getHandlers() {
+ return handlers;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/FullInstructionSequence.java b/src/org/jetbrains/java/decompiler/code/FullInstructionSequence.java
index f879fd0..eb8f819 100644
--- a/src/org/jetbrains/java/decompiler/code/FullInstructionSequence.java
+++ b/src/org/jetbrains/java/decompiler/code/FullInstructionSequence.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
@@ -19,20 +20,19 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection;
public class FullInstructionSequence extends InstructionSequence {
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public FullInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr, ExceptionTable extable) {
- this.collinstr = collinstr;
- this.exceptionTable = extable;
-
- // translate raw exception handlers to instr
- for(ExceptionHandler handler : extable.getHandlers()) {
- handler.from_instr = this.getPointerByAbsOffset(handler.from);
- handler.to_instr = this.getPointerByAbsOffset(handler.to);
- handler.handler_instr = this.getPointerByAbsOffset(handler.handler);
- }
- }
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public FullInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr, ExceptionTable extable) {
+ this.collinstr = collinstr;
+ this.exceptionTable = extable;
+ // translate raw exception handlers to instr
+ for (ExceptionHandler handler : extable.getHandlers()) {
+ handler.from_instr = this.getPointerByAbsOffset(handler.from);
+ handler.to_instr = this.getPointerByAbsOffset(handler.to);
+ handler.handler_instr = this.getPointerByAbsOffset(handler.handler);
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/IfInstruction.java b/src/org/jetbrains/java/decompiler/code/IfInstruction.java
index befae18..1d4bf6c 100644
--- a/src/org/jetbrains/java/decompiler/code/IfInstruction.java
+++ b/src/org/jetbrains/java/decompiler/code/IfInstruction.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
import java.io.DataOutputStream;
@@ -24,13 +25,12 @@ import java.io.IOException;
public class IfInstruction extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opcode);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opcode);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/Instruction.java b/src/org/jetbrains/java/decompiler/code/Instruction.java
index faa8926..2c0be6b 100644
--- a/src/org/jetbrains/java/decompiler/code/Instruction.java
+++ b/src/org/jetbrains/java/decompiler/code/Instruction.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
import java.io.DataOutputStream;
@@ -19,106 +20,107 @@ import java.io.IOException;
public class Instruction implements CodeConstants {
- // *****************************************************************************
- // public fields
- // *****************************************************************************
-
- public int opcode;
-
- public int group = CodeConstants.GROUP_GENERAL;
-
- public boolean wide = false;
-
- public int bytecode_version = BYTECODE_JAVA_LE_4;
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private int[] operands = null;
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public Instruction() {}
-
- public int length() {
- return 1;
- }
-
- public int operandsCount() {
- return (operands==null)?0:operands.length;
- }
-
- public int getOperand(int index) {
- return operands[index];
- }
-
- public Instruction clone() {
- return ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, operands==null?null:(int[])operands.clone());
- }
-
- public String toString() {
-
- String res = wide?"@wide ":"";
- res+="@"+ConstantsUtil.getName(opcode);
-
- int len = operandsCount();
- for(int i=0;i<len;i++) {
- int op = operands[i];
- if(op<0) {
- res+=" -"+Integer.toHexString(-op);
- } else {
- res+=" "+Integer.toHexString(op);
- }
- }
-
- return res;
-
- }
-
- public boolean canFallthrough() {
- return opcode!=opc_goto && opcode!=opc_goto_w && opcode!=opc_ret &&
- !(opcode>=opc_ireturn && opcode<=opc_return) && opcode!=opc_athrow
- && opcode!=opc_jsr && opcode!=opc_tableswitch && opcode!=opc_lookupswitch;
- }
-
- public boolean equalsInstruction(Instruction instr) {
- if(opcode != instr.opcode || wide != instr.wide
- || operandsCount() != instr.operandsCount()) {
- return false;
- }
-
- if(operands != null) {
- for(int i=0;i<operands.length;i++) {
- if(operands[i] != instr.getOperand(i)) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- // should be overwritten by subclasses
- public void initInstruction(InstructionSequence seq) {}
-
- // should be overwritten by subclasses
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opcode);
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public int[] getOperands() {
- return operands;
- }
-
- public void setOperands(int[] operands) {
- this.operands = operands;
- }
-
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int opcode;
+
+ public int group = CodeConstants.GROUP_GENERAL;
+
+ public boolean wide = false;
+
+ public int bytecode_version = BYTECODE_JAVA_LE_4;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private int[] operands = null;
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public Instruction() {
+ }
+
+ public int length() {
+ return 1;
+ }
+
+ public int operandsCount() {
+ return (operands == null) ? 0 : operands.length;
+ }
+
+ public int getOperand(int index) {
+ return operands[index];
+ }
+
+ public Instruction clone() {
+ return ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, operands == null ? null : (int[])operands.clone());
+ }
+
+ public String toString() {
+
+ String res = wide ? "@wide " : "";
+ res += "@" + ConstantsUtil.getName(opcode);
+
+ int len = operandsCount();
+ for (int i = 0; i < len; i++) {
+ int op = operands[i];
+ if (op < 0) {
+ res += " -" + Integer.toHexString(-op);
+ }
+ else {
+ res += " " + Integer.toHexString(op);
+ }
+ }
+
+ return res;
+ }
+
+ public boolean canFallthrough() {
+ return opcode != opc_goto && opcode != opc_goto_w && opcode != opc_ret &&
+ !(opcode >= opc_ireturn && opcode <= opc_return) && opcode != opc_athrow
+ && opcode != opc_jsr && opcode != opc_tableswitch && opcode != opc_lookupswitch;
+ }
+
+ public boolean equalsInstruction(Instruction instr) {
+ if (opcode != instr.opcode || wide != instr.wide
+ || operandsCount() != instr.operandsCount()) {
+ return false;
+ }
+
+ if (operands != null) {
+ for (int i = 0; i < operands.length; i++) {
+ if (operands[i] != instr.getOperand(i)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // should be overwritten by subclasses
+ public void initInstruction(InstructionSequence seq) {
+ }
+
+ // should be overwritten by subclasses
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opcode);
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public int[] getOperands() {
+ return operands;
+ }
+
+ public void setOperands(int[] operands) {
+ this.operands = operands;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/InstructionSequence.java b/src/org/jetbrains/java/decompiler/code/InstructionSequence.java
index 4c29820..696908c 100644
--- a/src/org/jetbrains/java/decompiler/code/InstructionSequence.java
+++ b/src/org/jetbrains/java/decompiler/code/InstructionSequence.java
@@ -1,219 +1,227 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.interpreter.Util;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.struct.StructContext;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
public abstract class InstructionSequence {
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- protected VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
-
- protected int pointer = 0;
-
- protected ExceptionTable exceptionTable = new ExceptionTable();
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- // to nbe overwritten
- public InstructionSequence clone() {return null;}
-
- public void clear() {
- collinstr.clear();
- pointer = 0;
- exceptionTable = new ExceptionTable();
- }
-
- public void addInstruction(Instruction inst, int offset){
- collinstr.addWithKey(inst, offset);
- }
-
- public void addInstruction(int index, Instruction inst, int offset){
- collinstr.addWithKeyAndIndex(index, inst, offset);
- }
-
- public void addSequence(InstructionSequence seq){
- for(int i=0;i<seq.length();i++) {
- addInstruction(seq.getInstr(i), -1); // TODO: any sensible value possible?
- }
- }
-
- public void removeInstruction(int index) {
- collinstr.remove(index);
- }
-
- public Instruction getCurrentInstr() {
- return (Instruction)collinstr.get(pointer);
- }
-
- public Instruction getInstr(int index) {
- return (Instruction)collinstr.get(index);
- }
-
- public Instruction getLastInstr() {
- return (Instruction)collinstr.getLast();
- }
-
- public int getCurrentOffset() {
- return ((Integer)collinstr.getKey(pointer)).intValue();
- }
-
- public int getOffset(int index) {
- return ((Integer)collinstr.getKey(index)).intValue();
- }
-
- public int getPointerByAbsOffset(int offset) {
- Integer absoffset = new Integer(offset);
- if(collinstr.containsKey(absoffset)) {
- return collinstr.getIndexByKey(absoffset);
- } else {
- return -1;
- }
- }
-
- public int getPointerByRelOffset(int offset) {
- Integer absoffset = new Integer(((Integer)collinstr.getKey(pointer)).intValue()+offset);
- if(collinstr.containsKey(absoffset)) {
- return collinstr.getIndexByKey(absoffset);
- } else {
- return -1;
- }
- }
-
- public void setPointerByAbsOffset(int offset) {
- Integer absoffset = new Integer(((Integer)collinstr.getKey(pointer)).intValue()+offset);
- if(collinstr.containsKey(absoffset)) {
- pointer = collinstr.getIndexByKey(absoffset);
- }
- }
-
- public int length() {
- return collinstr.size();
- }
-
- public boolean isEmpty() {
- return collinstr.isEmpty();
- }
-
- public void addToPointer(int diff) {
- this.pointer += diff;
- }
-
- public String toString() {
- return toString(0);
- }
-
- public String toString(int indent) {
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- StringBuffer buf = new StringBuffer();
-
- for(int i=0;i<collinstr.size();i++) {
- buf.append(InterpreterUtil.getIndentString(indent));
- buf.append(((Integer)collinstr.getKey(i)).intValue());
- buf.append(": ");
- buf.append(((Instruction)collinstr.get(i)).toString());
- buf.append(new_line_separator);
- }
-
- return buf.toString();
- }
-
- public void writeCodeToStream(DataOutputStream out) throws IOException {
-
- for(int i=0;i<collinstr.size();i++) {
- ((Instruction)collinstr.get(i)).writeToStream(out, ((Integer)collinstr.getKey(i)).intValue());
- }
- }
-
- public void writeExceptionsToStream(DataOutputStream out) throws IOException {
-
- List<ExceptionHandler> handlers = exceptionTable.getHandlers();
-
- out.writeShort(handlers.size());
- for(int i=0;i<handlers.size();i++) {
- ((ExceptionHandler)handlers.get(i)).writeToStream(out);
- }
- }
-
- public void sortHandlers(final StructContext context) {
-
- Collections.sort(exceptionTable.getHandlers(), new Comparator<ExceptionHandler>() {
-
- public int compare(ExceptionHandler handler0, ExceptionHandler handler1) {
-
- if(handler0.to == handler1.to) {
- if(handler0.exceptionClass == null) {
- return 1;
- } else {
- if(handler1.exceptionClass == null) {
- return -1;
- } else if(handler0.exceptionClass.equals(handler1.exceptionClass)){
- return (handler0.from > handler1.from)?-1:1; // invalid code
- } else {
- if(Util.instanceOf(context, handler0.exceptionClass, handler1.exceptionClass)) {
- return -1;
- } else {
- return 1;
- }
- }
- }
- } else {
- return (handler0.to > handler1.to)?1:-1;
- }
- }
- });
-
- }
-
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public int getPointer() {
- return pointer;
- }
-
- public void setPointer(int pointer) {
- this.pointer = pointer;
- }
-
- public ExceptionTable getExceptionTable() {
- return exceptionTable;
- }
-
- public void setExceptionTable(ExceptionTable exceptionTable) {
- this.exceptionTable = exceptionTable;
- }
-
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ protected VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
+
+ protected int pointer = 0;
+
+ protected ExceptionTable exceptionTable = new ExceptionTable();
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ // to nbe overwritten
+ public InstructionSequence clone() {
+ return null;
+ }
+
+ public void clear() {
+ collinstr.clear();
+ pointer = 0;
+ exceptionTable = new ExceptionTable();
+ }
+
+ public void addInstruction(Instruction inst, int offset) {
+ collinstr.addWithKey(inst, offset);
+ }
+
+ public void addInstruction(int index, Instruction inst, int offset) {
+ collinstr.addWithKeyAndIndex(index, inst, offset);
+ }
+
+ public void addSequence(InstructionSequence seq) {
+ for (int i = 0; i < seq.length(); i++) {
+ addInstruction(seq.getInstr(i), -1); // TODO: any sensible value possible?
+ }
+ }
+
+ public void removeInstruction(int index) {
+ collinstr.remove(index);
+ }
+
+ public Instruction getCurrentInstr() {
+ return (Instruction)collinstr.get(pointer);
+ }
+
+ public Instruction getInstr(int index) {
+ return (Instruction)collinstr.get(index);
+ }
+
+ public Instruction getLastInstr() {
+ return (Instruction)collinstr.getLast();
+ }
+
+ public int getCurrentOffset() {
+ return ((Integer)collinstr.getKey(pointer)).intValue();
+ }
+
+ public int getOffset(int index) {
+ return ((Integer)collinstr.getKey(index)).intValue();
+ }
+
+ public int getPointerByAbsOffset(int offset) {
+ Integer absoffset = new Integer(offset);
+ if (collinstr.containsKey(absoffset)) {
+ return collinstr.getIndexByKey(absoffset);
+ }
+ else {
+ return -1;
+ }
+ }
+
+ public int getPointerByRelOffset(int offset) {
+ Integer absoffset = new Integer(((Integer)collinstr.getKey(pointer)).intValue() + offset);
+ if (collinstr.containsKey(absoffset)) {
+ return collinstr.getIndexByKey(absoffset);
+ }
+ else {
+ return -1;
+ }
+ }
+
+ public void setPointerByAbsOffset(int offset) {
+ Integer absoffset = new Integer(((Integer)collinstr.getKey(pointer)).intValue() + offset);
+ if (collinstr.containsKey(absoffset)) {
+ pointer = collinstr.getIndexByKey(absoffset);
+ }
+ }
+
+ public int length() {
+ return collinstr.size();
+ }
+
+ public boolean isEmpty() {
+ return collinstr.isEmpty();
+ }
+
+ public void addToPointer(int diff) {
+ this.pointer += diff;
+ }
+
+ public String toString() {
+ return toString(0);
+ }
+
+ public String toString(int indent) {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuffer buf = new StringBuffer();
+
+ for (int i = 0; i < collinstr.size(); i++) {
+ buf.append(InterpreterUtil.getIndentString(indent));
+ buf.append(((Integer)collinstr.getKey(i)).intValue());
+ buf.append(": ");
+ buf.append(((Instruction)collinstr.get(i)).toString());
+ buf.append(new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public void writeCodeToStream(DataOutputStream out) throws IOException {
+
+ for (int i = 0; i < collinstr.size(); i++) {
+ ((Instruction)collinstr.get(i)).writeToStream(out, ((Integer)collinstr.getKey(i)).intValue());
+ }
+ }
+
+ public void writeExceptionsToStream(DataOutputStream out) throws IOException {
+
+ List<ExceptionHandler> handlers = exceptionTable.getHandlers();
+
+ out.writeShort(handlers.size());
+ for (int i = 0; i < handlers.size(); i++) {
+ ((ExceptionHandler)handlers.get(i)).writeToStream(out);
+ }
+ }
+
+ public void sortHandlers(final StructContext context) {
+
+ Collections.sort(exceptionTable.getHandlers(), new Comparator<ExceptionHandler>() {
+
+ public int compare(ExceptionHandler handler0, ExceptionHandler handler1) {
+
+ if (handler0.to == handler1.to) {
+ if (handler0.exceptionClass == null) {
+ return 1;
+ }
+ else {
+ if (handler1.exceptionClass == null) {
+ return -1;
+ }
+ else if (handler0.exceptionClass.equals(handler1.exceptionClass)) {
+ return (handler0.from > handler1.from) ? -1 : 1; // invalid code
+ }
+ else {
+ if (Util.instanceOf(context, handler0.exceptionClass, handler1.exceptionClass)) {
+ return -1;
+ }
+ else {
+ return 1;
+ }
+ }
+ }
+ }
+ else {
+ return (handler0.to > handler1.to) ? 1 : -1;
+ }
+ }
+ });
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public int getPointer() {
+ return pointer;
+ }
+
+ public void setPointer(int pointer) {
+ this.pointer = pointer;
+ }
+
+ public ExceptionTable getExceptionTable() {
+ return exceptionTable;
+ }
+
+ public void setExceptionTable(ExceptionTable exceptionTable) {
+ this.exceptionTable = exceptionTable;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/JumpInstruction.java b/src/org/jetbrains/java/decompiler/code/JumpInstruction.java
index 2daeeeb..44f4ff9 100644
--- a/src/org/jetbrains/java/decompiler/code/JumpInstruction.java
+++ b/src/org/jetbrains/java/decompiler/code/JumpInstruction.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
/*
@@ -23,19 +24,19 @@ package org.jetbrains.java.decompiler.code;
public class JumpInstruction extends Instruction {
- public int destination;
-
- public JumpInstruction() {}
-
- public void initInstruction(InstructionSequence seq) {
- destination = seq.getPointerByRelOffset(this.getOperand(0));
- }
-
- public JumpInstruction clone() {
- JumpInstruction newinstr = (JumpInstruction)super.clone();
-
- newinstr.destination = destination;
- return newinstr;
- }
-
+ public int destination;
+
+ public JumpInstruction() {
+ }
+
+ public void initInstruction(InstructionSequence seq) {
+ destination = seq.getPointerByRelOffset(this.getOperand(0));
+ }
+
+ public JumpInstruction clone() {
+ JumpInstruction newinstr = (JumpInstruction)super.clone();
+
+ newinstr.destination = destination;
+ return newinstr;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/SimpleInstructionSequence.java b/src/org/jetbrains/java/decompiler/code/SimpleInstructionSequence.java
index c082092..bcc3c4a 100644
--- a/src/org/jetbrains/java/decompiler/code/SimpleInstructionSequence.java
+++ b/src/org/jetbrains/java/decompiler/code/SimpleInstructionSequence.java
@@ -1,39 +1,39 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
public class SimpleInstructionSequence extends InstructionSequence {
- public SimpleInstructionSequence() {}
+ public SimpleInstructionSequence() {
+ }
+
+ public SimpleInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr) {
+ this.collinstr = collinstr;
+ }
+
+ public SimpleInstructionSequence clone() {
+ SimpleInstructionSequence newseq = new SimpleInstructionSequence(collinstr.clone());
+ newseq.setPointer(this.getPointer());
- public SimpleInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr) {
- this.collinstr = collinstr;
- }
-
- public SimpleInstructionSequence clone() {
- SimpleInstructionSequence newseq = new SimpleInstructionSequence(collinstr.clone());
- newseq.setPointer(this.getPointer());
-
- return newseq;
- }
+ return newseq;
+ }
- public void removeInstruction(int index) {
- collinstr.remove(index);
- }
-
-
+ public void removeInstruction(int index) {
+ collinstr.remove(index);
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java b/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java
index 63d0f4c..6aa6a7f 100644
--- a/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java
+++ b/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code;
/*
@@ -20,74 +21,77 @@ package org.jetbrains.java.decompiler.code;
public class SwitchInstruction extends Instruction {
- private int[] destinations;
-
- private int[] values;
-
- private int defaultdest;
-
- public SwitchInstruction() {}
-
-
- public void initInstruction(InstructionSequence seq) {
-
- int pref = (opcode==CodeConstants.opc_tableswitch?3:2);
- int len = this.getOperands().length - pref;
- defaultdest = seq.getPointerByRelOffset(this.getOperand(0));
-
- int low = 0;
-
- if(opcode==CodeConstants.opc_lookupswitch) {
- len/=2;
- } else {
- low = this.getOperand(1);
- }
-
- destinations = new int[len];
- values = new int[len];
-
- for(int i=0,k=0;i<len;i++,k++) {
- if(opcode==CodeConstants.opc_lookupswitch){
- values[i] = this.getOperand(pref+k);
- k++;
- } else {
- values[i] = low+k;
- }
- destinations[i] = seq.getPointerByRelOffset(this.getOperand(pref+k));
- }
- }
-
- public SwitchInstruction clone() {
- SwitchInstruction newinstr = (SwitchInstruction)super.clone();
-
- newinstr.defaultdest = defaultdest;
- newinstr.destinations = destinations.clone();
- newinstr.values = values.clone();
-
- return newinstr;
- }
-
- public int[] getDestinations() {
- return destinations;
- }
-
- public void setDestinations(int[] destinations) {
- this.destinations = destinations;
- }
-
- public int getDefaultdest() {
- return defaultdest;
- }
-
- public void setDefaultdest(int defaultdest) {
- this.defaultdest = defaultdest;
- }
-
- public int[] getValues() {
- return values;
- }
-
- public void setValues(int[] values) {
- this.values = values;
- }
+ private int[] destinations;
+
+ private int[] values;
+
+ private int defaultdest;
+
+ public SwitchInstruction() {
+ }
+
+
+ public void initInstruction(InstructionSequence seq) {
+
+ int pref = (opcode == CodeConstants.opc_tableswitch ? 3 : 2);
+ int len = this.getOperands().length - pref;
+ defaultdest = seq.getPointerByRelOffset(this.getOperand(0));
+
+ int low = 0;
+
+ if (opcode == CodeConstants.opc_lookupswitch) {
+ len /= 2;
+ }
+ else {
+ low = this.getOperand(1);
+ }
+
+ destinations = new int[len];
+ values = new int[len];
+
+ for (int i = 0, k = 0; i < len; i++, k++) {
+ if (opcode == CodeConstants.opc_lookupswitch) {
+ values[i] = this.getOperand(pref + k);
+ k++;
+ }
+ else {
+ values[i] = low + k;
+ }
+ destinations[i] = seq.getPointerByRelOffset(this.getOperand(pref + k));
+ }
+ }
+
+ public SwitchInstruction clone() {
+ SwitchInstruction newinstr = (SwitchInstruction)super.clone();
+
+ newinstr.defaultdest = defaultdest;
+ newinstr.destinations = destinations.clone();
+ newinstr.values = values.clone();
+
+ return newinstr;
+ }
+
+ public int[] getDestinations() {
+ return destinations;
+ }
+
+ public void setDestinations(int[] destinations) {
+ this.destinations = destinations;
+ }
+
+ public int getDefaultdest() {
+ return defaultdest;
+ }
+
+ public void setDefaultdest(int defaultdest) {
+ this.defaultdest = defaultdest;
+ }
+
+ public int[] getValues() {
+ return values;
+ }
+
+ public void setValues(int[] values) {
+ this.values = values;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java b/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java
index 917da08..f8bf793 100644
--- a/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java
+++ b/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java
@@ -1,265 +1,266 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.cfg;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.Instruction;
import org.jetbrains.java.decompiler.code.InstructionSequence;
import org.jetbrains.java.decompiler.code.SimpleInstructionSequence;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
+import java.util.ArrayList;
+import java.util.List;
+
public class BasicBlock implements IGraphNode {
- // *****************************************************************************
- // public fields
- // *****************************************************************************
-
- public int id = 0;
-
- public int mark = 0;
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private InstructionSequence seq = new SimpleInstructionSequence();
-
- private List<BasicBlock> preds = new ArrayList<BasicBlock>();
-
- private List<BasicBlock> succs = new ArrayList<BasicBlock>();
-
- private List<Integer> instrOldOffsets = new ArrayList<Integer>();
-
- private List<BasicBlock> predExceptions = new ArrayList<BasicBlock>();
-
- private List<BasicBlock> succExceptions = new ArrayList<BasicBlock>();
-
-
-
- public BasicBlock() {}
-
- public BasicBlock(int id) {
- this.id = id;
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public Object clone() {
-
- BasicBlock block = new BasicBlock();
- block.id = id;
- block.setSeq(seq.clone());
- block.setInstrOldOffsets(new ArrayList<Integer>(instrOldOffsets));
-
- return block;
- }
-
- public void free() {
- preds.clear();
- succs.clear();
- instrOldOffsets.clear();
- succExceptions.clear();
- seq = new SimpleInstructionSequence();
- }
-
- public Instruction getInstruction(int index) {
- return seq.getInstr(index);
- }
-
- public Instruction getLastInstruction() {
- if(seq.isEmpty()) {
- return null;
- } else {
- return seq.getLastInstr();
- }
- }
-
- public int size() {
- return seq.length();
- }
-
- public void addPredecessor(BasicBlock block) {
- preds.add(block);
- }
-
- public void removePredecessor(BasicBlock block) {
- while(preds.remove(block));
- }
-
- public void addSuccessor(BasicBlock block) {
- succs.add(block);
- block.addPredecessor(this);
- }
-
- public void removeSuccessor(BasicBlock block) {
- while(succs.remove(block));
- block.removePredecessor(this);
- }
-
- // FIXME: unify block comparisons: id or direkt equality
- public void replaceSuccessor(BasicBlock oldBlock, BasicBlock newBlock) {
- for(int i=0;i<succs.size();i++) {
- if(succs.get(i).id == oldBlock.id) {
- succs.set(i, newBlock);
- oldBlock.removePredecessor(this);
- newBlock.addPredecessor(this);
- }
- }
-
- for(int i=0;i<succExceptions.size();i++) {
- if(succExceptions.get(i).id == oldBlock.id) {
- succExceptions.set(i, newBlock);
- oldBlock.removePredecessorException(this);
- newBlock.addPredecessorException(this);
- }
- }
- }
-
- public void addPredecessorException(BasicBlock block) {
- predExceptions.add(block);
- }
-
- public void removePredecessorException(BasicBlock block) {
- while(predExceptions.remove(block));
- }
-
- public void addSuccessorException(BasicBlock block) {
- if(!succExceptions.contains(block)) {
- succExceptions.add(block);
- block.addPredecessorException(this);
- }
- }
-
- public void removeSuccessorException(BasicBlock block) {
- while(succExceptions.remove(block));
- block.removePredecessorException(this);
- }
-
- public String toString() {
- return toString(0);
- }
-
- public String toString(int indent) {
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- return id+":" + new_line_separator +seq.toString(indent);
- }
-
- public String toStringOldIndices() {
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- StringBuffer buf = new StringBuffer();
-
- for(int i=0;i<seq.length();i++) {
- if(i<instrOldOffsets.size()) {
- buf.append(instrOldOffsets.get(i));
- } else {
- buf.append("-1");
- }
- buf.append(": ");
- buf.append(seq.getInstr(i).toString());
- buf.append(new_line_separator);
- }
-
- return buf.toString();
- }
-
- public boolean isSuccessor(BasicBlock block) {
- for(BasicBlock succ : succs) {
- if(succ.id == block.id) {
- return true;
- }
- }
- return false;
- }
-
- public boolean isPredecessor(BasicBlock block) {
- for(int i=0;i<preds.size();i++) {
- if(preds.get(i).id == block.id) {
- return true;
- }
- }
- return false;
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public List<Integer> getInstrOldOffsets() {
- return instrOldOffsets;
- }
-
- public void setInstrOldOffsets(List<Integer> instrInds) {
- this.instrOldOffsets = instrInds;
- }
-
- public List<? extends IGraphNode> getPredecessors() {
- List<BasicBlock> lst = new ArrayList<BasicBlock>(preds);
- lst.addAll(predExceptions);
- return lst;
- }
-
- public List<BasicBlock> getPreds() {
- return preds;
- }
-
- public void setPreds(List<BasicBlock> preds) {
- this.preds = preds;
- }
-
- public InstructionSequence getSeq() {
- return seq;
- }
-
- public void setSeq(InstructionSequence seq) {
- this.seq = seq;
- }
-
- public List<BasicBlock> getSuccs() {
- return succs;
- }
-
- public void setSuccs(List<BasicBlock> succs) {
- this.succs = succs;
- }
-
-
- public List<BasicBlock> getSuccExceptions() {
- return succExceptions;
- }
-
-
- public void setSuccExceptions(List<BasicBlock> succExceptions) {
- this.succExceptions = succExceptions;
- }
-
- public List<BasicBlock> getPredExceptions() {
- return predExceptions;
- }
-
- public void setPredExceptions(List<BasicBlock> predExceptions) {
- this.predExceptions = predExceptions;
- }
-
-
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int id = 0;
+
+ public int mark = 0;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private InstructionSequence seq = new SimpleInstructionSequence();
+
+ private List<BasicBlock> preds = new ArrayList<BasicBlock>();
+
+ private List<BasicBlock> succs = new ArrayList<BasicBlock>();
+
+ private List<Integer> instrOldOffsets = new ArrayList<Integer>();
+
+ private List<BasicBlock> predExceptions = new ArrayList<BasicBlock>();
+
+ private List<BasicBlock> succExceptions = new ArrayList<BasicBlock>();
+
+
+ public BasicBlock() {
+ }
+
+ public BasicBlock(int id) {
+ this.id = id;
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public Object clone() {
+
+ BasicBlock block = new BasicBlock();
+ block.id = id;
+ block.setSeq(seq.clone());
+ block.setInstrOldOffsets(new ArrayList<Integer>(instrOldOffsets));
+
+ return block;
+ }
+
+ public void free() {
+ preds.clear();
+ succs.clear();
+ instrOldOffsets.clear();
+ succExceptions.clear();
+ seq = new SimpleInstructionSequence();
+ }
+
+ public Instruction getInstruction(int index) {
+ return seq.getInstr(index);
+ }
+
+ public Instruction getLastInstruction() {
+ if (seq.isEmpty()) {
+ return null;
+ }
+ else {
+ return seq.getLastInstr();
+ }
+ }
+
+ public int size() {
+ return seq.length();
+ }
+
+ public void addPredecessor(BasicBlock block) {
+ preds.add(block);
+ }
+
+ public void removePredecessor(BasicBlock block) {
+ while (preds.remove(block)) ;
+ }
+
+ public void addSuccessor(BasicBlock block) {
+ succs.add(block);
+ block.addPredecessor(this);
+ }
+
+ public void removeSuccessor(BasicBlock block) {
+ while (succs.remove(block)) ;
+ block.removePredecessor(this);
+ }
+
+ // FIXME: unify block comparisons: id or direkt equality
+ public void replaceSuccessor(BasicBlock oldBlock, BasicBlock newBlock) {
+ for (int i = 0; i < succs.size(); i++) {
+ if (succs.get(i).id == oldBlock.id) {
+ succs.set(i, newBlock);
+ oldBlock.removePredecessor(this);
+ newBlock.addPredecessor(this);
+ }
+ }
+
+ for (int i = 0; i < succExceptions.size(); i++) {
+ if (succExceptions.get(i).id == oldBlock.id) {
+ succExceptions.set(i, newBlock);
+ oldBlock.removePredecessorException(this);
+ newBlock.addPredecessorException(this);
+ }
+ }
+ }
+
+ public void addPredecessorException(BasicBlock block) {
+ predExceptions.add(block);
+ }
+
+ public void removePredecessorException(BasicBlock block) {
+ while (predExceptions.remove(block)) ;
+ }
+
+ public void addSuccessorException(BasicBlock block) {
+ if (!succExceptions.contains(block)) {
+ succExceptions.add(block);
+ block.addPredecessorException(this);
+ }
+ }
+
+ public void removeSuccessorException(BasicBlock block) {
+ while (succExceptions.remove(block)) ;
+ block.removePredecessorException(this);
+ }
+
+ public String toString() {
+ return toString(0);
+ }
+
+ public String toString(int indent) {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ return id + ":" + new_line_separator + seq.toString(indent);
+ }
+
+ public String toStringOldIndices() {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuffer buf = new StringBuffer();
+
+ for (int i = 0; i < seq.length(); i++) {
+ if (i < instrOldOffsets.size()) {
+ buf.append(instrOldOffsets.get(i));
+ }
+ else {
+ buf.append("-1");
+ }
+ buf.append(": ");
+ buf.append(seq.getInstr(i).toString());
+ buf.append(new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public boolean isSuccessor(BasicBlock block) {
+ for (BasicBlock succ : succs) {
+ if (succ.id == block.id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isPredecessor(BasicBlock block) {
+ for (int i = 0; i < preds.size(); i++) {
+ if (preds.get(i).id == block.id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public List<Integer> getInstrOldOffsets() {
+ return instrOldOffsets;
+ }
+
+ public void setInstrOldOffsets(List<Integer> instrInds) {
+ this.instrOldOffsets = instrInds;
+ }
+
+ public List<? extends IGraphNode> getPredecessors() {
+ List<BasicBlock> lst = new ArrayList<BasicBlock>(preds);
+ lst.addAll(predExceptions);
+ return lst;
+ }
+
+ public List<BasicBlock> getPreds() {
+ return preds;
+ }
+
+ public void setPreds(List<BasicBlock> preds) {
+ this.preds = preds;
+ }
+
+ public InstructionSequence getSeq() {
+ return seq;
+ }
+
+ public void setSeq(InstructionSequence seq) {
+ this.seq = seq;
+ }
+
+ public List<BasicBlock> getSuccs() {
+ return succs;
+ }
+
+ public void setSuccs(List<BasicBlock> succs) {
+ this.succs = succs;
+ }
+
+
+ public List<BasicBlock> getSuccExceptions() {
+ return succExceptions;
+ }
+
+
+ public void setSuccExceptions(List<BasicBlock> succExceptions) {
+ this.succExceptions = succExceptions;
+ }
+
+ public List<BasicBlock> getPredExceptions() {
+ return predExceptions;
+ }
+
+ public void setPredExceptions(List<BasicBlock> predExceptions) {
+ this.predExceptions = predExceptions;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java b/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java
index 824e8af..6b0624f 100644
--- a/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java
+++ b/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java
@@ -1,37 +1,21 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.cfg;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.code.ExceptionHandler;
-import org.jetbrains.java.decompiler.code.Instruction;
-import org.jetbrains.java.decompiler.code.InstructionSequence;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-import org.jetbrains.java.decompiler.code.SimpleInstructionSequence;
-import org.jetbrains.java.decompiler.code.SwitchInstruction;
+import org.jetbrains.java.decompiler.code.*;
import org.jetbrains.java.decompiler.code.interpreter.InstructionImpact;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper;
@@ -42,846 +26,852 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.ListStack;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.util.*;
+import java.util.Map.Entry;
+
public class ControlFlowGraph implements CodeConstants {
- public int last_id = 0;
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private VBStyleCollection<BasicBlock, Integer> blocks;
-
- private BasicBlock first;
-
- private BasicBlock last;
-
- private List<ExceptionRangeCFG> exceptions;
-
- private HashMap<BasicBlock, BasicBlock> subroutines;
-
- private HashSet<BasicBlock> finallyExits = new HashSet<BasicBlock>();
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public ControlFlowGraph(InstructionSequence seq) {
- buildBlocks(seq);
- }
-
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public void free() {
-
- for(BasicBlock block: blocks) {
- block.free();
- }
-
- blocks.clear();
- first = null;
- last = null;
- exceptions.clear();
- finallyExits.clear();
- }
-
- public void removeMarkers() {
- for(BasicBlock block: blocks) {
- block.mark = 0;
- }
- }
-
- public String toString() {
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- StringBuffer buf = new StringBuffer();
-
- for(BasicBlock block: blocks) {
- buf.append("----- Block "+block.id+" -----" + new_line_separator);
- buf.append(block.toString());
- buf.append("----- Edges -----" + new_line_separator);
-
- List<BasicBlock> suc = block.getSuccs();
- for(int j=0;j<suc.size();j++) {
- buf.append(">>>>>>>>(regular) Block "+((BasicBlock)suc.get(j)).id+new_line_separator);
- }
- suc = block.getSuccExceptions();
- for(int j=0;j<suc.size();j++) {
- BasicBlock handler = (BasicBlock)suc.get(j);
- ExceptionRangeCFG range = getExceptionRange(handler, block);
-
- if(range == null) {
- buf.append(">>>>>>>>(exception) Block "+handler.id+"\t"+"ERROR: range not found!"+new_line_separator);
- } else {
- List<String> exceptionTypes = range.getExceptionTypes();
- if(exceptionTypes == null) {
- buf.append(">>>>>>>>(exception) Block "+handler.id+"\t"+"NULL"+new_line_separator);
- } else {
- for(String exceptionType : exceptionTypes) {
- buf.append(">>>>>>>>(exception) Block "+handler.id+"\t"+exceptionType+new_line_separator);
- }
- }
- }
- }
- buf.append("----- ----- -----" + new_line_separator);
-
- }
-
- return buf.toString();
-
- }
-
- public void inlineJsr(StructMethod mt) {
- processJsr();
- removeJsr(mt);
-
- removeMarkers();
-
- DeadCodeHelper.removeEmptyBlocks(this);
- }
-
- public void removeBlock(BasicBlock block) {
-
- while(block.getSuccs().size()>0) {
- block.removeSuccessor((BasicBlock)block.getSuccs().get(0));
- }
-
- while(block.getSuccExceptions().size()>0) {
- block.removeSuccessorException((BasicBlock)block.getSuccExceptions().get(0));
- }
-
- while(block.getPreds().size()>0) {
- ((BasicBlock)block.getPreds().get(0)).removeSuccessor(block);
- }
-
- while(block.getPredExceptions().size()>0) {
- ((BasicBlock)block.getPredExceptions().get(0)).removeSuccessorException(block);
- }
-
- last.removePredecessor(block);
-
- blocks.removeWithKey(block.id);
-
- for(int i=exceptions.size()-1;i>=0;i--) {
- ExceptionRangeCFG range = (ExceptionRangeCFG)exceptions.get(i);
- if(range.getHandler() == block) {
- exceptions.remove(i);
- } else {
- List<BasicBlock> lstRange = range.getProtectedRange();
- lstRange.remove(block);
-
- if(lstRange.isEmpty()) {
- exceptions.remove(i);
- }
- }
- }
-
- Iterator<Entry<BasicBlock, BasicBlock>> it = subroutines.entrySet().iterator();
- while(it.hasNext()) {
- Entry<BasicBlock, BasicBlock> ent = it.next();
- if(ent.getKey() == block || ent.getValue() == block) {
- it.remove();
- }
- }
-
- }
-
- public ExceptionRangeCFG getExceptionRange(BasicBlock handler, BasicBlock block) {
-
- //List<ExceptionRangeCFG> ranges = new ArrayList<ExceptionRangeCFG>();
-
- for(int i=exceptions.size()-1;i>=0;i--) {
- ExceptionRangeCFG range = exceptions.get(i);
- if(range.getHandler() == handler && range.getProtectedRange().contains(block)) {
- return range;
- //ranges.add(range);
- }
- }
-
- return null;
- //return ranges.isEmpty() ? null : ranges;
- }
-
-// public String getExceptionsUniqueString(BasicBlock handler, BasicBlock block) {
-//
-// List<ExceptionRangeCFG> ranges = getExceptionRange(handler, block);
-//
-// if(ranges == null) {
-// return null;
-// } else {
-// Set<String> setExceptionStrings = new HashSet<String>();
-// for(ExceptionRangeCFG range : ranges) {
-// setExceptionStrings.add(range.getExceptionType());
-// }
-//
-// String ret = "";
-// for(String exception : setExceptionStrings) {
-// ret += exception;
-// }
-//
-// return ret;
-// }
-// }
-
-
- // *****************************************************************************
- // private methods
- // *****************************************************************************
-
- private void buildBlocks(InstructionSequence instrseq) {
-
- short[] states = findStartInstructions(instrseq);
-
- HashMap<Integer, BasicBlock> mapInstrBlocks = new HashMap<Integer, BasicBlock>();
- VBStyleCollection<BasicBlock, Integer> colBlocks = createBasicBlocks(states, instrseq, mapInstrBlocks);
-
- blocks = colBlocks;
-
- connectBlocks(colBlocks, mapInstrBlocks);
-
- setExceptionEdges(instrseq, mapInstrBlocks);
-
- setSubroutineEdges();
-
- setFirstAndLastBlocks();
- }
-
- private short[] findStartInstructions(InstructionSequence seq) {
-
- int len = seq.length();
- short[] inststates = new short[len];
-
- HashSet<Integer> excSet = new HashSet<Integer>();
-
- for(ExceptionHandler handler : seq.getExceptionTable().getHandlers()) {
- excSet.add(handler.from_instr);
- excSet.add(handler.to_instr);
- excSet.add(handler.handler_instr);
- }
-
-
- for(int i=0;i<len;i++) {
-
- // exception blocks
- if(excSet.contains(new Integer(i))) {
- inststates[i] = 1;
- }
-
- Instruction instr = seq.getInstr(i);
- switch(instr.group){
- case GROUP_JUMP:
- inststates[((JumpInstruction)instr).destination] = 1;
- case GROUP_RETURN:
- if(i+1 < len) {
- inststates[i+1] = 1;
- }
- break;
- case GROUP_SWITCH:
- SwitchInstruction swinstr = (SwitchInstruction)instr;
- int[] dests = swinstr.getDestinations();
- for(int j=dests.length-1;j>=0;j--) {
- inststates[dests[j]] = 1;
- }
- inststates[swinstr.getDefaultdest()] = 1;
- if(i+1 < len) {
- inststates[i+1] = 1;
- }
- }
- }
-
- // first instruction
- inststates[0] = 1;
-
- return inststates;
- }
-
-
- private VBStyleCollection<BasicBlock, Integer> createBasicBlocks(short[] startblock, InstructionSequence instrseq,
- HashMap<Integer, BasicBlock> mapInstrBlocks) {
-
- VBStyleCollection<BasicBlock, Integer> col = new VBStyleCollection<BasicBlock, Integer>();
-
- InstructionSequence currseq = null;
- ArrayList<Integer> lstOffs = null;
-
- int len = startblock.length;
- short counter = 0;
- int blockoffset = 0;
-
- BasicBlock currentBlock = null;
- for(int i=0;i<len;i++) {
-
- if (startblock[i] == 1) {
- currentBlock = new BasicBlock();
- currentBlock.id = ++counter;
-
- currseq = new SimpleInstructionSequence();
- lstOffs = new ArrayList<Integer>();
-
- currentBlock.setSeq(currseq);
- currentBlock.setInstrOldOffsets(lstOffs);
- col.addWithKey(currentBlock, currentBlock.id);
-
- blockoffset = instrseq.getOffset(i);
- }
-
- startblock[i] = counter;
- mapInstrBlocks.put(i, currentBlock);
-
- currseq.addInstruction(instrseq.getInstr(i), instrseq.getOffset(i)-blockoffset);
- lstOffs.add(instrseq.getOffset(i));
- }
-
- last_id = counter;
-
- return col;
- }
-
-
- private void connectBlocks(List<BasicBlock> lstbb, HashMap<Integer, BasicBlock> mapInstrBlocks) {
-
- for(int i=0;i<lstbb.size();i++) {
-
- BasicBlock block = lstbb.get(i);
- Instruction instr = block.getLastInstruction();
-
- boolean fallthrough = instr.canFallthrough();
- BasicBlock bTemp;
-
- switch(instr.group) {
- case GROUP_JUMP:
- int dest = ((JumpInstruction)instr).destination;
- bTemp = mapInstrBlocks.get(dest);
- block.addSuccessor(bTemp);
-
- break;
- case GROUP_SWITCH:
- SwitchInstruction sinstr = (SwitchInstruction)instr;
- int[] dests = sinstr.getDestinations();
-
- bTemp = mapInstrBlocks.get(((SwitchInstruction)instr).getDefaultdest());
- block.addSuccessor(bTemp);
- for(int j=0;j<dests.length;j++) {
- bTemp = mapInstrBlocks.get(dests[j]);
- block.addSuccessor(bTemp);
- }
- }
-
- if(fallthrough && i<lstbb.size()-1) {
- BasicBlock defaultBlock = lstbb.get(i+1);
- block.addSuccessor(defaultBlock);
- }
- }
-
- }
-
- private void setExceptionEdges(InstructionSequence instrseq, HashMap<Integer, BasicBlock> instrBlocks) {
-
- exceptions = new ArrayList<ExceptionRangeCFG>();
-
- Map<String, ExceptionRangeCFG> mapRanges = new HashMap<String, ExceptionRangeCFG>();
-
- for(ExceptionHandler handler : instrseq.getExceptionTable().getHandlers()) {
-
- BasicBlock from = instrBlocks.get(handler.from_instr);
- BasicBlock to = instrBlocks.get(handler.to_instr);
- BasicBlock handle = instrBlocks.get(handler.handler_instr);
-
- String key = from.id + ":" + to.id + ":" + handle.id;
-
- if(mapRanges.containsKey(key)) {
- ExceptionRangeCFG range = mapRanges.get(key);
- range.addExceptionType(handler.exceptionClass);
- } else {
-
- List<BasicBlock> protectedRange = new ArrayList<BasicBlock>();
- for(int j=from.id;j<to.id;j++) {
- BasicBlock block = blocks.getWithKey(j);
- protectedRange.add(block);
- block.addSuccessorException(handle);
- }
-
- ExceptionRangeCFG range = new ExceptionRangeCFG(protectedRange, handle, handler.exceptionClass == null ? null : Arrays.asList(new String[]{handler.exceptionClass}));
- mapRanges.put(key, range);
-
- exceptions.add(range);
- }
- }
- }
-
- private void setSubroutineEdges() {
-
- final HashMap<BasicBlock, BasicBlock> subroutines = new HashMap<BasicBlock, BasicBlock>();
-
- for(BasicBlock block : blocks) {
-
- if(block.getSeq().getLastInstr().opcode == CodeConstants.opc_jsr) {
-
- LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
- LinkedList<LinkedList<BasicBlock>> stackJsrStacks = new LinkedList<LinkedList<BasicBlock>>();
-
- HashSet<BasicBlock> setVisited = new HashSet<BasicBlock>();
-
- stack.add(block);
- stackJsrStacks.add(new LinkedList<BasicBlock>());
-
- while(!stack.isEmpty()) {
-
- BasicBlock node = stack.removeFirst();
- LinkedList<BasicBlock> jsrstack = stackJsrStacks.removeFirst();
-
- setVisited.add(node);
-
- switch(node.getSeq().getLastInstr().opcode) {
- case CodeConstants.opc_jsr:
- jsrstack.add(node);
- break;
- case CodeConstants.opc_ret:
- BasicBlock enter = jsrstack.getLast();
- BasicBlock exit = blocks.getWithKey(enter.id + 1); // FIXME: find successor in a better way
-
- if(exit!=null) {
- if(!node.isSuccessor(exit)) {
- node.addSuccessor(exit);
- }
- jsrstack.removeLast();
- subroutines.put(enter, exit);
- } else {
- throw new RuntimeException("ERROR: last instruction jsr");
- }
- }
-
- if(!jsrstack.isEmpty()) {
- for(BasicBlock succ : node.getSuccs()) {
- if(!setVisited.contains(succ)) {
- stack.add(succ);
- stackJsrStacks.add(new LinkedList<BasicBlock>(jsrstack));
- }
- }
- }
- }
- }
- }
-
- this.subroutines = subroutines;
- }
-
- private void processJsr() {
-
- while(processJsrRanges()!=0);
- }
-
- private int processJsrRanges() {
-
- List<Object[]> lstJsrAll = new ArrayList<Object[]>();
-
- // get all jsr ranges
- for(Entry<BasicBlock, BasicBlock> ent : subroutines.entrySet()){
- BasicBlock jsr = ent.getKey();
- BasicBlock ret = ent.getValue();
-
- lstJsrAll.add(new Object[]{jsr, getJsrRange(jsr, ret), ret});
- }
-
- // sort ranges
- // FIXME: better sort order
- List<Object[]> lstJsr = new ArrayList<Object[]>();
- for(Object[] arr : lstJsrAll) {
- int i=0;
- for(;i<lstJsr.size();i++) {
- Object[] arrJsr = lstJsr.get(i);
-
- if(((HashSet<BasicBlock>)arrJsr[1]).contains(arr[0])) {
- break;
- }
- }
-
- lstJsr.add(i, arr);
- }
-
- // find the first intersection
- for(int i=0;i<lstJsr.size();i++) {
- Object[] arr = (Object[])lstJsr.get(i);
- HashSet<BasicBlock> set = (HashSet<BasicBlock>)arr[1];
-
- for(int j=i+1;j<lstJsr.size();j++) {
- Object[] arr1 = (Object[])lstJsr.get(j);
- HashSet<BasicBlock> set1 = (HashSet<BasicBlock>)arr1[1];
-
- if(!set.contains(arr1[0]) && !set1.contains(arr[0])) { // rang 0 doesn't contain entry 1 and vice versa
- HashSet<BasicBlock> setc = new HashSet<BasicBlock>(set);
- setc.retainAll(set1);
-
- if(!setc.isEmpty()) {
- splitJsrRange((BasicBlock)arr[0], (BasicBlock)arr[2], setc);
- return 1;
- }
- }
- }
- }
-
- return 0;
- }
-
- private HashSet<BasicBlock> getJsrRange(BasicBlock jsr, BasicBlock ret) {
-
- HashSet<BasicBlock> blocks = new HashSet<BasicBlock>();
-
- LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
- lstNodes.add(jsr);
-
- BasicBlock dom = jsr.getSuccs().get(0);
-
- while(!lstNodes.isEmpty()) {
-
- BasicBlock node = lstNodes.remove(0);
-
- for(int j=0;j<2;j++) {
- List<BasicBlock> lst;
- if(j==0) {
- if(node.getLastInstruction().opcode == CodeConstants.opc_ret) {
- if(node.getSuccs().contains(ret)) {
- continue;
- }
- }
- lst = node.getSuccs();
- } else {
- if(node == jsr) {
- continue;
- }
- lst = node.getSuccExceptions();
- }
-
- CHILD:
- for(int i=lst.size()-1;i>=0;i--) {
-
- BasicBlock child = lst.get(i);
- if(!blocks.contains(child)) {
-
- if(node != jsr) {
- for(int k=0;k<child.getPreds().size();k++) {
- if(!DeadCodeHelper.isDominator(this, child.getPreds().get(k), dom)) {
- continue CHILD;
- }
- }
-
- for(int k=0;k<child.getPredExceptions().size();k++) {
- if(!DeadCodeHelper.isDominator(this, child.getPredExceptions().get(k), dom)) {
- continue CHILD;
- }
- }
- }
-
- // last block is a dummy one
- if(child!=last) {
- blocks.add(child);
- }
-
- lstNodes.add(child);
- }
- }
- }
- }
-
- return blocks;
- }
-
- private void splitJsrRange(BasicBlock jsr, BasicBlock ret, HashSet<BasicBlock> common_blocks) {
-
- LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
- HashMap<Integer, BasicBlock> mapNewNodes = new HashMap<Integer, BasicBlock>();
-
- lstNodes.add(jsr);
- mapNewNodes.put(jsr.id, jsr);
-
- while(!lstNodes.isEmpty()) {
-
- BasicBlock node = lstNodes.remove(0);
-
- for(int j=0;j<2;j++) {
- List<BasicBlock> lst;
- if(j==0) {
- if(node.getLastInstruction().opcode == CodeConstants.opc_ret) {
- if(node.getSuccs().contains(ret)) {
- continue;
- }
- }
- lst = node.getSuccs();
- } else {
- if(node == jsr) {
- continue;
- }
- lst = node.getSuccExceptions();
- }
-
-
- for(int i=lst.size()-1;i>=0;i--) {
-
- BasicBlock child = (BasicBlock)lst.get(i);
- Integer childid = child.id;
-
- if(mapNewNodes.containsKey(childid)) {
- node.replaceSuccessor(child, (BasicBlock)mapNewNodes.get(childid));
- } else if(common_blocks.contains(child)) {
-
- // make a copy of the current block
- BasicBlock copy = (BasicBlock)child.clone();
- copy.id = ++last_id;
- // copy all successors
- if(copy.getLastInstruction().opcode == CodeConstants.opc_ret &&
- child.getSuccs().contains(ret)) {
- copy.addSuccessor(ret);
- child.removeSuccessor(ret);
- } else {
- for(int k=0;k<child.getSuccs().size();k++) {
- copy.addSuccessor((BasicBlock)child.getSuccs().get(k));
- }
- }
- for(int k=0;k<child.getSuccExceptions().size();k++) {
- copy.addSuccessorException((BasicBlock)child.getSuccExceptions().get(k));
- }
-
- lstNodes.add(copy);
- mapNewNodes.put(childid, copy);
-
- if(last.getPreds().contains(child)) {
- last.addPredecessor(copy);
- }
-
- node.replaceSuccessor(child, copy);
- blocks.addWithKey(copy, copy.id);
- } else {
- // stop at the first fixed node
- //lstNodes.add(child);
- mapNewNodes.put(childid, child);
- }
- }
-
- }
- }
-
- // note: subroutines won't be copied!
- splitJsrExceptionRanges(common_blocks, mapNewNodes);
- }
-
- private void splitJsrExceptionRanges(HashSet<BasicBlock> common_blocks, HashMap<Integer, BasicBlock> mapNewNodes) {
-
- for(int i=exceptions.size()-1;i>=0;i--) {
-
- ExceptionRangeCFG range = (ExceptionRangeCFG)exceptions.get(i);
- List<BasicBlock> lstRange = range.getProtectedRange();
-
- HashSet<BasicBlock> setBoth = new HashSet<BasicBlock>(common_blocks);
- setBoth.retainAll(lstRange);
-
- if(setBoth.size()>0) {
- List<BasicBlock> lstNewRange;
-
- if(setBoth.size()==lstRange.size()) {
- lstNewRange = new ArrayList<BasicBlock>();
- ExceptionRangeCFG newRange = new ExceptionRangeCFG(lstNewRange,
- (BasicBlock)mapNewNodes.get(range.getHandler().id),range.getExceptionTypes());
- exceptions.add(newRange);
- } else {
- lstNewRange = lstRange;
- }
-
- for(BasicBlock block : setBoth) {
- lstNewRange.add(mapNewNodes.get(block.id));
- }
- }
- }
-
- }
-
- private void removeJsr(StructMethod mt) {
- removeJsrInstructions(mt.getClassStruct().getPool(), first, DataPoint.getInitialDataPoint(mt));
- }
-
- private void removeJsrInstructions(ConstantPool pool, BasicBlock block, DataPoint data) {
-
- ListStack<VarType> stack = data.getStack();
-
- InstructionSequence seq = block.getSeq();
- for(int i=0;i<seq.length();i++) {
- Instruction instr = seq.getInstr(i);
-
- VarType var = null;
- if(instr.opcode == CodeConstants.opc_astore || instr.opcode == CodeConstants.opc_pop) {
- var = stack.getByOffset(-1);
- }
-
- InstructionImpact.stepTypes(data, instr, pool);
-
- switch(instr.opcode) {
- case CodeConstants.opc_jsr:
- case CodeConstants.opc_ret:
- seq.removeInstruction(i);
- i--;
- break;
- case CodeConstants.opc_astore:
- case CodeConstants.opc_pop:
- if(var.type == CodeConstants.TYPE_ADDRESS) {
- seq.removeInstruction(i);
- i--;
- }
- }
-
- }
-
- block.mark = 1;
-
- for(int i=0;i<block.getSuccs().size();i++) {
- BasicBlock suc = (BasicBlock)block.getSuccs().get(i);
- if(suc.mark != 1) {
- removeJsrInstructions(pool, suc, data.copy());
- }
- }
-
- for(int i=0;i<block.getSuccExceptions().size();i++) {
- BasicBlock suc = (BasicBlock)block.getSuccExceptions().get(i);
- if(suc.mark != 1) {
-
- DataPoint point = new DataPoint();
- point.setLocalVariables(new ArrayList<VarType>(data.getLocalVariables()));
- point.getStack().push(new VarType(CodeConstants.TYPE_OBJECT, 0, null));
-
- removeJsrInstructions(pool, suc, point);
- }
- }
-
- }
-
- private void setFirstAndLastBlocks() {
-
- first = blocks.get(0);
-
- last = new BasicBlock();
- last.id = ++last_id;
- last.setSeq(new SimpleInstructionSequence());
-
- for(BasicBlock block: blocks) {
- if(block.getSuccs().isEmpty()) {
- last.addPredecessor(block);
- }
- }
- }
-
- public List<BasicBlock> getReversePostOrder() {
-
- LinkedList<BasicBlock> res = new LinkedList<BasicBlock>();
- addToReversePostOrderListIterative(first, res);
-
- return res;
- }
-
- private void addToReversePostOrderListIterative(BasicBlock root, List<BasicBlock> lst) {
-
- LinkedList<BasicBlock> stackNode = new LinkedList<BasicBlock>();
- LinkedList<Integer> stackIndex = new LinkedList<Integer>();
-
- HashSet<BasicBlock> setVisited = new HashSet<BasicBlock>();
-
- stackNode.add(root);
- stackIndex.add(0);
-
- while(!stackNode.isEmpty()) {
-
- BasicBlock node = stackNode.getLast();
- int index = stackIndex.removeLast();
-
- setVisited.add(node);
-
- List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(node.getSuccs());
- lstSuccs.addAll(node.getSuccExceptions());
-
- for(;index<lstSuccs.size();index++) {
- BasicBlock succ = lstSuccs.get(index);
-
- if(!setVisited.contains(succ)) {
- stackIndex.add(index+1);
-
- stackNode.add(succ);
- stackIndex.add(0);
-
- break;
- }
- }
-
- if(index == lstSuccs.size()) {
- lst.add(0, node);
-
- stackNode.removeLast();
- }
- }
-
- }
-
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public VBStyleCollection<BasicBlock, Integer> getBlocks() {
- return blocks;
- }
-
- public void setBlocks(VBStyleCollection<BasicBlock, Integer> blocks) {
- this.blocks = blocks;
- }
-
- public BasicBlock getFirst() {
- return first;
- }
-
- public void setFirst(BasicBlock first) {
- this.first = first;
- }
-
- public List<BasicBlock> getEndBlocks() {
- return last.getPreds();
- }
-
- public List<ExceptionRangeCFG> getExceptions() {
- return exceptions;
- }
-
- public void setExceptions(List<ExceptionRangeCFG> exceptions) {
- this.exceptions = exceptions;
- }
-
-
- public BasicBlock getLast() {
- return last;
- }
-
-
- public void setLast(BasicBlock last) {
- this.last = last;
- }
-
-
- public HashMap<BasicBlock, BasicBlock> getSubroutines() {
- return subroutines;
- }
-
-
- public void setSubroutines(HashMap<BasicBlock, BasicBlock> subroutines) {
- this.subroutines = subroutines;
- }
-
-
- public HashSet<BasicBlock> getFinallyExits() {
- return finallyExits;
- }
-
-
- public void setFinallyExits(HashSet<BasicBlock> finallyExits) {
- this.finallyExits = finallyExits;
- }
+ public int last_id = 0;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private VBStyleCollection<BasicBlock, Integer> blocks;
+
+ private BasicBlock first;
+
+ private BasicBlock last;
+
+ private List<ExceptionRangeCFG> exceptions;
+
+ private HashMap<BasicBlock, BasicBlock> subroutines;
+
+ private HashSet<BasicBlock> finallyExits = new HashSet<BasicBlock>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public ControlFlowGraph(InstructionSequence seq) {
+ buildBlocks(seq);
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void free() {
+
+ for (BasicBlock block : blocks) {
+ block.free();
+ }
+
+ blocks.clear();
+ first = null;
+ last = null;
+ exceptions.clear();
+ finallyExits.clear();
+ }
+
+ public void removeMarkers() {
+ for (BasicBlock block : blocks) {
+ block.mark = 0;
+ }
+ }
+
+ public String toString() {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuffer buf = new StringBuffer();
+
+ for (BasicBlock block : blocks) {
+ buf.append("----- Block " + block.id + " -----" + new_line_separator);
+ buf.append(block.toString());
+ buf.append("----- Edges -----" + new_line_separator);
+
+ List<BasicBlock> suc = block.getSuccs();
+ for (int j = 0; j < suc.size(); j++) {
+ buf.append(">>>>>>>>(regular) Block " + ((BasicBlock)suc.get(j)).id + new_line_separator);
+ }
+ suc = block.getSuccExceptions();
+ for (int j = 0; j < suc.size(); j++) {
+ BasicBlock handler = (BasicBlock)suc.get(j);
+ ExceptionRangeCFG range = getExceptionRange(handler, block);
+
+ if (range == null) {
+ buf.append(">>>>>>>>(exception) Block " + handler.id + "\t" + "ERROR: range not found!" + new_line_separator);
+ }
+ else {
+ List<String> exceptionTypes = range.getExceptionTypes();
+ if (exceptionTypes == null) {
+ buf.append(">>>>>>>>(exception) Block " + handler.id + "\t" + "NULL" + new_line_separator);
+ }
+ else {
+ for (String exceptionType : exceptionTypes) {
+ buf.append(">>>>>>>>(exception) Block " + handler.id + "\t" + exceptionType + new_line_separator);
+ }
+ }
+ }
+ }
+ buf.append("----- ----- -----" + new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public void inlineJsr(StructMethod mt) {
+ processJsr();
+ removeJsr(mt);
+
+ removeMarkers();
+
+ DeadCodeHelper.removeEmptyBlocks(this);
+ }
+
+ public void removeBlock(BasicBlock block) {
+
+ while (block.getSuccs().size() > 0) {
+ block.removeSuccessor((BasicBlock)block.getSuccs().get(0));
+ }
+
+ while (block.getSuccExceptions().size() > 0) {
+ block.removeSuccessorException((BasicBlock)block.getSuccExceptions().get(0));
+ }
+
+ while (block.getPreds().size() > 0) {
+ ((BasicBlock)block.getPreds().get(0)).removeSuccessor(block);
+ }
+
+ while (block.getPredExceptions().size() > 0) {
+ ((BasicBlock)block.getPredExceptions().get(0)).removeSuccessorException(block);
+ }
+
+ last.removePredecessor(block);
+
+ blocks.removeWithKey(block.id);
+
+ for (int i = exceptions.size() - 1; i >= 0; i--) {
+ ExceptionRangeCFG range = (ExceptionRangeCFG)exceptions.get(i);
+ if (range.getHandler() == block) {
+ exceptions.remove(i);
+ }
+ else {
+ List<BasicBlock> lstRange = range.getProtectedRange();
+ lstRange.remove(block);
+
+ if (lstRange.isEmpty()) {
+ exceptions.remove(i);
+ }
+ }
+ }
+
+ Iterator<Entry<BasicBlock, BasicBlock>> it = subroutines.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry<BasicBlock, BasicBlock> ent = it.next();
+ if (ent.getKey() == block || ent.getValue() == block) {
+ it.remove();
+ }
+ }
+ }
+
+ public ExceptionRangeCFG getExceptionRange(BasicBlock handler, BasicBlock block) {
+
+ //List<ExceptionRangeCFG> ranges = new ArrayList<ExceptionRangeCFG>();
+
+ for (int i = exceptions.size() - 1; i >= 0; i--) {
+ ExceptionRangeCFG range = exceptions.get(i);
+ if (range.getHandler() == handler && range.getProtectedRange().contains(block)) {
+ return range;
+ //ranges.add(range);
+ }
+ }
+
+ return null;
+ //return ranges.isEmpty() ? null : ranges;
+ }
+
+ // public String getExceptionsUniqueString(BasicBlock handler, BasicBlock block) {
+ //
+ // List<ExceptionRangeCFG> ranges = getExceptionRange(handler, block);
+ //
+ // if(ranges == null) {
+ // return null;
+ // } else {
+ // Set<String> setExceptionStrings = new HashSet<String>();
+ // for(ExceptionRangeCFG range : ranges) {
+ // setExceptionStrings.add(range.getExceptionType());
+ // }
+ //
+ // String ret = "";
+ // for(String exception : setExceptionStrings) {
+ // ret += exception;
+ // }
+ //
+ // return ret;
+ // }
+ // }
+
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private void buildBlocks(InstructionSequence instrseq) {
+
+ short[] states = findStartInstructions(instrseq);
+
+ HashMap<Integer, BasicBlock> mapInstrBlocks = new HashMap<Integer, BasicBlock>();
+ VBStyleCollection<BasicBlock, Integer> colBlocks = createBasicBlocks(states, instrseq, mapInstrBlocks);
+
+ blocks = colBlocks;
+
+ connectBlocks(colBlocks, mapInstrBlocks);
+
+ setExceptionEdges(instrseq, mapInstrBlocks);
+
+ setSubroutineEdges();
+
+ setFirstAndLastBlocks();
+ }
+
+ private short[] findStartInstructions(InstructionSequence seq) {
+
+ int len = seq.length();
+ short[] inststates = new short[len];
+
+ HashSet<Integer> excSet = new HashSet<Integer>();
+
+ for (ExceptionHandler handler : seq.getExceptionTable().getHandlers()) {
+ excSet.add(handler.from_instr);
+ excSet.add(handler.to_instr);
+ excSet.add(handler.handler_instr);
+ }
+
+
+ for (int i = 0; i < len; i++) {
+
+ // exception blocks
+ if (excSet.contains(new Integer(i))) {
+ inststates[i] = 1;
+ }
+
+ Instruction instr = seq.getInstr(i);
+ switch (instr.group) {
+ case GROUP_JUMP:
+ inststates[((JumpInstruction)instr).destination] = 1;
+ case GROUP_RETURN:
+ if (i + 1 < len) {
+ inststates[i + 1] = 1;
+ }
+ break;
+ case GROUP_SWITCH:
+ SwitchInstruction swinstr = (SwitchInstruction)instr;
+ int[] dests = swinstr.getDestinations();
+ for (int j = dests.length - 1; j >= 0; j--) {
+ inststates[dests[j]] = 1;
+ }
+ inststates[swinstr.getDefaultdest()] = 1;
+ if (i + 1 < len) {
+ inststates[i + 1] = 1;
+ }
+ }
+ }
+
+ // first instruction
+ inststates[0] = 1;
+
+ return inststates;
+ }
+
+
+ private VBStyleCollection<BasicBlock, Integer> createBasicBlocks(short[] startblock, InstructionSequence instrseq,
+ HashMap<Integer, BasicBlock> mapInstrBlocks) {
+
+ VBStyleCollection<BasicBlock, Integer> col = new VBStyleCollection<BasicBlock, Integer>();
+
+ InstructionSequence currseq = null;
+ ArrayList<Integer> lstOffs = null;
+
+ int len = startblock.length;
+ short counter = 0;
+ int blockoffset = 0;
+
+ BasicBlock currentBlock = null;
+ for (int i = 0; i < len; i++) {
+
+ if (startblock[i] == 1) {
+ currentBlock = new BasicBlock();
+ currentBlock.id = ++counter;
+
+ currseq = new SimpleInstructionSequence();
+ lstOffs = new ArrayList<Integer>();
+
+ currentBlock.setSeq(currseq);
+ currentBlock.setInstrOldOffsets(lstOffs);
+ col.addWithKey(currentBlock, currentBlock.id);
+
+ blockoffset = instrseq.getOffset(i);
+ }
+
+ startblock[i] = counter;
+ mapInstrBlocks.put(i, currentBlock);
+
+ currseq.addInstruction(instrseq.getInstr(i), instrseq.getOffset(i) - blockoffset);
+ lstOffs.add(instrseq.getOffset(i));
+ }
+
+ last_id = counter;
+
+ return col;
+ }
+
+
+ private void connectBlocks(List<BasicBlock> lstbb, HashMap<Integer, BasicBlock> mapInstrBlocks) {
+
+ for (int i = 0; i < lstbb.size(); i++) {
+
+ BasicBlock block = lstbb.get(i);
+ Instruction instr = block.getLastInstruction();
+
+ boolean fallthrough = instr.canFallthrough();
+ BasicBlock bTemp;
+
+ switch (instr.group) {
+ case GROUP_JUMP:
+ int dest = ((JumpInstruction)instr).destination;
+ bTemp = mapInstrBlocks.get(dest);
+ block.addSuccessor(bTemp);
+
+ break;
+ case GROUP_SWITCH:
+ SwitchInstruction sinstr = (SwitchInstruction)instr;
+ int[] dests = sinstr.getDestinations();
+
+ bTemp = mapInstrBlocks.get(((SwitchInstruction)instr).getDefaultdest());
+ block.addSuccessor(bTemp);
+ for (int j = 0; j < dests.length; j++) {
+ bTemp = mapInstrBlocks.get(dests[j]);
+ block.addSuccessor(bTemp);
+ }
+ }
+
+ if (fallthrough && i < lstbb.size() - 1) {
+ BasicBlock defaultBlock = lstbb.get(i + 1);
+ block.addSuccessor(defaultBlock);
+ }
+ }
+ }
+
+ private void setExceptionEdges(InstructionSequence instrseq, HashMap<Integer, BasicBlock> instrBlocks) {
+
+ exceptions = new ArrayList<ExceptionRangeCFG>();
+
+ Map<String, ExceptionRangeCFG> mapRanges = new HashMap<String, ExceptionRangeCFG>();
+
+ for (ExceptionHandler handler : instrseq.getExceptionTable().getHandlers()) {
+
+ BasicBlock from = instrBlocks.get(handler.from_instr);
+ BasicBlock to = instrBlocks.get(handler.to_instr);
+ BasicBlock handle = instrBlocks.get(handler.handler_instr);
+
+ String key = from.id + ":" + to.id + ":" + handle.id;
+
+ if (mapRanges.containsKey(key)) {
+ ExceptionRangeCFG range = mapRanges.get(key);
+ range.addExceptionType(handler.exceptionClass);
+ }
+ else {
+
+ List<BasicBlock> protectedRange = new ArrayList<BasicBlock>();
+ for (int j = from.id; j < to.id; j++) {
+ BasicBlock block = blocks.getWithKey(j);
+ protectedRange.add(block);
+ block.addSuccessorException(handle);
+ }
+
+ ExceptionRangeCFG range = new ExceptionRangeCFG(protectedRange, handle, handler.exceptionClass == null
+ ? null
+ : Arrays.asList(new String[]{handler.exceptionClass}));
+ mapRanges.put(key, range);
+
+ exceptions.add(range);
+ }
+ }
+ }
+
+ private void setSubroutineEdges() {
+
+ final HashMap<BasicBlock, BasicBlock> subroutines = new HashMap<BasicBlock, BasicBlock>();
+
+ for (BasicBlock block : blocks) {
+
+ if (block.getSeq().getLastInstr().opcode == CodeConstants.opc_jsr) {
+
+ LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
+ LinkedList<LinkedList<BasicBlock>> stackJsrStacks = new LinkedList<LinkedList<BasicBlock>>();
+
+ HashSet<BasicBlock> setVisited = new HashSet<BasicBlock>();
+
+ stack.add(block);
+ stackJsrStacks.add(new LinkedList<BasicBlock>());
+
+ while (!stack.isEmpty()) {
+
+ BasicBlock node = stack.removeFirst();
+ LinkedList<BasicBlock> jsrstack = stackJsrStacks.removeFirst();
+
+ setVisited.add(node);
+
+ switch (node.getSeq().getLastInstr().opcode) {
+ case CodeConstants.opc_jsr:
+ jsrstack.add(node);
+ break;
+ case CodeConstants.opc_ret:
+ BasicBlock enter = jsrstack.getLast();
+ BasicBlock exit = blocks.getWithKey(enter.id + 1); // FIXME: find successor in a better way
+
+ if (exit != null) {
+ if (!node.isSuccessor(exit)) {
+ node.addSuccessor(exit);
+ }
+ jsrstack.removeLast();
+ subroutines.put(enter, exit);
+ }
+ else {
+ throw new RuntimeException("ERROR: last instruction jsr");
+ }
+ }
+
+ if (!jsrstack.isEmpty()) {
+ for (BasicBlock succ : node.getSuccs()) {
+ if (!setVisited.contains(succ)) {
+ stack.add(succ);
+ stackJsrStacks.add(new LinkedList<BasicBlock>(jsrstack));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ this.subroutines = subroutines;
+ }
+
+ private void processJsr() {
+
+ while (processJsrRanges() != 0) ;
+ }
+
+ private int processJsrRanges() {
+
+ List<Object[]> lstJsrAll = new ArrayList<Object[]>();
+
+ // get all jsr ranges
+ for (Entry<BasicBlock, BasicBlock> ent : subroutines.entrySet()) {
+ BasicBlock jsr = ent.getKey();
+ BasicBlock ret = ent.getValue();
+
+ lstJsrAll.add(new Object[]{jsr, getJsrRange(jsr, ret), ret});
+ }
+
+ // sort ranges
+ // FIXME: better sort order
+ List<Object[]> lstJsr = new ArrayList<Object[]>();
+ for (Object[] arr : lstJsrAll) {
+ int i = 0;
+ for (; i < lstJsr.size(); i++) {
+ Object[] arrJsr = lstJsr.get(i);
+
+ if (((HashSet<BasicBlock>)arrJsr[1]).contains(arr[0])) {
+ break;
+ }
+ }
+
+ lstJsr.add(i, arr);
+ }
+
+ // find the first intersection
+ for (int i = 0; i < lstJsr.size(); i++) {
+ Object[] arr = (Object[])lstJsr.get(i);
+ HashSet<BasicBlock> set = (HashSet<BasicBlock>)arr[1];
+
+ for (int j = i + 1; j < lstJsr.size(); j++) {
+ Object[] arr1 = (Object[])lstJsr.get(j);
+ HashSet<BasicBlock> set1 = (HashSet<BasicBlock>)arr1[1];
+
+ if (!set.contains(arr1[0]) && !set1.contains(arr[0])) { // rang 0 doesn't contain entry 1 and vice versa
+ HashSet<BasicBlock> setc = new HashSet<BasicBlock>(set);
+ setc.retainAll(set1);
+
+ if (!setc.isEmpty()) {
+ splitJsrRange((BasicBlock)arr[0], (BasicBlock)arr[2], setc);
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ private HashSet<BasicBlock> getJsrRange(BasicBlock jsr, BasicBlock ret) {
+
+ HashSet<BasicBlock> blocks = new HashSet<BasicBlock>();
+
+ LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
+ lstNodes.add(jsr);
+
+ BasicBlock dom = jsr.getSuccs().get(0);
+
+ while (!lstNodes.isEmpty()) {
+
+ BasicBlock node = lstNodes.remove(0);
+
+ for (int j = 0; j < 2; j++) {
+ List<BasicBlock> lst;
+ if (j == 0) {
+ if (node.getLastInstruction().opcode == CodeConstants.opc_ret) {
+ if (node.getSuccs().contains(ret)) {
+ continue;
+ }
+ }
+ lst = node.getSuccs();
+ }
+ else {
+ if (node == jsr) {
+ continue;
+ }
+ lst = node.getSuccExceptions();
+ }
+
+ CHILD:
+ for (int i = lst.size() - 1; i >= 0; i--) {
+
+ BasicBlock child = lst.get(i);
+ if (!blocks.contains(child)) {
+
+ if (node != jsr) {
+ for (int k = 0; k < child.getPreds().size(); k++) {
+ if (!DeadCodeHelper.isDominator(this, child.getPreds().get(k), dom)) {
+ continue CHILD;
+ }
+ }
+
+ for (int k = 0; k < child.getPredExceptions().size(); k++) {
+ if (!DeadCodeHelper.isDominator(this, child.getPredExceptions().get(k), dom)) {
+ continue CHILD;
+ }
+ }
+ }
+
+ // last block is a dummy one
+ if (child != last) {
+ blocks.add(child);
+ }
+
+ lstNodes.add(child);
+ }
+ }
+ }
+ }
+
+ return blocks;
+ }
+
+ private void splitJsrRange(BasicBlock jsr, BasicBlock ret, HashSet<BasicBlock> common_blocks) {
+
+ LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
+ HashMap<Integer, BasicBlock> mapNewNodes = new HashMap<Integer, BasicBlock>();
+
+ lstNodes.add(jsr);
+ mapNewNodes.put(jsr.id, jsr);
+
+ while (!lstNodes.isEmpty()) {
+
+ BasicBlock node = lstNodes.remove(0);
+
+ for (int j = 0; j < 2; j++) {
+ List<BasicBlock> lst;
+ if (j == 0) {
+ if (node.getLastInstruction().opcode == CodeConstants.opc_ret) {
+ if (node.getSuccs().contains(ret)) {
+ continue;
+ }
+ }
+ lst = node.getSuccs();
+ }
+ else {
+ if (node == jsr) {
+ continue;
+ }
+ lst = node.getSuccExceptions();
+ }
+
+
+ for (int i = lst.size() - 1; i >= 0; i--) {
+
+ BasicBlock child = (BasicBlock)lst.get(i);
+ Integer childid = child.id;
+
+ if (mapNewNodes.containsKey(childid)) {
+ node.replaceSuccessor(child, (BasicBlock)mapNewNodes.get(childid));
+ }
+ else if (common_blocks.contains(child)) {
+
+ // make a copy of the current block
+ BasicBlock copy = (BasicBlock)child.clone();
+ copy.id = ++last_id;
+ // copy all successors
+ if (copy.getLastInstruction().opcode == CodeConstants.opc_ret &&
+ child.getSuccs().contains(ret)) {
+ copy.addSuccessor(ret);
+ child.removeSuccessor(ret);
+ }
+ else {
+ for (int k = 0; k < child.getSuccs().size(); k++) {
+ copy.addSuccessor((BasicBlock)child.getSuccs().get(k));
+ }
+ }
+ for (int k = 0; k < child.getSuccExceptions().size(); k++) {
+ copy.addSuccessorException((BasicBlock)child.getSuccExceptions().get(k));
+ }
+
+ lstNodes.add(copy);
+ mapNewNodes.put(childid, copy);
+
+ if (last.getPreds().contains(child)) {
+ last.addPredecessor(copy);
+ }
+
+ node.replaceSuccessor(child, copy);
+ blocks.addWithKey(copy, copy.id);
+ }
+ else {
+ // stop at the first fixed node
+ //lstNodes.add(child);
+ mapNewNodes.put(childid, child);
+ }
+ }
+ }
+ }
+
+ // note: subroutines won't be copied!
+ splitJsrExceptionRanges(common_blocks, mapNewNodes);
+ }
+
+ private void splitJsrExceptionRanges(HashSet<BasicBlock> common_blocks, HashMap<Integer, BasicBlock> mapNewNodes) {
+
+ for (int i = exceptions.size() - 1; i >= 0; i--) {
+
+ ExceptionRangeCFG range = (ExceptionRangeCFG)exceptions.get(i);
+ List<BasicBlock> lstRange = range.getProtectedRange();
+
+ HashSet<BasicBlock> setBoth = new HashSet<BasicBlock>(common_blocks);
+ setBoth.retainAll(lstRange);
+
+ if (setBoth.size() > 0) {
+ List<BasicBlock> lstNewRange;
+
+ if (setBoth.size() == lstRange.size()) {
+ lstNewRange = new ArrayList<BasicBlock>();
+ ExceptionRangeCFG newRange = new ExceptionRangeCFG(lstNewRange,
+ (BasicBlock)mapNewNodes.get(range.getHandler().id), range.getExceptionTypes());
+ exceptions.add(newRange);
+ }
+ else {
+ lstNewRange = lstRange;
+ }
+
+ for (BasicBlock block : setBoth) {
+ lstNewRange.add(mapNewNodes.get(block.id));
+ }
+ }
+ }
+ }
+
+ private void removeJsr(StructMethod mt) {
+ removeJsrInstructions(mt.getClassStruct().getPool(), first, DataPoint.getInitialDataPoint(mt));
+ }
+
+ private void removeJsrInstructions(ConstantPool pool, BasicBlock block, DataPoint data) {
+
+ ListStack<VarType> stack = data.getStack();
+
+ InstructionSequence seq = block.getSeq();
+ for (int i = 0; i < seq.length(); i++) {
+ Instruction instr = seq.getInstr(i);
+
+ VarType var = null;
+ if (instr.opcode == CodeConstants.opc_astore || instr.opcode == CodeConstants.opc_pop) {
+ var = stack.getByOffset(-1);
+ }
+
+ InstructionImpact.stepTypes(data, instr, pool);
+
+ switch (instr.opcode) {
+ case CodeConstants.opc_jsr:
+ case CodeConstants.opc_ret:
+ seq.removeInstruction(i);
+ i--;
+ break;
+ case CodeConstants.opc_astore:
+ case CodeConstants.opc_pop:
+ if (var.type == CodeConstants.TYPE_ADDRESS) {
+ seq.removeInstruction(i);
+ i--;
+ }
+ }
+ }
+
+ block.mark = 1;
+
+ for (int i = 0; i < block.getSuccs().size(); i++) {
+ BasicBlock suc = (BasicBlock)block.getSuccs().get(i);
+ if (suc.mark != 1) {
+ removeJsrInstructions(pool, suc, data.copy());
+ }
+ }
+
+ for (int i = 0; i < block.getSuccExceptions().size(); i++) {
+ BasicBlock suc = (BasicBlock)block.getSuccExceptions().get(i);
+ if (suc.mark != 1) {
+
+ DataPoint point = new DataPoint();
+ point.setLocalVariables(new ArrayList<VarType>(data.getLocalVariables()));
+ point.getStack().push(new VarType(CodeConstants.TYPE_OBJECT, 0, null));
+
+ removeJsrInstructions(pool, suc, point);
+ }
+ }
+ }
+
+ private void setFirstAndLastBlocks() {
+
+ first = blocks.get(0);
+
+ last = new BasicBlock();
+ last.id = ++last_id;
+ last.setSeq(new SimpleInstructionSequence());
+
+ for (BasicBlock block : blocks) {
+ if (block.getSuccs().isEmpty()) {
+ last.addPredecessor(block);
+ }
+ }
+ }
+
+ public List<BasicBlock> getReversePostOrder() {
+
+ LinkedList<BasicBlock> res = new LinkedList<BasicBlock>();
+ addToReversePostOrderListIterative(first, res);
+
+ return res;
+ }
+
+ private void addToReversePostOrderListIterative(BasicBlock root, List<BasicBlock> lst) {
+
+ LinkedList<BasicBlock> stackNode = new LinkedList<BasicBlock>();
+ LinkedList<Integer> stackIndex = new LinkedList<Integer>();
+
+ HashSet<BasicBlock> setVisited = new HashSet<BasicBlock>();
+
+ stackNode.add(root);
+ stackIndex.add(0);
+
+ while (!stackNode.isEmpty()) {
+
+ BasicBlock node = stackNode.getLast();
+ int index = stackIndex.removeLast();
+
+ setVisited.add(node);
+
+ List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(node.getSuccs());
+ lstSuccs.addAll(node.getSuccExceptions());
+
+ for (; index < lstSuccs.size(); index++) {
+ BasicBlock succ = lstSuccs.get(index);
+
+ if (!setVisited.contains(succ)) {
+ stackIndex.add(index + 1);
+
+ stackNode.add(succ);
+ stackIndex.add(0);
+
+ break;
+ }
+ }
+
+ if (index == lstSuccs.size()) {
+ lst.add(0, node);
+
+ stackNode.removeLast();
+ }
+ }
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public VBStyleCollection<BasicBlock, Integer> getBlocks() {
+ return blocks;
+ }
+
+ public void setBlocks(VBStyleCollection<BasicBlock, Integer> blocks) {
+ this.blocks = blocks;
+ }
+
+ public BasicBlock getFirst() {
+ return first;
+ }
+
+ public void setFirst(BasicBlock first) {
+ this.first = first;
+ }
+
+ public List<BasicBlock> getEndBlocks() {
+ return last.getPreds();
+ }
+
+ public List<ExceptionRangeCFG> getExceptions() {
+ return exceptions;
+ }
+
+ public void setExceptions(List<ExceptionRangeCFG> exceptions) {
+ this.exceptions = exceptions;
+ }
+
+
+ public BasicBlock getLast() {
+ return last;
+ }
+
+
+ public void setLast(BasicBlock last) {
+ this.last = last;
+ }
+
+
+ public HashMap<BasicBlock, BasicBlock> getSubroutines() {
+ return subroutines;
+ }
+
+
+ public void setSubroutines(HashMap<BasicBlock, BasicBlock> subroutines) {
+ this.subroutines = subroutines;
+ }
+
+
+ public HashSet<BasicBlock> getFinallyExits() {
+ return finallyExits;
+ }
+
+ public void setFinallyExits(HashSet<BasicBlock> finallyExits) {
+ this.finallyExits = finallyExits;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java b/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java
index 53f4a77..7d83ef6 100644
--- a/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java
+++ b/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java
@@ -1,128 +1,129 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.cfg;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
-
public class ExceptionRangeCFG {
-
- private List<BasicBlock> protectedRange = new ArrayList<BasicBlock>(); // FIXME: replace with set
-
- private BasicBlock handler;
-
- private List<String> exceptionTypes;
-
- public ExceptionRangeCFG(List<BasicBlock> protectedRange, BasicBlock handler, List<String> exceptionType) {
- this.protectedRange = protectedRange;
- this.handler = handler;
-
- if(exceptionType != null) {
- this.exceptionTypes = new ArrayList<String>(exceptionType);
- }
- }
-
- public boolean isCircular() {
- return protectedRange.contains(handler);
- }
-
- public String toString() {
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- StringBuffer buf = new StringBuffer();
-
- buf.append("exceptionType:");
- for(String exception_type : exceptionTypes) {
- buf.append(" "+exception_type);
- }
- buf.append(new_line_separator);
-
- buf.append("handler: "+handler.id+new_line_separator);
- buf.append("range: ");
- for(int i=0;i<protectedRange.size();i++) {
- buf.append(protectedRange.get(i).id+" ");
- }
- buf.append(new_line_separator);
-
- return buf.toString();
- }
-
- public BasicBlock getHandler() {
- return handler;
- }
-
- public void setHandler(BasicBlock handler) {
- this.handler = handler;
- }
-
- public List<BasicBlock> getProtectedRange() {
- return protectedRange;
- }
-
- public void setProtectedRange(List<BasicBlock> protectedRange) {
- this.protectedRange = protectedRange;
- }
-
- public List<String> getExceptionTypes() {
- return this.exceptionTypes;
- }
-
- public void addExceptionType(String exceptionType) {
-
- if(this.exceptionTypes == null) {
- return;
- }
-
- if(exceptionType == null) {
- this.exceptionTypes = null;
- } else {
- this.exceptionTypes.add(exceptionType);
- }
- }
-
- public String getUniqueExceptionsString() {
-
- if(exceptionTypes == null) {
- return null;
- }
-
- Set<String> setExceptionStrings = new HashSet<String>();
-
- for(String exceptionType : exceptionTypes) { // normalize order
- setExceptionStrings.add(exceptionType);
- }
-
- String ret = "";
- for(String exception : setExceptionStrings) {
- if(!ret.isEmpty()) {
- ret += ":";
- }
- ret += exception;
- }
-
- return ret;
- }
-
-
-// public void setExceptionType(String exceptionType) {
-// this.exceptionType = exceptionType;
-// }
-
+
+ private List<BasicBlock> protectedRange = new ArrayList<BasicBlock>(); // FIXME: replace with set
+
+ private BasicBlock handler;
+
+ private List<String> exceptionTypes;
+
+ public ExceptionRangeCFG(List<BasicBlock> protectedRange, BasicBlock handler, List<String> exceptionType) {
+ this.protectedRange = protectedRange;
+ this.handler = handler;
+
+ if (exceptionType != null) {
+ this.exceptionTypes = new ArrayList<String>(exceptionType);
+ }
+ }
+
+ public boolean isCircular() {
+ return protectedRange.contains(handler);
+ }
+
+ public String toString() {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuffer buf = new StringBuffer();
+
+ buf.append("exceptionType:");
+ for (String exception_type : exceptionTypes) {
+ buf.append(" " + exception_type);
+ }
+ buf.append(new_line_separator);
+
+ buf.append("handler: " + handler.id + new_line_separator);
+ buf.append("range: ");
+ for (int i = 0; i < protectedRange.size(); i++) {
+ buf.append(protectedRange.get(i).id + " ");
+ }
+ buf.append(new_line_separator);
+
+ return buf.toString();
+ }
+
+ public BasicBlock getHandler() {
+ return handler;
+ }
+
+ public void setHandler(BasicBlock handler) {
+ this.handler = handler;
+ }
+
+ public List<BasicBlock> getProtectedRange() {
+ return protectedRange;
+ }
+
+ public void setProtectedRange(List<BasicBlock> protectedRange) {
+ this.protectedRange = protectedRange;
+ }
+
+ public List<String> getExceptionTypes() {
+ return this.exceptionTypes;
+ }
+
+ public void addExceptionType(String exceptionType) {
+
+ if (this.exceptionTypes == null) {
+ return;
+ }
+
+ if (exceptionType == null) {
+ this.exceptionTypes = null;
+ }
+ else {
+ this.exceptionTypes.add(exceptionType);
+ }
+ }
+
+ public String getUniqueExceptionsString() {
+
+ if (exceptionTypes == null) {
+ return null;
+ }
+
+ Set<String> setExceptionStrings = new HashSet<String>();
+
+ for (String exceptionType : exceptionTypes) { // normalize order
+ setExceptionStrings.add(exceptionType);
+ }
+
+ String ret = "";
+ for (String exception : setExceptionStrings) {
+ if (!ret.isEmpty()) {
+ ret += ":";
+ }
+ ret += exception;
+ }
+
+ return ret;
+ }
+
+
+ // public void setExceptionType(String exceptionType) {
+ // this.exceptionType = exceptionType;
+ // }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/AALOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/AALOAD.java
index 6e92fe6..a460184 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/AALOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/AALOAD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/AASTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/AASTORE.java
index 09f5c4b..9e0805d 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/AASTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/AASTORE.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ACONST_NULL.java b/src/org/jetbrains/java/decompiler/code/instructions/ACONST_NULL.java
index 5733d40..2f78e54 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ACONST_NULL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ACONST_NULL.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ALOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/ALOAD.java
index a9c9e05..604585c 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ALOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ALOAD.java
@@ -1,43 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class ALOAD extends Instruction {
-
- private static int[] opcodes = new int[] {opc_aload_0,opc_aload_1,opc_aload_2,opc_aload_3};
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_aload);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
+ private static int[] opcodes = new int[]{opc_aload_0, opc_aload_1, opc_aload_2, opc_aload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_aload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
-
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ANEWARRAY.java b/src/org/jetbrains/java/decompiler/code/instructions/ANEWARRAY.java
index aa9a6c9..09afe91 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ANEWARRAY.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ANEWARRAY.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class ANEWARRAY extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_anewarray);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_anewarray);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ARETURN.java b/src/org/jetbrains/java/decompiler/code/instructions/ARETURN.java
index 915a50f..bf4bfae 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ARETURN.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ARETURN.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ARRAYLENGTH.java b/src/org/jetbrains/java/decompiler/code/instructions/ARRAYLENGTH.java
index a54aa41..6ddee94 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ARRAYLENGTH.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ARRAYLENGTH.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ASTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/ASTORE.java
index 701f082..67ef5dd 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ASTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ASTORE.java
@@ -1,42 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class ASTORE extends Instruction {
- private static int[] opcodes = new int[] {opc_astore_0,opc_astore_1,opc_astore_2,opc_astore_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_astore);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_astore_0, opc_astore_1, opc_astore_2, opc_astore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_astore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ATHROW.java b/src/org/jetbrains/java/decompiler/code/instructions/ATHROW.java
index 1ca07c5..66d22a0 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ATHROW.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ATHROW.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/BALOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/BALOAD.java
index c9d9e79..4a2e5d9 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/BALOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/BALOAD.java
@@ -1,7 +1,22 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
public class BALOAD extends Instruction {
-
+
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/BASTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/BASTORE.java
index 478a887..70e8f0d 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/BASTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/BASTORE.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/BIPUSH.java b/src/org/jetbrains/java/decompiler/code/instructions/BIPUSH.java
index 90874c5..836ee10 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/BIPUSH.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/BIPUSH.java
@@ -1,30 +1,48 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class BIPUSH extends Instruction {
- private static int[] opcodes = new int[] {opc_iconst_m1,opc_iconst_0,opc_iconst_1,opc_iconst_2,opc_iconst_3,opc_iconst_4,opc_iconst_5};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int value = getOperand(0);
- if(value<-1 || value > 5) {
- out.writeByte(opc_bipush);
- out.writeByte(value);
- } else {
- out.writeByte(opcodes[value+1]);
- }
- }
-
- public int length() {
- int value = getOperand(0);
- if(value<-1 || value > 5) {
- return 2;
- } else {
- return 1;
- }
- }
+ private static int[] opcodes =
+ new int[]{opc_iconst_m1, opc_iconst_0, opc_iconst_1, opc_iconst_2, opc_iconst_3, opc_iconst_4, opc_iconst_5};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int value = getOperand(0);
+ if (value < -1 || value > 5) {
+ out.writeByte(opc_bipush);
+ out.writeByte(value);
+ }
+ else {
+ out.writeByte(opcodes[value + 1]);
+ }
+ }
+
+ public int length() {
+ int value = getOperand(0);
+ if (value < -1 || value > 5) {
+ return 2;
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/CALOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/CALOAD.java
index cf3fb87..9646179 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/CALOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/CALOAD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/CASTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/CASTORE.java
index 2ed21e5..6222e2f 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/CASTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/CASTORE.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/CHECKCAST.java b/src/org/jetbrains/java/decompiler/code/instructions/CHECKCAST.java
index a3bb57e..bfff1cf 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/CHECKCAST.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/CHECKCAST.java
@@ -1,20 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class CHECKCAST extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_checkcast);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_checkcast);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/D2F.java b/src/org/jetbrains/java/decompiler/code/instructions/D2F.java
index fd42a2e..e40a093 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/D2F.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/D2F.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/D2I.java b/src/org/jetbrains/java/decompiler/code/instructions/D2I.java
index 4fc7801..97e1675 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/D2I.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/D2I.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/D2L.java b/src/org/jetbrains/java/decompiler/code/instructions/D2L.java
index cc90f1c..0d6a304 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/D2L.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/D2L.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DADD.java b/src/org/jetbrains/java/decompiler/code/instructions/DADD.java
index ac84423..e65a669 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DADD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DADD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DALOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/DALOAD.java
index 00a0d17..a356c5b 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DALOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DALOAD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DASTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/DASTORE.java
index e33959f..f1c6cda 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DASTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DASTORE.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DCMPG.java b/src/org/jetbrains/java/decompiler/code/instructions/DCMPG.java
index 2b853ac..8c1ffc0 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DCMPG.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DCMPG.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DCMPL.java b/src/org/jetbrains/java/decompiler/code/instructions/DCMPL.java
index 7fdba33..2b146a5 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DCMPL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DCMPL.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DCONST_0.java b/src/org/jetbrains/java/decompiler/code/instructions/DCONST_0.java
index d0023f2..78c5dde 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DCONST_0.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DCONST_0.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DCONST_1.java b/src/org/jetbrains/java/decompiler/code/instructions/DCONST_1.java
index bcd7c67..8127cfb 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DCONST_1.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DCONST_1.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DDIV.java b/src/org/jetbrains/java/decompiler/code/instructions/DDIV.java
index 40d86a8..d15e7af 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DDIV.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DDIV.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DLOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/DLOAD.java
index ee098d6..1d7fea4 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DLOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DLOAD.java
@@ -1,42 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class DLOAD extends Instruction {
- private static int[] opcodes = new int[] {opc_dload_0,opc_dload_1,opc_dload_2,opc_dload_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_dload);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_dload_0, opc_dload_1, opc_dload_2, opc_dload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_dload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DMUL.java b/src/org/jetbrains/java/decompiler/code/instructions/DMUL.java
index 65bedca..3fdc17a 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DMUL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DMUL.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DNEG.java b/src/org/jetbrains/java/decompiler/code/instructions/DNEG.java
index 15bd9f3..83f82c5 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DNEG.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DNEG.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DREM.java b/src/org/jetbrains/java/decompiler/code/instructions/DREM.java
index ab57911..55453fc 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DREM.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DREM.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DRETURN.java b/src/org/jetbrains/java/decompiler/code/instructions/DRETURN.java
index 0a6e376..b758dcb 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DRETURN.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DRETURN.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DSTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/DSTORE.java
index fe1feb8..e1e37e5 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DSTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DSTORE.java
@@ -1,41 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class DSTORE extends Instruction {
- private static int[] opcodes = new int[] {opc_dstore_0,opc_dstore_1,opc_dstore_2,opc_dstore_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_dstore);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
+ private static int[] opcodes = new int[]{opc_dstore_0, opc_dstore_1, opc_dstore_2, opc_dstore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_dstore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DSUB.java b/src/org/jetbrains/java/decompiler/code/instructions/DSUB.java
index d683a63..33026ca 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DSUB.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DSUB.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DUP.java b/src/org/jetbrains/java/decompiler/code/instructions/DUP.java
index 50119da..07a7c4f 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DUP.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DUP.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DUP2.java b/src/org/jetbrains/java/decompiler/code/instructions/DUP2.java
index 3929ee0..6451cf2 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DUP2.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DUP2.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DUP2_X1.java b/src/org/jetbrains/java/decompiler/code/instructions/DUP2_X1.java
index ad59230..deddd1b 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DUP2_X1.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DUP2_X1.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DUP2_X2.java b/src/org/jetbrains/java/decompiler/code/instructions/DUP2_X2.java
index d27ca93..deafca6 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DUP2_X2.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DUP2_X2.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DUP_X1.java b/src/org/jetbrains/java/decompiler/code/instructions/DUP_X1.java
index 9b6b271..a1268e9 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DUP_X1.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DUP_X1.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/DUP_X2.java b/src/org/jetbrains/java/decompiler/code/instructions/DUP_X2.java
index 8c4b03e..bf5f71d 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/DUP_X2.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/DUP_X2.java
@@ -1,7 +1,22 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
public class DUP_X2 extends Instruction {
-
+
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/F2D.java b/src/org/jetbrains/java/decompiler/code/instructions/F2D.java
index debb8de..dd5b4a6 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/F2D.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/F2D.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/F2I.java b/src/org/jetbrains/java/decompiler/code/instructions/F2I.java
index bbda5c8..0811e2b 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/F2I.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/F2I.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/F2L.java b/src/org/jetbrains/java/decompiler/code/instructions/F2L.java
index a58a398..a470414 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/F2L.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/F2L.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FADD.java b/src/org/jetbrains/java/decompiler/code/instructions/FADD.java
index ab7a357..bdd9b89 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FADD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FADD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FALOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/FALOAD.java
index cc56e21..e9befaf 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FALOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FALOAD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FASTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/FASTORE.java
index d18a2ef..6e280fc 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FASTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FASTORE.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FCMPG.java b/src/org/jetbrains/java/decompiler/code/instructions/FCMPG.java
index a86b2a9..4c3c9c5 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FCMPG.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FCMPG.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FCMPL.java b/src/org/jetbrains/java/decompiler/code/instructions/FCMPL.java
index 450546c..42dcb4b 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FCMPL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FCMPL.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FCONST_0.java b/src/org/jetbrains/java/decompiler/code/instructions/FCONST_0.java
index 77f4e84..957fe29 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FCONST_0.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FCONST_0.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FCONST_1.java b/src/org/jetbrains/java/decompiler/code/instructions/FCONST_1.java
index e90fd44..ab014c4 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FCONST_1.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FCONST_1.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FCONST_2.java b/src/org/jetbrains/java/decompiler/code/instructions/FCONST_2.java
index 7736565..fa6be0f 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FCONST_2.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FCONST_2.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FDIV.java b/src/org/jetbrains/java/decompiler/code/instructions/FDIV.java
index 0524b01..eb6dce4 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FDIV.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FDIV.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FLOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/FLOAD.java
index 03ba1d2..6640d5d 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FLOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FLOAD.java
@@ -1,42 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class FLOAD extends Instruction {
- private static int[] opcodes = new int[] {opc_fload_0,opc_fload_1,opc_fload_2,opc_fload_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_fload);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_fload_0, opc_fload_1, opc_fload_2, opc_fload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_fload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FMUL.java b/src/org/jetbrains/java/decompiler/code/instructions/FMUL.java
index 598145b..5a5cee3 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FMUL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FMUL.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FNEG.java b/src/org/jetbrains/java/decompiler/code/instructions/FNEG.java
index b1d96ea..ab68c82 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FNEG.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FNEG.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FREM.java b/src/org/jetbrains/java/decompiler/code/instructions/FREM.java
index b8dc0fe..91900a8 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FREM.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FREM.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FRETURN.java b/src/org/jetbrains/java/decompiler/code/instructions/FRETURN.java
index 3781401..a310022 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FRETURN.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FRETURN.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FSTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/FSTORE.java
index 203588b..15b5d42 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FSTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FSTORE.java
@@ -1,41 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class FSTORE extends Instruction {
- private static int[] opcodes = new int[] {opc_fstore_0,opc_fstore_1,opc_fstore_2,opc_fstore_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_fstore);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
+ private static int[] opcodes = new int[]{opc_fstore_0, opc_fstore_1, opc_fstore_2, opc_fstore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_fstore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/FSUB.java b/src/org/jetbrains/java/decompiler/code/instructions/FSUB.java
index 841ee0d..09a07b8 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/FSUB.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/FSUB.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/GETFIELD.java b/src/org/jetbrains/java/decompiler/code/instructions/GETFIELD.java
index 8500f46..93b46ae 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/GETFIELD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/GETFIELD.java
@@ -1,18 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class GETFIELD extends Instruction {
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_getfield);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_getfield);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/GETSTATIC.java b/src/org/jetbrains/java/decompiler/code/instructions/GETSTATIC.java
index 761624f..86f1b75 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/GETSTATIC.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/GETSTATIC.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class GETSTATIC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_getstatic);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_getstatic);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/GOTO.java b/src/org/jetbrains/java/decompiler/code/instructions/GOTO.java
index 91f5081..515275f 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/GOTO.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/GOTO.java
@@ -1,30 +1,46 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class GOTO extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int operand = getOperand(0);
- if(operand < -32768 || operand > 32767) {
- out.writeByte(opc_goto_w);
- out.writeInt(operand);
- } else {
- out.writeByte(opc_goto);
- out.writeShort(operand);
- }
- }
-
- public int length() {
- int operand = getOperand(0);
- if(operand < -32768 || operand > 32767) {
- return 5;
- } else {
- return 3;
- }
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ out.writeByte(opc_goto_w);
+ out.writeInt(operand);
+ }
+ else {
+ out.writeByte(opc_goto);
+ out.writeShort(operand);
+ }
+ }
+
+ public int length() {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ return 5;
+ }
+ else {
+ return 3;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/GOTO_W.java b/src/org/jetbrains/java/decompiler/code/instructions/GOTO_W.java
index 830b766..ec427f8 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/GOTO_W.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/GOTO_W.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class GOTO_W extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_goto_w);
- out.writeInt(getOperand(0));
- }
-
- public int length() {
- return 5;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_goto_w);
+ out.writeInt(getOperand(0));
+ }
+
+ public int length() {
+ return 5;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/I2B.java b/src/org/jetbrains/java/decompiler/code/instructions/I2B.java
index f5a3fbd..b6fc681 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/I2B.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/I2B.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/I2C.java b/src/org/jetbrains/java/decompiler/code/instructions/I2C.java
index a180a64..a1dca6b 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/I2C.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/I2C.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/I2D.java b/src/org/jetbrains/java/decompiler/code/instructions/I2D.java
index b0bad9a..6478d78 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/I2D.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/I2D.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/I2F.java b/src/org/jetbrains/java/decompiler/code/instructions/I2F.java
index ca1a0fb..1247eff 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/I2F.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/I2F.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/I2L.java b/src/org/jetbrains/java/decompiler/code/instructions/I2L.java
index 24bca4e..6e27d5a 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/I2L.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/I2L.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/I2S.java b/src/org/jetbrains/java/decompiler/code/instructions/I2S.java
index 370ae2f..e66b75b 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/I2S.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/I2S.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IADD.java b/src/org/jetbrains/java/decompiler/code/instructions/IADD.java
index f427c40..5922136 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IADD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IADD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IALOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/IALOAD.java
index d70fae6..645d6df 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IALOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IALOAD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IAND.java b/src/org/jetbrains/java/decompiler/code/instructions/IAND.java
index 00ae7a6..207ed34 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IAND.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IAND.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IASTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/IASTORE.java
index 78a1d28..56d3d24 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IASTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IASTORE.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IDIV.java b/src/org/jetbrains/java/decompiler/code/instructions/IDIV.java
index bec8cc9..60b4690 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IDIV.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IDIV.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IFEQ.java b/src/org/jetbrains/java/decompiler/code/instructions/IFEQ.java
index 47711d8..28cfd81 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IFEQ.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IFEQ.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IFEQ extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ifeq);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ifeq);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IFGE.java b/src/org/jetbrains/java/decompiler/code/instructions/IFGE.java
index 9cfaba4..d805789 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IFGE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IFGE.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IFGE extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ifge);
- out.writeShort(getOperand(0));
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ifge);
+ out.writeShort(getOperand(0));
+ }
- public int length() {
- return 3;
- }
-
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IFGT.java b/src/org/jetbrains/java/decompiler/code/instructions/IFGT.java
index 99b171e..13f650a 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IFGT.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IFGT.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IFGT extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ifgt);
- out.writeShort(getOperand(0));
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ifgt);
+ out.writeShort(getOperand(0));
+ }
- public int length() {
- return 3;
- }
-
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IFLE.java b/src/org/jetbrains/java/decompiler/code/instructions/IFLE.java
index b21b2cf..e03d915 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IFLE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IFLE.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IFLE extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ifle);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ifle);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IFLT.java b/src/org/jetbrains/java/decompiler/code/instructions/IFLT.java
index 66ba02b..0299a91 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IFLT.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IFLT.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IFLT extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_iflt);
- out.writeShort(getOperand(0));
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_iflt);
+ out.writeShort(getOperand(0));
+ }
- public int length() {
- return 3;
- }
-
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IFNE.java b/src/org/jetbrains/java/decompiler/code/instructions/IFNE.java
index 983fea2..3402362 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IFNE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IFNE.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IFNE extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ifne);
- out.writeShort(getOperand(0));
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ifne);
+ out.writeShort(getOperand(0));
+ }
- public int length() {
- return 3;
- }
-
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IFNONNULL.java b/src/org/jetbrains/java/decompiler/code/instructions/IFNONNULL.java
index 2555a80..64a12d0 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IFNONNULL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IFNONNULL.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IFNONNULL extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ifnonnull);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ifnonnull);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IFNULL.java b/src/org/jetbrains/java/decompiler/code/instructions/IFNULL.java
index b695787..71265b6 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IFNULL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IFNULL.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IFNULL extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ifnull);
- out.writeShort(getOperand(0));
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ifnull);
+ out.writeShort(getOperand(0));
+ }
- public int length() {
- return 3;
- }
-
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IF_ACMPEQ.java b/src/org/jetbrains/java/decompiler/code/instructions/IF_ACMPEQ.java
index 30e530b..5b23cbf 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IF_ACMPEQ.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IF_ACMPEQ.java
@@ -1,20 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IF_ACMPEQ extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_if_acmpeq);
- out.writeShort(getOperand(0));
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_if_acmpeq);
+ out.writeShort(getOperand(0));
+ }
- public int length() {
- return 3;
- }
-
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IF_ACMPNE.java b/src/org/jetbrains/java/decompiler/code/instructions/IF_ACMPNE.java
index ccb513f..e41ea9f 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IF_ACMPNE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IF_ACMPNE.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IF_ACMPNE extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_if_acmpne);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_if_acmpne);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPEQ.java b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPEQ.java
index 1343aca..dad633d 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPEQ.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPEQ.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IF_ICMPEQ extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_if_icmpeq);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_if_icmpeq);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPGE.java b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPGE.java
index beeabec..54f6295 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPGE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPGE.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IF_ICMPGE extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_if_icmpge);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_if_icmpge);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPGT.java b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPGT.java
index e41d261..e2e1972 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPGT.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPGT.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IF_ICMPGT extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_if_icmpgt);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_if_icmpgt);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPLE.java b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPLE.java
index c9288da..4f8c76c 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPLE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPLE.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IF_ICMPLE extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_if_icmple);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_if_icmple);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPLT.java b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPLT.java
index 107519e..d6a9a48 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPLT.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPLT.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IF_ICMPLT extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_if_icmplt);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_if_icmplt);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPNE.java b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPNE.java
index 703c10c..6484344 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPNE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IF_ICMPNE.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class IF_ICMPNE extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_if_icmpne);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_if_icmpne);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IINC.java b/src/org/jetbrains/java/decompiler/code/instructions/IINC.java
index 763a192..fc2506c 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IINC.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IINC.java
@@ -1,28 +1,43 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class IINC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_iinc);
- if(wide) {
- out.writeShort(getOperand(0));
- out.writeShort(getOperand(1));
- } else {
- out.writeByte(getOperand(0));
- out.writeByte(getOperand(1));
- }
- }
-
- public int length() {
- return wide?6:3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_iinc);
+ if (wide) {
+ out.writeShort(getOperand(0));
+ out.writeShort(getOperand(1));
+ }
+ else {
+ out.writeByte(getOperand(0));
+ out.writeByte(getOperand(1));
+ }
+ }
+
+ public int length() {
+ return wide ? 6 : 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ILOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/ILOAD.java
index 4b9bd59..3be609d 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ILOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ILOAD.java
@@ -1,38 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class ILOAD extends Instruction {
- private static int[] opcodes = new int[] {opc_iload_0,opc_iload_1,opc_iload_2,opc_iload_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_iload);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- return wide?4:2;
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_iload_0, opc_iload_1, opc_iload_2, opc_iload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_iload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IMUL.java b/src/org/jetbrains/java/decompiler/code/instructions/IMUL.java
index 64dd4cc..8cec91b 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IMUL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IMUL.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/INEG.java b/src/org/jetbrains/java/decompiler/code/instructions/INEG.java
index cf341e7..903a22d 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/INEG.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/INEG.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/INSTANCEOF.java b/src/org/jetbrains/java/decompiler/code/instructions/INSTANCEOF.java
index a4214ec..e5acd87 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/INSTANCEOF.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/INSTANCEOF.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INSTANCEOF extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_instanceof);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_instanceof);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/INVOKEINTERFACE.java b/src/org/jetbrains/java/decompiler/code/instructions/INVOKEINTERFACE.java
index bd1ce37..ecf15b1 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/INVOKEINTERFACE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/INVOKEINTERFACE.java
@@ -1,21 +1,35 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INVOKEINTERFACE extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_invokeinterface);
- out.writeShort(getOperand(0));
- out.writeByte(getOperand(1));
- out.writeByte(0);
- }
-
- public int length() {
- return 5;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokeinterface);
+ out.writeShort(getOperand(0));
+ out.writeByte(getOperand(1));
+ out.writeByte(0);
+ }
+
+ public int length() {
+ return 5;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/INVOKESPECIAL.java b/src/org/jetbrains/java/decompiler/code/instructions/INVOKESPECIAL.java
index d14a8ee..0f3ad00 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/INVOKESPECIAL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/INVOKESPECIAL.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INVOKESPECIAL extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_invokespecial);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokespecial);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/INVOKESTATIC.java b/src/org/jetbrains/java/decompiler/code/instructions/INVOKESTATIC.java
index 8ef9f26..1d21cd2 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/INVOKESTATIC.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/INVOKESTATIC.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INVOKESTATIC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_invokestatic);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokestatic);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/INVOKEVIRTUAL.java b/src/org/jetbrains/java/decompiler/code/instructions/INVOKEVIRTUAL.java
index 687c6e4..2ce543d 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/INVOKEVIRTUAL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/INVOKEVIRTUAL.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INVOKEVIRTUAL extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_invokevirtual);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokevirtual);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IOR.java b/src/org/jetbrains/java/decompiler/code/instructions/IOR.java
index b3e6bae..b8bc4b1 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IOR.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IOR.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IREM.java b/src/org/jetbrains/java/decompiler/code/instructions/IREM.java
index db1fbb8..4d299b7 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IREM.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IREM.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IRETURN.java b/src/org/jetbrains/java/decompiler/code/instructions/IRETURN.java
index 2a2e48c..7f95241 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IRETURN.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IRETURN.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ISHL.java b/src/org/jetbrains/java/decompiler/code/instructions/ISHL.java
index 5e0b1e0..f440380 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ISHL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ISHL.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ISHR.java b/src/org/jetbrains/java/decompiler/code/instructions/ISHR.java
index 9a8c182..6fa2b71 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ISHR.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ISHR.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ISTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/ISTORE.java
index 7bc1647..5d6024a 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ISTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ISTORE.java
@@ -1,38 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class ISTORE extends Instruction {
- private static int[] opcodes = new int[] {opc_istore_0,opc_istore_1,opc_istore_2,opc_istore_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_istore);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- return wide?4:2;
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_istore_0, opc_istore_1, opc_istore_2, opc_istore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_istore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/ISUB.java b/src/org/jetbrains/java/decompiler/code/instructions/ISUB.java
index 3007c8a..7e3caf0 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/ISUB.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/ISUB.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IUSHR.java b/src/org/jetbrains/java/decompiler/code/instructions/IUSHR.java
index 3171c1a..b548209 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IUSHR.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IUSHR.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/IXOR.java b/src/org/jetbrains/java/decompiler/code/instructions/IXOR.java
index f6568d2..261146b 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/IXOR.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/IXOR.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/JSR.java b/src/org/jetbrains/java/decompiler/code/instructions/JSR.java
index bb23f66..1c80177 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/JSR.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/JSR.java
@@ -1,30 +1,46 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class JSR extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int operand = getOperand(0);
- if(operand < -32768 || operand > 32767) {
- out.writeByte(opc_jsr_w);
- out.writeInt(operand);
- } else {
- out.writeByte(opc_jsr);
- out.writeShort(operand);
- }
- }
-
- public int length() {
- int operand = getOperand(0);
- if(operand < -32768 || operand > 32767) {
- return 5;
- } else {
- return 3;
- }
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ out.writeByte(opc_jsr_w);
+ out.writeInt(operand);
+ }
+ else {
+ out.writeByte(opc_jsr);
+ out.writeShort(operand);
+ }
+ }
+
+ public int length() {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ return 5;
+ }
+ else {
+ return 3;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/JSR_W.java b/src/org/jetbrains/java/decompiler/code/instructions/JSR_W.java
index 47af3e6..67cf91d 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/JSR_W.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/JSR_W.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class JSR_W extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_jsr_w);
- out.writeInt(getOperand(0));
- }
-
- public int length() {
- return 5;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_jsr_w);
+ out.writeInt(getOperand(0));
+ }
+
+ public int length() {
+ return 5;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/L2D.java b/src/org/jetbrains/java/decompiler/code/instructions/L2D.java
index 59178d2..5569d3f 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/L2D.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/L2D.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/L2F.java b/src/org/jetbrains/java/decompiler/code/instructions/L2F.java
index 37932b6..fcab0ba 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/L2F.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/L2F.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/L2I.java b/src/org/jetbrains/java/decompiler/code/instructions/L2I.java
index c197282..558e5f5 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/L2I.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/L2I.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LADD.java b/src/org/jetbrains/java/decompiler/code/instructions/LADD.java
index 8c5625c..358a788 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LADD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LADD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LALOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/LALOAD.java
index 3590f94..9e6b0b0 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LALOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LALOAD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LAND.java b/src/org/jetbrains/java/decompiler/code/instructions/LAND.java
index 46a396c..37da9bd 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LAND.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LAND.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LASTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/LASTORE.java
index 107af51..e89aeff 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LASTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LASTORE.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LCMP.java b/src/org/jetbrains/java/decompiler/code/instructions/LCMP.java
index 8a9dac5..399d231 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LCMP.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LCMP.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LCONST_0.java b/src/org/jetbrains/java/decompiler/code/instructions/LCONST_0.java
index 5617fbe..04bc841 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LCONST_0.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LCONST_0.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LCONST_1.java b/src/org/jetbrains/java/decompiler/code/instructions/LCONST_1.java
index 8244407..b58fadf 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LCONST_1.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LCONST_1.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LDC.java b/src/org/jetbrains/java/decompiler/code/instructions/LDC.java
index 088e5a5..aa1e9ac 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LDC.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LDC.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class LDC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ldc);
- out.writeByte(getOperand(0));
- }
-
- public int length() {
- return 2;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ldc);
+ out.writeByte(getOperand(0));
+ }
+
+ public int length() {
+ return 2;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LDC2_W.java b/src/org/jetbrains/java/decompiler/code/instructions/LDC2_W.java
index 9b67a7e..67ba631 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LDC2_W.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LDC2_W.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class LDC2_W extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ldc2_w);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ldc2_w);
+ out.writeShort(getOperand(0));
+ }
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LDC_W.java b/src/org/jetbrains/java/decompiler/code/instructions/LDC_W.java
index 290462e..1e5030a 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LDC_W.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LDC_W.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class LDC_W extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ldc_w);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ldc_w);
+ out.writeShort(getOperand(0));
+ }
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LDIV.java b/src/org/jetbrains/java/decompiler/code/instructions/LDIV.java
index 36b09ca..b90015b 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LDIV.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LDIV.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LLOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/LLOAD.java
index 0cf9695..44afa3b 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LLOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LLOAD.java
@@ -1,38 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class LLOAD extends Instruction {
- private static int[] opcodes = new int[] {opc_lload_0,opc_lload_1,opc_lload_2,opc_lload_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_lload);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
+ private static int[] opcodes = new int[]{opc_lload_0, opc_lload_1, opc_lload_2, opc_lload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_lload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- return wide?4:2;
- } else {
- return 1;
- }
- }
-
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LMUL.java b/src/org/jetbrains/java/decompiler/code/instructions/LMUL.java
index 075c50b..475030d 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LMUL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LMUL.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LNEG.java b/src/org/jetbrains/java/decompiler/code/instructions/LNEG.java
index b2c9f10..5cacf17 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LNEG.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LNEG.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LOOKUPSWITCH.java b/src/org/jetbrains/java/decompiler/code/instructions/LOOKUPSWITCH.java
index dbe5f03..04ec7ba 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LOOKUPSWITCH.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LOOKUPSWITCH.java
@@ -1,28 +1,42 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.SwitchInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.SwitchInstruction;
-
public class LOOKUPSWITCH extends SwitchInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
-
- out.writeByte(opc_lookupswitch);
-
- int padding = 3 - (offset%4);
- for(int i=0;i<padding;i++){
- out.writeByte(0);
- }
-
- for(int i=0;i<operandsCount();i++) {
- out.writeInt(getOperand(i));
- }
- }
-
- public int length() {
- return 1+operandsCount()*4;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+
+ out.writeByte(opc_lookupswitch);
+
+ int padding = 3 - (offset % 4);
+ for (int i = 0; i < padding; i++) {
+ out.writeByte(0);
+ }
+
+ for (int i = 0; i < operandsCount(); i++) {
+ out.writeInt(getOperand(i));
+ }
+ }
+
+ public int length() {
+ return 1 + operandsCount() * 4;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LOR.java b/src/org/jetbrains/java/decompiler/code/instructions/LOR.java
index 55921d4..0c65e5c 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LOR.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LOR.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LREM.java b/src/org/jetbrains/java/decompiler/code/instructions/LREM.java
index cd5073b..b75ebc5 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LREM.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LREM.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LRETURN.java b/src/org/jetbrains/java/decompiler/code/instructions/LRETURN.java
index e7dea00..b2f03de 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LRETURN.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LRETURN.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LSHL.java b/src/org/jetbrains/java/decompiler/code/instructions/LSHL.java
index 206f91a..ae5e9f2 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LSHL.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LSHL.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LSHR.java b/src/org/jetbrains/java/decompiler/code/instructions/LSHR.java
index b4276ad..7402178 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LSHR.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LSHR.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LSTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/LSTORE.java
index 1f5dfea..230c3e4 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LSTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LSTORE.java
@@ -1,38 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class LSTORE extends Instruction {
- private static int[] opcodes = new int[] {opc_lstore_0,opc_lstore_1,opc_lstore_2,opc_lstore_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_lstore);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- return wide?4:2;
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_lstore_0, opc_lstore_1, opc_lstore_2, opc_lstore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_lstore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LSUB.java b/src/org/jetbrains/java/decompiler/code/instructions/LSUB.java
index 14b019f..cce794a 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LSUB.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LSUB.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LUSHR.java b/src/org/jetbrains/java/decompiler/code/instructions/LUSHR.java
index 63d5ca4..ecdc444 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LUSHR.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LUSHR.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/LXOR.java b/src/org/jetbrains/java/decompiler/code/instructions/LXOR.java
index 9812a1a..d9f2644 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/LXOR.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/LXOR.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/MONITORENTER.java b/src/org/jetbrains/java/decompiler/code/instructions/MONITORENTER.java
index d2ed979..c92bbf0 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/MONITORENTER.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/MONITORENTER.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/MONITOREXIT.java b/src/org/jetbrains/java/decompiler/code/instructions/MONITOREXIT.java
index f1324be..1a645b9 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/MONITOREXIT.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/MONITOREXIT.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/MULTIANEWARRAY.java b/src/org/jetbrains/java/decompiler/code/instructions/MULTIANEWARRAY.java
index 313b708..9a1b16a 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/MULTIANEWARRAY.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/MULTIANEWARRAY.java
@@ -1,20 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class MULTIANEWARRAY extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_multianewarray);
- out.writeShort(getOperand(0));
- out.writeByte(getOperand(1));
- }
-
- public int length() {
- return 4;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_multianewarray);
+ out.writeShort(getOperand(0));
+ out.writeByte(getOperand(1));
+ }
+
+ public int length() {
+ return 4;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/NEW.java b/src/org/jetbrains/java/decompiler/code/instructions/NEW.java
index 8c5ab34..7ffbdd3 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/NEW.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/NEW.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class NEW extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_new);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_new);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/NEWARRAY.java b/src/org/jetbrains/java/decompiler/code/instructions/NEWARRAY.java
index eb25456..ec4ada8 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/NEWARRAY.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/NEWARRAY.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class NEWARRAY extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_newarray);
- out.writeByte(getOperand(0));
- }
-
- public int length() {
- return 2;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_newarray);
+ out.writeByte(getOperand(0));
+ }
+
+ public int length() {
+ return 2;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/NOP.java b/src/org/jetbrains/java/decompiler/code/instructions/NOP.java
index ef11da8..4c47938 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/NOP.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/NOP.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/POP.java b/src/org/jetbrains/java/decompiler/code/instructions/POP.java
index 8848163..99fa873 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/POP.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/POP.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/POP2.java b/src/org/jetbrains/java/decompiler/code/instructions/POP2.java
index f07d5d5..1ff12f3 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/POP2.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/POP2.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/PUTFIELD.java b/src/org/jetbrains/java/decompiler/code/instructions/PUTFIELD.java
index b37efb0..1ab8773 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/PUTFIELD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/PUTFIELD.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class PUTFIELD extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_putfield);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_putfield);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/PUTSTATIC.java b/src/org/jetbrains/java/decompiler/code/instructions/PUTSTATIC.java
index 260e57c..92e2271 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/PUTSTATIC.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/PUTSTATIC.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class PUTSTATIC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_putstatic);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_putstatic);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/RET.java b/src/org/jetbrains/java/decompiler/code/instructions/RET.java
index 490ad8c..c317be0 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/RET.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/RET.java
@@ -1,26 +1,41 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class RET extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_ret);
- if(wide) {
- out.writeShort(getOperand(0));
- } else {
- out.writeByte(getOperand(0));
- }
- }
-
- public int length() {
- return wide?4:2;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_ret);
+ if (wide) {
+ out.writeShort(getOperand(0));
+ }
+ else {
+ out.writeByte(getOperand(0));
+ }
+ }
+
+ public int length() {
+ return wide ? 4 : 2;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/RETURN.java b/src/org/jetbrains/java/decompiler/code/instructions/RETURN.java
index cbdcbfc..83bf8c7 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/RETURN.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/RETURN.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/SALOAD.java b/src/org/jetbrains/java/decompiler/code/instructions/SALOAD.java
index c9da26e..deb82e3 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/SALOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/SALOAD.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/SASTORE.java b/src/org/jetbrains/java/decompiler/code/instructions/SASTORE.java
index 4a90aac..e1ff283 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/SASTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/SASTORE.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/SIPUSH.java b/src/org/jetbrains/java/decompiler/code/instructions/SIPUSH.java
index a5f7025..7c5c55e 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/SIPUSH.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/SIPUSH.java
@@ -1,19 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class SIPUSH extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_sipush);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_sipush);
+ out.writeShort(getOperand(0));
+ }
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/SWAP.java b/src/org/jetbrains/java/decompiler/code/instructions/SWAP.java
index 9fd99b3..64d67f4 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/SWAP.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/SWAP.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/TABLESWITCH.java b/src/org/jetbrains/java/decompiler/code/instructions/TABLESWITCH.java
index 4a4be0a..ac5e6bd 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/TABLESWITCH.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/TABLESWITCH.java
@@ -1,29 +1,42 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
+import org.jetbrains.java.decompiler.code.SwitchInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.SwitchInstruction;
-
public class TABLESWITCH extends SwitchInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
-
- out.writeByte(opc_tableswitch);
-
- int padding = 3 - (offset%4);
- for(int i=0;i<padding;i++){
- out.writeByte(0);
- }
-
- for(int i=0;i<operandsCount();i++) {
- out.writeInt(getOperand(i));
- }
-
- }
-
- public int length() {
- return 1+operandsCount()*4;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+
+ out.writeByte(opc_tableswitch);
+
+ int padding = 3 - (offset % 4);
+ for (int i = 0; i < padding; i++) {
+ out.writeByte(0);
+ }
+
+ for (int i = 0; i < operandsCount(); i++) {
+ out.writeInt(getOperand(i));
+ }
+ }
+
+ public int length() {
+ return 1 + operandsCount() * 4;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/instructions/XXXUNUSEDXXX.java b/src/org/jetbrains/java/decompiler/code/instructions/XXXUNUSEDXXX.java
index 2907258..739aea9 100644
--- a/src/org/jetbrains/java/decompiler/code/instructions/XXXUNUSEDXXX.java
+++ b/src/org/jetbrains/java/decompiler/code/instructions/XXXUNUSEDXXX.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.instructions;
import org.jetbrains.java.decompiler.code.Instruction;
diff --git a/src/org/jetbrains/java/decompiler/code/interpreter/InstructionImpact.java b/src/org/jetbrains/java/decompiler/code/interpreter/InstructionImpact.java
index b155f05..a3da8a6 100644
--- a/src/org/jetbrains/java/decompiler/code/interpreter/InstructionImpact.java
+++ b/src/org/jetbrains/java/decompiler/code/interpreter/InstructionImpact.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.interpreter;
import org.jetbrains.java.decompiler.code.CodeConstants;
@@ -25,444 +26,502 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.ListStack;
public class InstructionImpact {
-
- // {read, write}
- private static final int[][][] stack_impact = {
-
- {null,null}, // public final static int opc_nop = 0;
- null, // public final static int opc_aconst_null = 1;
- null, // public final static int opc_iconst_m1 = 2;
- null, // public final static int opc_iconst_0 = 3;
- null, // public final static int opc_iconst_1 = 4;
- null, // public final static int opc_iconst_2 = 5;
- null, // public final static int opc_iconst_3 = 6;
- null, // public final static int opc_iconst_4 = 7;
- null, // public final static int opc_iconst_5 = 8;
- {null,{CodeConstants.TYPE_LONG}}, // public final static int opc_lconst_0 = 9;
- {null,{CodeConstants.TYPE_LONG}}, // public final static int opc_lconst_1 = 10;
- {null,{CodeConstants.TYPE_FLOAT}}, // public final static int opc_fconst_0 = 11;
- {null,{CodeConstants.TYPE_FLOAT}}, // public final static int opc_fconst_1 = 12;
- {null,{CodeConstants.TYPE_FLOAT}}, // public final static int opc_fconst_2 = 13;
- {null,{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dconst_0 = 14;
- {null,{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dconst_1 = 15;
- {null,{CodeConstants.TYPE_INT}}, // public final static int opc_bipush = 16;
- {null,{CodeConstants.TYPE_INT}}, // public final static int opc_sipush = 17;
- null, // public final static int opc_ldc = 18;
- null, // public final static int opc_ldc_w = 19;
- null, // public final static int opc_ldc2_w = 20;
- {null,{CodeConstants.TYPE_INT}}, // public final static int opc_iload = 21;
- {null,{CodeConstants.TYPE_LONG}}, // public final static int opc_lload = 22;
- {null,{CodeConstants.TYPE_FLOAT}}, // public final static int opc_fload = 23;
- {null,{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dload = 24;
- null, // public final static int opc_aload = 25;
- null, // public final static int opc_iload_0 = 26;
- null, // public final static int opc_iload_1 = 27;
- null, // public final static int opc_iload_2 = 28;
- null, // public final static int opc_iload_3 = 29;
- null, // public final static int opc_lload_0 = 30;
- null, // public final static int opc_lload_1 = 31;
- null, // public final static int opc_lload_2 = 32;
- null, // public final static int opc_lload_3 = 33;
- null, // public final static int opc_fload_0 = 34;
- null, // public final static int opc_fload_1 = 35;
- null, // public final static int opc_fload_2 = 36;
- null, // public final static int opc_fload_3 = 37;
- null, // public final static int opc_dload_0 = 38;
- null, // public final static int opc_dload_1 = 39;
- null, // public final static int opc_dload_2 = 40;
- null, // public final static int opc_dload_3 = 41;
- null, // public final static int opc_aload_0 = 42;
- null, // public final static int opc_aload_1 = 43;
- null, // public final static int opc_aload_2 = 44;
- null, // public final static int opc_aload_3 = 45;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_iaload = 46;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_LONG}}, // public final static int opc_laload = 47;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_FLOAT}}, // public final static int opc_faload = 48;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_daload = 49;
- null, // public final static int opc_aaload = 50;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_baload = 51;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_caload = 52;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_saload = 53;
- {{CodeConstants.TYPE_INT},null}, // public final static int opc_istore = 54;
- {{CodeConstants.TYPE_LONG},null}, // public final static int opc_lstore = 55;
- {{CodeConstants.TYPE_FLOAT},null}, // public final static int opc_fstore = 56;
- {{CodeConstants.TYPE_DOUBLE},null}, // public final static int opc_dstore = 57;
- null, // public final static int opc_astore = 58;
- null, // public final static int opc_istore_0 = 59;
- null, // public final static int opc_istore_1 = 60;
- null, // public final static int opc_istore_2 = 61;
- null, // public final static int opc_istore_3 = 62;
- null, // public final static int opc_lstore_0 = 63;
- null, // public final static int opc_lstore_1 = 64;
- null, // public final static int opc_lstore_2 = 65;
- null, // public final static int opc_lstore_3 = 66;
- null, // public final static int opc_fstore_0 = 67;
- null, // public final static int opc_fstore_1 = 68;
- null, // public final static int opc_fstore_2 = 69;
- null, // public final static int opc_fstore_3 = 70;
- null, // public final static int opc_dstore_0 = 71;
- null, // public final static int opc_dstore_1 = 72;
- null, // public final static int opc_dstore_2 = 73;
- null, // public final static int opc_dstore_3 = 74;
- null, // public final static int opc_astore_0 = 75;
- null, // public final static int opc_astore_1 = 76;
- null, // public final static int opc_astore_2 = 77;
- null, // public final static int opc_astore_3 = 78;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT,CodeConstants.TYPE_INT},null}, // public final static int opc_iastore = 79;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT,CodeConstants.TYPE_LONG},null}, // public final static int opc_lastore = 80;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT,CodeConstants.TYPE_FLOAT},null}, // public final static int opc_fastore = 81;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT,CodeConstants.TYPE_DOUBLE},null}, // public final static int opc_dastore = 82;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT,CodeConstants.TYPE_OBJECT},null}, // public final static int opc_aastore = 83;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT,CodeConstants.TYPE_INT},null}, // public final static int opc_bastore = 84;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT,CodeConstants.TYPE_INT},null}, // public final static int opc_castore = 85;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT,CodeConstants.TYPE_INT},null}, // public final static int opc_sastore = 86;
- {{CodeConstants.TYPE_ANY},null}, // public final static int opc_pop = 87;
- {{CodeConstants.TYPE_ANY, CodeConstants.TYPE_ANY},null}, // public final static int opc_pop2 = 88;
- null, // public final static int opc_dup = 89;
- null, // public final static int opc_dup_x1 = 90;
- null, // public final static int opc_dup_x2 = 91;
- null, // public final static int opc_dup2 = 92;
- null, // public final static int opc_dup2_x1 = 93;
- null, // public final static int opc_dup2_x2 = 94;
- null, // public final static int opc_swap = 95;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_iadd = 96;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG},{CodeConstants.TYPE_LONG}}, // public final static int opc_ladd = 97;
- {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_FLOAT}}, // public final static int opc_fadd = 98;
- {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dadd = 99;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_isub = 100;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG},{CodeConstants.TYPE_LONG}}, // public final static int opc_lsub = 101;
- {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_FLOAT}}, // public final static int opc_fsub = 102;
- {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dsub = 103;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_imul = 104;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG},{CodeConstants.TYPE_LONG}}, // public final static int opc_lmul = 105;
- {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_FLOAT}}, // public final static int opc_fmul = 106;
- {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dmul = 107;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_idiv = 108;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG},{CodeConstants.TYPE_LONG}}, // public final static int opc_ldiv = 109;
- {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_FLOAT}}, // public final static int opc_fdiv = 110;
- {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_ddiv = 111;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_irem = 112;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG},{CodeConstants.TYPE_LONG}}, // public final static int opc_lrem = 113;
- {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_FLOAT}}, // public final static int opc_frem = 114;
- {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_drem = 115;
- {{CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_ineg = 116;
- {{CodeConstants.TYPE_LONG},{CodeConstants.TYPE_LONG}}, // public final static int opc_lneg = 117;
- {{CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_FLOAT}}, // public final static int opc_fneg = 118;
- {{CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dneg = 119;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_ishl = 120;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_INT},{CodeConstants.TYPE_LONG}}, // public final static int opc_lshl = 121;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_ishr = 122;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_INT},{CodeConstants.TYPE_LONG}}, // public final static int opc_lshr = 123;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_iushr = 124;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_INT},{CodeConstants.TYPE_LONG}}, // public final static int opc_lushr = 125;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_iand = 126;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG},{CodeConstants.TYPE_LONG}}, // public final static int opc_land = 127;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_ior = 128;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG},{CodeConstants.TYPE_LONG}}, // public final static int opc_lor = 129;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_ixor = 130;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG},{CodeConstants.TYPE_LONG}}, // public final static int opc_lxor = 131;
- {null,null}, // public final static int opc_iinc = 132;
- {{CodeConstants.TYPE_INT},{CodeConstants.TYPE_LONG}}, // public final static int opc_i2l = 133;
- {{CodeConstants.TYPE_INT},{CodeConstants.TYPE_FLOAT}}, // public final static int opc_i2f = 134;
- {{CodeConstants.TYPE_INT},{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_i2d = 135;
- {{CodeConstants.TYPE_LONG},{CodeConstants.TYPE_INT}}, // public final static int opc_l2i = 136;
- {{CodeConstants.TYPE_LONG},{CodeConstants.TYPE_FLOAT}}, // public final static int opc_l2f = 137;
- {{CodeConstants.TYPE_LONG},{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_l2d = 138;
- {{CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_INT}}, // public final static int opc_f2i = 139;
- {{CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_LONG}}, // public final static int opc_f2l = 140;
- {{CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_DOUBLE}}, // public final static int opc_f2d = 141;
- {{CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_INT}}, // public final static int opc_d2i = 142;
- {{CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_LONG}}, // public final static int opc_d2l = 143;
- {{CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_FLOAT}}, // public final static int opc_d2f = 144;
- {{CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_i2b = 145;
- {{CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_i2c = 146;
- {{CodeConstants.TYPE_INT},{CodeConstants.TYPE_INT}}, // public final static int opc_i2s = 147;
- {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG},{CodeConstants.TYPE_INT}}, // public final static int opc_lcmp = 148;
- {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_INT}}, // public final static int opc_fcmpl = 149;
- {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT},{CodeConstants.TYPE_INT}}, // public final static int opc_fcmpg = 150;
- {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_INT}}, // public final static int opc_dcmpl = 151;
- {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE},{CodeConstants.TYPE_INT}}, // public final static int opc_dcmpg = 152;
- {{CodeConstants.TYPE_INT},null}, // public final static int opc_ifeq = 153;
- {{CodeConstants.TYPE_INT},null}, // public final static int opc_ifne = 154;
- {{CodeConstants.TYPE_INT},null}, // public final static int opc_iflt = 155;
- {{CodeConstants.TYPE_INT},null}, // public final static int opc_ifge = 156;
- {{CodeConstants.TYPE_INT},null}, // public final static int opc_ifgt = 157;
- {{CodeConstants.TYPE_INT},null}, // public final static int opc_ifle = 158;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},null}, // public final static int opc_if_icmpeq = 159;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},null}, // public final static int opc_if_icmpne = 160;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},null}, // public final static int opc_if_icmplt = 161;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},null}, // public final static int opc_if_icmpge = 162;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},null}, // public final static int opc_if_icmpgt = 163;
- {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT},null}, // public final static int opc_if_icmple = 164;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_OBJECT},null}, // public final static int opc_if_acmpeq = 165;
- {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_OBJECT},null}, // public final static int opc_if_acmpne = 166;
- {null,null}, // public final static int opc_goto = 167;
- {null,{CodeConstants.TYPE_ADDRESS}}, // public final static int opc_jsr = 168;
- {null,null}, // public final static int opc_ret = 169;
- {{CodeConstants.TYPE_INT},null}, // public final static int opc_tableswitch = 170;
- {{CodeConstants.TYPE_INT},null}, // public final static int opc_lookupswitch = 171;
- {{CodeConstants.TYPE_INT},null}, // public final static int opc_ireturn = 172;
- {{CodeConstants.TYPE_LONG},null}, // public final static int opc_lreturn = 173;
- {{CodeConstants.TYPE_FLOAT},null}, // public final static int opc_freturn = 174;
- {{CodeConstants.TYPE_DOUBLE},null}, // public final static int opc_dreturn = 175;
- {{CodeConstants.TYPE_OBJECT},null}, // public final static int opc_areturn = 176;
- {null,null}, // public final static int opc_return = 177;
- null, // public final static int opc_getstatic = 178;
- null, // public final static int opc_putstatic = 179;
- null, // public final static int opc_getfield = 180;
- null, // public final static int opc_putfield = 181;
- null, // public final static int opc_invokevirtual = 182;
- null, // public final static int opc_invokespecial = 183;
- null, // public final static int opc_invokestatic = 184;
- null, // public final static int opc_invokeinterface = 185;
- null, // public final static int opc_xxxunusedxxx = 186;
- null, // public final static int opc_new = 187;
- null, // public final static int opc_newarray = 188;
- null, // public final static int opc_anewarray = 189;
- {{CodeConstants.TYPE_OBJECT},{CodeConstants.TYPE_INT}}, // public final static int opc_arraylength = 190;
- null, // public final static int opc_athrow = 191;
- null, // public final static int opc_checkcast = 192;
- null, // public final static int opc_instanceof = 193;
- {{CodeConstants.TYPE_OBJECT},null}, // public final static int opc_monitorenter = 194;
- {{CodeConstants.TYPE_OBJECT},null}, // public final static int opc_monitorexit = 195;
- null, // public final static int opc_wide = 196;
- null, // public final static int opc_multianewarray = 197;
- {{CodeConstants.TYPE_OBJECT},null}, // public final static int opc_ifnull = 198;
- {{CodeConstants.TYPE_OBJECT},null}, // public final static int opc_ifnonnull = 199;
- {null,null}, // public final static int opc_goto_w = 200;
- {null,{CodeConstants.TYPE_ADDRESS}}, // public final static int opc_jsr_w = 201;
- };
- private static final int[] arr_type = new int[] {
- CodeConstants.TYPE_BOOLEAN,
- CodeConstants.TYPE_CHAR,
- CodeConstants.TYPE_FLOAT,
- CodeConstants.TYPE_DOUBLE,
- CodeConstants.TYPE_BYTE,
- CodeConstants.TYPE_SHORT,
- CodeConstants.TYPE_INT,
- CodeConstants.TYPE_LONG
- };
-
-
- // Sonderbehandlung
-// null, // public final static int opc_aconst_null = 1;
-// null, // public final static int opc_ldc = 18;
-// null, // public final static int opc_ldc_w = 19;
-// null, // public final static int opc_ldc2_w = 20;
-// null, // public final static int opc_aload = 25;
-// null, // public final static int opc_aaload = 50;
-// null, // public final static int opc_astore = 58;
-// null, // public final static int opc_dup = 89;
-// null, // public final static int opc_dup_x1 = 90;
-// null, // public final static int opc_dup_x2 = 91;
-// null, // public final static int opc_dup2 = 92;
-// null, // public final static int opc_dup2_x1 = 93;
-// null, // public final static int opc_dup2_x2 = 94;
-// null, // public final static int opc_swap = 95;
-// null, // public final static int opc_getstatic = 178;
-// null, // public final static int opc_putstatic = 179;
-// null, // public final static int opc_getfield = 180;
-// null, // public final static int opc_putfield = 181;
-// null, // public final static int opc_invokevirtual = 182;
-// null, // public final static int opc_invokespecial = 183;
-// null, // public final static int opc_invokestatic = 184;
-// null, // public final static int opc_invokeinterface = 185;
-// null, // public final static int opc_new = 187;
-// null, // public final static int opc_newarray = 188;
-// null, // public final static int opc_anewarray = 189;
-// null, // public final static int opc_athrow = 191;
-// null, // public final static int opc_checkcast = 192;
-// null, // public final static int opc_instanceof = 193;
-// null, // public final static int opc_multianewarray = 197;
-
-
- public static void stepTypes(DataPoint data, Instruction instr, ConstantPool pool) {
-
- ListStack<VarType> stack = data.getStack();
- int[][] arr = stack_impact[instr.opcode];
-
- if(arr != null) {
- // simple types only
-
- int[] read = arr[0];
- int[] write = arr[1];
-
- if(read!=null) {
- int depth = 0;
- for(int i=0;i<read.length;i++) {
- int type = read[i];
- depth++;
- if(type == CodeConstants.TYPE_LONG ||
- type == CodeConstants.TYPE_DOUBLE) {
- depth++;
- }
- }
-
- stack.removeMultiple(depth);
- }
-
- if(write!=null) {
- for(int i=0;i<write.length;i++) {
- int type = write[i];
- stack.push(new VarType(type));
- if(type == CodeConstants.TYPE_LONG ||
- type == CodeConstants.TYPE_DOUBLE) {
- stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
- }
- }
- }
-
- } else {
- // Sonderbehandlung
- processSpecialInstructions(data, instr, pool);
- }
-
- }
-
- private static void processSpecialInstructions(DataPoint data, Instruction instr, ConstantPool pool) {
-
- VarType var1;
- PrimitiveConstant cn;
- LinkConstant ck;
-
- ListStack<VarType> stack = data.getStack();
-
- switch(instr.opcode) {
- case CodeConstants.opc_aconst_null:
- stack.push(new VarType(CodeConstants.TYPE_NULL,0,null));
- break;
- case CodeConstants.opc_ldc:
- case CodeConstants.opc_ldc_w:
- case CodeConstants.opc_ldc2_w:
- cn = pool.getPrimitiveConstant(instr.getOperand(0));
- switch(cn.type) {
- case CodeConstants.CONSTANT_Integer:
- stack.push(new VarType(CodeConstants.TYPE_INT));
- break;
- case CodeConstants.CONSTANT_Float:
- stack.push(new VarType(CodeConstants.TYPE_FLOAT));
- break;
- case CodeConstants.CONSTANT_Long:
- stack.push(new VarType(CodeConstants.TYPE_LONG));
- stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
- break;
- case CodeConstants.CONSTANT_Double:
- stack.push(new VarType(CodeConstants.TYPE_DOUBLE));
- stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
- break;
- case CodeConstants.CONSTANT_String:
- stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/String"));
- break;
- case CodeConstants.CONSTANT_Class:
- stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Class"));
- break;
- }
- break;
- case CodeConstants.opc_aload:
- var1 = data.getVariable(instr.getOperand(0));
- if(var1!=null) {
- stack.push(var1);
- } else {
- stack.push(new VarType(CodeConstants.TYPE_OBJECT,0,null));
- }
- break;
- case CodeConstants.opc_aaload:
- var1 = stack.pop(2);
- stack.push(new VarType(var1.type, var1.arraydim-1, var1.value));
- break;
- case CodeConstants.opc_astore:
- data.setVariable(instr.getOperand(0), (VarType)stack.pop());
- break;
- case CodeConstants.opc_dup:
- case CodeConstants.opc_dup_x1:
- case CodeConstants.opc_dup_x2:
- int depth1 = 88 - instr.opcode;
- stack.insertByOffset(depth1, stack.getByOffset(-1).copy());
- break;
- case CodeConstants.opc_dup2:
- case CodeConstants.opc_dup2_x1:
- case CodeConstants.opc_dup2_x2:
- int depth2 = 90 - instr.opcode;
- stack.insertByOffset(depth2, stack.getByOffset(-2).copy());
- stack.insertByOffset(depth2, stack.getByOffset(-1).copy());
- break;
- case CodeConstants.opc_swap:
- var1 = stack.pop();
- stack.insertByOffset(-1, var1);
- break;
- case CodeConstants.opc_getfield:
- stack.pop();
- case CodeConstants.opc_getstatic:
- ck = pool.getLinkConstant(instr.getOperand(0));
- var1 = new VarType(ck.descriptor);
- stack.push(var1);
- if(var1.stack_size==2) {
- stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
- }
- break;
- case CodeConstants.opc_putfield:
- stack.pop();
- case CodeConstants.opc_putstatic:
- ck = pool.getLinkConstant(instr.getOperand(0));
- var1 = new VarType(ck.descriptor);
- stack.pop(var1.stack_size);
- break;
- case CodeConstants.opc_invokevirtual:
- case CodeConstants.opc_invokespecial:
- case CodeConstants.opc_invokeinterface:
- stack.pop();
- case CodeConstants.opc_invokestatic:
- case CodeConstants.opc_invokedynamic:
- if(instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
- ck = pool.getLinkConstant(instr.getOperand(0));
- MethodDescriptor md = MethodDescriptor.parseDescriptor(ck.descriptor);
- for(int i=0;i<md.params.length;i++) {
- stack.pop(md.params[i].stack_size);
- }
- if(md.ret.type != CodeConstants.TYPE_VOID) {
- stack.push(md.ret);
- if(md.ret.stack_size==2) {
- stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
- }
- }
- }
- break;
- case CodeConstants.opc_new:
- cn = pool.getPrimitiveConstant(instr.getOperand(0));
- stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
- break;
- case CodeConstants.opc_newarray:
- stack.pop();
- var1 = new VarType(arr_type[instr.getOperand(0)-4]);
- var1.arraydim = 1;
- stack.push(var1);
- break;
- case CodeConstants.opc_athrow:
- var1 = stack.pop();
- stack.clear();
- stack.push(var1);
- break;
- case CodeConstants.opc_checkcast:
- case CodeConstants.opc_instanceof:
- stack.pop();
- cn = pool.getPrimitiveConstant(instr.getOperand(0));
- stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
- break;
- case CodeConstants.opc_anewarray:
- case CodeConstants.opc_multianewarray:
- int dimensions = (instr.opcode==CodeConstants.opc_anewarray)?1:instr.getOperand(1);
- stack.pop(dimensions);
- cn = pool.getPrimitiveConstant(instr.getOperand(0));
- if(cn.isArray) {
- var1 = new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString());
- var1.arraydim+=dimensions;
- stack.push(var1);
- } else {
- stack.push(new VarType(CodeConstants.TYPE_OBJECT, dimensions, cn.getString()));
- }
- }
-
- }
-
+ // {read, write}
+ private static final int[][][] stack_impact = {
+
+ {null, null}, // public final static int opc_nop = 0;
+ null, // public final static int opc_aconst_null = 1;
+ null, // public final static int opc_iconst_m1 = 2;
+ null, // public final static int opc_iconst_0 = 3;
+ null, // public final static int opc_iconst_1 = 4;
+ null, // public final static int opc_iconst_2 = 5;
+ null, // public final static int opc_iconst_3 = 6;
+ null, // public final static int opc_iconst_4 = 7;
+ null, // public final static int opc_iconst_5 = 8;
+ {null, {CodeConstants.TYPE_LONG}}, // public final static int opc_lconst_0 = 9;
+ {null, {CodeConstants.TYPE_LONG}}, // public final static int opc_lconst_1 = 10;
+ {null, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_fconst_0 = 11;
+ {null, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_fconst_1 = 12;
+ {null, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_fconst_2 = 13;
+ {null, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dconst_0 = 14;
+ {null, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dconst_1 = 15;
+ {null, {CodeConstants.TYPE_INT}}, // public final static int opc_bipush = 16;
+ {null, {CodeConstants.TYPE_INT}}, // public final static int opc_sipush = 17;
+ null, // public final static int opc_ldc = 18;
+ null, // public final static int opc_ldc_w = 19;
+ null, // public final static int opc_ldc2_w = 20;
+ {null, {CodeConstants.TYPE_INT}}, // public final static int opc_iload = 21;
+ {null, {CodeConstants.TYPE_LONG}}, // public final static int opc_lload = 22;
+ {null, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_fload = 23;
+ {null, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dload = 24;
+ null, // public final static int opc_aload = 25;
+ null, // public final static int opc_iload_0 = 26;
+ null, // public final static int opc_iload_1 = 27;
+ null, // public final static int opc_iload_2 = 28;
+ null, // public final static int opc_iload_3 = 29;
+ null, // public final static int opc_lload_0 = 30;
+ null, // public final static int opc_lload_1 = 31;
+ null, // public final static int opc_lload_2 = 32;
+ null, // public final static int opc_lload_3 = 33;
+ null, // public final static int opc_fload_0 = 34;
+ null, // public final static int opc_fload_1 = 35;
+ null, // public final static int opc_fload_2 = 36;
+ null, // public final static int opc_fload_3 = 37;
+ null, // public final static int opc_dload_0 = 38;
+ null, // public final static int opc_dload_1 = 39;
+ null, // public final static int opc_dload_2 = 40;
+ null, // public final static int opc_dload_3 = 41;
+ null, // public final static int opc_aload_0 = 42;
+ null, // public final static int opc_aload_1 = 43;
+ null, // public final static int opc_aload_2 = 44;
+ null, // public final static int opc_aload_3 = 45;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_iaload = 46;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_laload = 47;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_faload = 48;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_daload = 49;
+ null, // public final static int opc_aaload = 50;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_baload = 51;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_caload = 52;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_saload = 53;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_istore = 54;
+ {{CodeConstants.TYPE_LONG}, null}, // public final static int opc_lstore = 55;
+ {{CodeConstants.TYPE_FLOAT}, null}, // public final static int opc_fstore = 56;
+ {{CodeConstants.TYPE_DOUBLE}, null}, // public final static int opc_dstore = 57;
+ null, // public final static int opc_astore = 58;
+ null, // public final static int opc_istore_0 = 59;
+ null, // public final static int opc_istore_1 = 60;
+ null, // public final static int opc_istore_2 = 61;
+ null, // public final static int opc_istore_3 = 62;
+ null, // public final static int opc_lstore_0 = 63;
+ null, // public final static int opc_lstore_1 = 64;
+ null, // public final static int opc_lstore_2 = 65;
+ null, // public final static int opc_lstore_3 = 66;
+ null, // public final static int opc_fstore_0 = 67;
+ null, // public final static int opc_fstore_1 = 68;
+ null, // public final static int opc_fstore_2 = 69;
+ null, // public final static int opc_fstore_3 = 70;
+ null, // public final static int opc_dstore_0 = 71;
+ null, // public final static int opc_dstore_1 = 72;
+ null, // public final static int opc_dstore_2 = 73;
+ null, // public final static int opc_dstore_3 = 74;
+ null, // public final static int opc_astore_0 = 75;
+ null, // public final static int opc_astore_1 = 76;
+ null, // public final static int opc_astore_2 = 77;
+ null, // public final static int opc_astore_3 = 78;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null},
+ // public final static int opc_iastore = 79;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_LONG}, null},
+ // public final static int opc_lastore = 80;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_FLOAT}, null},
+ // public final static int opc_fastore = 81;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_DOUBLE}, null},
+ // public final static int opc_dastore = 82;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_OBJECT}, null},
+ // public final static int opc_aastore = 83;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null},
+ // public final static int opc_bastore = 84;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null},
+ // public final static int opc_castore = 85;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null},
+ // public final static int opc_sastore = 86;
+ {{CodeConstants.TYPE_ANY}, null}, // public final static int opc_pop = 87;
+ {{CodeConstants.TYPE_ANY, CodeConstants.TYPE_ANY}, null}, // public final static int opc_pop2 = 88;
+ null, // public final static int opc_dup = 89;
+ null, // public final static int opc_dup_x1 = 90;
+ null, // public final static int opc_dup_x2 = 91;
+ null, // public final static int opc_dup2 = 92;
+ null, // public final static int opc_dup2_x1 = 93;
+ null, // public final static int opc_dup2_x2 = 94;
+ null, // public final static int opc_swap = 95;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_iadd = 96;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_ladd = 97;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_fadd = 98;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_dadd = 99;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_isub = 100;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lsub = 101;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_fsub = 102;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_dsub = 103;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_imul = 104;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lmul = 105;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_fmul = 106;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_dmul = 107;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_idiv = 108;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_ldiv = 109;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_fdiv = 110;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_ddiv = 111;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_irem = 112;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lrem = 113;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_frem = 114;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_drem = 115;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}}, // public final static int opc_ineg = 116;
+ {{CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}}, // public final static int opc_lneg = 117;
+ {{CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_fneg = 118;
+ {{CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dneg = 119;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_ishl = 120;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lshl = 121;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_ishr = 122;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lshr = 123;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_iushr = 124;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lushr = 125;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_iand = 126;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_land = 127;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_ior = 128;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lor = 129;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_ixor = 130;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lxor = 131;
+ {null, null}, // public final static int opc_iinc = 132;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_LONG}}, // public final static int opc_i2l = 133;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_i2f = 134;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_i2d = 135;
+ {{CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_INT}}, // public final static int opc_l2i = 136;
+ {{CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_l2f = 137;
+ {{CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_l2d = 138;
+ {{CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_INT}}, // public final static int opc_f2i = 139;
+ {{CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_LONG}}, // public final static int opc_f2l = 140;
+ {{CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_f2d = 141;
+ {{CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_INT}}, // public final static int opc_d2i = 142;
+ {{CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_LONG}}, // public final static int opc_d2l = 143;
+ {{CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_d2f = 144;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}}, // public final static int opc_i2b = 145;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}}, // public final static int opc_i2c = 146;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}}, // public final static int opc_i2s = 147;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_lcmp = 148;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_fcmpl = 149;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_fcmpg = 150;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_dcmpl = 151;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_dcmpg = 152;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ifeq = 153;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ifne = 154;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_iflt = 155;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ifge = 156;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ifgt = 157;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ifle = 158;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmpeq = 159;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmpne = 160;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmplt = 161;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmpge = 162;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmpgt = 163;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmple = 164;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_OBJECT}, null},
+ // public final static int opc_if_acmpeq = 165;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_OBJECT}, null},
+ // public final static int opc_if_acmpne = 166;
+ {null, null}, // public final static int opc_goto = 167;
+ {null, {CodeConstants.TYPE_ADDRESS}}, // public final static int opc_jsr = 168;
+ {null, null}, // public final static int opc_ret = 169;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_tableswitch = 170;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_lookupswitch = 171;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ireturn = 172;
+ {{CodeConstants.TYPE_LONG}, null}, // public final static int opc_lreturn = 173;
+ {{CodeConstants.TYPE_FLOAT}, null}, // public final static int opc_freturn = 174;
+ {{CodeConstants.TYPE_DOUBLE}, null}, // public final static int opc_dreturn = 175;
+ {{CodeConstants.TYPE_OBJECT}, null}, // public final static int opc_areturn = 176;
+ {null, null}, // public final static int opc_return = 177;
+ null, // public final static int opc_getstatic = 178;
+ null, // public final static int opc_putstatic = 179;
+ null, // public final static int opc_getfield = 180;
+ null, // public final static int opc_putfield = 181;
+ null, // public final static int opc_invokevirtual = 182;
+ null, // public final static int opc_invokespecial = 183;
+ null, // public final static int opc_invokestatic = 184;
+ null, // public final static int opc_invokeinterface = 185;
+ null, // public final static int opc_xxxunusedxxx = 186;
+ null, // public final static int opc_new = 187;
+ null, // public final static int opc_newarray = 188;
+ null, // public final static int opc_anewarray = 189;
+ {{CodeConstants.TYPE_OBJECT}, {CodeConstants.TYPE_INT}}, // public final static int opc_arraylength = 190;
+ null,
+ // public final static int opc_athrow = 191;
+ null,
+ // public final static int opc_checkcast = 192;
+ null,
+ // public final static int opc_instanceof = 193;
+ {{CodeConstants.TYPE_OBJECT}, null}, // public final static int opc_monitorenter = 194;
+ {{CodeConstants.TYPE_OBJECT}, null}, // public final static int opc_monitorexit = 195;
+ null,
+ // public final static int opc_wide = 196;
+ null,
+ // public final static int opc_multianewarray = 197;
+ {{CodeConstants.TYPE_OBJECT}, null}, // public final static int opc_ifnull = 198;
+ {{CodeConstants.TYPE_OBJECT}, null}, // public final static int opc_ifnonnull = 199;
+ {null, null}, // public final static int opc_goto_w = 200;
+ {null, {CodeConstants.TYPE_ADDRESS}}, // public final static int opc_jsr_w = 201;
+ };
+
+ private static final int[] arr_type = new int[]{
+ CodeConstants.TYPE_BOOLEAN,
+ CodeConstants.TYPE_CHAR,
+ CodeConstants.TYPE_FLOAT,
+ CodeConstants.TYPE_DOUBLE,
+ CodeConstants.TYPE_BYTE,
+ CodeConstants.TYPE_SHORT,
+ CodeConstants.TYPE_INT,
+ CodeConstants.TYPE_LONG
+ };
+
+
+ // Sonderbehandlung
+ // null, // public final static int opc_aconst_null = 1;
+ // null, // public final static int opc_ldc = 18;
+ // null, // public final static int opc_ldc_w = 19;
+ // null, // public final static int opc_ldc2_w = 20;
+ // null, // public final static int opc_aload = 25;
+ // null, // public final static int opc_aaload = 50;
+ // null, // public final static int opc_astore = 58;
+ // null, // public final static int opc_dup = 89;
+ // null, // public final static int opc_dup_x1 = 90;
+ // null, // public final static int opc_dup_x2 = 91;
+ // null, // public final static int opc_dup2 = 92;
+ // null, // public final static int opc_dup2_x1 = 93;
+ // null, // public final static int opc_dup2_x2 = 94;
+ // null, // public final static int opc_swap = 95;
+ // null, // public final static int opc_getstatic = 178;
+ // null, // public final static int opc_putstatic = 179;
+ // null, // public final static int opc_getfield = 180;
+ // null, // public final static int opc_putfield = 181;
+ // null, // public final static int opc_invokevirtual = 182;
+ // null, // public final static int opc_invokespecial = 183;
+ // null, // public final static int opc_invokestatic = 184;
+ // null, // public final static int opc_invokeinterface = 185;
+ // null, // public final static int opc_new = 187;
+ // null, // public final static int opc_newarray = 188;
+ // null, // public final static int opc_anewarray = 189;
+ // null, // public final static int opc_athrow = 191;
+ // null, // public final static int opc_checkcast = 192;
+ // null, // public final static int opc_instanceof = 193;
+ // null, // public final static int opc_multianewarray = 197;
+
+
+ public static void stepTypes(DataPoint data, Instruction instr, ConstantPool pool) {
+
+ ListStack<VarType> stack = data.getStack();
+ int[][] arr = stack_impact[instr.opcode];
+
+ if (arr != null) {
+ // simple types only
+
+ int[] read = arr[0];
+ int[] write = arr[1];
+
+ if (read != null) {
+ int depth = 0;
+ for (int i = 0; i < read.length; i++) {
+ int type = read[i];
+ depth++;
+ if (type == CodeConstants.TYPE_LONG ||
+ type == CodeConstants.TYPE_DOUBLE) {
+ depth++;
+ }
+ }
+
+ stack.removeMultiple(depth);
+ }
+
+ if (write != null) {
+ for (int i = 0; i < write.length; i++) {
+ int type = write[i];
+ stack.push(new VarType(type));
+ if (type == CodeConstants.TYPE_LONG ||
+ type == CodeConstants.TYPE_DOUBLE) {
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ }
+ }
+ }
+ }
+ else {
+ // Sonderbehandlung
+ processSpecialInstructions(data, instr, pool);
+ }
+ }
+
+ private static void processSpecialInstructions(DataPoint data, Instruction instr, ConstantPool pool) {
+
+ VarType var1;
+ PrimitiveConstant cn;
+ LinkConstant ck;
+
+ ListStack<VarType> stack = data.getStack();
+
+ switch (instr.opcode) {
+ case CodeConstants.opc_aconst_null:
+ stack.push(new VarType(CodeConstants.TYPE_NULL, 0, null));
+ break;
+ case CodeConstants.opc_ldc:
+ case CodeConstants.opc_ldc_w:
+ case CodeConstants.opc_ldc2_w:
+ cn = pool.getPrimitiveConstant(instr.getOperand(0));
+ switch (cn.type) {
+ case CodeConstants.CONSTANT_Integer:
+ stack.push(new VarType(CodeConstants.TYPE_INT));
+ break;
+ case CodeConstants.CONSTANT_Float:
+ stack.push(new VarType(CodeConstants.TYPE_FLOAT));
+ break;
+ case CodeConstants.CONSTANT_Long:
+ stack.push(new VarType(CodeConstants.TYPE_LONG));
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ break;
+ case CodeConstants.CONSTANT_Double:
+ stack.push(new VarType(CodeConstants.TYPE_DOUBLE));
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ break;
+ case CodeConstants.CONSTANT_String:
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/String"));
+ break;
+ case CodeConstants.CONSTANT_Class:
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Class"));
+ break;
+ }
+ break;
+ case CodeConstants.opc_aload:
+ var1 = data.getVariable(instr.getOperand(0));
+ if (var1 != null) {
+ stack.push(var1);
+ }
+ else {
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, null));
+ }
+ break;
+ case CodeConstants.opc_aaload:
+ var1 = stack.pop(2);
+ stack.push(new VarType(var1.type, var1.arraydim - 1, var1.value));
+ break;
+ case CodeConstants.opc_astore:
+ data.setVariable(instr.getOperand(0), (VarType)stack.pop());
+ break;
+ case CodeConstants.opc_dup:
+ case CodeConstants.opc_dup_x1:
+ case CodeConstants.opc_dup_x2:
+ int depth1 = 88 - instr.opcode;
+ stack.insertByOffset(depth1, stack.getByOffset(-1).copy());
+ break;
+ case CodeConstants.opc_dup2:
+ case CodeConstants.opc_dup2_x1:
+ case CodeConstants.opc_dup2_x2:
+ int depth2 = 90 - instr.opcode;
+ stack.insertByOffset(depth2, stack.getByOffset(-2).copy());
+ stack.insertByOffset(depth2, stack.getByOffset(-1).copy());
+ break;
+ case CodeConstants.opc_swap:
+ var1 = stack.pop();
+ stack.insertByOffset(-1, var1);
+ break;
+ case CodeConstants.opc_getfield:
+ stack.pop();
+ case CodeConstants.opc_getstatic:
+ ck = pool.getLinkConstant(instr.getOperand(0));
+ var1 = new VarType(ck.descriptor);
+ stack.push(var1);
+ if (var1.stack_size == 2) {
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ }
+ break;
+ case CodeConstants.opc_putfield:
+ stack.pop();
+ case CodeConstants.opc_putstatic:
+ ck = pool.getLinkConstant(instr.getOperand(0));
+ var1 = new VarType(ck.descriptor);
+ stack.pop(var1.stack_size);
+ break;
+ case CodeConstants.opc_invokevirtual:
+ case CodeConstants.opc_invokespecial:
+ case CodeConstants.opc_invokeinterface:
+ stack.pop();
+ case CodeConstants.opc_invokestatic:
+ case CodeConstants.opc_invokedynamic:
+ if (instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
+ ck = pool.getLinkConstant(instr.getOperand(0));
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(ck.descriptor);
+ for (int i = 0; i < md.params.length; i++) {
+ stack.pop(md.params[i].stack_size);
+ }
+ if (md.ret.type != CodeConstants.TYPE_VOID) {
+ stack.push(md.ret);
+ if (md.ret.stack_size == 2) {
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ }
+ }
+ }
+ break;
+ case CodeConstants.opc_new:
+ cn = pool.getPrimitiveConstant(instr.getOperand(0));
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
+ break;
+ case CodeConstants.opc_newarray:
+ stack.pop();
+ var1 = new VarType(arr_type[instr.getOperand(0) - 4]);
+ var1.arraydim = 1;
+ stack.push(var1);
+ break;
+ case CodeConstants.opc_athrow:
+ var1 = stack.pop();
+ stack.clear();
+ stack.push(var1);
+ break;
+ case CodeConstants.opc_checkcast:
+ case CodeConstants.opc_instanceof:
+ stack.pop();
+ cn = pool.getPrimitiveConstant(instr.getOperand(0));
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
+ break;
+ case CodeConstants.opc_anewarray:
+ case CodeConstants.opc_multianewarray:
+ int dimensions = (instr.opcode == CodeConstants.opc_anewarray) ? 1 : instr.getOperand(1);
+ stack.pop(dimensions);
+ cn = pool.getPrimitiveConstant(instr.getOperand(0));
+ if (cn.isArray) {
+ var1 = new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString());
+ var1.arraydim += dimensions;
+ stack.push(var1);
+ }
+ else {
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, dimensions, cn.getString()));
+ }
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/interpreter/Util.java b/src/org/jetbrains/java/decompiler/code/interpreter/Util.java
index 30aaf2c..bf1e5eb 100644
--- a/src/org/jetbrains/java/decompiler/code/interpreter/Util.java
+++ b/src/org/jetbrains/java/decompiler/code/interpreter/Util.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.interpreter;
import org.jetbrains.java.decompiler.code.Instruction;
@@ -21,245 +22,265 @@ import org.jetbrains.java.decompiler.struct.StructContext;
// FIXME: move to StructContext
public class Util {
-
- private static final String[][] runtime_exceptions = {
-
- null, // public final static int opc_nop = 0;
- null, // public final static int opc_aconst_null = 1;
- null, // public final static int opc_iconst_m1 = 2;
- null, // public final static int opc_iconst_0 = 3;
- null, // public final static int opc_iconst_1 = 4;
- null, // public final static int opc_iconst_2 = 5;
- null, // public final static int opc_iconst_3 = 6;
- null, // public final static int opc_iconst_4 = 7;
- null, // public final static int opc_iconst_5 = 8;
- null, // public final static int opc_lconst_0 = 9;
- null, // public final static int opc_lconst_1 = 10;
- null, // public final static int opc_fconst_0 = 11;
- null, // public final static int opc_fconst_1 = 12;
- null, // public final static int opc_fconst_2 = 13;
- null, // public final static int opc_dconst_0 = 14;
- null, // public final static int opc_dconst_1 = 15;
- null, // public final static int opc_bipush = 16;
- null, // public final static int opc_sipush = 17;
- null, // public final static int opc_ldc = 18;
- null, // public final static int opc_ldc_w = 19;
- null, // public final static int opc_ldc2_w = 20;
- null, // public final static int opc_iload = 21;
- null, // public final static int opc_lload = 22;
- null, // public final static int opc_fload = 23;
- null, // public final static int opc_dload = 24;
- null, // public final static int opc_aload = 25;
- null, // public final static int opc_iload_0 = 26;
- null, // public final static int opc_iload_1 = 27;
- null, // public final static int opc_iload_2 = 28;
- null, // public final static int opc_iload_3 = 29;
- null, // public final static int opc_lload_0 = 30;
- null, // public final static int opc_lload_1 = 31;
- null, // public final static int opc_lload_2 = 32;
- null, // public final static int opc_lload_3 = 33;
- null, // public final static int opc_fload_0 = 34;
- null, // public final static int opc_fload_1 = 35;
- null, // public final static int opc_fload_2 = 36;
- null, // public final static int opc_fload_3 = 37;
- null, // public final static int opc_dload_0 = 38;
- null, // public final static int opc_dload_1 = 39;
- null, // public final static int opc_dload_2 = 40;
- null, // public final static int opc_dload_3 = 41;
- null, // public final static int opc_aload_0 = 42;
- null, // public final static int opc_aload_1 = 43;
- null, // public final static int opc_aload_2 = 44;
- null, // public final static int opc_aload_3 = 45;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_iaload = 46;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_laload = 47;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_faload = 48;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_daload = 49;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_aaload = 50;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_baload = 51;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_caload = 52;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_saload = 53;
- null, // public final static int opc_istore = 54;
- null, // public final static int opc_lstore = 55;
- null, // public final static int opc_fstore = 56;
- null, // public final static int opc_dstore = 57;
- null, // public final static int opc_astore = 58;
- null, // public final static int opc_istore_0 = 59;
- null, // public final static int opc_istore_1 = 60;
- null, // public final static int opc_istore_2 = 61;
- null, // public final static int opc_istore_3 = 62;
- null, // public final static int opc_lstore_0 = 63;
- null, // public final static int opc_lstore_1 = 64;
- null, // public final static int opc_lstore_2 = 65;
- null, // public final static int opc_lstore_3 = 66;
- null, // public final static int opc_fstore_0 = 67;
- null, // public final static int opc_fstore_1 = 68;
- null, // public final static int opc_fstore_2 = 69;
- null, // public final static int opc_fstore_3 = 70;
- null, // public final static int opc_dstore_0 = 71;
- null, // public final static int opc_dstore_1 = 72;
- null, // public final static int opc_dstore_2 = 73;
- null, // public final static int opc_dstore_3 = 74;
- null, // public final static int opc_astore_0 = 75;
- null, // public final static int opc_astore_1 = 76;
- null, // public final static int opc_astore_2 = 77;
- null, // public final static int opc_astore_3 = 78;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_iastore = 79;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_lastore = 80;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_fastore = 81;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_dastore = 82;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException", "java/lang/ArrayStoreException"}, // public final static int opc_aastore = 83;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_bastore = 84;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_castore = 85;
- {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"}, // public final static int opc_sastore = 86;
- null, // public final static int opc_pop = 87;
- null, // public final static int opc_pop2 = 88;
- null, // public final static int opc_dup = 89;
- null, // public final static int opc_dup_x1 = 90;
- null, // public final static int opc_dup_x2 = 91;
- null, // public final static int opc_dup2 = 92;
- null, // public final static int opc_dup2_x1 = 93;
- null, // public final static int opc_dup2_x2 = 94;
- null, // public final static int opc_swap = 95;
- null, // public final static int opc_iadd = 96;
- null, // public final static int opc_ladd = 97;
- null, // public final static int opc_fadd = 98;
- null, // public final static int opc_dadd = 99;
- null, // public final static int opc_isub = 100;
- null, // public final static int opc_lsub = 101;
- null, // public final static int opc_fsub = 102;
- null, // public final static int opc_dsub = 103;
- null, // public final static int opc_imul = 104;
- null, // public final static int opc_lmul = 105;
- null, // public final static int opc_fmul = 106;
- null, // public final static int opc_dmul = 107;
- {"java/lang/ArithmeticException"}, // public final static int opc_idiv = 108;
- {"java/lang/ArithmeticException"}, // public final static int opc_ldiv = 109;
- null, // public final static int opc_fdiv = 110;
- null, // public final static int opc_ddiv = 111;
- {"java/lang/ArithmeticException"}, // public final static int opc_irem = 112;
- {"java/lang/ArithmeticException"}, // public final static int opc_lrem = 113;
- null, // public final static int opc_frem = 114;
- null, // public final static int opc_drem = 115;
- null, // public final static int opc_ineg = 116;
- null, // public final static int opc_lneg = 117;
- null, // public final static int opc_fneg = 118;
- null, // public final static int opc_dneg = 119;
- null, // public final static int opc_ishl = 120;
- null, // public final static int opc_lshl = 121;
- null, // public final static int opc_ishr = 122;
- null, // public final static int opc_lshr = 123;
- null, // public final static int opc_iushr = 124;
- null, // public final static int opc_lushr = 125;
- null, // public final static int opc_iand = 126;
- null, // public final static int opc_land = 127;
- null, // public final static int opc_ior = 128;
- null, // public final static int opc_lor = 129;
- null, // public final static int opc_ixor = 130;
- null, // public final static int opc_lxor = 131;
- null, // public final static int opc_iinc = 132;
- null, // public final static int opc_i2l = 133;
- null, // public final static int opc_i2f = 134;
- null, // public final static int opc_i2d = 135;
- null, // public final static int opc_l2i = 136;
- null, // public final static int opc_l2f = 137;
- null, // public final static int opc_l2d = 138;
- null, // public final static int opc_f2i = 139;
- null, // public final static int opc_f2l = 140;
- null, // public final static int opc_f2d = 141;
- null, // public final static int opc_d2i = 142;
- null, // public final static int opc_d2l = 143;
- null, // public final static int opc_d2f = 144;
- null, // public final static int opc_i2b = 145;
- null, // public final static int opc_i2c = 146;
- null, // public final static int opc_i2s = 147;
- null, // public final static int opc_lcmp = 148;
- null, // public final static int opc_fcmpl = 149;
- null, // public final static int opc_fcmpg = 150;
- null, // public final static int opc_dcmpl = 151;
- null, // public final static int opc_dcmpg = 152;
- null, // public final static int opc_ifeq = 153;
- null, // public final static int opc_ifne = 154;
- null, // public final static int opc_iflt = 155;
- null, // public final static int opc_ifge = 156;
- null, // public final static int opc_ifgt = 157;
- null, // public final static int opc_ifle = 158;
- null, // public final static int opc_if_icmpeq = 159;
- null, // public final static int opc_if_icmpne = 160;
- null, // public final static int opc_if_icmplt = 161;
- null, // public final static int opc_if_icmpge = 162;
- null, // public final static int opc_if_icmpgt = 163;
- null, // public final static int opc_if_icmple = 164;
- null, // public final static int opc_if_acmpeq = 165;
- null, // public final static int opc_if_acmpne = 166;
- null, // public final static int opc_goto = 167;
- null, // public final static int opc_jsr = 168;
- null, // public final static int opc_ret = 169;
- null, // public final static int opc_tableswitch = 170;
- null, // public final static int opc_lookupswitch = 171;
- {"java/lang/IllegalMonitorStateException"}, // public final static int opc_ireturn = 172;
- {"java/lang/IllegalMonitorStateException"}, // public final static int opc_lreturn = 173;
- {"java/lang/IllegalMonitorStateException"}, // public final static int opc_freturn = 174;
- {"java/lang/IllegalMonitorStateException"}, // public final static int opc_dreturn = 175;
- {"java/lang/IllegalMonitorStateException"}, // public final static int opc_areturn = 176;
- {"java/lang/IllegalMonitorStateException"}, // public final static int opc_return = 177;
- null, // public final static int opc_getstatic = 178;
- null, // public final static int opc_putstatic = 179;
- {"java/lang/NullPointerException"}, // public final static int opc_getfield = 180;
- {"java/lang/NullPointerException"}, // public final static int opc_putfield = 181;
- {"java/lang/NullPointerException", "java/lang/AbstractMethodError", "java/lang/UnsatisfiedLinkError"}, // public final static int opc_invokevirtual = 182;
- {"java/lang/NullPointerException", "java/lang/UnsatisfiedLinkError"}, // public final static int opc_invokespecial = 183;
- {"java/lang/UnsatisfiedLinkError"}, // public final static int opc_invokestatic = 184;
- {"java/lang/NullPointerException", "java/lang/IncompatibleClassChangeError", "java/lang/IllegalAccessError", "java/lang/java/lang/AbstractMethodError", "java/lang/UnsatisfiedLinkError"}, // public final static int opc_invokeinterface = 185;
- null, // public final static int opc_xxxunusedxxx = 186;
- null, // public final static int opc_new = 187;
- {"java/lang/NegativeArraySizeException"}, // public final static int opc_newarray = 188;
- {"java/lang/NegativeArraySizeException"}, // public final static int opc_anewarray = 189;
- {"java/lang/NullPointerException"}, // public final static int opc_arraylength = 190;
- {"java/lang/NullPointerException", "java/lang/IllegalMonitorStateException"}, // public final static int opc_athrow = 191;
- {"java/lang/ClassCastException"}, // public final static int opc_checkcast = 192;
- null, // public final static int opc_instanceof = 193;
- {"java/lang/NullPointerException"}, // public final static int opc_monitorenter = 194;
- {"java/lang/NullPointerException", "java/lang/IllegalMonitorStateException"}, // public final static int opc_monitorexit = 195;
- null, // public final static int opc_wide = 196;
- {"java/lang/NegativeArraySizeException"}, // public final static int opc_multianewarray = 197;
- null, // public final static int opc_ifnull = 198;
- null, // public final static int opc_ifnonnull = 199;
- null, // public final static int opc_goto_w = 200;
- null, // public final static int opc_jsr_w = 201;
- };
-
-
- public static boolean instanceOf(StructContext context, String valclass, String refclass) {
-
- if(valclass.equals(refclass)) {
- return true;
- }
-
- StructClass cl = context.getClass(valclass);
- if(cl==null) {
- return false;
- }
-
- if(cl.superClass!=null && instanceOf(context, cl.superClass.getString(), refclass)) {
- return true;
- }
-
- int[] interfaces = cl.getInterfaces();
- for(int i=0;i<interfaces.length;i++) {
- String intfc = cl.getPool().getPrimitiveConstant(interfaces[i]).getString();
-
- if(instanceOf(context, intfc, refclass)) {
- return true;
- }
- }
-
- return false;
- }
-
- public static String[] getRuntimeExceptions(Instruction instr) {
- return runtime_exceptions[instr.opcode];
- }
-
+ private static final String[][] runtime_exceptions = {
+
+ null, // public final static int opc_nop = 0;
+ null, // public final static int opc_aconst_null = 1;
+ null, // public final static int opc_iconst_m1 = 2;
+ null, // public final static int opc_iconst_0 = 3;
+ null, // public final static int opc_iconst_1 = 4;
+ null, // public final static int opc_iconst_2 = 5;
+ null, // public final static int opc_iconst_3 = 6;
+ null, // public final static int opc_iconst_4 = 7;
+ null, // public final static int opc_iconst_5 = 8;
+ null, // public final static int opc_lconst_0 = 9;
+ null, // public final static int opc_lconst_1 = 10;
+ null, // public final static int opc_fconst_0 = 11;
+ null, // public final static int opc_fconst_1 = 12;
+ null, // public final static int opc_fconst_2 = 13;
+ null, // public final static int opc_dconst_0 = 14;
+ null, // public final static int opc_dconst_1 = 15;
+ null, // public final static int opc_bipush = 16;
+ null, // public final static int opc_sipush = 17;
+ null, // public final static int opc_ldc = 18;
+ null, // public final static int opc_ldc_w = 19;
+ null, // public final static int opc_ldc2_w = 20;
+ null, // public final static int opc_iload = 21;
+ null, // public final static int opc_lload = 22;
+ null, // public final static int opc_fload = 23;
+ null, // public final static int opc_dload = 24;
+ null, // public final static int opc_aload = 25;
+ null, // public final static int opc_iload_0 = 26;
+ null, // public final static int opc_iload_1 = 27;
+ null, // public final static int opc_iload_2 = 28;
+ null, // public final static int opc_iload_3 = 29;
+ null, // public final static int opc_lload_0 = 30;
+ null, // public final static int opc_lload_1 = 31;
+ null, // public final static int opc_lload_2 = 32;
+ null, // public final static int opc_lload_3 = 33;
+ null, // public final static int opc_fload_0 = 34;
+ null, // public final static int opc_fload_1 = 35;
+ null, // public final static int opc_fload_2 = 36;
+ null, // public final static int opc_fload_3 = 37;
+ null, // public final static int opc_dload_0 = 38;
+ null, // public final static int opc_dload_1 = 39;
+ null, // public final static int opc_dload_2 = 40;
+ null, // public final static int opc_dload_3 = 41;
+ null, // public final static int opc_aload_0 = 42;
+ null, // public final static int opc_aload_1 = 43;
+ null, // public final static int opc_aload_2 = 44;
+ null, // public final static int opc_aload_3 = 45;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_iaload = 46;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_laload = 47;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_faload = 48;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_daload = 49;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_aaload = 50;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_baload = 51;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_caload = 52;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_saload = 53;
+ null, // public final static int opc_istore = 54;
+ null, // public final static int opc_lstore = 55;
+ null, // public final static int opc_fstore = 56;
+ null, // public final static int opc_dstore = 57;
+ null, // public final static int opc_astore = 58;
+ null, // public final static int opc_istore_0 = 59;
+ null, // public final static int opc_istore_1 = 60;
+ null, // public final static int opc_istore_2 = 61;
+ null, // public final static int opc_istore_3 = 62;
+ null, // public final static int opc_lstore_0 = 63;
+ null, // public final static int opc_lstore_1 = 64;
+ null, // public final static int opc_lstore_2 = 65;
+ null, // public final static int opc_lstore_3 = 66;
+ null, // public final static int opc_fstore_0 = 67;
+ null, // public final static int opc_fstore_1 = 68;
+ null, // public final static int opc_fstore_2 = 69;
+ null, // public final static int opc_fstore_3 = 70;
+ null, // public final static int opc_dstore_0 = 71;
+ null, // public final static int opc_dstore_1 = 72;
+ null, // public final static int opc_dstore_2 = 73;
+ null, // public final static int opc_dstore_3 = 74;
+ null, // public final static int opc_astore_0 = 75;
+ null, // public final static int opc_astore_1 = 76;
+ null, // public final static int opc_astore_2 = 77;
+ null, // public final static int opc_astore_3 = 78;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_iastore = 79;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_lastore = 80;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_fastore = 81;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_dastore = 82;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException", "java/lang/ArrayStoreException"},
+ // public final static int opc_aastore = 83;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_bastore = 84;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_castore = 85;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_sastore = 86;
+ null, // public final static int opc_pop = 87;
+ null, // public final static int opc_pop2 = 88;
+ null, // public final static int opc_dup = 89;
+ null, // public final static int opc_dup_x1 = 90;
+ null, // public final static int opc_dup_x2 = 91;
+ null, // public final static int opc_dup2 = 92;
+ null, // public final static int opc_dup2_x1 = 93;
+ null, // public final static int opc_dup2_x2 = 94;
+ null, // public final static int opc_swap = 95;
+ null, // public final static int opc_iadd = 96;
+ null, // public final static int opc_ladd = 97;
+ null, // public final static int opc_fadd = 98;
+ null, // public final static int opc_dadd = 99;
+ null, // public final static int opc_isub = 100;
+ null, // public final static int opc_lsub = 101;
+ null, // public final static int opc_fsub = 102;
+ null, // public final static int opc_dsub = 103;
+ null, // public final static int opc_imul = 104;
+ null, // public final static int opc_lmul = 105;
+ null, // public final static int opc_fmul = 106;
+ null, // public final static int opc_dmul = 107;
+ {"java/lang/ArithmeticException"}, // public final static int opc_idiv = 108;
+ {"java/lang/ArithmeticException"}, // public final static int opc_ldiv = 109;
+ null, // public final static int opc_fdiv = 110;
+ null, // public final static int opc_ddiv = 111;
+ {"java/lang/ArithmeticException"}, // public final static int opc_irem = 112;
+ {"java/lang/ArithmeticException"}, // public final static int opc_lrem = 113;
+ null, // public final static int opc_frem = 114;
+ null, // public final static int opc_drem = 115;
+ null, // public final static int opc_ineg = 116;
+ null, // public final static int opc_lneg = 117;
+ null, // public final static int opc_fneg = 118;
+ null, // public final static int opc_dneg = 119;
+ null, // public final static int opc_ishl = 120;
+ null, // public final static int opc_lshl = 121;
+ null, // public final static int opc_ishr = 122;
+ null, // public final static int opc_lshr = 123;
+ null, // public final static int opc_iushr = 124;
+ null, // public final static int opc_lushr = 125;
+ null, // public final static int opc_iand = 126;
+ null, // public final static int opc_land = 127;
+ null, // public final static int opc_ior = 128;
+ null, // public final static int opc_lor = 129;
+ null, // public final static int opc_ixor = 130;
+ null, // public final static int opc_lxor = 131;
+ null, // public final static int opc_iinc = 132;
+ null, // public final static int opc_i2l = 133;
+ null, // public final static int opc_i2f = 134;
+ null, // public final static int opc_i2d = 135;
+ null, // public final static int opc_l2i = 136;
+ null, // public final static int opc_l2f = 137;
+ null, // public final static int opc_l2d = 138;
+ null, // public final static int opc_f2i = 139;
+ null, // public final static int opc_f2l = 140;
+ null, // public final static int opc_f2d = 141;
+ null, // public final static int opc_d2i = 142;
+ null, // public final static int opc_d2l = 143;
+ null, // public final static int opc_d2f = 144;
+ null, // public final static int opc_i2b = 145;
+ null, // public final static int opc_i2c = 146;
+ null, // public final static int opc_i2s = 147;
+ null, // public final static int opc_lcmp = 148;
+ null, // public final static int opc_fcmpl = 149;
+ null, // public final static int opc_fcmpg = 150;
+ null, // public final static int opc_dcmpl = 151;
+ null, // public final static int opc_dcmpg = 152;
+ null, // public final static int opc_ifeq = 153;
+ null, // public final static int opc_ifne = 154;
+ null, // public final static int opc_iflt = 155;
+ null, // public final static int opc_ifge = 156;
+ null, // public final static int opc_ifgt = 157;
+ null, // public final static int opc_ifle = 158;
+ null, // public final static int opc_if_icmpeq = 159;
+ null, // public final static int opc_if_icmpne = 160;
+ null, // public final static int opc_if_icmplt = 161;
+ null, // public final static int opc_if_icmpge = 162;
+ null, // public final static int opc_if_icmpgt = 163;
+ null, // public final static int opc_if_icmple = 164;
+ null, // public final static int opc_if_acmpeq = 165;
+ null, // public final static int opc_if_acmpne = 166;
+ null, // public final static int opc_goto = 167;
+ null, // public final static int opc_jsr = 168;
+ null, // public final static int opc_ret = 169;
+ null, // public final static int opc_tableswitch = 170;
+ null, // public final static int opc_lookupswitch = 171;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_ireturn = 172;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_lreturn = 173;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_freturn = 174;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_dreturn = 175;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_areturn = 176;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_return = 177;
+ null, // public final static int opc_getstatic = 178;
+ null, // public final static int opc_putstatic = 179;
+ {"java/lang/NullPointerException"}, // public final static int opc_getfield = 180;
+ {"java/lang/NullPointerException"}, // public final static int opc_putfield = 181;
+ {"java/lang/NullPointerException", "java/lang/AbstractMethodError", "java/lang/UnsatisfiedLinkError"},
+ // public final static int opc_invokevirtual = 182;
+ {"java/lang/NullPointerException", "java/lang/UnsatisfiedLinkError"},
+ // public final static int opc_invokespecial = 183;
+ {"java/lang/UnsatisfiedLinkError"}, // public final static int opc_invokestatic = 184;
+ {"java/lang/NullPointerException", "java/lang/IncompatibleClassChangeError", "java/lang/IllegalAccessError",
+ "java/lang/java/lang/AbstractMethodError", "java/lang/UnsatisfiedLinkError"},
+ // public final static int opc_invokeinterface = 185;
+ null, // public final static int opc_xxxunusedxxx = 186;
+ null, // public final static int opc_new = 187;
+ {"java/lang/NegativeArraySizeException"}, // public final static int opc_newarray = 188;
+ {"java/lang/NegativeArraySizeException"}, // public final static int opc_anewarray = 189;
+ {"java/lang/NullPointerException"}, // public final static int opc_arraylength = 190;
+ {"java/lang/NullPointerException", "java/lang/IllegalMonitorStateException"},
+ // public final static int opc_athrow = 191;
+ {"java/lang/ClassCastException"}, // public final static int opc_checkcast = 192;
+ null, // public final static int opc_instanceof = 193;
+ {"java/lang/NullPointerException"}, // public final static int opc_monitorenter = 194;
+ {"java/lang/NullPointerException", "java/lang/IllegalMonitorStateException"},
+ // public final static int opc_monitorexit = 195;
+ null, // public final static int opc_wide = 196;
+ {"java/lang/NegativeArraySizeException"}, // public final static int opc_multianewarray = 197;
+ null, // public final static int opc_ifnull = 198;
+ null, // public final static int opc_ifnonnull = 199;
+ null, // public final static int opc_goto_w = 200;
+ null, // public final static int opc_jsr_w = 201;
+ };
+
+
+ public static boolean instanceOf(StructContext context, String valclass, String refclass) {
+
+ if (valclass.equals(refclass)) {
+ return true;
+ }
+
+ StructClass cl = context.getClass(valclass);
+ if (cl == null) {
+ return false;
+ }
+
+ if (cl.superClass != null && instanceOf(context, cl.superClass.getString(), refclass)) {
+ return true;
+ }
+
+ int[] interfaces = cl.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ String intfc = cl.getPool().getPrimitiveConstant(interfaces[i]).getString();
+
+ if (instanceOf(context, intfc, refclass)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static String[] getRuntimeExceptions(Instruction instr) {
+ return runtime_exceptions[instr.opcode];
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/ALOAD.java b/src/org/jetbrains/java/decompiler/code/optinstructions/ALOAD.java
index b2727cf..788795e 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/ALOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/ALOAD.java
@@ -1,56 +1,60 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class ALOAD extends Instruction {
-
- private static int[] opcodes = new int[] {opc_aload_0,opc_aload_1,opc_aload_2,opc_aload_3};
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_aload);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_aload_0, opc_aload_1, opc_aload_2, opc_aload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_aload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/ANEWARRAY.java b/src/org/jetbrains/java/decompiler/code/optinstructions/ANEWARRAY.java
index 1e0d4ff..d514ffe 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/ANEWARRAY.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/ANEWARRAY.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class ANEWARRAY extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_anewarray);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_anewarray);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/ASTORE.java b/src/org/jetbrains/java/decompiler/code/optinstructions/ASTORE.java
index 475df11..40336f4 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/ASTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/ASTORE.java
@@ -1,56 +1,60 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class ASTORE extends Instruction {
- private static int[] opcodes = new int[] {opc_astore_0,opc_astore_1,opc_astore_2,opc_astore_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_astore);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_astore_0, opc_astore_1, opc_astore_2, opc_astore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_astore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/BIPUSH.java b/src/org/jetbrains/java/decompiler/code/optinstructions/BIPUSH.java
index 2fb2db5..4686051 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/BIPUSH.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/BIPUSH.java
@@ -1,44 +1,48 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class BIPUSH extends Instruction {
- private static int[] opcodes = new int[] {opc_iconst_m1,opc_iconst_0,opc_iconst_1,opc_iconst_2,opc_iconst_3,opc_iconst_4,opc_iconst_5};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int value = getOperand(0);
- if(value<-1 || value > 5) {
- out.writeByte(opc_bipush);
- out.writeByte(value);
- } else {
- out.writeByte(opcodes[value+1]);
- }
- }
-
- public int length() {
- int value = getOperand(0);
- if(value<-1 || value > 5) {
- return 2;
- } else {
- return 1;
- }
- }
+ private static int[] opcodes =
+ new int[]{opc_iconst_m1, opc_iconst_0, opc_iconst_1, opc_iconst_2, opc_iconst_3, opc_iconst_4, opc_iconst_5};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int value = getOperand(0);
+ if (value < -1 || value > 5) {
+ out.writeByte(opc_bipush);
+ out.writeByte(value);
+ }
+ else {
+ out.writeByte(opcodes[value + 1]);
+ }
+ }
+
+ public int length() {
+ int value = getOperand(0);
+ if (value < -1 || value > 5) {
+ return 2;
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/CHECKCAST.java b/src/org/jetbrains/java/decompiler/code/optinstructions/CHECKCAST.java
index 73417de..9a42f65 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/CHECKCAST.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/CHECKCAST.java
@@ -1,34 +1,34 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class CHECKCAST extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_checkcast);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_checkcast);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/DLOAD.java b/src/org/jetbrains/java/decompiler/code/optinstructions/DLOAD.java
index 96d5449..7630185 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/DLOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/DLOAD.java
@@ -1,56 +1,60 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class DLOAD extends Instruction {
- private static int[] opcodes = new int[] {opc_dload_0,opc_dload_1,opc_dload_2,opc_dload_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_dload);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_dload_0, opc_dload_1, opc_dload_2, opc_dload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_dload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/DSTORE.java b/src/org/jetbrains/java/decompiler/code/optinstructions/DSTORE.java
index 61a8776..2bdb749 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/DSTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/DSTORE.java
@@ -1,55 +1,60 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class DSTORE extends Instruction {
- private static int[] opcodes = new int[] {opc_dstore_0,opc_dstore_1,opc_dstore_2,opc_dstore_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_dstore);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
+ private static int[] opcodes = new int[]{opc_dstore_0, opc_dstore_1, opc_dstore_2, opc_dstore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_dstore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/FLOAD.java b/src/org/jetbrains/java/decompiler/code/optinstructions/FLOAD.java
index 5c8fe26..8a89dff 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/FLOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/FLOAD.java
@@ -1,56 +1,60 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class FLOAD extends Instruction {
- private static int[] opcodes = new int[] {opc_fload_0,opc_fload_1,opc_fload_2,opc_fload_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_fload);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_fload_0, opc_fload_1, opc_fload_2, opc_fload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_fload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/FSTORE.java b/src/org/jetbrains/java/decompiler/code/optinstructions/FSTORE.java
index 3685254..9061913 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/FSTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/FSTORE.java
@@ -1,55 +1,60 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class FSTORE extends Instruction {
- private static int[] opcodes = new int[] {opc_fstore_0,opc_fstore_1,opc_fstore_2,opc_fstore_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_fstore);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- return 4;
- } else {
- return 2;
- }
- } else {
- return 1;
- }
- }
+ private static int[] opcodes = new int[]{opc_fstore_0, opc_fstore_1, opc_fstore_2, opc_fstore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_fstore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/GETFIELD.java b/src/org/jetbrains/java/decompiler/code/optinstructions/GETFIELD.java
index b9a8ab5..6b95aaf 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/GETFIELD.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/GETFIELD.java
@@ -1,32 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class GETFIELD extends Instruction {
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_getfield);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_getfield);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/GETSTATIC.java b/src/org/jetbrains/java/decompiler/code/optinstructions/GETSTATIC.java
index 1890bc0..c1401a6 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/GETSTATIC.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/GETSTATIC.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class GETSTATIC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_getstatic);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_getstatic);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO.java b/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO.java
index 3a81194..97374c0 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO.java
@@ -1,44 +1,46 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class GOTO extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int operand = getOperand(0);
- if(operand < -32768 || operand > 32767) {
- out.writeByte(opc_goto_w);
- out.writeInt(operand);
- } else {
- out.writeByte(opc_goto);
- out.writeShort(operand);
- }
- }
-
- public int length() {
- int operand = getOperand(0);
- if(operand < -32768 || operand > 32767) {
- return 5;
- } else {
- return 3;
- }
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ out.writeByte(opc_goto_w);
+ out.writeInt(operand);
+ }
+ else {
+ out.writeByte(opc_goto);
+ out.writeShort(operand);
+ }
+ }
+
+ public int length() {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ return 5;
+ }
+ else {
+ return 3;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO_W.java b/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO_W.java
index 6e1f6e7..56ba9e8 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO_W.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO_W.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class GOTO_W extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_goto_w);
- out.writeInt(getOperand(0));
- }
-
- public int length() {
- return 5;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_goto_w);
+ out.writeInt(getOperand(0));
+ }
+
+ public int length() {
+ return 5;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/IINC.java b/src/org/jetbrains/java/decompiler/code/optinstructions/IINC.java
index e945969..05b446c 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/IINC.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/IINC.java
@@ -1,42 +1,43 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class IINC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_iinc);
- if(wide) {
- out.writeShort(getOperand(0));
- out.writeShort(getOperand(1));
- } else {
- out.writeByte(getOperand(0));
- out.writeByte(getOperand(1));
- }
- }
-
- public int length() {
- return wide?6:3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_iinc);
+ if (wide) {
+ out.writeShort(getOperand(0));
+ out.writeShort(getOperand(1));
+ }
+ else {
+ out.writeByte(getOperand(0));
+ out.writeByte(getOperand(1));
+ }
+ }
+
+ public int length() {
+ return wide ? 6 : 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/ILOAD.java b/src/org/jetbrains/java/decompiler/code/optinstructions/ILOAD.java
index 40bfa4d..24b95ff 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/ILOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/ILOAD.java
@@ -1,52 +1,55 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class ILOAD extends Instruction {
- private static int[] opcodes = new int[] {opc_iload_0,opc_iload_1,opc_iload_2,opc_iload_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_iload);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- return wide?4:2;
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_iload_0, opc_iload_1, opc_iload_2, opc_iload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_iload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/INSTANCEOF.java b/src/org/jetbrains/java/decompiler/code/optinstructions/INSTANCEOF.java
index f02dfc6..f93d5b8 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/INSTANCEOF.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/INSTANCEOF.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INSTANCEOF extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_instanceof);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_instanceof);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEDYNAMIC.java b/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEDYNAMIC.java
index ee8c785..917c5bd 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEDYNAMIC.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEDYNAMIC.java
@@ -1,20 +1,35 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INVOKEDYNAMIC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_invokedynamic);
- out.writeShort(getOperand(0));
- out.writeByte(0);
- out.writeByte(0);
- }
-
- public int length() {
- return 5;
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokedynamic);
+ out.writeShort(getOperand(0));
+ out.writeByte(0);
+ out.writeByte(0);
+ }
+
+ public int length() {
+ return 5;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEINTERFACE.java b/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEINTERFACE.java
index e4f06f2..51259ff 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEINTERFACE.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEINTERFACE.java
@@ -1,35 +1,35 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INVOKEINTERFACE extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_invokeinterface);
- out.writeShort(getOperand(0));
- out.writeByte(getOperand(1));
- out.writeByte(0);
- }
-
- public int length() {
- return 5;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokeinterface);
+ out.writeShort(getOperand(0));
+ out.writeByte(getOperand(1));
+ out.writeByte(0);
+ }
+
+ public int length() {
+ return 5;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESPECIAL.java b/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESPECIAL.java
index 6b9b559..2436803 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESPECIAL.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESPECIAL.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INVOKESPECIAL extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_invokespecial);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokespecial);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESTATIC.java b/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESTATIC.java
index 0f1ad16..f036a1d 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESTATIC.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESTATIC.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INVOKESTATIC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_invokestatic);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokestatic);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEVIRTUAL.java b/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEVIRTUAL.java
index f4537f3..ca3bcd3 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEVIRTUAL.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEVIRTUAL.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class INVOKEVIRTUAL extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_invokevirtual);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokevirtual);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/ISTORE.java b/src/org/jetbrains/java/decompiler/code/optinstructions/ISTORE.java
index 0ced128..5907538 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/ISTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/ISTORE.java
@@ -1,52 +1,55 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class ISTORE extends Instruction {
- private static int[] opcodes = new int[] {opc_istore_0,opc_istore_1,opc_istore_2,opc_istore_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_istore);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- return wide?4:2;
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_istore_0, opc_istore_1, opc_istore_2, opc_istore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_istore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/JSR.java b/src/org/jetbrains/java/decompiler/code/optinstructions/JSR.java
index ef6c2ad..bb000a7 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/JSR.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/JSR.java
@@ -1,44 +1,46 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class JSR extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int operand = getOperand(0);
- if(operand < -32768 || operand > 32767) {
- out.writeByte(opc_jsr_w);
- out.writeInt(operand);
- } else {
- out.writeByte(opc_jsr);
- out.writeShort(operand);
- }
- }
-
- public int length() {
- int operand = getOperand(0);
- if(operand < -32768 || operand > 32767) {
- return 5;
- } else {
- return 3;
- }
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ out.writeByte(opc_jsr_w);
+ out.writeInt(operand);
+ }
+ else {
+ out.writeByte(opc_jsr);
+ out.writeShort(operand);
+ }
+ }
+
+ public int length() {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ return 5;
+ }
+ else {
+ return 3;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/JSR_W.java b/src/org/jetbrains/java/decompiler/code/optinstructions/JSR_W.java
index bc7ae59..fb04ed9 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/JSR_W.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/JSR_W.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.JumpInstruction;
-
public class JSR_W extends JumpInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_jsr_w);
- out.writeInt(getOperand(0));
- }
-
- public int length() {
- return 5;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_jsr_w);
+ out.writeInt(getOperand(0));
+ }
+
+ public int length() {
+ return 5;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/LDC.java b/src/org/jetbrains/java/decompiler/code/optinstructions/LDC.java
index 4b1a715..ae7b3c6 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/LDC.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/LDC.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class LDC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ldc);
- out.writeByte(getOperand(0));
- }
-
- public int length() {
- return 2;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ldc);
+ out.writeByte(getOperand(0));
+ }
+
+ public int length() {
+ return 2;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/LDC2_W.java b/src/org/jetbrains/java/decompiler/code/optinstructions/LDC2_W.java
index 4b7ea0b..6ba1964 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/LDC2_W.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/LDC2_W.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class LDC2_W extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ldc2_w);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ldc2_w);
+ out.writeShort(getOperand(0));
+ }
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/LDC_W.java b/src/org/jetbrains/java/decompiler/code/optinstructions/LDC_W.java
index 6a4e3a6..71e5fe0 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/LDC_W.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/LDC_W.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class LDC_W extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_ldc_w);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ldc_w);
+ out.writeShort(getOperand(0));
+ }
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/LLOAD.java b/src/org/jetbrains/java/decompiler/code/optinstructions/LLOAD.java
index 52f2b5c..6e50659 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/LLOAD.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/LLOAD.java
@@ -1,52 +1,55 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class LLOAD extends Instruction {
- private static int[] opcodes = new int[] {opc_lload_0,opc_lload_1,opc_lload_2,opc_lload_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_lload);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
+ private static int[] opcodes = new int[]{opc_lload_0, opc_lload_1, opc_lload_2, opc_lload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_lload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- return wide?4:2;
- } else {
- return 1;
- }
- }
-
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/LOOKUPSWITCH.java b/src/org/jetbrains/java/decompiler/code/optinstructions/LOOKUPSWITCH.java
index 1654622..4183168 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/LOOKUPSWITCH.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/LOOKUPSWITCH.java
@@ -1,42 +1,42 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.SwitchInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.SwitchInstruction;
-
public class LOOKUPSWITCH extends SwitchInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
-
- out.writeByte(opc_lookupswitch);
-
- int padding = 3 - (offset%4);
- for(int i=0;i<padding;i++){
- out.writeByte(0);
- }
-
- for(int i=0;i<operandsCount();i++) {
- out.writeInt(getOperand(i));
- }
- }
-
- public int length() {
- return 1+operandsCount()*4;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+
+ out.writeByte(opc_lookupswitch);
+
+ int padding = 3 - (offset % 4);
+ for (int i = 0; i < padding; i++) {
+ out.writeByte(0);
+ }
+
+ for (int i = 0; i < operandsCount(); i++) {
+ out.writeInt(getOperand(i));
+ }
+ }
+
+ public int length() {
+ return 1 + operandsCount() * 4;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/LSTORE.java b/src/org/jetbrains/java/decompiler/code/optinstructions/LSTORE.java
index 410d19a..9095f04 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/LSTORE.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/LSTORE.java
@@ -1,52 +1,55 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class LSTORE extends Instruction {
- private static int[] opcodes = new int[] {opc_lstore_0,opc_lstore_1,opc_lstore_2,opc_lstore_3};
-
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- int index = getOperand(0);
- if(index>3) {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_lstore);
- if(wide) {
- out.writeShort(index);
- } else {
- out.writeByte(index);
- }
- } else {
- out.writeByte(opcodes[index]);
- }
- }
-
- public int length() {
- int index = getOperand(0);
- if(index>3) {
- return wide?4:2;
- } else {
- return 1;
- }
- }
-
+ private static int[] opcodes = new int[]{opc_lstore_0, opc_lstore_1, opc_lstore_2, opc_lstore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_lstore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/MULTIANEWARRAY.java b/src/org/jetbrains/java/decompiler/code/optinstructions/MULTIANEWARRAY.java
index c7eb0b9..b6835e8 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/MULTIANEWARRAY.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/MULTIANEWARRAY.java
@@ -1,34 +1,34 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class MULTIANEWARRAY extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_multianewarray);
- out.writeShort(getOperand(0));
- out.writeByte(getOperand(1));
- }
-
- public int length() {
- return 4;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_multianewarray);
+ out.writeShort(getOperand(0));
+ out.writeByte(getOperand(1));
+ }
+
+ public int length() {
+ return 4;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/NEW.java b/src/org/jetbrains/java/decompiler/code/optinstructions/NEW.java
index eafe17c..2e8854f 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/NEW.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/NEW.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class NEW extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_new);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_new);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/NEWARRAY.java b/src/org/jetbrains/java/decompiler/code/optinstructions/NEWARRAY.java
index 8764a6f..f2f8e4d 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/NEWARRAY.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/NEWARRAY.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class NEWARRAY extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_newarray);
- out.writeByte(getOperand(0));
- }
-
- public int length() {
- return 2;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_newarray);
+ out.writeByte(getOperand(0));
+ }
+
+ public int length() {
+ return 2;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/PUTFIELD.java b/src/org/jetbrains/java/decompiler/code/optinstructions/PUTFIELD.java
index 096da07..c1e3e92 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/PUTFIELD.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/PUTFIELD.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class PUTFIELD extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_putfield);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_putfield);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/PUTSTATIC.java b/src/org/jetbrains/java/decompiler/code/optinstructions/PUTSTATIC.java
index e543c88..0fe0240 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/PUTSTATIC.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/PUTSTATIC.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class PUTSTATIC extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_putstatic);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_putstatic);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/RET.java b/src/org/jetbrains/java/decompiler/code/optinstructions/RET.java
index d52d2a2..93f62ff 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/RET.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/RET.java
@@ -1,40 +1,41 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class RET extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- if(wide) {
- out.writeByte(opc_wide);
- }
- out.writeByte(opc_ret);
- if(wide) {
- out.writeShort(getOperand(0));
- } else {
- out.writeByte(getOperand(0));
- }
- }
-
- public int length() {
- return wide?4:2;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_ret);
+ if (wide) {
+ out.writeShort(getOperand(0));
+ }
+ else {
+ out.writeByte(getOperand(0));
+ }
+ }
+
+ public int length() {
+ return wide ? 4 : 2;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/SIPUSH.java b/src/org/jetbrains/java/decompiler/code/optinstructions/SIPUSH.java
index 5bac32f..08b10a5 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/SIPUSH.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/SIPUSH.java
@@ -1,33 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.Instruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.Instruction;
-
public class SIPUSH extends Instruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
- out.writeByte(opc_sipush);
- out.writeShort(getOperand(0));
- }
-
- public int length() {
- return 3;
- }
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_sipush);
+ out.writeShort(getOperand(0));
+ }
+ public int length() {
+ return 3;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/code/optinstructions/TABLESWITCH.java b/src/org/jetbrains/java/decompiler/code/optinstructions/TABLESWITCH.java
index ca2eae5..0b41ecf 100644
--- a/src/org/jetbrains/java/decompiler/code/optinstructions/TABLESWITCH.java
+++ b/src/org/jetbrains/java/decompiler/code/optinstructions/TABLESWITCH.java
@@ -1,43 +1,42 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.code.optinstructions;
+import org.jetbrains.java.decompiler.code.SwitchInstruction;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.SwitchInstruction;
-
public class TABLESWITCH extends SwitchInstruction {
- public void writeToStream(DataOutputStream out, int offset) throws IOException {
-
- out.writeByte(opc_tableswitch);
-
- int padding = 3 - (offset%4);
- for(int i=0;i<padding;i++){
- out.writeByte(0);
- }
-
- for(int i=0;i<operandsCount();i++) {
- out.writeInt(getOperand(i));
- }
-
- }
-
- public int length() {
- return 1+operandsCount()*4;
- }
-
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+
+ out.writeByte(opc_tableswitch);
+
+ int padding = 3 - (offset % 4);
+ for (int i = 0; i < padding; i++) {
+ out.writeByte(0);
+ }
+
+ for (int i = 0; i < operandsCount(); i++) {
+ out.writeInt(getOperand(i));
+ }
+ }
+
+ public int length() {
+ return 1 + operandsCount() * 4;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/AssertProcessor.java b/src/org/jetbrains/java/decompiler/main/AssertProcessor.java
index 86e5c59..265ca5c 100644
--- a/src/org/jetbrains/java/decompiler/main/AssertProcessor.java
+++ b/src/org/jetbrains/java/decompiler/main/AssertProcessor.java
@@ -1,23 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
@@ -27,295 +24,292 @@ import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
import org.jetbrains.java.decompiler.modules.decompiler.SecondaryFunctionsHelper;
import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssertExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
import org.jetbrains.java.decompiler.struct.StructField;
import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
public class AssertProcessor {
-
- private static final VarType CLASS_ASSERTION_ERROR = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/AssertionError");
-
- public static void buildAssertions(ClassNode node) {
-
- ClassWrapper wrapper = node.wrapper;
-
- StructField field = findAssertionField(node);
-
- if(field != null) {
-
- String key = InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor());
-
- boolean res = false;
-
- for(MethodWrapper meth : wrapper.getMethods()) {
- RootStatement root = meth.root;
- if(root != null) {
- res |= replaceAssertions(root, wrapper.getClassStruct().qualifiedName, key);
- }
- }
-
- if(res) {
- // hide the helper field
- wrapper.getHideMembers().add(key);
- }
- }
-
- }
-
- private static StructField findAssertionField(ClassNode node) {
-
- ClassWrapper wrapper = node.wrapper;
-
- boolean nosynthflag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
-
- for(StructField fd: wrapper.getClassStruct().getFields()) {
-
- String keyField = InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor());
-
- // initializer exists
- if(wrapper.getStaticFieldInitializers().containsKey(keyField)) {
-
- int flags = fd.access_flags;
- boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic");
-
- // access flags set
- if((flags & CodeConstants.ACC_STATIC) != 0 && (flags & CodeConstants.ACC_FINAL) != 0 &&
- (isSynthetic || nosynthflag)) {
-
- // field type boolean
- FieldDescriptor fdescr = FieldDescriptor.parseDescriptor(fd.getDescriptor());
- if(VarType.VARTYPE_BOOLEAN.equals(fdescr.type)) {
-
- Exprent initializer = wrapper.getStaticFieldInitializers().getWithKey(keyField);
- if(initializer.type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent fexpr = (FunctionExprent)initializer;
-
- if(fexpr.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT &&
- fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_INVOCATION) {
-
- InvocationExprent invexpr = (InvocationExprent)fexpr.getLstOperands().get(0);
-
- if(invexpr.getInstance() != null && invexpr.getInstance().type == Exprent.EXPRENT_CONST && "desiredAssertionStatus".equals(invexpr.getName())
- && "java/lang/Class".equals(invexpr.getClassname()) && invexpr.getLstParameters().isEmpty()) {
-
- ConstExprent cexpr = (ConstExprent)invexpr.getInstance();
- if(VarType.VARTYPE_CLASS.equals(cexpr.getConsttype())) {
-
- ClassNode nd = node;
- while(nd != null) {
- if(nd.wrapper.getClassStruct().qualifiedName.equals(cexpr.getValue())) {
- break;
- }
- nd = nd.parent;
- }
-
- if(nd != null) { // found enclosing class with the same name
- return fd;
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
-
- return null;
- }
-
-
- private static boolean replaceAssertions(Statement statement, String classname, String key) {
-
- boolean res = false;
-
- for(Statement st : statement.getStats()) {
- res |= replaceAssertions(st, classname, key);
- }
-
- boolean replaced = true;
- while(replaced) {
- replaced = false;
-
- for(Statement st : statement.getStats()) {
- if(st.type == Statement.TYPE_IF) {
- if(replaceAssertion(statement, (IfStatement)st, classname, key)) {
- replaced = true;
- break;
- }
- }
- }
-
- res |= replaced;
- }
-
- return res;
- }
-
- private static boolean replaceAssertion(Statement parent, IfStatement stat, String classname, String key) {
-
- Statement ifstat = stat.getIfstat();
- InvocationExprent throwError = isAssertionError(ifstat);
-
- if(throwError == null) {
- return false;
- }
-
- Object[] exprres = getAssertionExprent(stat.getHeadexprent().getCondition().copy(), classname, key);
- if(!(Boolean)exprres[1]) {
- return false;
- }
-
- List<Exprent> lstParams = new ArrayList<Exprent>();
-
- Exprent ascond = null, retcond = null;
- if(exprres[0] != null) {
- ascond = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
- Arrays.asList(new Exprent[]{(Exprent)exprres[0]}));
- retcond = SecondaryFunctionsHelper.propagateBoolNot(ascond);
- }
-
- lstParams.add(retcond==null?ascond:retcond);
- if(!throwError.getLstParameters().isEmpty()) {
- lstParams.add(throwError.getLstParameters().get(0));
- }
-
- AssertExprent asexpr = new AssertExprent(lstParams);
-
- Statement newstat = new BasicBlockStatement(new BasicBlock(
- DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
- newstat.setExprents(Arrays.asList(new Exprent[] {asexpr}));
-
- Statement first = stat.getFirst();
-
- if(stat.iftype == IfStatement.IFTYPE_IFELSE || (first.getExprents() != null &&
- !first.getExprents().isEmpty())) {
-
- first.removeSuccessor(stat.getIfEdge());
- first.removeSuccessor(stat.getElseEdge());
-
- List<Statement> lstStatements = new ArrayList<Statement>();
- if(first.getExprents() != null && !first.getExprents().isEmpty()) {
- lstStatements.add(first);
- }
- lstStatements.add(newstat);
- if(stat.iftype == IfStatement.IFTYPE_IFELSE) {
- lstStatements.add(stat.getElsestat());
- }
-
- SequenceStatement sequence = new SequenceStatement(lstStatements);
- sequence.setAllParent();
-
- for(int i=0;i<sequence.getStats().size()-1;i++) {
- sequence.getStats().get(i).addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR,
- sequence.getStats().get(i), sequence.getStats().get(i+1)));
- }
-
- if(stat.iftype == IfStatement.IFTYPE_IFELSE) {
- Statement ifelse = stat.getElsestat();
-
- List<StatEdge> lstSuccs = ifelse.getAllSuccessorEdges();
- if(!lstSuccs.isEmpty()) {
- StatEdge endedge = lstSuccs.get(0);
- if(endedge.closure == stat) {
- sequence.addLabeledEdge(endedge);
- }
- }
- }
-
- newstat = sequence;
- }
-
- newstat.getVarDefinitions().addAll(stat.getVarDefinitions());
- parent.replaceStatement(stat, newstat);
-
- return true;
- }
-
- private static InvocationExprent isAssertionError(Statement stat) {
-
- if(stat == null || stat.getExprents() == null || stat.getExprents().size() !=1) {
- return null;
- }
-
- Exprent expr = stat.getExprents().get(0);
-
- if(expr.type == Exprent.EXPRENT_EXIT) {
- ExitExprent exexpr = (ExitExprent)expr;
- if(exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_NEW) {
- NewExprent nexpr = (NewExprent)exexpr.getValue();
- if(CLASS_ASSERTION_ERROR.equals(nexpr.getNewtype()) && nexpr.getConstructor() != null) {
- return nexpr.getConstructor();
- }
- }
- }
-
- return null;
- }
-
- private static Object[] getAssertionExprent(Exprent exprent, String classname, String key) {
-
- if(exprent.type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent fexpr = (FunctionExprent)exprent;
- if(fexpr.getFunctype() == FunctionExprent.FUNCTION_CADD) {
-
- for(int i=0;i<2;i++) {
- Exprent param = fexpr.getLstOperands().get(i);
-
- if(isAssertionField(param, classname, key)) {
- return new Object[] {fexpr.getLstOperands().get(1-i), true};
- }
- }
-
- for(int i=0;i<2;i++) {
- Exprent param = fexpr.getLstOperands().get(i);
-
- Object[] res = getAssertionExprent(param, classname, key);
- if((Boolean)res[1]) {
- if(param != res[0]) {
- fexpr.getLstOperands().set(i, (Exprent)res[0]);
- }
- return new Object[] {fexpr, true};
- }
- }
- } else if(isAssertionField(fexpr, classname, key)) {
- // assert false;
- return new Object[] {null, true};
- }
- }
-
- return new Object[] {exprent, false};
- }
-
- private static boolean isAssertionField(Exprent exprent, String classname, String key) {
-
- if(exprent.type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent fparam = (FunctionExprent)exprent;
- if(fparam.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT &&
- fparam.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
- FieldExprent fdparam = (FieldExprent)fparam.getLstOperands().get(0);
- if(classname.equals(fdparam.getClassname())
- && key.equals(InterpreterUtil.makeUniqueKey(fdparam.getName(), fdparam.getDescriptor().descriptorString))) {
- return true;
- }
- }
- }
-
- return false;
- }
+
+ private static final VarType CLASS_ASSERTION_ERROR = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/AssertionError");
+
+ public static void buildAssertions(ClassNode node) {
+
+ ClassWrapper wrapper = node.wrapper;
+
+ StructField field = findAssertionField(node);
+
+ if (field != null) {
+
+ String key = InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor());
+
+ boolean res = false;
+
+ for (MethodWrapper meth : wrapper.getMethods()) {
+ RootStatement root = meth.root;
+ if (root != null) {
+ res |= replaceAssertions(root, wrapper.getClassStruct().qualifiedName, key);
+ }
+ }
+
+ if (res) {
+ // hide the helper field
+ wrapper.getHideMembers().add(key);
+ }
+ }
+ }
+
+ private static StructField findAssertionField(ClassNode node) {
+
+ ClassWrapper wrapper = node.wrapper;
+
+ boolean nosynthflag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
+
+ for (StructField fd : wrapper.getClassStruct().getFields()) {
+
+ String keyField = InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor());
+
+ // initializer exists
+ if (wrapper.getStaticFieldInitializers().containsKey(keyField)) {
+
+ int flags = fd.access_flags;
+ boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic");
+
+ // access flags set
+ if ((flags & CodeConstants.ACC_STATIC) != 0 && (flags & CodeConstants.ACC_FINAL) != 0 &&
+ (isSynthetic || nosynthflag)) {
+
+ // field type boolean
+ FieldDescriptor fdescr = FieldDescriptor.parseDescriptor(fd.getDescriptor());
+ if (VarType.VARTYPE_BOOLEAN.equals(fdescr.type)) {
+
+ Exprent initializer = wrapper.getStaticFieldInitializers().getWithKey(keyField);
+ if (initializer.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)initializer;
+
+ if (fexpr.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT &&
+ fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_INVOCATION) {
+
+ InvocationExprent invexpr = (InvocationExprent)fexpr.getLstOperands().get(0);
+
+ if (invexpr.getInstance() != null &&
+ invexpr.getInstance().type == Exprent.EXPRENT_CONST &&
+ "desiredAssertionStatus".equals(invexpr.getName())
+ &&
+ "java/lang/Class".equals(invexpr.getClassname()) &&
+ invexpr.getLstParameters().isEmpty()) {
+
+ ConstExprent cexpr = (ConstExprent)invexpr.getInstance();
+ if (VarType.VARTYPE_CLASS.equals(cexpr.getConsttype())) {
+
+ ClassNode nd = node;
+ while (nd != null) {
+ if (nd.wrapper.getClassStruct().qualifiedName.equals(cexpr.getValue())) {
+ break;
+ }
+ nd = nd.parent;
+ }
+
+ if (nd != null) { // found enclosing class with the same name
+ return fd;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ return null;
+ }
+
+
+ private static boolean replaceAssertions(Statement statement, String classname, String key) {
+
+ boolean res = false;
+
+ for (Statement st : statement.getStats()) {
+ res |= replaceAssertions(st, classname, key);
+ }
+
+ boolean replaced = true;
+ while (replaced) {
+ replaced = false;
+
+ for (Statement st : statement.getStats()) {
+ if (st.type == Statement.TYPE_IF) {
+ if (replaceAssertion(statement, (IfStatement)st, classname, key)) {
+ replaced = true;
+ break;
+ }
+ }
+ }
+
+ res |= replaced;
+ }
+
+ return res;
+ }
+
+ private static boolean replaceAssertion(Statement parent, IfStatement stat, String classname, String key) {
+
+ Statement ifstat = stat.getIfstat();
+ InvocationExprent throwError = isAssertionError(ifstat);
+
+ if (throwError == null) {
+ return false;
+ }
+
+ Object[] exprres = getAssertionExprent(stat.getHeadexprent().getCondition().copy(), classname, key);
+ if (!(Boolean)exprres[1]) {
+ return false;
+ }
+
+ List<Exprent> lstParams = new ArrayList<Exprent>();
+
+ Exprent ascond = null, retcond = null;
+ if (exprres[0] != null) {
+ ascond = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
+ Arrays.asList(new Exprent[]{(Exprent)exprres[0]}));
+ retcond = SecondaryFunctionsHelper.propagateBoolNot(ascond);
+ }
+
+ lstParams.add(retcond == null ? ascond : retcond);
+ if (!throwError.getLstParameters().isEmpty()) {
+ lstParams.add(throwError.getLstParameters().get(0));
+ }
+
+ AssertExprent asexpr = new AssertExprent(lstParams);
+
+ Statement newstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ newstat.setExprents(Arrays.asList(new Exprent[]{asexpr}));
+
+ Statement first = stat.getFirst();
+
+ if (stat.iftype == IfStatement.IFTYPE_IFELSE || (first.getExprents() != null &&
+ !first.getExprents().isEmpty())) {
+
+ first.removeSuccessor(stat.getIfEdge());
+ first.removeSuccessor(stat.getElseEdge());
+
+ List<Statement> lstStatements = new ArrayList<Statement>();
+ if (first.getExprents() != null && !first.getExprents().isEmpty()) {
+ lstStatements.add(first);
+ }
+ lstStatements.add(newstat);
+ if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
+ lstStatements.add(stat.getElsestat());
+ }
+
+ SequenceStatement sequence = new SequenceStatement(lstStatements);
+ sequence.setAllParent();
+
+ for (int i = 0; i < sequence.getStats().size() - 1; i++) {
+ sequence.getStats().get(i).addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR,
+ sequence.getStats().get(i), sequence.getStats().get(i + 1)));
+ }
+
+ if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
+ Statement ifelse = stat.getElsestat();
+
+ List<StatEdge> lstSuccs = ifelse.getAllSuccessorEdges();
+ if (!lstSuccs.isEmpty()) {
+ StatEdge endedge = lstSuccs.get(0);
+ if (endedge.closure == stat) {
+ sequence.addLabeledEdge(endedge);
+ }
+ }
+ }
+
+ newstat = sequence;
+ }
+
+ newstat.getVarDefinitions().addAll(stat.getVarDefinitions());
+ parent.replaceStatement(stat, newstat);
+
+ return true;
+ }
+
+ private static InvocationExprent isAssertionError(Statement stat) {
+
+ if (stat == null || stat.getExprents() == null || stat.getExprents().size() != 1) {
+ return null;
+ }
+
+ Exprent expr = stat.getExprents().get(0);
+
+ if (expr.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exexpr = (ExitExprent)expr;
+ if (exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_NEW) {
+ NewExprent nexpr = (NewExprent)exexpr.getValue();
+ if (CLASS_ASSERTION_ERROR.equals(nexpr.getNewtype()) && nexpr.getConstructor() != null) {
+ return nexpr.getConstructor();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static Object[] getAssertionExprent(Exprent exprent, String classname, String key) {
+
+ if (exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+ if (fexpr.getFunctype() == FunctionExprent.FUNCTION_CADD) {
+
+ for (int i = 0; i < 2; i++) {
+ Exprent param = fexpr.getLstOperands().get(i);
+
+ if (isAssertionField(param, classname, key)) {
+ return new Object[]{fexpr.getLstOperands().get(1 - i), true};
+ }
+ }
+
+ for (int i = 0; i < 2; i++) {
+ Exprent param = fexpr.getLstOperands().get(i);
+
+ Object[] res = getAssertionExprent(param, classname, key);
+ if ((Boolean)res[1]) {
+ if (param != res[0]) {
+ fexpr.getLstOperands().set(i, (Exprent)res[0]);
+ }
+ return new Object[]{fexpr, true};
+ }
+ }
+ }
+ else if (isAssertionField(fexpr, classname, key)) {
+ // assert false;
+ return new Object[]{null, true};
+ }
+ }
+
+ return new Object[]{exprent, false};
+ }
+
+ private static boolean isAssertionField(Exprent exprent, String classname, String key) {
+
+ if (exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fparam = (FunctionExprent)exprent;
+ if (fparam.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT &&
+ fparam.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
+ FieldExprent fdparam = (FieldExprent)fparam.getLstOperands().get(0);
+ if (classname.equals(fdparam.getClassname())
+ && key.equals(InterpreterUtil.makeUniqueKey(fdparam.getName(), fdparam.getDescriptor().descriptorString))) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java b/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
index cdad6ca..411789c 100644
--- a/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
+++ b/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
@@ -1,39 +1,26 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
@@ -46,264 +33,272 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map.Entry;
+
public class ClassReference14Processor {
-
- public ExitExprent bodyexprent;
-
- public ExitExprent handlerexprent;
-
-
- public ClassReference14Processor() {
-
- InvocationExprent invfor = new InvocationExprent();
- invfor.setName("forName");
- invfor.setClassname("java/lang/Class");
- invfor.setStringDescriptor("(Ljava/lang/String;)Ljava/lang/Class;");
- invfor.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/String;)Ljava/lang/Class;"));
- invfor.setStatic(true);
- invfor.setLstParameters(Arrays.asList(new Exprent[] {new VarExprent(0, VarType.VARTYPE_STRING, null)}));
-
- bodyexprent = new ExitExprent(ExitExprent.EXIT_RETURN,
- invfor,
- VarType.VARTYPE_CLASS);
-
- InvocationExprent constr = new InvocationExprent();
- constr.setName("<init>");
- constr.setClassname("java/lang/NoClassDefFoundError");
- constr.setStringDescriptor("()V");
- constr.setFunctype(InvocationExprent.TYP_INIT);
- constr.setDescriptor(MethodDescriptor.parseDescriptor("()V"));
-
- NewExprent newexpr = new NewExprent(new VarType(CodeConstants.TYPE_OBJECT,0,"java/lang/NoClassDefFoundError"), new ArrayList<Exprent>());
- newexpr.setConstructor(constr);
-
- InvocationExprent invcause = new InvocationExprent();
- invcause.setName("initCause");
- invcause.setClassname("java/lang/NoClassDefFoundError");
- invcause.setStringDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
- invcause.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;"));
- invcause.setInstance(newexpr);
- invcause.setLstParameters(Arrays.asList(new Exprent[] {new VarExprent(2, new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"), null)}));
-
- handlerexprent = new ExitExprent(ExitExprent.EXIT_THROW,
- invcause,
- null);
- }
-
-
- public void processClassReferences(ClassNode node) {
-
- ClassWrapper wrapper = node.wrapper;
-
-// int major_version = wrapper.getClassStruct().major_version;
-// int minor_version = wrapper.getClassStruct().minor_version;
-//
-// if(major_version > 48 || (major_version == 48 && minor_version > 0)) {
-// // version 1.5 or above
-// return;
-// }
-
- if(wrapper.getClassStruct().isVersionGE_1_5()) {
- // version 1.5 or above
- return;
- }
-
- // find the synthetic method Class class$(String) if present
- HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<ClassWrapper, MethodWrapper>();
- findClassMethod(node, mapClassMeths);
-
- if(mapClassMeths.isEmpty()) {
- return;
- }
-
- HashSet<ClassWrapper> setFound = new HashSet<ClassWrapper>();
- processClassRec(node, mapClassMeths, setFound);
-
- if(!setFound.isEmpty()) {
- for(ClassWrapper wrp : setFound) {
- StructMethod mt = mapClassMeths.get(wrp).methodStruct;
- wrp.getHideMembers().add(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
- }
- }
-
- }
-
- private void processClassRec(ClassNode node, final HashMap<ClassWrapper, MethodWrapper> mapClassMeths, final HashSet<ClassWrapper> setFound) {
-
- final ClassWrapper wrapper = node.wrapper;
-
- // search code
- for(MethodWrapper meth : wrapper.getMethods()) {
-
- RootStatement root = meth.root;
- if(root != null) {
-
- DirectGraph graph = meth.getOrBuildGraph();
-
- graph.iterateExprents(new DirectGraph.ExprentIterator() {
- public int processExprent(Exprent exprent) {
- for(Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
- if(replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
- setFound.add(ent.getKey());
- }
- }
- return 0;
- }
- });
-
- }
- }
-
- // search initializers
- for(int j=0;j<2;j++) {
- VBStyleCollection<Exprent, String> initializers = j==0?wrapper.getStaticFieldInitializers():wrapper.getDynamicFieldInitializers();
-
- for(int i=0; i<initializers.size();i++) {
- for(Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
- Exprent exprent = initializers.get(i);
- if(replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
- setFound.add(ent.getKey());
- }
-
- String cl = isClass14Invocation(exprent, ent.getKey(), ent.getValue());
- if(cl != null) {
- initializers.set(i, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/')));
- setFound.add(ent.getKey());
- }
- }
- }
- }
-
- // iterate nested classes
- for(ClassNode nd : node.nested) {
- processClassRec(nd, mapClassMeths, setFound);
- }
-
- }
-
- private void findClassMethod(ClassNode node, HashMap<ClassWrapper, MethodWrapper> mapClassMeths) {
-
- boolean nosynthflag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
-
- ClassWrapper wrapper = node.wrapper;
-
- for(MethodWrapper meth : wrapper.getMethods()) {
- StructMethod mt = meth.methodStruct;
-
- if(((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic")
- || nosynthflag) &&
- mt.getDescriptor().equals("(Ljava/lang/String;)Ljava/lang/Class;") &&
- (mt.getAccessFlags() & CodeConstants.ACC_STATIC) != 0) {
-
- RootStatement root = meth.root;
- if(root != null) {
- if(root.getFirst().type == Statement.TYPE_TRYCATCH) {
- CatchStatement cst = (CatchStatement)root.getFirst();
- if(cst.getStats().size() == 2 && cst.getFirst().type == Statement.TYPE_BASICBLOCK &&
- cst.getStats().get(1).type == Statement.TYPE_BASICBLOCK &&
- cst.getVars().get(0).getVartype().equals(new VarType(CodeConstants.TYPE_OBJECT,0,"java/lang/ClassNotFoundException"))) {
-
- BasicBlockStatement body = (BasicBlockStatement)cst.getFirst();
- BasicBlockStatement handler = (BasicBlockStatement)cst.getStats().get(1);
-
- if(body.getExprents().size() == 1 && handler.getExprents().size() == 1) {
- if(bodyexprent.equals(body.getExprents().get(0)) &&
- handlerexprent.equals(handler.getExprents().get(0))) {
- mapClassMeths.put(wrapper, meth);
- break;
- }
- }
- }
- }
- }
- }
- }
-
- // iterate nested classes
- for(ClassNode nd : node.nested) {
- findClassMethod(nd, mapClassMeths);
- }
-
- }
-
-
- private boolean replaceInvocations(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
-
- boolean res = false;
-
- for(;;) {
-
- boolean found = false;
-
- for(Exprent expr : exprent.getAllExprents()) {
- String cl = isClass14Invocation(expr, wrapper, meth);
- if(cl != null) {
- exprent.replaceExprent(expr, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/')));
- found = true;
- res = true;
- break;
- }
-
- res |= replaceInvocations(expr, wrapper, meth);
- }
-
- if(!found) {
- break;
- }
- }
-
- return res;
- }
-
-
-
- private String isClass14Invocation(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
-
- if(exprent.type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent fexpr = (FunctionExprent)exprent;
- if(fexpr.getFunctype() == FunctionExprent.FUNCTION_IIF) {
- if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent headexpr = (FunctionExprent)fexpr.getLstOperands().get(0);
- if(headexpr.getFunctype() == FunctionExprent.FUNCTION_EQ) {
- if(headexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD &&
- headexpr.getLstOperands().get(1).type == Exprent.EXPRENT_CONST &&
- ((ConstExprent)headexpr.getLstOperands().get(1)).getConsttype().equals(VarType.VARTYPE_NULL)) {
-
- FieldExprent field = (FieldExprent)headexpr.getLstOperands().get(0);
- ClassNode fieldnode = DecompilerContext.getClassprocessor().getMapRootClasses().get(field.getClassname());
-
- if(fieldnode != null && fieldnode.classStruct.qualifiedName.equals(wrapper.getClassStruct().qualifiedName)) { // source class
- StructField fd = wrapper.getClassStruct().getField(field.getName(), field.getDescriptor().descriptorString); // FIXME: can be null! why??
-
- if(fd != null && (fd.access_flags & CodeConstants.ACC_STATIC) != 0 &&
- ((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic")
- || DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET))) {
-
- if(fexpr.getLstOperands().get(1).type == Exprent.EXPRENT_ASSIGNMENT && fexpr.getLstOperands().get(2).equals(field)) {
- AssignmentExprent asexpr = (AssignmentExprent)fexpr.getLstOperands().get(1);
-
- if(asexpr.getLeft().equals(field) && asexpr.getRight().type == Exprent.EXPRENT_INVOCATION) {
- InvocationExprent invexpr = (InvocationExprent)asexpr.getRight();
-
- if(invexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName) &&
- invexpr.getName().equals(meth.methodStruct.getName()) &&
- invexpr.getStringDescriptor().equals(meth.methodStruct.getDescriptor())) {
-
- if(invexpr.getLstParameters().get(0).type == Exprent.EXPRENT_CONST) {
- wrapper.getHideMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); // hide synthetic field
- return ((ConstExprent)invexpr.getLstParameters().get(0)).getValue().toString();
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- return null;
- }
+
+ public ExitExprent bodyexprent;
+
+ public ExitExprent handlerexprent;
+
+
+ public ClassReference14Processor() {
+
+ InvocationExprent invfor = new InvocationExprent();
+ invfor.setName("forName");
+ invfor.setClassname("java/lang/Class");
+ invfor.setStringDescriptor("(Ljava/lang/String;)Ljava/lang/Class;");
+ invfor.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/String;)Ljava/lang/Class;"));
+ invfor.setStatic(true);
+ invfor.setLstParameters(Arrays.asList(new Exprent[]{new VarExprent(0, VarType.VARTYPE_STRING, null)}));
+
+ bodyexprent = new ExitExprent(ExitExprent.EXIT_RETURN,
+ invfor,
+ VarType.VARTYPE_CLASS);
+
+ InvocationExprent constr = new InvocationExprent();
+ constr.setName("<init>");
+ constr.setClassname("java/lang/NoClassDefFoundError");
+ constr.setStringDescriptor("()V");
+ constr.setFunctype(InvocationExprent.TYP_INIT);
+ constr.setDescriptor(MethodDescriptor.parseDescriptor("()V"));
+
+ NewExprent newexpr =
+ new NewExprent(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/NoClassDefFoundError"), new ArrayList<Exprent>());
+ newexpr.setConstructor(constr);
+
+ InvocationExprent invcause = new InvocationExprent();
+ invcause.setName("initCause");
+ invcause.setClassname("java/lang/NoClassDefFoundError");
+ invcause.setStringDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
+ invcause.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;"));
+ invcause.setInstance(newexpr);
+ invcause.setLstParameters(
+ Arrays.asList(new Exprent[]{new VarExprent(2, new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"), null)}));
+
+ handlerexprent = new ExitExprent(ExitExprent.EXIT_THROW,
+ invcause,
+ null);
+ }
+
+
+ public void processClassReferences(ClassNode node) {
+
+ ClassWrapper wrapper = node.wrapper;
+
+ // int major_version = wrapper.getClassStruct().major_version;
+ // int minor_version = wrapper.getClassStruct().minor_version;
+ //
+ // if(major_version > 48 || (major_version == 48 && minor_version > 0)) {
+ // // version 1.5 or above
+ // return;
+ // }
+
+ if (wrapper.getClassStruct().isVersionGE_1_5()) {
+ // version 1.5 or above
+ return;
+ }
+
+ // find the synthetic method Class class$(String) if present
+ HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<ClassWrapper, MethodWrapper>();
+ findClassMethod(node, mapClassMeths);
+
+ if (mapClassMeths.isEmpty()) {
+ return;
+ }
+
+ HashSet<ClassWrapper> setFound = new HashSet<ClassWrapper>();
+ processClassRec(node, mapClassMeths, setFound);
+
+ if (!setFound.isEmpty()) {
+ for (ClassWrapper wrp : setFound) {
+ StructMethod mt = mapClassMeths.get(wrp).methodStruct;
+ wrp.getHideMembers().add(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
+ }
+ }
+ }
+
+ private void processClassRec(ClassNode node,
+ final HashMap<ClassWrapper, MethodWrapper> mapClassMeths,
+ final HashSet<ClassWrapper> setFound) {
+
+ final ClassWrapper wrapper = node.wrapper;
+
+ // search code
+ for (MethodWrapper meth : wrapper.getMethods()) {
+
+ RootStatement root = meth.root;
+ if (root != null) {
+
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ graph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ for (Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
+ if (replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
+ setFound.add(ent.getKey());
+ }
+ }
+ return 0;
+ }
+ });
+ }
+ }
+
+ // search initializers
+ for (int j = 0; j < 2; j++) {
+ VBStyleCollection<Exprent, String> initializers =
+ j == 0 ? wrapper.getStaticFieldInitializers() : wrapper.getDynamicFieldInitializers();
+
+ for (int i = 0; i < initializers.size(); i++) {
+ for (Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
+ Exprent exprent = initializers.get(i);
+ if (replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
+ setFound.add(ent.getKey());
+ }
+
+ String cl = isClass14Invocation(exprent, ent.getKey(), ent.getValue());
+ if (cl != null) {
+ initializers.set(i, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/')));
+ setFound.add(ent.getKey());
+ }
+ }
+ }
+ }
+
+ // iterate nested classes
+ for (ClassNode nd : node.nested) {
+ processClassRec(nd, mapClassMeths, setFound);
+ }
+ }
+
+ private void findClassMethod(ClassNode node, HashMap<ClassWrapper, MethodWrapper> mapClassMeths) {
+
+ boolean nosynthflag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
+
+ ClassWrapper wrapper = node.wrapper;
+
+ for (MethodWrapper meth : wrapper.getMethods()) {
+ StructMethod mt = meth.methodStruct;
+
+ if (((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic")
+ || nosynthflag) &&
+ mt.getDescriptor().equals("(Ljava/lang/String;)Ljava/lang/Class;") &&
+ (mt.getAccessFlags() & CodeConstants.ACC_STATIC) != 0) {
+
+ RootStatement root = meth.root;
+ if (root != null) {
+ if (root.getFirst().type == Statement.TYPE_TRYCATCH) {
+ CatchStatement cst = (CatchStatement)root.getFirst();
+ if (cst.getStats().size() == 2 && cst.getFirst().type == Statement.TYPE_BASICBLOCK &&
+ cst.getStats().get(1).type == Statement.TYPE_BASICBLOCK &&
+ cst.getVars().get(0).getVartype().equals(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"))) {
+
+ BasicBlockStatement body = (BasicBlockStatement)cst.getFirst();
+ BasicBlockStatement handler = (BasicBlockStatement)cst.getStats().get(1);
+
+ if (body.getExprents().size() == 1 && handler.getExprents().size() == 1) {
+ if (bodyexprent.equals(body.getExprents().get(0)) &&
+ handlerexprent.equals(handler.getExprents().get(0))) {
+ mapClassMeths.put(wrapper, meth);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // iterate nested classes
+ for (ClassNode nd : node.nested) {
+ findClassMethod(nd, mapClassMeths);
+ }
+ }
+
+
+ private boolean replaceInvocations(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
+
+ boolean res = false;
+
+ for (; ; ) {
+
+ boolean found = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ String cl = isClass14Invocation(expr, wrapper, meth);
+ if (cl != null) {
+ exprent.replaceExprent(expr, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/')));
+ found = true;
+ res = true;
+ break;
+ }
+
+ res |= replaceInvocations(expr, wrapper, meth);
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ return res;
+ }
+
+
+ private String isClass14Invocation(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
+
+ if (exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+ if (fexpr.getFunctype() == FunctionExprent.FUNCTION_IIF) {
+ if (fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent headexpr = (FunctionExprent)fexpr.getLstOperands().get(0);
+ if (headexpr.getFunctype() == FunctionExprent.FUNCTION_EQ) {
+ if (headexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD &&
+ headexpr.getLstOperands().get(1).type == Exprent.EXPRENT_CONST &&
+ ((ConstExprent)headexpr.getLstOperands().get(1)).getConsttype().equals(VarType.VARTYPE_NULL)) {
+
+ FieldExprent field = (FieldExprent)headexpr.getLstOperands().get(0);
+ ClassNode fieldnode = DecompilerContext.getClassprocessor().getMapRootClasses().get(field.getClassname());
+
+ if (fieldnode != null && fieldnode.classStruct.qualifiedName.equals(wrapper.getClassStruct().qualifiedName)) { // source class
+ StructField fd =
+ wrapper.getClassStruct().getField(field.getName(), field.getDescriptor().descriptorString); // FIXME: can be null! why??
+
+ if (fd != null && (fd.access_flags & CodeConstants.ACC_STATIC) != 0 &&
+ ((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic")
+ || DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET))) {
+
+ if (fexpr.getLstOperands().get(1).type == Exprent.EXPRENT_ASSIGNMENT && fexpr.getLstOperands().get(2).equals(field)) {
+ AssignmentExprent asexpr = (AssignmentExprent)fexpr.getLstOperands().get(1);
+
+ if (asexpr.getLeft().equals(field) && asexpr.getRight().type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)asexpr.getRight();
+
+ if (invexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName) &&
+ invexpr.getName().equals(meth.methodStruct.getName()) &&
+ invexpr.getStringDescriptor().equals(meth.methodStruct.getDescriptor())) {
+
+ if (invexpr.getLstParameters().get(0).type == Exprent.EXPRENT_CONST) {
+ wrapper.getHideMembers()
+ .add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); // hide synthetic field
+ return ((ConstExprent)invexpr.getLstParameters().get(0)).getValue().toString();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java
index c14fe79..3c8afab 100644
--- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java
+++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java
@@ -1,27 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
@@ -40,1068 +33,1106 @@ import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructField;
import org.jetbrains.java.decompiler.struct.StructMethod;
-import org.jetbrains.java.decompiler.struct.attr.StructAnnDefaultAttribute;
-import org.jetbrains.java.decompiler.struct.attr.StructAnnotationAttribute;
-import org.jetbrains.java.decompiler.struct.attr.StructAnnotationParameterAttribute;
-import org.jetbrains.java.decompiler.struct.attr.StructConstantValueAttribute;
-import org.jetbrains.java.decompiler.struct.attr.StructExceptionsAttribute;
-import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
-import org.jetbrains.java.decompiler.struct.attr.StructGenericSignatureAttribute;
+import org.jetbrains.java.decompiler.struct.attr.*;
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
-import org.jetbrains.java.decompiler.struct.gen.generics.GenericClassDescriptor;
-import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor;
-import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain;
-import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor;
-import org.jetbrains.java.decompiler.struct.gen.generics.GenericType;
+import org.jetbrains.java.decompiler.struct.gen.generics.*;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
public class ClassWriter {
-
- private static final int[] modval_class = new int[] {CodeConstants.ACC_PUBLIC, CodeConstants.ACC_PROTECTED, CodeConstants.ACC_PRIVATE,
- CodeConstants.ACC_ABSTRACT, CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL, CodeConstants.ACC_STRICT};
-
- private static final String[] modstr_class = new String[] {"public ", "protected ", "private ", "abstract ", "static ", "final ", "strictfp "};
-
- private static final int[] modval_field = new int[] {CodeConstants.ACC_PUBLIC, CodeConstants.ACC_PROTECTED, CodeConstants.ACC_PRIVATE,
- CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL, CodeConstants.ACC_TRANSIENT, CodeConstants.ACC_VOLATILE};
-
- private static final String[] modstr_field = new String[] {"public ", "protected ", "private ", "static ", "final ", "transient ", "volatile "};
-
- private static final int[] modval_meth = new int[] {CodeConstants.ACC_PUBLIC, CodeConstants.ACC_PROTECTED, CodeConstants.ACC_PRIVATE,
- CodeConstants.ACC_ABSTRACT, CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL, CodeConstants.ACC_SYNCHRONIZED,
- CodeConstants.ACC_NATIVE, CodeConstants.ACC_STRICT};
-
- private static final String[] modstr_meth = new String[] {"public ", "protected ", "private ", "abstract ", "static ", "final ", "synchronized ", "native ", "strictfp "};
-
- private static final HashSet<Integer> mod_notinterface = new HashSet<Integer>(Arrays.asList(new Integer[] {CodeConstants.ACC_ABSTRACT, CodeConstants.ACC_STATIC}));
- private static final HashSet<Integer> mod_notinterface_fields = new HashSet<Integer>(Arrays.asList(new Integer[] {CodeConstants.ACC_PUBLIC, CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL}));
- private static final HashSet<Integer> mod_notinterface_meth = new HashSet<Integer>(Arrays.asList(new Integer[] {CodeConstants.ACC_PUBLIC, CodeConstants.ACC_ABSTRACT}));
-
- private ClassReference14Processor ref14processor;
-
- private PoolInterceptor interceptor;
-
- public ClassWriter() {
- ref14processor = new ClassReference14Processor();
- interceptor = DecompilerContext.getPoolInterceptor();
- }
-
-
- private void invokeProcessors(ClassNode node) {
-
- ClassWrapper wrapper = node.wrapper;
- StructClass cl = wrapper.getClassStruct();
-
- InitializerProcessor.extractInitializers(wrapper);
-
- if(node.type == ClassNode.CLASS_ROOT && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4)) {
- ref14processor.processClassReferences(node);
- }
-
- if(DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (cl.access_flags & CodeConstants.ACC_ENUM) != 0) {
- EnumProcessor.clearEnum(wrapper);
- }
-
- if(DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ASSERTIONS)) {
- AssertProcessor.buildAssertions(node);
- }
-
- }
-
- public void classLambdaToJava(ClassNode node, BufferedWriter writer, Exprent method_object, int indent) throws IOException {
-
- // get the class node with the content method
- ClassNode node_content = node;
- while(node_content != null && node_content.type == ClassNode.CLASS_LAMBDA) {
- node_content = node_content.parent;
- }
-
- if(node_content == null) {
- return;
- }
-
- boolean lambda_to_anonymous = DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS);
-
- ClassNode nodeold = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
- DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, node);
-
- ClassWrapper wrapper = node_content.wrapper;
- StructClass cl = wrapper.getClassStruct();
-
- DecompilerContext.getLogger().startWriteClass(node.simpleName);
-
- if(node.lambda_information.is_method_reference) {
-
- if(!node.lambda_information.is_content_method_static && method_object != null) { // reference to a virtual method
- writer.write(method_object.toJava(indent));
- } else { // reference to a static method
- writer.write(ExprProcessor.getCastTypeName(new VarType(node.lambda_information.content_class_name, false)));
- }
-
- writer.write("::");
- writer.write(node.lambda_information.content_method_name);
-
- writer.flush();
-
- } else {
-
- // lambda method
- StructMethod mt = cl.getMethod(node.lambda_information.content_method_key);
- MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
-
- MethodDescriptor md_content = MethodDescriptor.parseDescriptor(node.lambda_information.content_method_descriptor);
- MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(node.lambda_information.method_descriptor);
-
- if(!lambda_to_anonymous) { // lambda parameters '() ->'
-
- StringBuilder buff = new StringBuilder("(");
-
- boolean firstpar = true;
- int index = node.lambda_information.is_content_method_static ? 0 : 1;;
-
- int start_index = md_content.params.length - md_lambda.params.length;
-
- for(int i=0;i<md_content.params.length;i++) {
-
- if(i >= start_index) {
-
- if(!firstpar) {
- buff.append(", ");
- }
-
- String parname = meth.varproc.getVarName(new VarVersionPaar(index, 0));
- buff.append(parname==null ? "param"+index : parname); // null iff decompiled with errors
-
- firstpar = false;
- }
-
- index+=md_content.params[i].stack_size;
- }
- buff.append(") ->");
-
- writer.write(buff.toString());
- }
-
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
-
- if(lambda_to_anonymous) {
- methodLambdaToJava(node, node_content, mt, bufstrwriter, indent+1, false);
- } else {
- methodLambdaToJava(node, node_content, mt, bufstrwriter, indent, true);
- }
-
- bufstrwriter.flush();
-
- // closing up class definition
- writer.write(" {");
- writer.write(DecompilerContext.getNewLineSeparator());
-
- writer.write(strwriter.toString());
-
- writer.write(InterpreterUtil.getIndentString(indent));
- writer.write("}");
- writer.flush();
- }
-
- DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, nodeold);
-
- DecompilerContext.getLogger().endWriteClass();
- }
-
- public void classToJava(ClassNode node, BufferedWriter writer, int indent) throws IOException {
-
- ClassWrapper wrapper = node.wrapper;
- StructClass cl = wrapper.getClassStruct();
-
- ClassNode nodeold = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
- DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, node);
-
- // last minute processing
- invokeProcessors(node);
-
- DecompilerContext.getLogger().startWriteClass(cl.qualifiedName);
-
- writeClassDefinition(node, writer, indent);
-
- // methods
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
-
- boolean firstmt = true;
- boolean mthidden = false;
-
- for(StructMethod mt : cl.getMethods()) {
-
- int flags = mt.getAccessFlags();
-
- boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic");
- boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0;
-
- if((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) &&
- (!isBridge || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE)) &&
- !wrapper.getHideMembers().contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()))) {
- if(!mthidden && (!firstmt || node.type != ClassNode.CLASS_ANONYMOUS)) {
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- firstmt = false;
- }
-
- mthidden = !methodToJava(node, mt, bufstrwriter, indent+1);
- }
- }
- bufstrwriter.flush();
-
- StringWriter strwriter1 = new StringWriter();
- BufferedWriter bufstrwriter1 = new BufferedWriter(strwriter1);
-
- int fields_count = 0;
-
- boolean enumfields = false;
-
- // fields
- for(StructField fd: cl.getFields()) {
- int flags = fd.access_flags;
- boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic");
- if((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC))
- && !wrapper.getHideMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()))) {
-
- boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
- if(isEnum) {
- if(enumfields) {
- bufstrwriter1.write(",");
- bufstrwriter1.write(DecompilerContext.getNewLineSeparator());
- } else {
- enumfields = true;
- }
- } else {
- if(enumfields) {
- bufstrwriter1.write(";");
- bufstrwriter1.write(DecompilerContext.getNewLineSeparator());
- enumfields = false;
- }
- }
-
- fieldToJava(wrapper, cl, fd, bufstrwriter1, indent+1);
- fields_count++;
- }
- }
-
- if(enumfields) {
- bufstrwriter1.write(";");
- bufstrwriter1.write(DecompilerContext.getNewLineSeparator());
- }
-
- bufstrwriter1.flush();
-
- if(fields_count > 0) {
- writer.write(DecompilerContext.getNewLineSeparator());
- writer.write(strwriter1.toString());
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
-
- // methods
- writer.write(strwriter.toString());
-
- // member classes
- for(ClassNode inner : node.nested) {
- if(inner.type == ClassNode.CLASS_MEMBER) {
- StructClass innercl = inner.classStruct;
-
- boolean isSynthetic = ((inner.access | innercl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || innercl.getAttributes().containsKey("Synthetic");
- if((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC))
- && !wrapper.getHideMembers().contains(innercl.qualifiedName)) {
- writer.write(DecompilerContext.getNewLineSeparator());
- classToJava(inner, writer, indent+1);
- }
- }
- }
-
- writer.write(InterpreterUtil.getIndentString(indent));
- writer.write("}");
- if(node.type != ClassNode.CLASS_ANONYMOUS) {
- writer.write(DecompilerContext.getNewLineSeparator());
- }
- writer.flush();
-
- DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, nodeold);
-
- DecompilerContext.getLogger().endWriteClass();
- }
-
- private void writeClassDefinition(ClassNode node, BufferedWriter writer, int indent) throws IOException {
-
- if(node.type == ClassNode.CLASS_ANONYMOUS) {
- writer.write(" {");
- writer.write(DecompilerContext.getNewLineSeparator());
- } else {
-
- String indstr = InterpreterUtil.getIndentString(indent);
-
- ClassWrapper wrapper = node.wrapper;
- StructClass cl = wrapper.getClassStruct();
-
- int flags = node.type == ClassNode.CLASS_ROOT?cl.access_flags:node.access;
- boolean isInterface = (flags & CodeConstants.ACC_INTERFACE) != 0;
- boolean isAnnotation = (flags & CodeConstants.ACC_ANNOTATION) != 0;
- boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
-
- boolean isDeprecated = cl.getAttributes().containsKey("Deprecated");
-
- if(interceptor != null) {
- String oldname = interceptor.getOldName(cl.qualifiedName);
- if(oldname != null) {
- writer.write(indstr);
- writer.write("// $FF: renamed from: "+getDescriptorPrintOut(oldname, 0));
- writer.write(DecompilerContext.getNewLineSeparator());
- }
- }
-
- if (isDeprecated) {
- writer.write(indstr);
- writer.write("/** @deprecated */");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
- // class annotations
- List<AnnotationExprent> lstAnn = getAllAnnotations(cl.getAttributes());
- for(AnnotationExprent annexpr : lstAnn) {
- writer.write(annexpr.toJava(indent));
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
- boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic");
-
- if(isSynthetic) {
- writer.write(indstr);
- writer.write("// $FF: synthetic class");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
- writer.write(indstr);
-
- if(isEnum) {
- // remove abstract and final flags (JLS 8.9 Enums)
- flags &=~CodeConstants.ACC_ABSTRACT;
- flags &=~CodeConstants.ACC_FINAL;
- }
-
- for(int i=0;i<modval_class.length;i++) {
- if(!isInterface || !mod_notinterface.contains(modval_class[i])) {
- if((flags & modval_class[i]) != 0) {
- writer.write(modstr_class[i]);
- }
- }
- }
-
- if(isEnum) {
- writer.write("enum ");
- }else if(isInterface) {
- if(isAnnotation) {
- writer.write("@");
- }
- writer.write("interface ");
- } else {
- writer.write("class ");
- }
-
- GenericClassDescriptor descriptor = null;
- if(DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
- StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)cl.getAttributes().getWithKey("Signature");
- if(attr != null) {
- descriptor = GenericMain.parseClassSignature(attr.getSignature());
- }
- }
-
- writer.write(node.simpleName);
- if(descriptor != null && !descriptor.fparameters.isEmpty()) {
- writer.write("<");
- for(int i=0;i<descriptor.fparameters.size();i++) {
- if(i>0) {
- writer.write(", ");
- }
- writer.write(descriptor.fparameters.get(i));
-
- List<GenericType> lstBounds = descriptor.fbounds.get(i);
+
+ private static final int[] modval_class = new int[]{CodeConstants.ACC_PUBLIC, CodeConstants.ACC_PROTECTED, CodeConstants.ACC_PRIVATE,
+ CodeConstants.ACC_ABSTRACT, CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL, CodeConstants.ACC_STRICT};
+
+ private static final String[] modstr_class =
+ new String[]{"public ", "protected ", "private ", "abstract ", "static ", "final ", "strictfp "};
+
+ private static final int[] modval_field = new int[]{CodeConstants.ACC_PUBLIC, CodeConstants.ACC_PROTECTED, CodeConstants.ACC_PRIVATE,
+ CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL, CodeConstants.ACC_TRANSIENT, CodeConstants.ACC_VOLATILE};
+
+ private static final String[] modstr_field =
+ new String[]{"public ", "protected ", "private ", "static ", "final ", "transient ", "volatile "};
+
+ private static final int[] modval_meth = new int[]{CodeConstants.ACC_PUBLIC, CodeConstants.ACC_PROTECTED, CodeConstants.ACC_PRIVATE,
+ CodeConstants.ACC_ABSTRACT, CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL, CodeConstants.ACC_SYNCHRONIZED,
+ CodeConstants.ACC_NATIVE, CodeConstants.ACC_STRICT};
+
+ private static final String[] modstr_meth =
+ new String[]{"public ", "protected ", "private ", "abstract ", "static ", "final ", "synchronized ", "native ", "strictfp "};
+
+ private static final HashSet<Integer> mod_notinterface =
+ new HashSet<Integer>(Arrays.asList(new Integer[]{CodeConstants.ACC_ABSTRACT, CodeConstants.ACC_STATIC}));
+ private static final HashSet<Integer> mod_notinterface_fields =
+ new HashSet<Integer>(Arrays.asList(new Integer[]{CodeConstants.ACC_PUBLIC, CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL}));
+ private static final HashSet<Integer> mod_notinterface_meth =
+ new HashSet<Integer>(Arrays.asList(new Integer[]{CodeConstants.ACC_PUBLIC, CodeConstants.ACC_ABSTRACT}));
+
+ private ClassReference14Processor ref14processor;
+
+ private PoolInterceptor interceptor;
+
+ public ClassWriter() {
+ ref14processor = new ClassReference14Processor();
+ interceptor = DecompilerContext.getPoolInterceptor();
+ }
+
+
+ private void invokeProcessors(ClassNode node) {
+
+ ClassWrapper wrapper = node.wrapper;
+ StructClass cl = wrapper.getClassStruct();
+
+ InitializerProcessor.extractInitializers(wrapper);
+
+ if (node.type == ClassNode.CLASS_ROOT && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4)) {
+ ref14processor.processClassReferences(node);
+ }
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (cl.access_flags & CodeConstants.ACC_ENUM) != 0) {
+ EnumProcessor.clearEnum(wrapper);
+ }
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ASSERTIONS)) {
+ AssertProcessor.buildAssertions(node);
+ }
+ }
+
+ public void classLambdaToJava(ClassNode node, BufferedWriter writer, Exprent method_object, int indent) throws IOException {
+
+ // get the class node with the content method
+ ClassNode node_content = node;
+ while (node_content != null && node_content.type == ClassNode.CLASS_LAMBDA) {
+ node_content = node_content.parent;
+ }
+
+ if (node_content == null) {
+ return;
+ }
+
+ boolean lambda_to_anonymous = DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS);
+
+ ClassNode nodeold = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, node);
+
+ ClassWrapper wrapper = node_content.wrapper;
+ StructClass cl = wrapper.getClassStruct();
+
+ DecompilerContext.getLogger().startWriteClass(node.simpleName);
+
+ if (node.lambda_information.is_method_reference) {
+
+ if (!node.lambda_information.is_content_method_static && method_object != null) { // reference to a virtual method
+ writer.write(method_object.toJava(indent));
+ }
+ else { // reference to a static method
+ writer.write(ExprProcessor.getCastTypeName(new VarType(node.lambda_information.content_class_name, false)));
+ }
+
+ writer.write("::");
+ writer.write(node.lambda_information.content_method_name);
+
+ writer.flush();
+ }
+ else {
+
+ // lambda method
+ StructMethod mt = cl.getMethod(node.lambda_information.content_method_key);
+ MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
+
+ MethodDescriptor md_content = MethodDescriptor.parseDescriptor(node.lambda_information.content_method_descriptor);
+ MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(node.lambda_information.method_descriptor);
+
+ if (!lambda_to_anonymous) { // lambda parameters '() ->'
+
+ StringBuilder buff = new StringBuilder("(");
+
+ boolean firstpar = true;
+ int index = node.lambda_information.is_content_method_static ? 0 : 1;
+ ;
+
+ int start_index = md_content.params.length - md_lambda.params.length;
+
+ for (int i = 0; i < md_content.params.length; i++) {
+
+ if (i >= start_index) {
+
+ if (!firstpar) {
+ buff.append(", ");
+ }
+
+ String parname = meth.varproc.getVarName(new VarVersionPaar(index, 0));
+ buff.append(parname == null ? "param" + index : parname); // null iff decompiled with errors
+
+ firstpar = false;
+ }
+
+ index += md_content.params[i].stack_size;
+ }
+ buff.append(") ->");
+
+ writer.write(buff.toString());
+ }
+
+ StringWriter strwriter = new StringWriter();
+ BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+
+ if (lambda_to_anonymous) {
+ methodLambdaToJava(node, node_content, mt, bufstrwriter, indent + 1, false);
+ }
+ else {
+ methodLambdaToJava(node, node_content, mt, bufstrwriter, indent, true);
+ }
+
+ bufstrwriter.flush();
+
+ // closing up class definition
+ writer.write(" {");
+ writer.write(DecompilerContext.getNewLineSeparator());
+
+ writer.write(strwriter.toString());
+
+ writer.write(InterpreterUtil.getIndentString(indent));
+ writer.write("}");
+ writer.flush();
+ }
+
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, nodeold);
+
+ DecompilerContext.getLogger().endWriteClass();
+ }
+
+ public void classToJava(ClassNode node, BufferedWriter writer, int indent) throws IOException {
+
+ ClassWrapper wrapper = node.wrapper;
+ StructClass cl = wrapper.getClassStruct();
+
+ ClassNode nodeold = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, node);
+
+ // last minute processing
+ invokeProcessors(node);
+
+ DecompilerContext.getLogger().startWriteClass(cl.qualifiedName);
+
+ writeClassDefinition(node, writer, indent);
+
+ // methods
+ StringWriter strwriter = new StringWriter();
+ BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+
+ boolean firstmt = true;
+ boolean mthidden = false;
+
+ for (StructMethod mt : cl.getMethods()) {
+
+ int flags = mt.getAccessFlags();
+
+ boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic");
+ boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0;
+
+ if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) &&
+ (!isBridge || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE)) &&
+ !wrapper.getHideMembers().contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()))) {
+ if (!mthidden && (!firstmt || node.type != ClassNode.CLASS_ANONYMOUS)) {
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ firstmt = false;
+ }
+
+ mthidden = !methodToJava(node, mt, bufstrwriter, indent + 1);
+ }
+ }
+ bufstrwriter.flush();
+
+ StringWriter strwriter1 = new StringWriter();
+ BufferedWriter bufstrwriter1 = new BufferedWriter(strwriter1);
+
+ int fields_count = 0;
+
+ boolean enumfields = false;
+
+ // fields
+ for (StructField fd : cl.getFields()) {
+ int flags = fd.access_flags;
+ boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic");
+ if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC))
+ && !wrapper.getHideMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()))) {
+
+ boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
+ if (isEnum) {
+ if (enumfields) {
+ bufstrwriter1.write(",");
+ bufstrwriter1.write(DecompilerContext.getNewLineSeparator());
+ }
+ else {
+ enumfields = true;
+ }
+ }
+ else {
+ if (enumfields) {
+ bufstrwriter1.write(";");
+ bufstrwriter1.write(DecompilerContext.getNewLineSeparator());
+ enumfields = false;
+ }
+ }
+
+ fieldToJava(wrapper, cl, fd, bufstrwriter1, indent + 1);
+ fields_count++;
+ }
+ }
+
+ if (enumfields) {
+ bufstrwriter1.write(";");
+ bufstrwriter1.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ bufstrwriter1.flush();
+
+ if (fields_count > 0) {
+ writer.write(DecompilerContext.getNewLineSeparator());
+ writer.write(strwriter1.toString());
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+
+
+ // methods
+ writer.write(strwriter.toString());
+
+ // member classes
+ for (ClassNode inner : node.nested) {
+ if (inner.type == ClassNode.CLASS_MEMBER) {
+ StructClass innercl = inner.classStruct;
+
+ boolean isSynthetic =
+ ((inner.access | innercl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || innercl.getAttributes().containsKey("Synthetic");
+ if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC))
+ && !wrapper.getHideMembers().contains(innercl.qualifiedName)) {
+ writer.write(DecompilerContext.getNewLineSeparator());
+ classToJava(inner, writer, indent + 1);
+ }
+ }
+ }
+
+ writer.write(InterpreterUtil.getIndentString(indent));
+ writer.write("}");
+ if (node.type != ClassNode.CLASS_ANONYMOUS) {
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+ writer.flush();
+
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, nodeold);
+
+ DecompilerContext.getLogger().endWriteClass();
+ }
+
+ private void writeClassDefinition(ClassNode node, BufferedWriter writer, int indent) throws IOException {
+
+ if (node.type == ClassNode.CLASS_ANONYMOUS) {
+ writer.write(" {");
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+ else {
+
+ String indstr = InterpreterUtil.getIndentString(indent);
+
+ ClassWrapper wrapper = node.wrapper;
+ StructClass cl = wrapper.getClassStruct();
+
+ int flags = node.type == ClassNode.CLASS_ROOT ? cl.access_flags : node.access;
+ boolean isInterface = (flags & CodeConstants.ACC_INTERFACE) != 0;
+ boolean isAnnotation = (flags & CodeConstants.ACC_ANNOTATION) != 0;
+ boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
+
+ boolean isDeprecated = cl.getAttributes().containsKey("Deprecated");
+
+ if (interceptor != null) {
+ String oldname = interceptor.getOldName(cl.qualifiedName);
+ if (oldname != null) {
+ writer.write(indstr);
+ writer.write("// $FF: renamed from: " + getDescriptorPrintOut(oldname, 0));
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+ }
+
+ if (isDeprecated) {
+ writer.write(indstr);
+ writer.write("/** @deprecated */");
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ // class annotations
+ List<AnnotationExprent> lstAnn = getAllAnnotations(cl.getAttributes());
+ for (AnnotationExprent annexpr : lstAnn) {
+ writer.write(annexpr.toJava(indent));
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic");
+
+ if (isSynthetic) {
+ writer.write(indstr);
+ writer.write("// $FF: synthetic class");
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ writer.write(indstr);
+
+ if (isEnum) {
+ // remove abstract and final flags (JLS 8.9 Enums)
+ flags &= ~CodeConstants.ACC_ABSTRACT;
+ flags &= ~CodeConstants.ACC_FINAL;
+ }
+
+ for (int i = 0; i < modval_class.length; i++) {
+ if (!isInterface || !mod_notinterface.contains(modval_class[i])) {
+ if ((flags & modval_class[i]) != 0) {
+ writer.write(modstr_class[i]);
+ }
+ }
+ }
+
+ if (isEnum) {
+ writer.write("enum ");
+ }
+ else if (isInterface) {
+ if (isAnnotation) {
+ writer.write("@");
+ }
+ writer.write("interface ");
+ }
+ else {
+ writer.write("class ");
+ }
+
+ GenericClassDescriptor descriptor = null;
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
+ StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)cl.getAttributes().getWithKey("Signature");
+ if (attr != null) {
+ descriptor = GenericMain.parseClassSignature(attr.getSignature());
+ }
+ }
+
+ writer.write(node.simpleName);
+ if (descriptor != null && !descriptor.fparameters.isEmpty()) {
+ writer.write("<");
+ for (int i = 0; i < descriptor.fparameters.size(); i++) {
+ if (i > 0) {
+ writer.write(", ");
+ }
+ writer.write(descriptor.fparameters.get(i));
+
+ List<GenericType> lstBounds = descriptor.fbounds.get(i);
if (lstBounds.size() > 1 || !"java/lang/Object".equals(lstBounds.get(0).value)) {
writer.write(" extends ");
writer.write(GenericMain.getGenericCastTypeName(lstBounds.get(0)));
- for(int j=1;j<lstBounds.size();j++) {
+ for (int j = 1; j < lstBounds.size(); j++) {
writer.write(" & " + GenericMain.getGenericCastTypeName(lstBounds.get(j)));
}
}
- }
- writer.write(">");
- }
- writer.write(" ");
-
- if(!isEnum && !isInterface && cl.superClass != null) {
- VarType supertype = new VarType(cl.superClass.getString(), true);
- if(!VarType.VARTYPE_OBJECT.equals(supertype)) {
- writer.write("extends ");
- if(descriptor != null) {
- writer.write(GenericMain.getGenericCastTypeName(descriptor.superclass));
- } else {
- writer.write(ExprProcessor.getCastTypeName(supertype));
- }
- writer.write(" ");
- }
- }
-
- if(!isAnnotation) {
- int[] interfaces = cl.getInterfaces();
- if(interfaces.length > 0) {
- writer.write(isInterface?"extends ":"implements ");
- for(int i=0;i<interfaces.length;i++) {
- if(i>0) {
- writer.write(", ");
- }
- if(descriptor != null) {
- writer.write(GenericMain.getGenericCastTypeName(descriptor.superinterfaces.get(i)));
- } else {
- writer.write(ExprProcessor.getCastTypeName(new VarType(cl.getInterface(i), true)));
- }
- }
- writer.write(" ");
- }
- }
-
- writer.write("{");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
- }
-
- private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, BufferedWriter writer, int indent) throws IOException {
-
- String indstr = InterpreterUtil.getIndentString(indent);
-
- boolean isInterface = (cl.access_flags & CodeConstants.ACC_INTERFACE) != 0;
- int flags = fd.access_flags;
-
- if(interceptor != null) {
- String oldname = interceptor.getOldName(cl.qualifiedName+" "+fd.getName()+" "+fd.getDescriptor());
- if(oldname != null) {
- String[] element = oldname.split(" ");
-
- writer.write(indstr);
- writer.write("// $FF: renamed from: "+element[1]+" "+getDescriptorPrintOut(element[2], 1));
- writer.write(DecompilerContext.getNewLineSeparator());
- }
- }
-
- boolean isDeprecated = fd.getAttributes().containsKey("Deprecated");
-
- if (isDeprecated) {
- writer.write(indstr);
- writer.write("/** @deprecated */");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
- // field annotations
- List<AnnotationExprent> lstAnn = getAllAnnotations(fd.getAttributes());
- for(AnnotationExprent annexpr : lstAnn) {
- writer.write(annexpr.toJava(indent));
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
- boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic");
- boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
-
- if(isSynthetic) {
- writer.write(indstr);
- writer.write("// $FF: synthetic field");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
- writer.write(indstr);
-
- if(!isEnum) {
- for(int i=0;i<modval_field.length;i++) {
- if(!isInterface || !mod_notinterface_fields.contains(modval_field[i])) {
- if((flags & modval_field[i]) != 0) {
- writer.write(modstr_field[i]);
- }
- }
- }
- }
-
- VarType fieldType = new VarType(fd.getDescriptor(), false);
-
- GenericFieldDescriptor descriptor = null;
- if(DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
- StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)fd.getAttributes().getWithKey("Signature");
- if(attr != null) {
- descriptor = GenericMain.parseFieldSignature(attr.getSignature());
- }
- }
-
- if(!isEnum) {
- if(descriptor != null) {
- writer.write(GenericMain.getGenericCastTypeName(descriptor.type));
- } else {
- writer.write(ExprProcessor.getCastTypeName(fieldType));
- }
- writer.write(" ");
- }
-
- writer.write(fd.getName());
-
- Exprent initializer;
- if((flags & CodeConstants.ACC_STATIC) != 0) {
- initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
- } else {
- initializer = wrapper.getDynamicFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
- }
-
- if(initializer != null) {
- if(isEnum && initializer.type == Exprent.EXPRENT_NEW) {
- NewExprent nexpr = (NewExprent)initializer;
- nexpr.setEnumconst(true);
- writer.write(nexpr.toJava(indent));
- } else {
- writer.write(" = ");
- writer.write(initializer.toJava(indent));
- }
- } else if((flags & CodeConstants.ACC_FINAL) != 0 && (flags & CodeConstants.ACC_STATIC) != 0) {
- StructConstantValueAttribute attr = (StructConstantValueAttribute)fd.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE);
- if(attr != null) {
- PrimitiveConstant cnst = cl.getPool().getPrimitiveConstant(attr.getIndex());
- writer.write(" = ");
- writer.write(new ConstExprent(fieldType, cnst.value).toJava(indent));
- }
- }
-
- if(!isEnum) {
- writer.write(";");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
- }
-
- public boolean methodLambdaToJava(ClassNode node_lambda, ClassNode node_content, StructMethod mt, BufferedWriter writer, int indent, boolean code_only) throws IOException {
-
- ClassWrapper wrapper = node_content.wrapper;
-
- MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
-
- MethodWrapper methold = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
- DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, meth);
-
- String indstr = InterpreterUtil.getIndentString(indent);
-
- String method_name = node_lambda.lambda_information.method_name;
- MethodDescriptor md_content = MethodDescriptor.parseDescriptor(node_lambda.lambda_information.content_method_descriptor);
- MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(node_lambda.lambda_information.method_descriptor);
-
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
-
- if(!code_only) {
- bufstrwriter.write(indstr);
- bufstrwriter.write("public ");
- bufstrwriter.write(method_name);
- bufstrwriter.write("(");
-
- boolean firstpar = true;
- int index = node_lambda.lambda_information.is_content_method_static ? 0 : 1;;
-
- int start_index = md_content.params.length - md_lambda.params.length;
-
- for(int i=0;i<md_content.params.length;i++) {
-
- if(i >= start_index) {
-
- if(!firstpar) {
- bufstrwriter.write(", ");
- }
-
- VarType partype = md_content.params[i].copy();
-
- String strpartype = ExprProcessor.getCastTypeName(partype);
- if(ExprProcessor.UNDEFINED_TYPE_STRING.equals(strpartype) && DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
- strpartype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
- }
-
- bufstrwriter.write(strpartype);
- bufstrwriter.write(" ");
-
- String parname = meth.varproc.getVarName(new VarVersionPaar(index, 0));
- bufstrwriter.write(parname==null?"param"+index:parname); // null iff decompiled with errors
-
- firstpar = false;
- }
-
- index+=md_content.params[i].stack_size;
- }
-
- bufstrwriter.write(")");
- bufstrwriter.write(" ");
- bufstrwriter.write("{");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
-
- RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
-
- if(root != null && !meth.decompiledWithErrors) { // check for existence
- try {
- String code = root.toJava(indent+1);
- bufstrwriter.write(code);
- } catch(Throwable ex) {
- DecompilerContext.getLogger().writeMessage("Method "+mt.getName()+" "+mt.getDescriptor()+" couldn't be written.", ex);
- meth.decompiledWithErrors = true;
- }
- }
-
- if(meth.decompiledWithErrors) {
- bufstrwriter.write(InterpreterUtil.getIndentString(indent+1));
- bufstrwriter.write("// $FF: Couldn't be decompiled");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
-
- if(!code_only) {
- bufstrwriter.write(indstr+"}");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
-
- bufstrwriter.flush();
-
- writer.write(strwriter.toString());
-
- DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methold);
-
- return true;
- }
-
- public boolean methodToJava(ClassNode node, StructMethod mt, BufferedWriter writer, int indent) throws IOException {
-
- ClassWrapper wrapper = node.wrapper;
- StructClass cl = wrapper.getClassStruct();
-
- MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
-
- MethodWrapper methold = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
- DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, meth);
-
- boolean isInterface = (cl.access_flags & CodeConstants.ACC_INTERFACE) != 0;
- boolean isAnnotation = (cl.access_flags & CodeConstants.ACC_ANNOTATION) != 0;
- boolean isEnum = (cl.access_flags & CodeConstants.ACC_ENUM) != 0 && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
- boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");
-
- String indstr = InterpreterUtil.getIndentString(indent);
- boolean clinit = false, init = false, dinit = false;
-
- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
-
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
-
- int flags = mt.getAccessFlags();
- if((flags & CodeConstants.ACC_NATIVE) != 0) {
- flags &= ~CodeConstants.ACC_STRICT; // compiler bug: a strictfp class sets all methods to strictfp
- }
-
- if("<clinit>".equals(mt.getName())) {
- flags &= CodeConstants.ACC_STATIC; // ingnore all modifiers except 'static' in a static initializer
- }
-
- if(interceptor != null) {
- String oldname = interceptor.getOldName(cl.qualifiedName+" "+mt.getName()+" "+mt.getDescriptor());
- if(oldname != null) {
- String[] element = oldname.split(" ");
-
- bufstrwriter.write(indstr);
- bufstrwriter.write("// $FF: renamed from: "+element[1]+" "+getDescriptorPrintOut(element[2], 2));
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
- }
-
- if (isDeprecated) {
- writer.write(indstr);
- writer.write("/** @deprecated */");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
- // method annotations
- List<AnnotationExprent> lstAnn = getAllAnnotations(mt.getAttributes());
- for(AnnotationExprent annexpr : lstAnn) {
- bufstrwriter.write(annexpr.toJava(indent));
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
-
- boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic");
- boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0;
-
- if(isSynthetic) {
- bufstrwriter.write(indstr);
- bufstrwriter.write("// $FF: synthetic method");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
-
- if(isBridge) {
- bufstrwriter.write(indstr);
- bufstrwriter.write("// $FF: bridge method");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
-
- bufstrwriter.write(indstr);
- for(int i=0;i<modval_meth.length;i++) {
- if(!isInterface || !mod_notinterface_meth.contains(modval_meth[i])) {
- if((flags & modval_meth[i]) != 0) {
- bufstrwriter.write(modstr_meth[i]);
- }
- }
- }
-
- // 'default' modifier (Java 8)
- if(isInterface && mt.containsCode()) {
- bufstrwriter.write("default ");
- }
-
- String name = mt.getName();
- if ("<init>".equals(name)) {
- if (node.type == ClassNode.CLASS_ANONYMOUS) {
- name = "";
- dinit = true;
- } else {
- name = node.simpleName;
- init = true;
- }
- } else if ("<clinit>".equals(name)) {
- name = "";
- clinit = true;
- }
-
- GenericMethodDescriptor descriptor = null;
- if(DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
- StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature");
- if(attr != null) {
- descriptor = GenericMain.parseMethodSignature(attr.getSignature());
+ }
+ writer.write(">");
+ }
+ writer.write(" ");
+
+ if (!isEnum && !isInterface && cl.superClass != null) {
+ VarType supertype = new VarType(cl.superClass.getString(), true);
+ if (!VarType.VARTYPE_OBJECT.equals(supertype)) {
+ writer.write("extends ");
+ if (descriptor != null) {
+ writer.write(GenericMain.getGenericCastTypeName(descriptor.superclass));
+ }
+ else {
+ writer.write(ExprProcessor.getCastTypeName(supertype));
+ }
+ writer.write(" ");
+ }
+ }
+
+ if (!isAnnotation) {
+ int[] interfaces = cl.getInterfaces();
+ if (interfaces.length > 0) {
+ writer.write(isInterface ? "extends " : "implements ");
+ for (int i = 0; i < interfaces.length; i++) {
+ if (i > 0) {
+ writer.write(", ");
+ }
+ if (descriptor != null) {
+ writer.write(GenericMain.getGenericCastTypeName(descriptor.superinterfaces.get(i)));
+ }
+ else {
+ writer.write(ExprProcessor.getCastTypeName(new VarType(cl.getInterface(i), true)));
+ }
+ }
+ writer.write(" ");
+ }
+ }
+
+ writer.write("{");
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+ }
+
+ private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, BufferedWriter writer, int indent) throws IOException {
+
+ String indstr = InterpreterUtil.getIndentString(indent);
+
+ boolean isInterface = (cl.access_flags & CodeConstants.ACC_INTERFACE) != 0;
+ int flags = fd.access_flags;
+
+ if (interceptor != null) {
+ String oldname = interceptor.getOldName(cl.qualifiedName + " " + fd.getName() + " " + fd.getDescriptor());
+ if (oldname != null) {
+ String[] element = oldname.split(" ");
+
+ writer.write(indstr);
+ writer.write("// $FF: renamed from: " + element[1] + " " + getDescriptorPrintOut(element[2], 1));
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+ }
+
+ boolean isDeprecated = fd.getAttributes().containsKey("Deprecated");
+
+ if (isDeprecated) {
+ writer.write(indstr);
+ writer.write("/** @deprecated */");
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ // field annotations
+ List<AnnotationExprent> lstAnn = getAllAnnotations(fd.getAttributes());
+ for (AnnotationExprent annexpr : lstAnn) {
+ writer.write(annexpr.toJava(indent));
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic");
+ boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
+
+ if (isSynthetic) {
+ writer.write(indstr);
+ writer.write("// $FF: synthetic field");
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ writer.write(indstr);
+
+ if (!isEnum) {
+ for (int i = 0; i < modval_field.length; i++) {
+ if (!isInterface || !mod_notinterface_fields.contains(modval_field[i])) {
+ if ((flags & modval_field[i]) != 0) {
+ writer.write(modstr_field[i]);
+ }
+ }
+ }
+ }
+
+ VarType fieldType = new VarType(fd.getDescriptor(), false);
+
+ GenericFieldDescriptor descriptor = null;
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
+ StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)fd.getAttributes().getWithKey("Signature");
+ if (attr != null) {
+ descriptor = GenericMain.parseFieldSignature(attr.getSignature());
+ }
+ }
+
+ if (!isEnum) {
+ if (descriptor != null) {
+ writer.write(GenericMain.getGenericCastTypeName(descriptor.type));
+ }
+ else {
+ writer.write(ExprProcessor.getCastTypeName(fieldType));
+ }
+ writer.write(" ");
+ }
+
+ writer.write(fd.getName());
+
+ Exprent initializer;
+ if ((flags & CodeConstants.ACC_STATIC) != 0) {
+ initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
+ }
+ else {
+ initializer = wrapper.getDynamicFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
+ }
+
+ if (initializer != null) {
+ if (isEnum && initializer.type == Exprent.EXPRENT_NEW) {
+ NewExprent nexpr = (NewExprent)initializer;
+ nexpr.setEnumconst(true);
+ writer.write(nexpr.toJava(indent));
+ }
+ else {
+ writer.write(" = ");
+ writer.write(initializer.toJava(indent));
+ }
+ }
+ else if ((flags & CodeConstants.ACC_FINAL) != 0 && (flags & CodeConstants.ACC_STATIC) != 0) {
+ StructConstantValueAttribute attr =
+ (StructConstantValueAttribute)fd.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE);
+ if (attr != null) {
+ PrimitiveConstant cnst = cl.getPool().getPrimitiveConstant(attr.getIndex());
+ writer.write(" = ");
+ writer.write(new ConstExprent(fieldType, cnst.value).toJava(indent));
+ }
+ }
+
+ if (!isEnum) {
+ writer.write(";");
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+ }
+
+ public boolean methodLambdaToJava(ClassNode node_lambda,
+ ClassNode node_content,
+ StructMethod mt,
+ BufferedWriter writer,
+ int indent,
+ boolean code_only) throws IOException {
+
+ ClassWrapper wrapper = node_content.wrapper;
+
+ MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
+
+ MethodWrapper methold = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, meth);
+
+ String indstr = InterpreterUtil.getIndentString(indent);
+
+ String method_name = node_lambda.lambda_information.method_name;
+ MethodDescriptor md_content = MethodDescriptor.parseDescriptor(node_lambda.lambda_information.content_method_descriptor);
+ MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(node_lambda.lambda_information.method_descriptor);
+
+ StringWriter strwriter = new StringWriter();
+ BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+
+ if (!code_only) {
+ bufstrwriter.write(indstr);
+ bufstrwriter.write("public ");
+ bufstrwriter.write(method_name);
+ bufstrwriter.write("(");
+
+ boolean firstpar = true;
+ int index = node_lambda.lambda_information.is_content_method_static ? 0 : 1;
+ ;
+
+ int start_index = md_content.params.length - md_lambda.params.length;
+
+ for (int i = 0; i < md_content.params.length; i++) {
+
+ if (i >= start_index) {
+
+ if (!firstpar) {
+ bufstrwriter.write(", ");
+ }
+
+ VarType partype = md_content.params[i].copy();
+
+ String strpartype = ExprProcessor.getCastTypeName(partype);
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(strpartype) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ strpartype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
+ }
+
+ bufstrwriter.write(strpartype);
+ bufstrwriter.write(" ");
+
+ String parname = meth.varproc.getVarName(new VarVersionPaar(index, 0));
+ bufstrwriter.write(parname == null ? "param" + index : parname); // null iff decompiled with errors
+
+ firstpar = false;
+ }
+
+ index += md_content.params[i].stack_size;
+ }
+
+ bufstrwriter.write(")");
+ bufstrwriter.write(" ");
+ bufstrwriter.write("{");
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
+
+ if (root != null && !meth.decompiledWithErrors) { // check for existence
+ try {
+ String code = root.toJava(indent + 1);
+ bufstrwriter.write(code);
+ }
+ catch (Throwable ex) {
+ DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.", ex);
+ meth.decompiledWithErrors = true;
+ }
+ }
+
+ if (meth.decompiledWithErrors) {
+ bufstrwriter.write(InterpreterUtil.getIndentString(indent + 1));
+ bufstrwriter.write("// $FF: Couldn't be decompiled");
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ if (!code_only) {
+ bufstrwriter.write(indstr + "}");
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ bufstrwriter.flush();
+
+ writer.write(strwriter.toString());
+
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methold);
+
+ return true;
+ }
+
+ public boolean methodToJava(ClassNode node, StructMethod mt, BufferedWriter writer, int indent) throws IOException {
+
+ ClassWrapper wrapper = node.wrapper;
+ StructClass cl = wrapper.getClassStruct();
+
+ MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
+
+ MethodWrapper methold = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, meth);
+
+ boolean isInterface = (cl.access_flags & CodeConstants.ACC_INTERFACE) != 0;
+ boolean isAnnotation = (cl.access_flags & CodeConstants.ACC_ANNOTATION) != 0;
+ boolean isEnum = (cl.access_flags & CodeConstants.ACC_ENUM) != 0 && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
+ boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");
+
+ String indstr = InterpreterUtil.getIndentString(indent);
+ boolean clinit = false, init = false, dinit = false;
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ StringWriter strwriter = new StringWriter();
+ BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+
+ int flags = mt.getAccessFlags();
+ if ((flags & CodeConstants.ACC_NATIVE) != 0) {
+ flags &= ~CodeConstants.ACC_STRICT; // compiler bug: a strictfp class sets all methods to strictfp
+ }
+
+ if ("<clinit>".equals(mt.getName())) {
+ flags &= CodeConstants.ACC_STATIC; // ingnore all modifiers except 'static' in a static initializer
+ }
+
+ if (interceptor != null) {
+ String oldname = interceptor.getOldName(cl.qualifiedName + " " + mt.getName() + " " + mt.getDescriptor());
+ if (oldname != null) {
+ String[] element = oldname.split(" ");
+
+ bufstrwriter.write(indstr);
+ bufstrwriter.write("// $FF: renamed from: " + element[1] + " " + getDescriptorPrintOut(element[2], 2));
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+ }
+
+ if (isDeprecated) {
+ writer.write(indstr);
+ writer.write("/** @deprecated */");
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ // method annotations
+ List<AnnotationExprent> lstAnn = getAllAnnotations(mt.getAttributes());
+ for (AnnotationExprent annexpr : lstAnn) {
+ bufstrwriter.write(annexpr.toJava(indent));
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic");
+ boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0;
+
+ if (isSynthetic) {
+ bufstrwriter.write(indstr);
+ bufstrwriter.write("// $FF: synthetic method");
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ if (isBridge) {
+ bufstrwriter.write(indstr);
+ bufstrwriter.write("// $FF: bridge method");
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ bufstrwriter.write(indstr);
+ for (int i = 0; i < modval_meth.length; i++) {
+ if (!isInterface || !mod_notinterface_meth.contains(modval_meth[i])) {
+ if ((flags & modval_meth[i]) != 0) {
+ bufstrwriter.write(modstr_meth[i]);
+ }
+ }
+ }
+
+ // 'default' modifier (Java 8)
+ if (isInterface && mt.containsCode()) {
+ bufstrwriter.write("default ");
+ }
+
+ String name = mt.getName();
+ if ("<init>".equals(name)) {
+ if (node.type == ClassNode.CLASS_ANONYMOUS) {
+ name = "";
+ dinit = true;
+ }
+ else {
+ name = node.simpleName;
+ init = true;
+ }
+ }
+ else if ("<clinit>".equals(name)) {
+ name = "";
+ clinit = true;
+ }
+
+ GenericMethodDescriptor descriptor = null;
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
+ StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature");
+ if (attr != null) {
+ descriptor = GenericMain.parseMethodSignature(attr.getSignature());
int actualParams = md.params.length;
- if(isEnum && init) actualParams -= 2;
- if(actualParams != descriptor.params.size()) {
- DecompilerContext.getLogger().writeMessage("Inconsistent generic signature in method "+mt.getName()+" "+mt.getDescriptor(), IFernflowerLogger.WARNING);
- descriptor = null;
- }
- }
- }
-
- boolean throwsExceptions = false;
-
- int param_count_explicit = 0;
-
- if(!clinit && !dinit) {
-
- boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
-
- // formal type parameters
- if(descriptor != null && !descriptor.fparameters.isEmpty()) {
- bufstrwriter.write("<");
- for(int i=0;i<descriptor.fparameters.size();i++) {
- if(i>0) {
- bufstrwriter.write(", ");
- }
- bufstrwriter.write(descriptor.fparameters.get(i));
-
- List<GenericType> lstBounds = descriptor.fbounds.get(i);
- if (lstBounds.size() > 1 || !"java/lang/Object".equals(lstBounds.get(0).value)) {
- bufstrwriter.write(" extends ");
- bufstrwriter.write(GenericMain.getGenericCastTypeName(lstBounds.get(0)));
-
- for(int j = 1; j < lstBounds.size(); j++) {
- bufstrwriter.write(" & " + GenericMain.getGenericCastTypeName(lstBounds.get(j)));
- }
- }
- }
- bufstrwriter.write("> ");
- }
-
- if(!init) {
- if(descriptor != null) {
- bufstrwriter.write(GenericMain.getGenericCastTypeName(descriptor.ret));
- } else {
- bufstrwriter.write(ExprProcessor.getCastTypeName(md.ret));
- }
- bufstrwriter.write(" ");
- }
-
- bufstrwriter.write(name);
- bufstrwriter.write("(");
-
- // parameter annotations
- List<List<AnnotationExprent>> lstParAnn = getAllParameterAnnotations(mt.getAttributes());
-
- List<VarVersionPaar> signFields = meth.signatureFields;
-
- // compute last visible parameter
- int lastparam_index = -1;
- for(int i=0;i<md.params.length;i++) {
- if(signFields == null || signFields.get(i) == null) {
- lastparam_index = i;
- }
- }
-
- boolean firstpar = true;
- int index = isEnum && init ? 3 : thisvar ? 1 : 0;
- int start = isEnum && init && descriptor == null ? 2 : 0;
- int params = descriptor == null ? md.params.length : descriptor.params.size();
- for(int i = start; i < params; i++) {
- if (signFields == null || signFields.get(i) == null) {
-
- if(!firstpar) {
- bufstrwriter.write(", ");
- }
-
- if(lstParAnn.size() > param_count_explicit) {
- List<AnnotationExprent> annotations = lstParAnn.get(param_count_explicit);
- for(int j=0;j<annotations.size();j++) {
- AnnotationExprent annexpr = annotations.get(j);
- if(annexpr.getAnnotationType() == AnnotationExprent.ANNOTATION_NORMAL) {
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- bufstrwriter.write(annexpr.toJava(indent+1));
- } else {
- bufstrwriter.write(annexpr.toJava(0));
- }
- bufstrwriter.write(" ");
- }
- }
-
- if(meth.varproc.getVarFinal(new VarVersionPaar(index, 0)) == VarTypeProcessor.VAR_FINALEXPLICIT) {
- bufstrwriter.write("final ");
- }
-
-
- if(descriptor != null) {
- GenericType partype = descriptor.params.get(i);
-
- boolean isVarArgs = (i == lastparam_index && (mt.getAccessFlags() & CodeConstants.ACC_VARARGS) != 0
- && partype.arraydim > 0);
-
- if(isVarArgs) {
- partype.arraydim--;
- }
-
- String strpartype = GenericMain.getGenericCastTypeName(partype);
- if(ExprProcessor.UNDEFINED_TYPE_STRING.equals(strpartype) &&
- DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
- strpartype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
- }
-
- bufstrwriter.write(strpartype);
-
- if(isVarArgs) {
- bufstrwriter.write(" ...");
- }
-
- } else {
- VarType partype = md.params[i].copy();
-
- boolean isVarArgs = (i == lastparam_index && (mt.getAccessFlags() & CodeConstants.ACC_VARARGS) != 0
- && partype.arraydim > 0);
-
- if(isVarArgs) {
- partype.decArrayDim();
- }
-
- String strpartype = ExprProcessor.getCastTypeName(partype);
- if(ExprProcessor.UNDEFINED_TYPE_STRING.equals(strpartype) &&
- DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
- strpartype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
- }
-
- bufstrwriter.write(strpartype);
-
- if(isVarArgs) {
- bufstrwriter.write(" ...");
- }
- }
-
- bufstrwriter.write(" ");
- String parname = meth.varproc.getVarName(new VarVersionPaar(index, 0));
- bufstrwriter.write(parname==null?"param"+index:parname); // null iff decompiled with errors
- firstpar = false;
- param_count_explicit++;
- }
-
- index+=md.params[i].stack_size;
- }
-
- bufstrwriter.write(")");
-
- StructExceptionsAttribute attr = (StructExceptionsAttribute)mt.getAttributes().getWithKey("Exceptions");
- if((descriptor!=null && !descriptor.exceptions.isEmpty()) || attr != null) {
- throwsExceptions = true;
- bufstrwriter.write(" throws ");
-
- for(int i=0;i<attr.getThrowsExceptions().size();i++) {
- if(i>0) {
- bufstrwriter.write(", ");
- }
- if(descriptor!=null && !descriptor.exceptions.isEmpty()) {
- bufstrwriter.write(GenericMain.getGenericCastTypeName(descriptor.exceptions.get(i)));
- } else {
- VarType exctype = new VarType(attr.getExcClassname(i, cl.getPool()), true);
- bufstrwriter.write(ExprProcessor.getCastTypeName(exctype));
- }
- }
- }
- }
-
- boolean hidemethod = false;
-
- if((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE)) != 0) { // native or abstract method (explicit or interface)
- if(isAnnotation) {
- StructAnnDefaultAttribute attr = (StructAnnDefaultAttribute)mt.getAttributes().getWithKey("AnnotationDefault");
- if(attr != null) {
- bufstrwriter.write(" default ");
- bufstrwriter.write(attr.getDefaultValue().toJava(indent+1));
- }
- }
-
- bufstrwriter.write(";");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- } else {
- if(!clinit && !dinit) {
- bufstrwriter.write(" ");
- }
- bufstrwriter.write("{");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
-
- RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
-
- if(root != null && !meth.decompiledWithErrors) { // check for existence
- try {
- String code = root.toJava(indent+1);
-
- boolean singleinit = false;
- if(init && param_count_explicit == 0 && !throwsExceptions && DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
- int init_counter = 0;
- for(MethodWrapper mth : wrapper.getMethods()) {
- if("<init>".equals(mth.methodStruct.getName())) {
- init_counter++;
- }
- }
- singleinit = (init_counter == 1);
- }
-
- hidemethod = (clinit || dinit || singleinit) && code.length() == 0;
-
- bufstrwriter.write(code);
- } catch(Throwable ex) {
- DecompilerContext.getLogger().writeMessage("Method "+mt.getName()+" "+mt.getDescriptor()+" couldn't be written.", ex);
- meth.decompiledWithErrors = true;
- }
- }
-
- if(meth.decompiledWithErrors) {
- bufstrwriter.write(InterpreterUtil.getIndentString(indent+1));
- bufstrwriter.write("// $FF: Couldn't be decompiled");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
-
- bufstrwriter.write(indstr+"}");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
-
- bufstrwriter.flush();
-
- if(!hidemethod) {
- writer.write(strwriter.toString());
- }
-
- DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methold);
-
- return !hidemethod;
- }
-
- private List<AnnotationExprent> getAllAnnotations(VBStyleCollection<StructGeneralAttribute, String> attributes) {
-
- String[] annattrnames = new String[] {StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS,
- StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS};
-
- List<AnnotationExprent> lst = new ArrayList<AnnotationExprent>();
-
- for(String attrname : annattrnames) {
- StructAnnotationAttribute attr = (StructAnnotationAttribute)attributes.getWithKey(attrname);
- if(attr != null) {
- lst.addAll(attr.getAnnotations());
- }
- }
-
- return lst;
- }
-
- private List<List<AnnotationExprent>> getAllParameterAnnotations(VBStyleCollection<StructGeneralAttribute, String> attributes) {
-
- String[] annattrnames = new String[] {StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
- StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS};
-
- List<List<AnnotationExprent>> ret = new ArrayList<List<AnnotationExprent>>();
-
- for(String attrname : annattrnames) {
- StructAnnotationParameterAttribute attr = (StructAnnotationParameterAttribute)attributes.getWithKey(attrname);
- if(attr != null) {
- for(int i=0;i<attr.getParamAnnotations().size();i++) {
- List<AnnotationExprent> lst = new ArrayList<AnnotationExprent>();
- boolean isnew = (ret.size()<=i);
-
- if(!isnew) {
- lst = ret.get(i);
- }
- lst.addAll(attr.getParamAnnotations().get(i));
-
- if(isnew) {
- ret.add(lst);
- } else {
- ret.set(i, lst);
- }
- }
- }
- }
-
- return ret;
- }
-
- private String getDescriptorPrintOut(String descriptor, int element) {
-
- switch(element) {
- case 0: // class
- return ExprProcessor.buildJavaClassName(descriptor);
- case 1: // field
- return getTypePrintOut(FieldDescriptor.parseDescriptor(descriptor).type);
- case 2: // method
- default:
- MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
-
- StringBuilder buffer = new StringBuilder("(");
-
- boolean first = true;
- for(VarType partype : md.params) {
- if(first) {
- first = false;
- } else {
- buffer.append(", ");
- }
- buffer.append(getTypePrintOut(partype));
- }
- buffer.append(") ");
- buffer.append(getTypePrintOut(md.ret));
-
- return buffer.toString();
- }
- }
-
- private String getTypePrintOut(VarType type) {
- String strtype = ExprProcessor.getCastTypeName(type, false);
- if(ExprProcessor.UNDEFINED_TYPE_STRING.equals(strtype) &&
- DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
- strtype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT, false);
- }
- return strtype;
- }
+ if (isEnum && init) actualParams -= 2;
+ if (actualParams != descriptor.params.size()) {
+ DecompilerContext.getLogger()
+ .writeMessage("Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor(), IFernflowerLogger.WARNING);
+ descriptor = null;
+ }
+ }
+ }
+
+ boolean throwsExceptions = false;
+
+ int param_count_explicit = 0;
+
+ if (!clinit && !dinit) {
+
+ boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
+
+ // formal type parameters
+ if (descriptor != null && !descriptor.fparameters.isEmpty()) {
+ bufstrwriter.write("<");
+ for (int i = 0; i < descriptor.fparameters.size(); i++) {
+ if (i > 0) {
+ bufstrwriter.write(", ");
+ }
+ bufstrwriter.write(descriptor.fparameters.get(i));
+
+ List<GenericType> lstBounds = descriptor.fbounds.get(i);
+ if (lstBounds.size() > 1 || !"java/lang/Object".equals(lstBounds.get(0).value)) {
+ bufstrwriter.write(" extends ");
+ bufstrwriter.write(GenericMain.getGenericCastTypeName(lstBounds.get(0)));
+
+ for (int j = 1; j < lstBounds.size(); j++) {
+ bufstrwriter.write(" & " + GenericMain.getGenericCastTypeName(lstBounds.get(j)));
+ }
+ }
+ }
+ bufstrwriter.write("> ");
+ }
+
+ if (!init) {
+ if (descriptor != null) {
+ bufstrwriter.write(GenericMain.getGenericCastTypeName(descriptor.ret));
+ }
+ else {
+ bufstrwriter.write(ExprProcessor.getCastTypeName(md.ret));
+ }
+ bufstrwriter.write(" ");
+ }
+
+ bufstrwriter.write(name);
+ bufstrwriter.write("(");
+
+ // parameter annotations
+ List<List<AnnotationExprent>> lstParAnn = getAllParameterAnnotations(mt.getAttributes());
+
+ List<VarVersionPaar> signFields = meth.signatureFields;
+
+ // compute last visible parameter
+ int lastparam_index = -1;
+ for (int i = 0; i < md.params.length; i++) {
+ if (signFields == null || signFields.get(i) == null) {
+ lastparam_index = i;
+ }
+ }
+
+ boolean firstpar = true;
+ int index = isEnum && init ? 3 : thisvar ? 1 : 0;
+ int start = isEnum && init && descriptor == null ? 2 : 0;
+ int params = descriptor == null ? md.params.length : descriptor.params.size();
+ for (int i = start; i < params; i++) {
+ if (signFields == null || signFields.get(i) == null) {
+
+ if (!firstpar) {
+ bufstrwriter.write(", ");
+ }
+
+ if (lstParAnn.size() > param_count_explicit) {
+ List<AnnotationExprent> annotations = lstParAnn.get(param_count_explicit);
+ for (int j = 0; j < annotations.size(); j++) {
+ AnnotationExprent annexpr = annotations.get(j);
+ if (annexpr.getAnnotationType() == AnnotationExprent.ANNOTATION_NORMAL) {
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ bufstrwriter.write(annexpr.toJava(indent + 1));
+ }
+ else {
+ bufstrwriter.write(annexpr.toJava(0));
+ }
+ bufstrwriter.write(" ");
+ }
+ }
+
+ if (meth.varproc.getVarFinal(new VarVersionPaar(index, 0)) == VarTypeProcessor.VAR_FINALEXPLICIT) {
+ bufstrwriter.write("final ");
+ }
+
+
+ if (descriptor != null) {
+ GenericType partype = descriptor.params.get(i);
+
+ boolean isVarArgs = (i == lastparam_index && (mt.getAccessFlags() & CodeConstants.ACC_VARARGS) != 0
+ && partype.arraydim > 0);
+
+ if (isVarArgs) {
+ partype.arraydim--;
+ }
+
+ String strpartype = GenericMain.getGenericCastTypeName(partype);
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(strpartype) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ strpartype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
+ }
+
+ bufstrwriter.write(strpartype);
+
+ if (isVarArgs) {
+ bufstrwriter.write(" ...");
+ }
+ }
+ else {
+ VarType partype = md.params[i].copy();
+
+ boolean isVarArgs = (i == lastparam_index && (mt.getAccessFlags() & CodeConstants.ACC_VARARGS) != 0
+ && partype.arraydim > 0);
+
+ if (isVarArgs) {
+ partype.decArrayDim();
+ }
+
+ String strpartype = ExprProcessor.getCastTypeName(partype);
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(strpartype) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ strpartype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
+ }
+
+ bufstrwriter.write(strpartype);
+
+ if (isVarArgs) {
+ bufstrwriter.write(" ...");
+ }
+ }
+
+ bufstrwriter.write(" ");
+ String parname = meth.varproc.getVarName(new VarVersionPaar(index, 0));
+ bufstrwriter.write(parname == null ? "param" + index : parname); // null iff decompiled with errors
+ firstpar = false;
+ param_count_explicit++;
+ }
+
+ index += md.params[i].stack_size;
+ }
+
+ bufstrwriter.write(")");
+
+ StructExceptionsAttribute attr = (StructExceptionsAttribute)mt.getAttributes().getWithKey("Exceptions");
+ if ((descriptor != null && !descriptor.exceptions.isEmpty()) || attr != null) {
+ throwsExceptions = true;
+ bufstrwriter.write(" throws ");
+
+ for (int i = 0; i < attr.getThrowsExceptions().size(); i++) {
+ if (i > 0) {
+ bufstrwriter.write(", ");
+ }
+ if (descriptor != null && !descriptor.exceptions.isEmpty()) {
+ bufstrwriter.write(GenericMain.getGenericCastTypeName(descriptor.exceptions.get(i)));
+ }
+ else {
+ VarType exctype = new VarType(attr.getExcClassname(i, cl.getPool()), true);
+ bufstrwriter.write(ExprProcessor.getCastTypeName(exctype));
+ }
+ }
+ }
+ }
+
+ boolean hidemethod = false;
+
+ if ((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE)) != 0) { // native or abstract method (explicit or interface)
+ if (isAnnotation) {
+ StructAnnDefaultAttribute attr = (StructAnnDefaultAttribute)mt.getAttributes().getWithKey("AnnotationDefault");
+ if (attr != null) {
+ bufstrwriter.write(" default ");
+ bufstrwriter.write(attr.getDefaultValue().toJava(indent + 1));
+ }
+ }
+
+ bufstrwriter.write(";");
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+ else {
+ if (!clinit && !dinit) {
+ bufstrwriter.write(" ");
+ }
+ bufstrwriter.write("{");
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+
+ RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
+
+ if (root != null && !meth.decompiledWithErrors) { // check for existence
+ try {
+ String code = root.toJava(indent + 1);
+
+ boolean singleinit = false;
+ if (init &&
+ param_count_explicit == 0 &&
+ !throwsExceptions &&
+ DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
+ int init_counter = 0;
+ for (MethodWrapper mth : wrapper.getMethods()) {
+ if ("<init>".equals(mth.methodStruct.getName())) {
+ init_counter++;
+ }
+ }
+ singleinit = (init_counter == 1);
+ }
+
+ hidemethod = (clinit || dinit || singleinit) && code.length() == 0;
+
+ bufstrwriter.write(code);
+ }
+ catch (Throwable ex) {
+ DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.", ex);
+ meth.decompiledWithErrors = true;
+ }
+ }
+
+ if (meth.decompiledWithErrors) {
+ bufstrwriter.write(InterpreterUtil.getIndentString(indent + 1));
+ bufstrwriter.write("// $FF: Couldn't be decompiled");
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ bufstrwriter.write(indstr + "}");
+ bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ bufstrwriter.flush();
+
+ if (!hidemethod) {
+ writer.write(strwriter.toString());
+ }
+
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methold);
+
+ return !hidemethod;
+ }
+
+ private List<AnnotationExprent> getAllAnnotations(VBStyleCollection<StructGeneralAttribute, String> attributes) {
+
+ String[] annattrnames = new String[]{StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS,
+ StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS};
+
+ List<AnnotationExprent> lst = new ArrayList<AnnotationExprent>();
+
+ for (String attrname : annattrnames) {
+ StructAnnotationAttribute attr = (StructAnnotationAttribute)attributes.getWithKey(attrname);
+ if (attr != null) {
+ lst.addAll(attr.getAnnotations());
+ }
+ }
+
+ return lst;
+ }
+
+ private List<List<AnnotationExprent>> getAllParameterAnnotations(VBStyleCollection<StructGeneralAttribute, String> attributes) {
+
+ String[] annattrnames = new String[]{StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
+ StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS};
+
+ List<List<AnnotationExprent>> ret = new ArrayList<List<AnnotationExprent>>();
+
+ for (String attrname : annattrnames) {
+ StructAnnotationParameterAttribute attr = (StructAnnotationParameterAttribute)attributes.getWithKey(attrname);
+ if (attr != null) {
+ for (int i = 0; i < attr.getParamAnnotations().size(); i++) {
+ List<AnnotationExprent> lst = new ArrayList<AnnotationExprent>();
+ boolean isnew = (ret.size() <= i);
+
+ if (!isnew) {
+ lst = ret.get(i);
+ }
+ lst.addAll(attr.getParamAnnotations().get(i));
+
+ if (isnew) {
+ ret.add(lst);
+ }
+ else {
+ ret.set(i, lst);
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ private String getDescriptorPrintOut(String descriptor, int element) {
+
+ switch (element) {
+ case 0: // class
+ return ExprProcessor.buildJavaClassName(descriptor);
+ case 1: // field
+ return getTypePrintOut(FieldDescriptor.parseDescriptor(descriptor).type);
+ case 2: // method
+ default:
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
+
+ StringBuilder buffer = new StringBuilder("(");
+
+ boolean first = true;
+ for (VarType partype : md.params) {
+ if (first) {
+ first = false;
+ }
+ else {
+ buffer.append(", ");
+ }
+ buffer.append(getTypePrintOut(partype));
+ }
+ buffer.append(") ");
+ buffer.append(getTypePrintOut(md.ret));
+
+ return buffer.toString();
+ }
+ }
+
+ private String getTypePrintOut(VarType type) {
+ String strtype = ExprProcessor.getCastTypeName(type, false);
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(strtype) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ strtype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT, false);
+ }
+ return strtype;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
index e0e144f..155dee0 100644
--- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
+++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
@@ -1,32 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
@@ -46,242 +34,254 @@ import org.jetbrains.java.decompiler.struct.attr.StructInnerClassesAttribute;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.Map.Entry;
+
public class ClassesProcessor {
- private HashMap<String, ClassNode> mapRootClasses = new HashMap<String, ClassNode>();
-
- public ClassesProcessor(StructContext context) {
-
- HashMap<String, Object[]> mapInnerClasses = new HashMap<String, Object[]>();
-
- HashMap<String, HashSet<String>> mapNestedClassReferences = new HashMap<String, HashSet<String>>();
- HashMap<String, HashSet<String>> mapEnclosingClassReferences = new HashMap<String, HashSet<String>>();
-
- HashMap<String, String> mapNewSimpleNames = new HashMap<String, String>();
-
- boolean bDecompileInner = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_INNER);
-
- // create class nodes
- for(StructClass cl: context.getClasses().values()) {
- if(cl.isOwn() && !mapRootClasses.containsKey(cl.qualifiedName)) {
-
- if(bDecompileInner) {
- StructInnerClassesAttribute inner = (StructInnerClassesAttribute)cl.getAttributes().getWithKey("InnerClasses");
- if(inner != null) {
-
- for(int i=0;i<inner.getClassentries().size();i++) {
-
- int[] entry = inner.getClassentries().get(i);
- String[] strentry = inner.getStringentries().get(i);
-
- Object[] arr = new Object[4]; // arr[0] not used
-
- String innername = strentry[0];
-
- // nested class type
- arr[2] = entry[1] == 0?(entry[2]==0?ClassNode.CLASS_ANONYMOUS:ClassNode.CLASS_LOCAL):ClassNode.CLASS_MEMBER;
-
- // original simple name
- String simpleName = strentry[2];
- String savedName = mapNewSimpleNames.get(innername);
-
- if(savedName != null) {
- simpleName = savedName;
- } else if(simpleName != null && DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
- IIdentifierRenamer renamer = DecompilerContext.getPoolInterceptor().getHelper();
- if(renamer.toBeRenamed(IIdentifierRenamer.ELEMENT_CLASS, simpleName, null, null)) {
- simpleName = renamer.getNextClassname(innername, simpleName);
- mapNewSimpleNames.put(innername, simpleName);
- }
- }
-
- arr[1] = simpleName;
-
- // original access flags
- arr[3] = entry[3];
-
- // enclosing class
- String enclClassName = null;
- if(entry[1] != 0) {
- enclClassName = strentry[1];
- } else {
- enclClassName = cl.qualifiedName;
- }
-
- if(!innername.equals(enclClassName)) { // self reference
- StructClass enclosing_class = context.getClasses().get(enclClassName);
- if(enclosing_class != null && enclosing_class.isOwn()) { // own classes only
-
- Object[] arrold = mapInnerClasses.get(innername);
- if(arrold == null) {
- mapInnerClasses.put(innername, arr);
- } else {
- if(!InterpreterUtil.equalObjectArrays(arrold, arr)){
- DecompilerContext.getLogger().writeMessage("Inconsistent inner class entries for "+innername+"!", IFernflowerLogger.WARNING);
- }
- }
-
- // reference to the nested class
- HashSet<String> set = mapNestedClassReferences.get(enclClassName);
- if(set == null) {
- mapNestedClassReferences.put(enclClassName, set = new HashSet<String>());
- }
- set.add(innername);
-
- // reference to the enclosing class
- set = mapEnclosingClassReferences.get(innername);
- if(set == null) {
- mapEnclosingClassReferences.put(innername, set = new HashSet<String>());
- }
- set.add(enclClassName);
- }
- }
- }
- }
- }
-
- ClassNode node = new ClassNode(ClassNode.CLASS_ROOT, cl);
- node.access = cl.access_flags;
- mapRootClasses.put(cl.qualifiedName, node);
- }
- }
-
- if(bDecompileInner) {
-
- // connect nested classes
- for(Entry<String, ClassNode> ent: mapRootClasses.entrySet()) {
- // root class?
- if(!mapInnerClasses.containsKey(ent.getKey())) {
-
- HashSet<String> setVisited = new HashSet<String>();
- LinkedList<String> stack = new LinkedList<String>();
-
- stack.add(ent.getKey());
- setVisited.add(ent.getKey());
-
- while(!stack.isEmpty()) {
-
- String superClass = stack.removeFirst();
- ClassNode supernode = mapRootClasses.get(superClass);
-
- HashSet<String> setNestedClasses = mapNestedClassReferences.get(superClass);
- if(setNestedClasses != null) {
-
- StructClass scl = supernode.classStruct;
- StructInnerClassesAttribute inner = (StructInnerClassesAttribute) scl.getAttributes().getWithKey("InnerClasses");
- for(int i = 0; i < inner.getStringentries().size(); i++) {
- String nestedClass = inner.getStringentries().get(i)[0];
- if (!setNestedClasses.contains(nestedClass)) {
- continue;
- }
-
- if(setVisited.contains(nestedClass)) {
- continue;
- }
- setVisited.add(nestedClass);
-
- ClassNode nestednode = mapRootClasses.get(nestedClass);
- if(nestednode == null) {
- DecompilerContext.getLogger().writeMessage("Nested class "+nestedClass+" missing!", IFernflowerLogger.WARNING);
- continue;
- }
-
- Object[] arr = mapInnerClasses.get(nestedClass);
-
- if((Integer)arr[2] == ClassNode.CLASS_MEMBER) {
- // FIXME: check for consistent naming
- }
-
- nestednode.type = (Integer)arr[2];
- nestednode.simpleName = (String)arr[1];
- nestednode.access = (Integer)arr[3];
-
- if(nestednode.type == ClassNode.CLASS_ANONYMOUS) {
- StructClass cl = nestednode.classStruct;
-
- // remove static if anonymous class
- // a common compiler bug
- nestednode.access &= ~CodeConstants.ACC_STATIC;
-
- int[] interfaces = cl.getInterfaces();
-
- if(interfaces.length > 0) {
- if(interfaces.length > 1) {
- DecompilerContext.getLogger().writeMessage("Inconsistent anonymous class definition: "+cl.qualifiedName, IFernflowerLogger.WARNING);
- }
- nestednode.anonimousClassType = new VarType(cl.getInterface(0), true);
- } else {
- nestednode.anonimousClassType = new VarType(cl.superClass.getString(), true);
- }
- } else if(nestednode.type == ClassNode.CLASS_LOCAL) {
- // only abstract and final are permitted
- // a common compiler bug
- nestednode.access &= (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_FINAL);
- }
-
- supernode.nested.add(nestednode);
- nestednode.parent = supernode;
-
- nestednode.enclosingClasses.addAll(mapEnclosingClassReferences.get(nestedClass));
-
- stack.add(nestedClass);
- }
- }
- }
- }
- }
-
- }
-
- }
-
-
- public void writeClass(StructContext context, StructClass cl, BufferedWriter outwriter) throws IOException {
-
- ClassNode root = mapRootClasses.get(cl.qualifiedName);
- if(root.type != ClassNode.CLASS_ROOT) {
- return;
- }
-
- try {
- DecompilerContext.setImpcollector(new ImportCollector(root));
- DecompilerContext.setCountercontainer(new CounterContainer());
-
- // lambda processing
- LambdaProcessor lambda_proc = new LambdaProcessor();
- lambda_proc.processClass(root);
-
- // add simple class names to implicit import
- addClassnameToImport(root, DecompilerContext.getImpcollector());
- // build wrappers for all nested classes
- // that's where the actual processing takes place
- initWrappers(root);
-
- NestedClassProcessor nestedproc = new NestedClassProcessor();
- nestedproc.processClass(root, root);
-
- NestedMemberAccess nstmember = new NestedMemberAccess();
- nstmember.propagateMemberAccess(root);
-
- ClassWriter clwriter = new ClassWriter();
-
- StringWriter strwriter = new StringWriter();
- clwriter.classToJava(root, new BufferedWriter(strwriter), 0);
-
- if(DecompilerContext.getOption(IFernflowerPreferences.OUTPUT_COPYRIGHT_COMMENT)) {
- outwriter.write("// Decompiled by: Fernflower "+Fernflower.version);
- outwriter.write(DecompilerContext.getNewLineSeparator());
- outwriter.write("// Date: "+new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(new Date()));
- outwriter.write(DecompilerContext.getNewLineSeparator());
- outwriter.write("// Copyright: 2008-2010, Stiver");
- outwriter.write(DecompilerContext.getNewLineSeparator());
- outwriter.write("// Home page: http://www.reversed-java.com");
- outwriter.write(DecompilerContext.getNewLineSeparator());
- outwriter.write(DecompilerContext.getNewLineSeparator());
- }
-
- int index = cl.qualifiedName.lastIndexOf("/");
- if(index >= 0) {
+ private HashMap<String, ClassNode> mapRootClasses = new HashMap<String, ClassNode>();
+
+ public ClassesProcessor(StructContext context) {
+
+ HashMap<String, Object[]> mapInnerClasses = new HashMap<String, Object[]>();
+
+ HashMap<String, HashSet<String>> mapNestedClassReferences = new HashMap<String, HashSet<String>>();
+ HashMap<String, HashSet<String>> mapEnclosingClassReferences = new HashMap<String, HashSet<String>>();
+
+ HashMap<String, String> mapNewSimpleNames = new HashMap<String, String>();
+
+ boolean bDecompileInner = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_INNER);
+
+ // create class nodes
+ for (StructClass cl : context.getClasses().values()) {
+ if (cl.isOwn() && !mapRootClasses.containsKey(cl.qualifiedName)) {
+
+ if (bDecompileInner) {
+ StructInnerClassesAttribute inner = (StructInnerClassesAttribute)cl.getAttributes().getWithKey("InnerClasses");
+ if (inner != null) {
+
+ for (int i = 0; i < inner.getClassentries().size(); i++) {
+
+ int[] entry = inner.getClassentries().get(i);
+ String[] strentry = inner.getStringentries().get(i);
+
+ Object[] arr = new Object[4]; // arr[0] not used
+
+ String innername = strentry[0];
+
+ // nested class type
+ arr[2] = entry[1] == 0 ? (entry[2] == 0 ? ClassNode.CLASS_ANONYMOUS : ClassNode.CLASS_LOCAL) : ClassNode.CLASS_MEMBER;
+
+ // original simple name
+ String simpleName = strentry[2];
+ String savedName = mapNewSimpleNames.get(innername);
+
+ if (savedName != null) {
+ simpleName = savedName;
+ }
+ else if (simpleName != null && DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
+ IIdentifierRenamer renamer = DecompilerContext.getPoolInterceptor().getHelper();
+ if (renamer.toBeRenamed(IIdentifierRenamer.ELEMENT_CLASS, simpleName, null, null)) {
+ simpleName = renamer.getNextClassname(innername, simpleName);
+ mapNewSimpleNames.put(innername, simpleName);
+ }
+ }
+
+ arr[1] = simpleName;
+
+ // original access flags
+ arr[3] = entry[3];
+
+ // enclosing class
+ String enclClassName = null;
+ if (entry[1] != 0) {
+ enclClassName = strentry[1];
+ }
+ else {
+ enclClassName = cl.qualifiedName;
+ }
+
+ if (!innername.equals(enclClassName)) { // self reference
+ StructClass enclosing_class = context.getClasses().get(enclClassName);
+ if (enclosing_class != null && enclosing_class.isOwn()) { // own classes only
+
+ Object[] arrold = mapInnerClasses.get(innername);
+ if (arrold == null) {
+ mapInnerClasses.put(innername, arr);
+ }
+ else {
+ if (!InterpreterUtil.equalObjectArrays(arrold, arr)) {
+ DecompilerContext.getLogger()
+ .writeMessage("Inconsistent inner class entries for " + innername + "!", IFernflowerLogger.WARNING);
+ }
+ }
+
+ // reference to the nested class
+ HashSet<String> set = mapNestedClassReferences.get(enclClassName);
+ if (set == null) {
+ mapNestedClassReferences.put(enclClassName, set = new HashSet<String>());
+ }
+ set.add(innername);
+
+ // reference to the enclosing class
+ set = mapEnclosingClassReferences.get(innername);
+ if (set == null) {
+ mapEnclosingClassReferences.put(innername, set = new HashSet<String>());
+ }
+ set.add(enclClassName);
+ }
+ }
+ }
+ }
+ }
+
+ ClassNode node = new ClassNode(ClassNode.CLASS_ROOT, cl);
+ node.access = cl.access_flags;
+ mapRootClasses.put(cl.qualifiedName, node);
+ }
+ }
+
+ if (bDecompileInner) {
+
+ // connect nested classes
+ for (Entry<String, ClassNode> ent : mapRootClasses.entrySet()) {
+ // root class?
+ if (!mapInnerClasses.containsKey(ent.getKey())) {
+
+ HashSet<String> setVisited = new HashSet<String>();
+ LinkedList<String> stack = new LinkedList<String>();
+
+ stack.add(ent.getKey());
+ setVisited.add(ent.getKey());
+
+ while (!stack.isEmpty()) {
+
+ String superClass = stack.removeFirst();
+ ClassNode supernode = mapRootClasses.get(superClass);
+
+ HashSet<String> setNestedClasses = mapNestedClassReferences.get(superClass);
+ if (setNestedClasses != null) {
+
+ StructClass scl = supernode.classStruct;
+ StructInnerClassesAttribute inner = (StructInnerClassesAttribute)scl.getAttributes().getWithKey("InnerClasses");
+ for (int i = 0; i < inner.getStringentries().size(); i++) {
+ String nestedClass = inner.getStringentries().get(i)[0];
+ if (!setNestedClasses.contains(nestedClass)) {
+ continue;
+ }
+
+ if (setVisited.contains(nestedClass)) {
+ continue;
+ }
+ setVisited.add(nestedClass);
+
+ ClassNode nestednode = mapRootClasses.get(nestedClass);
+ if (nestednode == null) {
+ DecompilerContext.getLogger().writeMessage("Nested class " + nestedClass + " missing!", IFernflowerLogger.WARNING);
+ continue;
+ }
+
+ Object[] arr = mapInnerClasses.get(nestedClass);
+
+ if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) {
+ // FIXME: check for consistent naming
+ }
+
+ nestednode.type = (Integer)arr[2];
+ nestednode.simpleName = (String)arr[1];
+ nestednode.access = (Integer)arr[3];
+
+ if (nestednode.type == ClassNode.CLASS_ANONYMOUS) {
+ StructClass cl = nestednode.classStruct;
+
+ // remove static if anonymous class
+ // a common compiler bug
+ nestednode.access &= ~CodeConstants.ACC_STATIC;
+
+ int[] interfaces = cl.getInterfaces();
+
+ if (interfaces.length > 0) {
+ if (interfaces.length > 1) {
+ DecompilerContext.getLogger()
+ .writeMessage("Inconsistent anonymous class definition: " + cl.qualifiedName, IFernflowerLogger.WARNING);
+ }
+ nestednode.anonimousClassType = new VarType(cl.getInterface(0), true);
+ }
+ else {
+ nestednode.anonimousClassType = new VarType(cl.superClass.getString(), true);
+ }
+ }
+ else if (nestednode.type == ClassNode.CLASS_LOCAL) {
+ // only abstract and final are permitted
+ // a common compiler bug
+ nestednode.access &= (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_FINAL);
+ }
+
+ supernode.nested.add(nestednode);
+ nestednode.parent = supernode;
+
+ nestednode.enclosingClasses.addAll(mapEnclosingClassReferences.get(nestedClass));
+
+ stack.add(nestedClass);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ public void writeClass(StructContext context, StructClass cl, BufferedWriter outwriter) throws IOException {
+
+ ClassNode root = mapRootClasses.get(cl.qualifiedName);
+ if (root.type != ClassNode.CLASS_ROOT) {
+ return;
+ }
+
+ try {
+ DecompilerContext.setImpcollector(new ImportCollector(root));
+ DecompilerContext.setCountercontainer(new CounterContainer());
+
+ // lambda processing
+ LambdaProcessor lambda_proc = new LambdaProcessor();
+ lambda_proc.processClass(root);
+
+ // add simple class names to implicit import
+ addClassnameToImport(root, DecompilerContext.getImpcollector());
+ // build wrappers for all nested classes
+ // that's where the actual processing takes place
+ initWrappers(root);
+
+ NestedClassProcessor nestedproc = new NestedClassProcessor();
+ nestedproc.processClass(root, root);
+
+ NestedMemberAccess nstmember = new NestedMemberAccess();
+ nstmember.propagateMemberAccess(root);
+
+ ClassWriter clwriter = new ClassWriter();
+
+ StringWriter strwriter = new StringWriter();
+ clwriter.classToJava(root, new BufferedWriter(strwriter), 0);
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.OUTPUT_COPYRIGHT_COMMENT)) {
+ outwriter.write("// Decompiled by: Fernflower " + Fernflower.version);
+ outwriter.write(DecompilerContext.getNewLineSeparator());
+ outwriter.write("// Date: " + new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(new Date()));
+ outwriter.write(DecompilerContext.getNewLineSeparator());
+ outwriter.write("// Copyright: 2008-2010, Stiver");
+ outwriter.write(DecompilerContext.getNewLineSeparator());
+ outwriter.write("// Home page: http://www.reversed-java.com");
+ outwriter.write(DecompilerContext.getNewLineSeparator());
+ outwriter.write(DecompilerContext.getNewLineSeparator());
+ }
+
+ int index = cl.qualifiedName.lastIndexOf("/");
+ if (index >= 0) {
String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');
outwriter.write("package ");
outwriter.write(packageName);
@@ -289,161 +289,169 @@ public class ClassesProcessor {
outwriter.write(DecompilerContext.getNewLineSeparator());
outwriter.write(DecompilerContext.getNewLineSeparator());
}
-
- DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, root);
-
- DecompilerContext.getImpcollector().writeImports(outwriter);
- outwriter.write(DecompilerContext.getNewLineSeparator());
-
- outwriter.write(strwriter.toString());
- outwriter.flush();
-
- } finally {
- destroyWrappers(root);
- }
- }
-
- private void initWrappers(ClassNode node) throws IOException {
-
- if(node.type == ClassNode.CLASS_LAMBDA) {
- return;
- }
-
- ClassWrapper wrapper = new ClassWrapper(node.classStruct);
- wrapper.init();
-
- node.wrapper = wrapper;
-
- for(ClassNode nd: node.nested) {
- initWrappers(nd);
- }
- }
-
- private void addClassnameToImport(ClassNode node, ImportCollector imp) {
-
- if(node.simpleName != null && node.simpleName.length() > 0) {
- imp.getShortName(node.type == ClassNode.CLASS_ROOT?node.classStruct.qualifiedName:node.simpleName, false);
- }
-
- for(ClassNode nd: node.nested) {
- addClassnameToImport(nd, imp);
- }
- }
-
- private void destroyWrappers(ClassNode node) {
-
- node.wrapper = null;
- node.classStruct.releaseResources();
-
- for(ClassNode nd: node.nested) {
- destroyWrappers(nd);
- }
- }
-
- public HashMap<String, ClassNode> getMapRootClasses() {
- return mapRootClasses;
- }
-
-
- public class ClassNode {
-
- public static final int CLASS_ROOT = 0;
- public static final int CLASS_MEMBER = 1;
- public static final int CLASS_ANONYMOUS = 2;
- public static final int CLASS_LOCAL = 4;
- public static final int CLASS_LAMBDA = 8;
-
- public int type;
-
- public int access;
-
- public String simpleName;
-
- public StructClass classStruct;
-
- public ClassWrapper wrapper;
-
- public String enclosingMethod;
-
- public InvocationExprent superInvocation;
-
- public HashMap<String, VarVersionPaar> mapFieldsToVars = new HashMap<String, VarVersionPaar>();
-
- public VarType anonimousClassType;
-
- public List<ClassNode> nested = new ArrayList<ClassNode>();
-
- public Set<String> enclosingClasses = new HashSet<String>();
-
- public ClassNode parent;
-
- public LambdaInformation lambda_information;
-
- public ClassNode(String content_class_name, String content_method_name, String content_method_descriptor, int content_method_invokation_type,
- String lambda_class_name, String lambda_method_name, String lambda_method_descriptor, StructClass classStruct) { // lambda class constructor
- this.type = CLASS_LAMBDA;
- this.classStruct = classStruct; // 'parent' class containing the static function
-
- lambda_information = new LambdaInformation();
-
- lambda_information.class_name = lambda_class_name;
- lambda_information.method_name = lambda_method_name;
- lambda_information.method_descriptor = lambda_method_descriptor;
-
- lambda_information.content_class_name = content_class_name;
- lambda_information.content_method_name = content_method_name;
- lambda_information.content_method_descriptor = content_method_descriptor;
- lambda_information.content_method_invokation_type = content_method_invokation_type;
-
- lambda_information.content_method_key = InterpreterUtil.makeUniqueKey(lambda_information.content_method_name, lambda_information.content_method_descriptor);
-
- anonimousClassType = new VarType(lambda_class_name, true);
-
- boolean is_method_reference = (content_class_name != classStruct.qualifiedName);
- StructMethod mt = null;
-
- if(!is_method_reference) { // content method in the same class, check synthetic flag
- mt = classStruct.getMethod(content_method_name, content_method_descriptor);
- is_method_reference = !((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic")); // if not synthetic -> method reference
- }
-
- lambda_information.is_method_reference = is_method_reference;
- lambda_information.is_content_method_static = (lambda_information.content_method_invokation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic); // FIXME: redundant?
- }
-
- public ClassNode(int type, StructClass classStruct) {
- this.type = type;
- this.classStruct = classStruct;
-
- simpleName = classStruct.qualifiedName.substring(classStruct.qualifiedName.lastIndexOf('/')+1);
- }
-
- public ClassNode getClassNode(String qualifiedName) {
- for(ClassNode node : nested) {
- if(qualifiedName.equals(node.classStruct.qualifiedName)) {
- return node;
- }
- }
- return null;
- }
-
- public class LambdaInformation {
-
-
-
- public String class_name;
- public String method_name;
- public String method_descriptor;
-
- public String content_class_name;
- public String content_method_name;
- public String content_method_descriptor;
- public int content_method_invokation_type; // values from CONSTANT_MethodHandle_REF_*
-
- public String content_method_key;
-
- public boolean is_method_reference;
- public boolean is_content_method_static;
- }
- }
+
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, root);
+
+ DecompilerContext.getImpcollector().writeImports(outwriter);
+ outwriter.write(DecompilerContext.getNewLineSeparator());
+
+ outwriter.write(strwriter.toString());
+ outwriter.flush();
+ }
+ finally {
+ destroyWrappers(root);
+ }
+ }
+
+ private void initWrappers(ClassNode node) throws IOException {
+
+ if (node.type == ClassNode.CLASS_LAMBDA) {
+ return;
+ }
+
+ ClassWrapper wrapper = new ClassWrapper(node.classStruct);
+ wrapper.init();
+
+ node.wrapper = wrapper;
+
+ for (ClassNode nd : node.nested) {
+ initWrappers(nd);
+ }
+ }
+
+ private void addClassnameToImport(ClassNode node, ImportCollector imp) {
+
+ if (node.simpleName != null && node.simpleName.length() > 0) {
+ imp.getShortName(node.type == ClassNode.CLASS_ROOT ? node.classStruct.qualifiedName : node.simpleName, false);
+ }
+
+ for (ClassNode nd : node.nested) {
+ addClassnameToImport(nd, imp);
+ }
+ }
+
+ private void destroyWrappers(ClassNode node) {
+
+ node.wrapper = null;
+ node.classStruct.releaseResources();
+
+ for (ClassNode nd : node.nested) {
+ destroyWrappers(nd);
+ }
+ }
+
+ public HashMap<String, ClassNode> getMapRootClasses() {
+ return mapRootClasses;
+ }
+
+
+ public class ClassNode {
+
+ public static final int CLASS_ROOT = 0;
+ public static final int CLASS_MEMBER = 1;
+ public static final int CLASS_ANONYMOUS = 2;
+ public static final int CLASS_LOCAL = 4;
+ public static final int CLASS_LAMBDA = 8;
+
+ public int type;
+
+ public int access;
+
+ public String simpleName;
+
+ public StructClass classStruct;
+
+ public ClassWrapper wrapper;
+
+ public String enclosingMethod;
+
+ public InvocationExprent superInvocation;
+
+ public HashMap<String, VarVersionPaar> mapFieldsToVars = new HashMap<String, VarVersionPaar>();
+
+ public VarType anonimousClassType;
+
+ public List<ClassNode> nested = new ArrayList<ClassNode>();
+
+ public Set<String> enclosingClasses = new HashSet<String>();
+
+ public ClassNode parent;
+
+ public LambdaInformation lambda_information;
+
+ public ClassNode(String content_class_name,
+ String content_method_name,
+ String content_method_descriptor,
+ int content_method_invokation_type,
+ String lambda_class_name,
+ String lambda_method_name,
+ String lambda_method_descriptor,
+ StructClass classStruct) { // lambda class constructor
+ this.type = CLASS_LAMBDA;
+ this.classStruct = classStruct; // 'parent' class containing the static function
+
+ lambda_information = new LambdaInformation();
+
+ lambda_information.class_name = lambda_class_name;
+ lambda_information.method_name = lambda_method_name;
+ lambda_information.method_descriptor = lambda_method_descriptor;
+
+ lambda_information.content_class_name = content_class_name;
+ lambda_information.content_method_name = content_method_name;
+ lambda_information.content_method_descriptor = content_method_descriptor;
+ lambda_information.content_method_invokation_type = content_method_invokation_type;
+
+ lambda_information.content_method_key =
+ InterpreterUtil.makeUniqueKey(lambda_information.content_method_name, lambda_information.content_method_descriptor);
+
+ anonimousClassType = new VarType(lambda_class_name, true);
+
+ boolean is_method_reference = (content_class_name != classStruct.qualifiedName);
+ StructMethod mt = null;
+
+ if (!is_method_reference) { // content method in the same class, check synthetic flag
+ mt = classStruct.getMethod(content_method_name, content_method_descriptor);
+ is_method_reference = !((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) != 0 ||
+ mt.getAttributes().containsKey("Synthetic")); // if not synthetic -> method reference
+ }
+
+ lambda_information.is_method_reference = is_method_reference;
+ lambda_information.is_content_method_static =
+ (lambda_information.content_method_invokation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic); // FIXME: redundant?
+ }
+
+ public ClassNode(int type, StructClass classStruct) {
+ this.type = type;
+ this.classStruct = classStruct;
+
+ simpleName = classStruct.qualifiedName.substring(classStruct.qualifiedName.lastIndexOf('/') + 1);
+ }
+
+ public ClassNode getClassNode(String qualifiedName) {
+ for (ClassNode node : nested) {
+ if (qualifiedName.equals(node.classStruct.qualifiedName)) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ public class LambdaInformation {
+
+
+ public String class_name;
+ public String method_name;
+ public String method_descriptor;
+
+ public String content_class_name;
+ public String content_method_name;
+ public String content_method_descriptor;
+ public int content_method_invokation_type; // values from CONSTANT_MethodHandle_REF_*
+
+ public String content_method_key;
+
+ public boolean is_method_reference;
+ public boolean is_content_method_static;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/DecompilerContext.java b/src/org/jetbrains/java/decompiler/main/DecompilerContext.java
index fc721b7..cb4bbc8 100644
--- a/src/org/jetbrains/java/decompiler/main/DecompilerContext.java
+++ b/src/org/jetbrains/java/decompiler/main/DecompilerContext.java
@@ -1,21 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main;
-import java.util.HashMap;
-
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
@@ -24,174 +23,176 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
import org.jetbrains.java.decompiler.struct.StructContext;
+import java.util.HashMap;
+
public class DecompilerContext {
-
- public static final String CURRENT_CLASS = "CURRENT_CLASS";
- public static final String CURRENT_METHOD = "CURRENT_METHOD";
- public static final String CURRENT_METHOD_DESCRIPTOR = "CURRENT_METHOD_DESCRIPTOR";
- public static final String CURRENT_VAR_PROCESSOR = "CURRENT_VAR_PROCESSOR";
-
- public static final String CURRENT_CLASSNODE = "CURRENT_CLASSNODE";
- public static final String CURRENT_METHOD_WRAPPER = "CURRENT_METHOD_WRAPPER";
-
- private static ThreadLocal<DecompilerContext> currentContext = new ThreadLocal<DecompilerContext>();
-
- private HashMap<String, Object> properties = new HashMap<String, Object>();
-
- private StructContext structcontext;
-
- private ImportCollector impcollector;
-
- private VarNamesCollector varncollector;
-
- private CounterContainer countercontainer;
-
- private ClassesProcessor classprocessor;
-
- private PoolInterceptor poolinterceptor;
-
- private IFernflowerLogger logger;
-
-
- private DecompilerContext(HashMap<String, Object> properties) {
- this.properties.putAll(properties);
- }
-
- public static void initContext(HashMap<String, Object> propertiesCustom) {
-
- HashMap<String, Object> mapDefault = new HashMap<String, Object>();
-
- // default settings
- mapDefault.put(IFernflowerPreferences.DECOMPILE_INNER, "1");
- mapDefault.put(IFernflowerPreferences.DECOMPILE_CLASS_1_4, "1");
- mapDefault.put(IFernflowerPreferences.DECOMPILE_ASSERTIONS, "1");
- mapDefault.put(IFernflowerPreferences.REMOVE_BRIDGE, "1");
- mapDefault.put(IFernflowerPreferences.REMOVE_SYNTHETIC, "0");
- mapDefault.put(IFernflowerPreferences.HIDE_EMPTY_SUPER, "1");
- mapDefault.put(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR, "1");
- mapDefault.put(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "0");
- mapDefault.put(IFernflowerPreferences.OUTPUT_COPYRIGHT_COMMENT, "0");
- mapDefault.put(IFernflowerPreferences.NO_EXCEPTIONS_RETURN, "1");
- mapDefault.put(IFernflowerPreferences.DECOMPILE_ENUM, "1");
- mapDefault.put(IFernflowerPreferences.FINALLY_DEINLINE, "1");
- mapDefault.put(IFernflowerPreferences.REMOVE_GETCLASS_NEW, "1");
- mapDefault.put(IFernflowerPreferences.LITERALS_AS_IS, "0");
- mapDefault.put(IFernflowerPreferences.ASCII_STRING_CHARACTERS, "0");
- mapDefault.put(IFernflowerPreferences.BOOLEAN_TRUE_ONE, "1");
- mapDefault.put(IFernflowerPreferences.SYNTHETIC_NOT_SET, "1");
- mapDefault.put(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT, "1");
-
- mapDefault.put(IFernflowerPreferences.USE_DEBUG_VARNAMES, "1");
- mapDefault.put(IFernflowerPreferences.MAX_PROCESSING_METHOD, "0");
-
- mapDefault.put(IFernflowerPreferences.REMOVE_EMPTY_RANGES, "1");
-
- mapDefault.put(IFernflowerPreferences.NEW_LINE_SEPARATOR, "0");
- mapDefault.put(IFernflowerPreferences.INDENT_STRING, " ");
-
- mapDefault.put(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION, "1");
-
- if(propertiesCustom != null) {
- mapDefault.putAll(propertiesCustom);
- }
-
- currentContext.set(new DecompilerContext(mapDefault));
- }
-
- public static DecompilerContext getCurrentContext() {
- return currentContext.get();
- }
-
- public static void setCurrentContext(DecompilerContext context) {
- currentContext.set(context);
- }
-
- public static Object getProperty(String key) {
- return getCurrentContext().properties.get(key);
- }
-
- public static void setProperty(String key, Object value) {
- getCurrentContext().properties.put(key, value);
- }
-
- public static boolean getOption(String key) {
- return "1".equals(getCurrentContext().properties.get(key));
- }
-
- public static ImportCollector getImpcollector() {
- return getCurrentContext().impcollector;
- }
-
- public static void setImpcollector(ImportCollector impcollector) {
- getCurrentContext().impcollector = impcollector;
- }
-
- public static VarNamesCollector getVarncollector() {
- return getCurrentContext().varncollector;
- }
-
- public static void setVarncollector(VarNamesCollector varncollector) {
- getCurrentContext().varncollector = varncollector;
- }
-
- public static StructContext getStructcontext() {
- return getCurrentContext().structcontext;
- }
-
- public static void setStructcontext(StructContext structcontext) {
- getCurrentContext().structcontext = structcontext;
- }
-
- public static CounterContainer getCountercontainer() {
- return getCurrentContext().countercontainer;
- }
-
- public static void setCountercontainer(CounterContainer countercontainer) {
- getCurrentContext().countercontainer = countercontainer;
- }
-
- public static ClassesProcessor getClassprocessor() {
- return getCurrentContext().classprocessor;
- }
-
- public static void setClassprocessor(ClassesProcessor classprocessor) {
- getCurrentContext().classprocessor = classprocessor;
- }
-
- public static PoolInterceptor getPoolInterceptor() {
- return getCurrentContext().poolinterceptor;
- }
-
- public static void setPoolInterceptor(PoolInterceptor poolinterceptor) {
- getCurrentContext().poolinterceptor = poolinterceptor;
- }
-
- public static IFernflowerLogger getLogger() {
- return getCurrentContext().logger;
- }
-
- public static void setLogger(IFernflowerLogger logger) {
- getCurrentContext().logger = logger;
- setLogSeverity();
- }
-
- private static void setLogSeverity() {
- IFernflowerLogger logger = getCurrentContext().logger;
-
- if(logger != null) {
- String severity = (String)getProperty(IFernflowerPreferences.LOG_LEVEL);
- if(severity != null) {
- Integer iSeverity = IFernflowerLogger.mapLogLevel.get(severity.toUpperCase());
- if(iSeverity != null) {
- logger.setSeverity(iSeverity);
- }
- }
- }
- }
-
- public static String getNewLineSeparator() {
- return getOption(IFernflowerPreferences.NEW_LINE_SEPARATOR) ?
- IFernflowerPreferences.LINE_SEPARATOR_LIN : IFernflowerPreferences.LINE_SEPARATOR_WIN ;
- }
+
+ public static final String CURRENT_CLASS = "CURRENT_CLASS";
+ public static final String CURRENT_METHOD = "CURRENT_METHOD";
+ public static final String CURRENT_METHOD_DESCRIPTOR = "CURRENT_METHOD_DESCRIPTOR";
+ public static final String CURRENT_VAR_PROCESSOR = "CURRENT_VAR_PROCESSOR";
+
+ public static final String CURRENT_CLASSNODE = "CURRENT_CLASSNODE";
+ public static final String CURRENT_METHOD_WRAPPER = "CURRENT_METHOD_WRAPPER";
+
+ private static ThreadLocal<DecompilerContext> currentContext = new ThreadLocal<DecompilerContext>();
+
+ private HashMap<String, Object> properties = new HashMap<String, Object>();
+
+ private StructContext structcontext;
+
+ private ImportCollector impcollector;
+
+ private VarNamesCollector varncollector;
+
+ private CounterContainer countercontainer;
+
+ private ClassesProcessor classprocessor;
+
+ private PoolInterceptor poolinterceptor;
+
+ private IFernflowerLogger logger;
+
+
+ private DecompilerContext(HashMap<String, Object> properties) {
+ this.properties.putAll(properties);
+ }
+
+ public static void initContext(HashMap<String, Object> propertiesCustom) {
+
+ HashMap<String, Object> mapDefault = new HashMap<String, Object>();
+
+ // default settings
+ mapDefault.put(IFernflowerPreferences.DECOMPILE_INNER, "1");
+ mapDefault.put(IFernflowerPreferences.DECOMPILE_CLASS_1_4, "1");
+ mapDefault.put(IFernflowerPreferences.DECOMPILE_ASSERTIONS, "1");
+ mapDefault.put(IFernflowerPreferences.REMOVE_BRIDGE, "1");
+ mapDefault.put(IFernflowerPreferences.REMOVE_SYNTHETIC, "0");
+ mapDefault.put(IFernflowerPreferences.HIDE_EMPTY_SUPER, "1");
+ mapDefault.put(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR, "1");
+ mapDefault.put(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "0");
+ mapDefault.put(IFernflowerPreferences.OUTPUT_COPYRIGHT_COMMENT, "0");
+ mapDefault.put(IFernflowerPreferences.NO_EXCEPTIONS_RETURN, "1");
+ mapDefault.put(IFernflowerPreferences.DECOMPILE_ENUM, "1");
+ mapDefault.put(IFernflowerPreferences.FINALLY_DEINLINE, "1");
+ mapDefault.put(IFernflowerPreferences.REMOVE_GETCLASS_NEW, "1");
+ mapDefault.put(IFernflowerPreferences.LITERALS_AS_IS, "0");
+ mapDefault.put(IFernflowerPreferences.ASCII_STRING_CHARACTERS, "0");
+ mapDefault.put(IFernflowerPreferences.BOOLEAN_TRUE_ONE, "1");
+ mapDefault.put(IFernflowerPreferences.SYNTHETIC_NOT_SET, "1");
+ mapDefault.put(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT, "1");
+
+ mapDefault.put(IFernflowerPreferences.USE_DEBUG_VARNAMES, "1");
+ mapDefault.put(IFernflowerPreferences.MAX_PROCESSING_METHOD, "0");
+
+ mapDefault.put(IFernflowerPreferences.REMOVE_EMPTY_RANGES, "1");
+
+ mapDefault.put(IFernflowerPreferences.NEW_LINE_SEPARATOR, "0");
+ mapDefault.put(IFernflowerPreferences.INDENT_STRING, " ");
+
+ mapDefault.put(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION, "1");
+
+ if (propertiesCustom != null) {
+ mapDefault.putAll(propertiesCustom);
+ }
+
+ currentContext.set(new DecompilerContext(mapDefault));
+ }
+
+ public static DecompilerContext getCurrentContext() {
+ return currentContext.get();
+ }
+
+ public static void setCurrentContext(DecompilerContext context) {
+ currentContext.set(context);
+ }
+
+ public static Object getProperty(String key) {
+ return getCurrentContext().properties.get(key);
+ }
+
+ public static void setProperty(String key, Object value) {
+ getCurrentContext().properties.put(key, value);
+ }
+
+ public static boolean getOption(String key) {
+ return "1".equals(getCurrentContext().properties.get(key));
+ }
+
+ public static ImportCollector getImpcollector() {
+ return getCurrentContext().impcollector;
+ }
+
+ public static void setImpcollector(ImportCollector impcollector) {
+ getCurrentContext().impcollector = impcollector;
+ }
+
+ public static VarNamesCollector getVarncollector() {
+ return getCurrentContext().varncollector;
+ }
+
+ public static void setVarncollector(VarNamesCollector varncollector) {
+ getCurrentContext().varncollector = varncollector;
+ }
+
+ public static StructContext getStructcontext() {
+ return getCurrentContext().structcontext;
+ }
+
+ public static void setStructcontext(StructContext structcontext) {
+ getCurrentContext().structcontext = structcontext;
+ }
+
+ public static CounterContainer getCountercontainer() {
+ return getCurrentContext().countercontainer;
+ }
+
+ public static void setCountercontainer(CounterContainer countercontainer) {
+ getCurrentContext().countercontainer = countercontainer;
+ }
+
+ public static ClassesProcessor getClassprocessor() {
+ return getCurrentContext().classprocessor;
+ }
+
+ public static void setClassprocessor(ClassesProcessor classprocessor) {
+ getCurrentContext().classprocessor = classprocessor;
+ }
+
+ public static PoolInterceptor getPoolInterceptor() {
+ return getCurrentContext().poolinterceptor;
+ }
+
+ public static void setPoolInterceptor(PoolInterceptor poolinterceptor) {
+ getCurrentContext().poolinterceptor = poolinterceptor;
+ }
+
+ public static IFernflowerLogger getLogger() {
+ return getCurrentContext().logger;
+ }
+
+ public static void setLogger(IFernflowerLogger logger) {
+ getCurrentContext().logger = logger;
+ setLogSeverity();
+ }
+
+ private static void setLogSeverity() {
+ IFernflowerLogger logger = getCurrentContext().logger;
+
+ if (logger != null) {
+ String severity = (String)getProperty(IFernflowerPreferences.LOG_LEVEL);
+ if (severity != null) {
+ Integer iSeverity = IFernflowerLogger.mapLogLevel.get(severity.toUpperCase());
+ if (iSeverity != null) {
+ logger.setSeverity(iSeverity);
+ }
+ }
+ }
+ }
+
+ public static String getNewLineSeparator() {
+ return getOption(IFernflowerPreferences.NEW_LINE_SEPARATOR) ?
+ IFernflowerPreferences.LINE_SEPARATOR_LIN : IFernflowerPreferences.LINE_SEPARATOR_WIN;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/EnumProcessor.java b/src/org/jetbrains/java/decompiler/main/EnumProcessor.java
index 7537596..e991827 100644
--- a/src/org/jetbrains/java/decompiler/main/EnumProcessor.java
+++ b/src/org/jetbrains/java/decompiler/main/EnumProcessor.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.code.CodeConstants;
@@ -33,127 +34,125 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil;
public class EnumProcessor {
- public static void clearEnum(ClassWrapper wrapper) {
-
- StructClass cl = wrapper.getClassStruct();
-
- // hide values() and valueOf()
- for(StructMethod meth : cl.getMethods()) {
-
- String name = meth.getName();
- int flag = 0;
-
- if("values".equals(name)) {
- flag = 1;
- } else if("valueOf".equals(name)) {
- flag = 2;
- }
-
- if(flag>0) {
- String[] arr = meth.getDescriptor().split("[()]");
- String par = arr[1];
-
- if((flag == 1 && par.length() == 0) ||
- flag == 2 && "Ljava/lang/String;".equals(par)) {
- wrapper.getHideMembers().add(InterpreterUtil.makeUniqueKey(name, meth.getDescriptor()));
- }
- }
- }
-
- // hide all super invocations
- for(MethodWrapper meth : wrapper.getMethods()) {
- if("<init>".equals(meth.methodStruct.getName())) {
- Statement firstdata = findFirstData(meth.root);
- if(firstdata == null || firstdata.getExprents().isEmpty()) {
- return;
- }
-
- Exprent exprent = firstdata.getExprents().get(0);
- if(exprent.type == Exprent.EXPRENT_INVOCATION) {
- InvocationExprent invexpr = (InvocationExprent)exprent;
- if(isInvocationSuperConstructor(invexpr, meth, wrapper)) {
- firstdata.getExprents().remove(0);
- }
- }
- }
- }
-
- // hide dummy synthetic fields of enum constants
- for(StructField fd: cl.getFields()) {
- if((fd.access_flags & CodeConstants.ACC_ENUM) != 0) {
- Exprent initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
- if(initializer != null && initializer.type == Exprent.EXPRENT_NEW) {
- NewExprent nexpr = (NewExprent)initializer;
- if(nexpr.isAnonymous()) {
- ClassNode child = DecompilerContext.getClassprocessor().getMapRootClasses().get(nexpr.getNewtype().value);
- hideDummyFieldInConstant(child.wrapper);
+ public static void clearEnum(ClassWrapper wrapper) {
+
+ StructClass cl = wrapper.getClassStruct();
+
+ // hide values() and valueOf()
+ for (StructMethod meth : cl.getMethods()) {
+
+ String name = meth.getName();
+ int flag = 0;
+
+ if ("values".equals(name)) {
+ flag = 1;
+ }
+ else if ("valueOf".equals(name)) {
+ flag = 2;
+ }
+
+ if (flag > 0) {
+ String[] arr = meth.getDescriptor().split("[()]");
+ String par = arr[1];
+
+ if ((flag == 1 && par.length() == 0) ||
+ flag == 2 && "Ljava/lang/String;".equals(par)) {
+ wrapper.getHideMembers().add(InterpreterUtil.makeUniqueKey(name, meth.getDescriptor()));
+ }
+ }
+ }
+
+ // hide all super invocations
+ for (MethodWrapper meth : wrapper.getMethods()) {
+ if ("<init>".equals(meth.methodStruct.getName())) {
+ Statement firstdata = findFirstData(meth.root);
+ if (firstdata == null || firstdata.getExprents().isEmpty()) {
+ return;
+ }
+
+ Exprent exprent = firstdata.getExprents().get(0);
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)exprent;
+ if (isInvocationSuperConstructor(invexpr, meth, wrapper)) {
+ firstdata.getExprents().remove(0);
}
- }
- }
- }
-
-
-
- }
-
- private static void hideDummyFieldInConstant(ClassWrapper wrapper) {
-
- StructClass cl = wrapper.getClassStruct();
- for(StructField fd: cl.getFields()) {
- if((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0) {
- FieldDescriptor descr = FieldDescriptor.parseDescriptor(fd.getDescriptor());
- VarType ret = descr.type;
-
- if(ret.type == CodeConstants.TYPE_OBJECT && ret.arraydim == 1 && cl.qualifiedName.equals(ret.value)) {
- wrapper.getHideMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
- }
- }
- }
-
- }
-
- // FIXME: move to a util class (see also InitializerProcessor)
- private static Statement findFirstData(Statement stat) {
-
- if(stat.getExprents() != null) {
- return stat;
- } else {
- if(stat.isLabeled()) {
- return null;
- }
-
- switch(stat.type) {
- case Statement.TYPE_SEQUENCE:
- case Statement.TYPE_IF:
- case Statement.TYPE_ROOT:
- case Statement.TYPE_SWITCH:
- case Statement.TYPE_SYNCRONIZED:
- return findFirstData(stat.getFirst());
- default:
- return null;
- }
- }
- }
-
- // FIXME: move to util class (see also InitializerProcessor)
- private static boolean isInvocationSuperConstructor(InvocationExprent inv, MethodWrapper meth, ClassWrapper wrapper) {
-
- if(inv.getFunctype() == InvocationExprent.TYP_INIT) {
- if(inv.getInstance().type == Exprent.EXPRENT_VAR) {
- VarExprent instvar = (VarExprent)inv.getInstance();
- VarVersionPaar varpaar = new VarVersionPaar(instvar);
-
- String classname = meth.varproc.getThisvars().get(varpaar);
-
- if(classname!=null) { // any this instance. TODO: Restrict to current class?
- if(!wrapper.getClassStruct().qualifiedName.equals(inv.getClassname())) {
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
+ }
+ }
+ }
+
+ // hide dummy synthetic fields of enum constants
+ for (StructField fd : cl.getFields()) {
+ if ((fd.access_flags & CodeConstants.ACC_ENUM) != 0) {
+ Exprent initializer =
+ wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
+ if (initializer != null && initializer.type == Exprent.EXPRENT_NEW) {
+ NewExprent nexpr = (NewExprent)initializer;
+ if (nexpr.isAnonymous()) {
+ ClassNode child = DecompilerContext.getClassprocessor().getMapRootClasses().get(nexpr.getNewtype().value);
+ hideDummyFieldInConstant(child.wrapper);
+ }
+ }
+ }
+ }
+ }
+
+ private static void hideDummyFieldInConstant(ClassWrapper wrapper) {
+
+ StructClass cl = wrapper.getClassStruct();
+ for (StructField fd : cl.getFields()) {
+ if ((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0) {
+ FieldDescriptor descr = FieldDescriptor.parseDescriptor(fd.getDescriptor());
+ VarType ret = descr.type;
+
+ if (ret.type == CodeConstants.TYPE_OBJECT && ret.arraydim == 1 && cl.qualifiedName.equals(ret.value)) {
+ wrapper.getHideMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
+ }
+ }
+ }
+ }
+
+ // FIXME: move to a util class (see also InitializerProcessor)
+ private static Statement findFirstData(Statement stat) {
+
+ if (stat.getExprents() != null) {
+ return stat;
+ }
+ else {
+ if (stat.isLabeled()) {
+ return null;
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_SEQUENCE:
+ case Statement.TYPE_IF:
+ case Statement.TYPE_ROOT:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ return findFirstData(stat.getFirst());
+ default:
+ return null;
+ }
+ }
+ }
+
+ // FIXME: move to util class (see also InitializerProcessor)
+ private static boolean isInvocationSuperConstructor(InvocationExprent inv, MethodWrapper meth, ClassWrapper wrapper) {
+
+ if (inv.getFunctype() == InvocationExprent.TYP_INIT) {
+ if (inv.getInstance().type == Exprent.EXPRENT_VAR) {
+ VarExprent instvar = (VarExprent)inv.getInstance();
+ VarVersionPaar varpaar = new VarVersionPaar(instvar);
+
+ String classname = meth.varproc.getThisvars().get(varpaar);
+
+ if (classname != null) { // any this instance. TODO: Restrict to current class?
+ if (!wrapper.getClassStruct().qualifiedName.equals(inv.getClassname())) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/Fernflower.java b/src/org/jetbrains/java/decompiler/main/Fernflower.java
index 021ab1a..4365ca1 100644
--- a/src/org/jetbrains/java/decompiler/main/Fernflower.java
+++ b/src/org/jetbrains/java/decompiler/main/Fernflower.java
@@ -1,23 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main;
-import java.io.BufferedWriter;
-import java.io.StringWriter;
-import java.util.HashMap;
-
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
@@ -29,82 +26,88 @@ import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructContext;
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
+import java.io.BufferedWriter;
+import java.io.StringWriter;
+import java.util.HashMap;
+
public class Fernflower implements IDecompiledData {
-
- public static final String version = "v0.8.4";
-
- private StructContext structcontext;
-
- private ClassesProcessor clprocessor;
-
- public Fernflower(IBytecodeProvider provider, IDecompilatSaver saver,
- HashMap<String, Object> propertiesCustom) {
-
- StructContext context = new StructContext(saver, this, new LazyLoader(provider));
-
- structcontext = context;
-
- DecompilerContext.initContext(propertiesCustom);
- DecompilerContext.setCountercontainer(new CounterContainer());
-
- }
-
- public void decompileContext() {
-
- if(DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
- IdentifierConverter ren = new IdentifierConverter();
- ren.rename(structcontext);
- ren = null;
- }
-
- clprocessor = new ClassesProcessor(structcontext);
-
- DecompilerContext.setClassprocessor(clprocessor);
- DecompilerContext.setStructcontext(structcontext);
-
- structcontext.saveContext();
- }
+
+ public static final String version = "v0.8.4";
+
+ private StructContext structcontext;
+
+ private ClassesProcessor clprocessor;
+
+ public Fernflower(IBytecodeProvider provider, IDecompilatSaver saver,
+ HashMap<String, Object> propertiesCustom) {
+
+ StructContext context = new StructContext(saver, this, new LazyLoader(provider));
+
+ structcontext = context;
+
+ DecompilerContext.initContext(propertiesCustom);
+ DecompilerContext.setCountercontainer(new CounterContainer());
+ }
+
+ public void decompileContext() {
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
+ IdentifierConverter ren = new IdentifierConverter();
+ ren.rename(structcontext);
+ ren = null;
+ }
+
+ clprocessor = new ClassesProcessor(structcontext);
+
+ DecompilerContext.setClassprocessor(clprocessor);
+ DecompilerContext.setStructcontext(structcontext);
+
+ structcontext.saveContext();
+ }
public void clearContext() {
DecompilerContext.setCurrentContext(null);
}
- public String getClassEntryName(StructClass cl, String entryname) {
-
- ClassNode node = clprocessor.getMapRootClasses().get(cl.qualifiedName);
- if(node.type != ClassNode.CLASS_ROOT) {
- return null;
- } else {
- if(DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
- String simple_classname = cl.qualifiedName.substring(cl.qualifiedName.lastIndexOf('/')+1);
- return entryname.substring(0, entryname.lastIndexOf('/')+1)+simple_classname+".java";
- } else {
- return entryname.substring(0, entryname.lastIndexOf(".class"))+".java";
- }
- }
- }
-
- public StructContext getStructcontext() {
- return structcontext;
- }
-
- public String getClassContent(StructClass cl) {
-
- String res = null;
-
- try {
- StringWriter strwriter = new StringWriter();
- clprocessor.writeClass(structcontext, cl, new BufferedWriter(strwriter));
-
- res = strwriter.toString();
- } catch(ThreadDeath ex) {
- throw ex;
- } catch(Throwable ex) {
- DecompilerContext.getLogger().writeMessage("Class "+cl.qualifiedName+" couldn't be fully decompiled.", ex);
- }
-
- return res;
- }
-
+ public String getClassEntryName(StructClass cl, String entryname) {
+
+ ClassNode node = clprocessor.getMapRootClasses().get(cl.qualifiedName);
+ if (node.type != ClassNode.CLASS_ROOT) {
+ return null;
+ }
+ else {
+ if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
+ String simple_classname = cl.qualifiedName.substring(cl.qualifiedName.lastIndexOf('/') + 1);
+ return entryname.substring(0, entryname.lastIndexOf('/') + 1) + simple_classname + ".java";
+ }
+ else {
+ return entryname.substring(0, entryname.lastIndexOf(".class")) + ".java";
+ }
+ }
+ }
+
+ public StructContext getStructcontext() {
+ return structcontext;
+ }
+
+ public String getClassContent(StructClass cl) {
+
+ String res = null;
+
+ try {
+ StringWriter strwriter = new StringWriter();
+ clprocessor.writeClass(structcontext, cl, new BufferedWriter(strwriter));
+
+ res = strwriter.toString();
+ }
+ catch (ThreadDeath ex) {
+ throw ex;
+ }
+ catch (Throwable ex) {
+ DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", ex);
+ }
+
+ return res;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java
index ff6233c..c738163 100644
--- a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java
+++ b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java
@@ -1,32 +1,26 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
@@ -34,288 +28,296 @@ import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructField;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.List;
+
public class InitializerProcessor {
- public static void extractInitializers(ClassWrapper wrapper) {
-
- MethodWrapper meth = wrapper.getMethodWrapper("<clinit>", "()V");
- if(meth != null && meth.root != null) { // successfully decompiled static constructor
- extractStaticInitializers(wrapper, meth);
- }
-
- extractDynamicInitializers(wrapper);
-
- // required e.g. if anonymous class is being decompiled as a standard one.
- // This can happen if InnerClasses attributes are erased
- liftConstructor(wrapper);
-
- if(DecompilerContext.getOption(IFernflowerPreferences.HIDE_EMPTY_SUPER)) {
- hideEmptySuper(wrapper);
- }
- }
-
-
- private static void liftConstructor(ClassWrapper wrapper) {
-
- for(MethodWrapper meth : wrapper.getMethods()) {
- if("<init>".equals(meth.methodStruct.getName()) && meth.root != null) {
- Statement firstdata = findFirstData(meth.root);
- if(firstdata == null) {
- return;
- }
-
-
- int index = 0;
- List<Exprent> lstExprents = firstdata.getExprents();
-
- for(Exprent exprent : lstExprents) {
-
- int action = 0;
-
- if(exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent asexpr = (AssignmentExprent)exprent;
- if(asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
- FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
- if(fexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName)) {
- StructField structField = wrapper.getClassStruct().getField(fexpr.getName(), fexpr.getDescriptor().descriptorString);
- if(structField != null && (structField.access_flags & CodeConstants.ACC_FINAL) != 0) {
- action = 1;
- }
- }
- }
- } else if(index > 0 && exprent.type == Exprent.EXPRENT_INVOCATION &&
- isInvocationInitConstructor((InvocationExprent)exprent, meth, wrapper, true)) {
- // this() or super()
- lstExprents.add(0, lstExprents.remove(index));
- action = 2;
- }
-
- if(action != 1) {
- break;
- }
-
- index++;
- }
- }
- }
- }
-
-
- private static void hideEmptySuper(ClassWrapper wrapper) {
-
- for(MethodWrapper meth : wrapper.getMethods()) {
- if("<init>".equals(meth.methodStruct.getName()) && meth.root != null) {
- Statement firstdata = findFirstData(meth.root);
- if(firstdata == null || firstdata.getExprents().isEmpty()) {
- return;
- }
-
- Exprent exprent = firstdata.getExprents().get(0);
- if(exprent.type == Exprent.EXPRENT_INVOCATION) {
- InvocationExprent invexpr = (InvocationExprent)exprent;
- if(isInvocationInitConstructor(invexpr, meth, wrapper, false) && invexpr.getLstParameters().isEmpty()) {
- firstdata.getExprents().remove(0);
- }
- }
- }
- }
- }
-
- private static void extractStaticInitializers(ClassWrapper wrapper, MethodWrapper meth) {
-
- RootStatement root = meth.root;
- StructClass cl = wrapper.getClassStruct();
-
- Statement firstdata = findFirstData(root);
- if(firstdata != null) {
- while(!firstdata.getExprents().isEmpty()) {
- Exprent exprent = firstdata.getExprents().get(0);
-
- boolean found = false;
-
- if(exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent asexpr = (AssignmentExprent)exprent;
- if(asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
- FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
- if(fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) &&
- cl.hasField(fexpr.getName(), fexpr.getDescriptor().descriptorString)) {
-
- if(isExprentIndependent(asexpr.getRight(), meth)) {
-
- String keyField = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString);
- if(!wrapper.getStaticFieldInitializers().containsKey(keyField)) {
- wrapper.getStaticFieldInitializers().addWithKey(asexpr.getRight(), keyField);
- firstdata.getExprents().remove(0);
- found = true;
- }
- }
- }
- }
- }
-
- if(!found) {
- break;
- }
- }
- }
- }
-
- private static void extractDynamicInitializers(ClassWrapper wrapper) {
-
- StructClass cl = wrapper.getClassStruct();
-
- boolean isAnonymous = DecompilerContext.getClassprocessor().getMapRootClasses().get(cl.qualifiedName).type == ClassNode.CLASS_ANONYMOUS;
-
- List<List<Exprent>> lstFirst = new ArrayList<List<Exprent>>();
- List<MethodWrapper> lstMethWrappers = new ArrayList<MethodWrapper>();
-
- for(MethodWrapper meth : wrapper.getMethods()) {
- if("<init>".equals(meth.methodStruct.getName()) && meth.root != null) { // successfully decompiled constructor
- Statement firstdata = findFirstData(meth.root);
- if(firstdata == null || firstdata.getExprents().isEmpty()) {
- return;
- }
- lstFirst.add(firstdata.getExprents());
- lstMethWrappers.add(meth);
-
- Exprent exprent = firstdata.getExprents().get(0);
- if(!isAnonymous) { // FIXME: doesn't make sense
- if(exprent.type != Exprent.EXPRENT_INVOCATION || !isInvocationInitConstructor((InvocationExprent)exprent, meth, wrapper, false)) {
- return;
- }
- }
- }
- }
-
- if(lstFirst.isEmpty()) {
- return;
- }
-
- for(;;) {
-
- String fieldWithDescr = null;
- Exprent value = null;
-
- for(int i=0; i<lstFirst.size(); i++) {
-
- List<Exprent> lst = lstFirst.get(i);
-
- if(lst.size() < (isAnonymous?1:2)) {
- return;
- }
-
- Exprent exprent = lst.get(isAnonymous?0:1);
-
- boolean found = false;
-
- if(exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent asexpr = (AssignmentExprent)exprent;
- if(asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
- FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
- if(!fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) &&
- cl.hasField(fexpr.getName(), fexpr.getDescriptor().descriptorString)) { // check for the physical existence of the field. Could be defined in a superclass.
-
- if(isExprentIndependent(asexpr.getRight(), lstMethWrappers.get(i))) {
- String fieldKey = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString);
- if(fieldWithDescr == null) {
- fieldWithDescr = fieldKey;
- value = asexpr.getRight();
- } else {
- if(!fieldWithDescr.equals(fieldKey) ||
- !value.equals(asexpr.getRight())) {
- return;
- }
- }
- found = true;
- }
- }
- }
- }
-
- if(!found) {
- return;
- }
- }
-
- if(!wrapper.getDynamicFieldInitializers().containsKey(fieldWithDescr)) {
- wrapper.getDynamicFieldInitializers().addWithKey(value, fieldWithDescr);
-
- for(List<Exprent> lst : lstFirst) {
- lst.remove(isAnonymous?0:1);
- }
- } else {
- return;
- }
- }
-
- }
-
- private static boolean isExprentIndependent(Exprent exprent, MethodWrapper meth) {
-
- List<Exprent> lst = exprent.getAllExprents(true);
- lst.add(exprent);
-
- for(Exprent expr : lst) {
- switch(expr.type) {
- case Exprent.EXPRENT_VAR:
- VarVersionPaar varpaar = new VarVersionPaar((VarExprent)expr);
- if(!meth.varproc.getExternvars().contains(varpaar)) {
- String varname = meth.varproc.getVarName(varpaar);
-
- if(!varname.equals("this") && !varname.endsWith(".this")) { // FIXME: remove direct comparison with strings
- return false;
- }
- }
- break;
- case Exprent.EXPRENT_FIELD:
- return false;
- }
- }
-
- return true;
- }
-
-
- private static Statement findFirstData(Statement stat) {
-
- if(stat.getExprents() != null) {
- return stat;
- } else {
- if(stat.isLabeled()) { // FIXME: Why??
- return null;
- }
-
- switch(stat.type) {
- case Statement.TYPE_SEQUENCE:
- case Statement.TYPE_IF:
- case Statement.TYPE_ROOT:
- case Statement.TYPE_SWITCH:
- case Statement.TYPE_SYNCRONIZED:
- return findFirstData(stat.getFirst());
- default:
- return null;
- }
- }
- }
-
- private static boolean isInvocationInitConstructor(InvocationExprent inv, MethodWrapper meth, ClassWrapper wrapper, boolean withThis) {
-
- if(inv.getFunctype() == InvocationExprent.TYP_INIT) {
- if(inv.getInstance().type == Exprent.EXPRENT_VAR) {
- VarExprent instvar = (VarExprent)inv.getInstance();
- VarVersionPaar varpaar = new VarVersionPaar(instvar);
-
- String classname = meth.varproc.getThisvars().get(varpaar);
-
- if(classname!=null) { // any this instance. TODO: Restrict to current class?
- if(withThis || !wrapper.getClassStruct().qualifiedName.equals(inv.getClassname())) {
- return true;
- }
- }
- }
- }
-
- return false;
- }
+ public static void extractInitializers(ClassWrapper wrapper) {
+
+ MethodWrapper meth = wrapper.getMethodWrapper("<clinit>", "()V");
+ if (meth != null && meth.root != null) { // successfully decompiled static constructor
+ extractStaticInitializers(wrapper, meth);
+ }
+
+ extractDynamicInitializers(wrapper);
+
+ // required e.g. if anonymous class is being decompiled as a standard one.
+ // This can happen if InnerClasses attributes are erased
+ liftConstructor(wrapper);
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.HIDE_EMPTY_SUPER)) {
+ hideEmptySuper(wrapper);
+ }
+ }
+
+
+ private static void liftConstructor(ClassWrapper wrapper) {
+
+ for (MethodWrapper meth : wrapper.getMethods()) {
+ if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) {
+ Statement firstdata = findFirstData(meth.root);
+ if (firstdata == null) {
+ return;
+ }
+
+
+ int index = 0;
+ List<Exprent> lstExprents = firstdata.getExprents();
+
+ for (Exprent exprent : lstExprents) {
+
+ int action = 0;
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
+ FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
+ if (fexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName)) {
+ StructField structField = wrapper.getClassStruct().getField(fexpr.getName(), fexpr.getDescriptor().descriptorString);
+ if (structField != null && (structField.access_flags & CodeConstants.ACC_FINAL) != 0) {
+ action = 1;
+ }
+ }
+ }
+ }
+ else if (index > 0 && exprent.type == Exprent.EXPRENT_INVOCATION &&
+ isInvocationInitConstructor((InvocationExprent)exprent, meth, wrapper, true)) {
+ // this() or super()
+ lstExprents.add(0, lstExprents.remove(index));
+ action = 2;
+ }
+
+ if (action != 1) {
+ break;
+ }
+
+ index++;
+ }
+ }
+ }
+ }
+
+
+ private static void hideEmptySuper(ClassWrapper wrapper) {
+
+ for (MethodWrapper meth : wrapper.getMethods()) {
+ if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) {
+ Statement firstdata = findFirstData(meth.root);
+ if (firstdata == null || firstdata.getExprents().isEmpty()) {
+ return;
+ }
+
+ Exprent exprent = firstdata.getExprents().get(0);
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)exprent;
+ if (isInvocationInitConstructor(invexpr, meth, wrapper, false) && invexpr.getLstParameters().isEmpty()) {
+ firstdata.getExprents().remove(0);
+ }
+ }
+ }
+ }
+ }
+
+ private static void extractStaticInitializers(ClassWrapper wrapper, MethodWrapper meth) {
+
+ RootStatement root = meth.root;
+ StructClass cl = wrapper.getClassStruct();
+
+ Statement firstdata = findFirstData(root);
+ if (firstdata != null) {
+ while (!firstdata.getExprents().isEmpty()) {
+ Exprent exprent = firstdata.getExprents().get(0);
+
+ boolean found = false;
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
+ FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
+ if (fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) &&
+ cl.hasField(fexpr.getName(), fexpr.getDescriptor().descriptorString)) {
+
+ if (isExprentIndependent(asexpr.getRight(), meth)) {
+
+ String keyField = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString);
+ if (!wrapper.getStaticFieldInitializers().containsKey(keyField)) {
+ wrapper.getStaticFieldInitializers().addWithKey(asexpr.getRight(), keyField);
+ firstdata.getExprents().remove(0);
+ found = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+ }
+ }
+
+ private static void extractDynamicInitializers(ClassWrapper wrapper) {
+
+ StructClass cl = wrapper.getClassStruct();
+
+ boolean isAnonymous = DecompilerContext.getClassprocessor().getMapRootClasses().get(cl.qualifiedName).type == ClassNode.CLASS_ANONYMOUS;
+
+ List<List<Exprent>> lstFirst = new ArrayList<List<Exprent>>();
+ List<MethodWrapper> lstMethWrappers = new ArrayList<MethodWrapper>();
+
+ for (MethodWrapper meth : wrapper.getMethods()) {
+ if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) { // successfully decompiled constructor
+ Statement firstdata = findFirstData(meth.root);
+ if (firstdata == null || firstdata.getExprents().isEmpty()) {
+ return;
+ }
+ lstFirst.add(firstdata.getExprents());
+ lstMethWrappers.add(meth);
+
+ Exprent exprent = firstdata.getExprents().get(0);
+ if (!isAnonymous) { // FIXME: doesn't make sense
+ if (exprent.type != Exprent.EXPRENT_INVOCATION ||
+ !isInvocationInitConstructor((InvocationExprent)exprent, meth, wrapper, false)) {
+ return;
+ }
+ }
+ }
+ }
+
+ if (lstFirst.isEmpty()) {
+ return;
+ }
+
+ for (; ; ) {
+
+ String fieldWithDescr = null;
+ Exprent value = null;
+
+ for (int i = 0; i < lstFirst.size(); i++) {
+
+ List<Exprent> lst = lstFirst.get(i);
+
+ if (lst.size() < (isAnonymous ? 1 : 2)) {
+ return;
+ }
+
+ Exprent exprent = lst.get(isAnonymous ? 0 : 1);
+
+ boolean found = false;
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
+ FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
+ if (!fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) &&
+ cl.hasField(fexpr.getName(), fexpr
+ .getDescriptor().descriptorString)) { // check for the physical existence of the field. Could be defined in a superclass.
+
+ if (isExprentIndependent(asexpr.getRight(), lstMethWrappers.get(i))) {
+ String fieldKey = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString);
+ if (fieldWithDescr == null) {
+ fieldWithDescr = fieldKey;
+ value = asexpr.getRight();
+ }
+ else {
+ if (!fieldWithDescr.equals(fieldKey) ||
+ !value.equals(asexpr.getRight())) {
+ return;
+ }
+ }
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ return;
+ }
+ }
+
+ if (!wrapper.getDynamicFieldInitializers().containsKey(fieldWithDescr)) {
+ wrapper.getDynamicFieldInitializers().addWithKey(value, fieldWithDescr);
+
+ for (List<Exprent> lst : lstFirst) {
+ lst.remove(isAnonymous ? 0 : 1);
+ }
+ }
+ else {
+ return;
+ }
+ }
+ }
+
+ private static boolean isExprentIndependent(Exprent exprent, MethodWrapper meth) {
+
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ switch (expr.type) {
+ case Exprent.EXPRENT_VAR:
+ VarVersionPaar varpaar = new VarVersionPaar((VarExprent)expr);
+ if (!meth.varproc.getExternvars().contains(varpaar)) {
+ String varname = meth.varproc.getVarName(varpaar);
+
+ if (!varname.equals("this") && !varname.endsWith(".this")) { // FIXME: remove direct comparison with strings
+ return false;
+ }
+ }
+ break;
+ case Exprent.EXPRENT_FIELD:
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ private static Statement findFirstData(Statement stat) {
+
+ if (stat.getExprents() != null) {
+ return stat;
+ }
+ else {
+ if (stat.isLabeled()) { // FIXME: Why??
+ return null;
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_SEQUENCE:
+ case Statement.TYPE_IF:
+ case Statement.TYPE_ROOT:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ return findFirstData(stat.getFirst());
+ default:
+ return null;
+ }
+ }
+ }
+
+ private static boolean isInvocationInitConstructor(InvocationExprent inv, MethodWrapper meth, ClassWrapper wrapper, boolean withThis) {
+
+ if (inv.getFunctype() == InvocationExprent.TYP_INIT) {
+ if (inv.getInstance().type == Exprent.EXPRENT_VAR) {
+ VarExprent instvar = (VarExprent)inv.getInstance();
+ VarVersionPaar varpaar = new VarVersionPaar(instvar);
+
+ String classname = meth.varproc.getThisvars().get(varpaar);
+
+ if (classname != null) { // any this instance. TODO: Restrict to current class?
+ if (withThis || !wrapper.getClassStruct().qualifiedName.equals(inv.getClassname())) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/collectors/CounterContainer.java b/src/org/jetbrains/java/decompiler/main/collectors/CounterContainer.java
index dcc1968..04d50a7 100644
--- a/src/org/jetbrains/java/decompiler/main/collectors/CounterContainer.java
+++ b/src/org/jetbrains/java/decompiler/main/collectors/CounterContainer.java
@@ -1,37 +1,37 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.collectors;
public class CounterContainer {
- public static final int STATEMENT_COUNTER = 0;
- public static final int EXPRENT_COUNTER = 1;
- public static final int VAR_COUNTER = 2;
-
- private int[] values = new int[]{1, 1, 1};
-
- public void setCounter(int counter, int value) {
- values[counter] = value;
- }
+ public static final int STATEMENT_COUNTER = 0;
+ public static final int EXPRENT_COUNTER = 1;
+ public static final int VAR_COUNTER = 2;
+
+ private int[] values = new int[]{1, 1, 1};
+
+ public void setCounter(int counter, int value) {
+ values[counter] = value;
+ }
- public int getCounter(int counter) {
- return values[counter];
- }
+ public int getCounter(int counter) {
+ return values[counter];
+ }
- public int getCounterAndIncrement(int counter) {
- return values[counter]++;
- }
-
+ public int getCounterAndIncrement(int counter) {
+ return values[counter]++;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java b/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
index cdc6529..f45bf27 100644
--- a/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
+++ b/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
@@ -1,157 +1,152 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.collectors;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.main.ClassesProcessor;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.struct.StructContext;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.util.*;
+import java.util.Map.Entry;
+
public class ImportCollector {
- private static final String JAVA_LANG_PACKAGE = "java.lang";
-
- private HashMap<String, String> mapSimpleNames = new HashMap<String, String>();
-
- private HashSet<String> setNotImportedNames = new HashSet<String>();
-
- private String currentPackageSlash = "";
-
- private String currentPackagePoint = "";
-
- public ImportCollector(ClassNode root) {
-
- String clname = root.classStruct.qualifiedName;
- int index = clname.lastIndexOf("/");
- if(index >= 0) {
- currentPackageSlash = clname.substring(0, index);
- currentPackagePoint = currentPackageSlash.replace('/', '.');
- currentPackageSlash += "/";
- }
- }
-
- public String getShortName(String fullname) {
- return getShortName(fullname, true);
- }
-
- public String getShortName(String fullname, boolean imported) {
-
- ClassesProcessor clproc = DecompilerContext.getClassprocessor();
- ClassNode node = clproc.getMapRootClasses().get(fullname.replace('.', '/'));
-
- String retname = null;
-
- if(node != null && node.classStruct.isOwn()) {
-
- retname = node.simpleName;
-
- while(node.parent != null && node.type == ClassNode.CLASS_MEMBER) {
- retname = node.parent.simpleName+"."+retname;
- node = node.parent;
- }
-
- if(node.type == ClassNode.CLASS_ROOT) {
- fullname = node.classStruct.qualifiedName;
- fullname = fullname.replace('/', '.');
- } else {
- return retname;
- }
-
- } else if(node == null || !node.classStruct.isOwn()) {
- fullname = fullname.replace('$', '.');
- }
-
- String nshort = fullname;
- String npackage = "";
-
- int lastpoint = fullname.lastIndexOf(".");
-
- if(lastpoint >= 0) {
- nshort = fullname.substring(lastpoint+1);
- npackage = fullname.substring(0, lastpoint);
- }
-
- StructContext context = DecompilerContext.getStructcontext();
-
- boolean existsDefaultClass = (context.getClass(currentPackageSlash+nshort) != null
- && !npackage.equals(currentPackagePoint)) // current package
- || (context.getClass(nshort) != null); // default package
-
- if(existsDefaultClass ||
- (mapSimpleNames.containsKey(nshort) && !npackage.equals(mapSimpleNames.get(nshort)))) {
- return fullname;
- } else if(!mapSimpleNames.containsKey(nshort)) {
- mapSimpleNames.put(nshort, npackage);
-
- if(!imported) {
- setNotImportedNames.add(nshort);
- }
- }
-
- return retname==null?nshort:retname;
- }
-
- public void writeImports(BufferedWriter writer) throws IOException {
-
- for(String s: packImports()) {
- writer.write("import ");
- writer.write(s);
- writer.write(";");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
-
- }
-
- private List<String> packImports() {
-
- List<Entry<String, String>> lst = new ArrayList<Entry<String, String>>(mapSimpleNames.entrySet());
-
- Collections.sort(lst, new Comparator<Entry<String, String>>() {
- public int compare(Entry<String, String> par0, Entry<String, String> par1) {
- int res = par0.getValue().compareTo(par1.getValue());
- if(res == 0) {
- res = par0.getKey().compareTo(par1.getKey());
- }
- return res;
- }
- });
-
- List<String> res = new ArrayList<String>();
- for(Entry<String, String> ent: lst) {
- if(!setNotImportedNames.contains(ent.getKey()) // not the current class or one of the nested ones. Also not the empty package.
- && !JAVA_LANG_PACKAGE.equals(ent.getValue())
- && ent.getValue().length() > 0) {
-
- String imp = ent.getValue()+"."+ent.getKey();
- res.add(imp);
- }
- }
-
- return res;
- }
-
-
+ private static final String JAVA_LANG_PACKAGE = "java.lang";
+
+ private HashMap<String, String> mapSimpleNames = new HashMap<String, String>();
+
+ private HashSet<String> setNotImportedNames = new HashSet<String>();
+
+ private String currentPackageSlash = "";
+
+ private String currentPackagePoint = "";
+
+ public ImportCollector(ClassNode root) {
+
+ String clname = root.classStruct.qualifiedName;
+ int index = clname.lastIndexOf("/");
+ if (index >= 0) {
+ currentPackageSlash = clname.substring(0, index);
+ currentPackagePoint = currentPackageSlash.replace('/', '.');
+ currentPackageSlash += "/";
+ }
+ }
+
+ public String getShortName(String fullname) {
+ return getShortName(fullname, true);
+ }
+
+ public String getShortName(String fullname, boolean imported) {
+
+ ClassesProcessor clproc = DecompilerContext.getClassprocessor();
+ ClassNode node = clproc.getMapRootClasses().get(fullname.replace('.', '/'));
+
+ String retname = null;
+
+ if (node != null && node.classStruct.isOwn()) {
+
+ retname = node.simpleName;
+
+ while (node.parent != null && node.type == ClassNode.CLASS_MEMBER) {
+ retname = node.parent.simpleName + "." + retname;
+ node = node.parent;
+ }
+
+ if (node.type == ClassNode.CLASS_ROOT) {
+ fullname = node.classStruct.qualifiedName;
+ fullname = fullname.replace('/', '.');
+ }
+ else {
+ return retname;
+ }
+ }
+ else if (node == null || !node.classStruct.isOwn()) {
+ fullname = fullname.replace('$', '.');
+ }
+
+ String nshort = fullname;
+ String npackage = "";
+
+ int lastpoint = fullname.lastIndexOf(".");
+
+ if (lastpoint >= 0) {
+ nshort = fullname.substring(lastpoint + 1);
+ npackage = fullname.substring(0, lastpoint);
+ }
+
+ StructContext context = DecompilerContext.getStructcontext();
+
+ boolean existsDefaultClass = (context.getClass(currentPackageSlash + nshort) != null
+ && !npackage.equals(currentPackagePoint)) // current package
+ || (context.getClass(nshort) != null); // default package
+
+ if (existsDefaultClass ||
+ (mapSimpleNames.containsKey(nshort) && !npackage.equals(mapSimpleNames.get(nshort)))) {
+ return fullname;
+ }
+ else if (!mapSimpleNames.containsKey(nshort)) {
+ mapSimpleNames.put(nshort, npackage);
+
+ if (!imported) {
+ setNotImportedNames.add(nshort);
+ }
+ }
+
+ return retname == null ? nshort : retname;
+ }
+
+ public void writeImports(BufferedWriter writer) throws IOException {
+
+ for (String s : packImports()) {
+ writer.write("import ");
+ writer.write(s);
+ writer.write(";");
+ writer.write(DecompilerContext.getNewLineSeparator());
+ }
+ }
+
+ private List<String> packImports() {
+
+ List<Entry<String, String>> lst = new ArrayList<Entry<String, String>>(mapSimpleNames.entrySet());
+
+ Collections.sort(lst, new Comparator<Entry<String, String>>() {
+ public int compare(Entry<String, String> par0, Entry<String, String> par1) {
+ int res = par0.getValue().compareTo(par1.getValue());
+ if (res == 0) {
+ res = par0.getKey().compareTo(par1.getKey());
+ }
+ return res;
+ }
+ });
+
+ List<String> res = new ArrayList<String>();
+ for (Entry<String, String> ent : lst) {
+ if (!setNotImportedNames.contains(ent.getKey()) // not the current class or one of the nested ones. Also not the empty package.
+ && !JAVA_LANG_PACKAGE.equals(ent.getValue())
+ && ent.getValue().length() > 0) {
+
+ String imp = ent.getValue() + "." + ent.getKey();
+ res.add(imp);
+ }
+ }
+
+ return res;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java b/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java
index 5fd33c0..dfde971 100644
--- a/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java
+++ b/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java
@@ -1,50 +1,51 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.collectors;
import java.util.HashSet;
public class VarNamesCollector {
- private HashSet<String> usedNames = new HashSet<String>();
-
- public VarNamesCollector() {}
-
- public VarNamesCollector(HashSet<String> setNames) {
- usedNames.addAll(setNames);
- }
-
- public void addName(String value) {
- usedNames.add(value);
- }
-
- public String getFreeName(int index) {
- return getFreeName("var"+index);
- }
-
- public String getFreeName(String proposition) {
-
- while(usedNames.contains(proposition)) {
- proposition+="x";
- }
- usedNames.add(proposition);
- return proposition;
- }
-
- public HashSet<String> getUsedNames() {
- return usedNames;
- }
-
+ private HashSet<String> usedNames = new HashSet<String>();
+
+ public VarNamesCollector() {
+ }
+
+ public VarNamesCollector(HashSet<String> setNames) {
+ usedNames.addAll(setNames);
+ }
+
+ public void addName(String value) {
+ usedNames.add(value);
+ }
+
+ public String getFreeName(int index) {
+ return getFreeName("var" + index);
+ }
+
+ public String getFreeName(String proposition) {
+
+ while (usedNames.contains(proposition)) {
+ proposition += "x";
+ }
+ usedNames.add(proposition);
+ return proposition;
+ }
+
+ public HashSet<String> getUsedNames() {
+ return usedNames;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java b/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java
index 408c430..995f8c2 100644
--- a/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java
+++ b/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java
@@ -1,37 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.decompiler;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipOutputStream;
-
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.Fernflower;
import org.jetbrains.java.decompiler.main.decompiler.helper.PrintStreamLogger;
@@ -40,284 +23,301 @@ import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.io.*;
+import java.util.*;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
public class ConsoleDecompiler implements IBytecodeProvider, IDecompilatSaver {
- private File root;
-
- private Fernflower fernflower;
-
- private HashMap<String, ZipOutputStream> mapArchiveStreams = new HashMap<String, ZipOutputStream>();
-
- private HashMap<String, HashSet<String>> mapArchiveEntries = new HashMap<String, HashSet<String>>();
-
- public ConsoleDecompiler() {
- this(null);
- }
-
- public ConsoleDecompiler(HashMap<String, Object> propertiesCustom) {
- this(new PrintStreamLogger(IFernflowerLogger.WARNING, System.out), propertiesCustom);
- }
-
- protected ConsoleDecompiler(IFernflowerLogger logger, HashMap<String, Object> propertiesCustom) {
- fernflower = new Fernflower(this, this, propertiesCustom);
- DecompilerContext.setLogger(logger);
- }
-
- public static void main(String[] args) {
-
- try {
-
- if(args != null && args.length > 1) {
-
- HashMap<String, Object> mapOptions = new HashMap<String, Object>();
-
- List<String> lstSources = new ArrayList<String>();
- List<String> lstLibraries = new ArrayList<String>();
-
- boolean isOption = true;
- for(int i = 0; i < args.length - 1; ++i) { // last parameter - destination
- String arg = args[i];
-
- if(isOption && arg.startsWith("-") &&
- arg.length()>5 && arg.charAt(4) == '=') {
- String value = arg.substring(5).toUpperCase();
- if("TRUE".equals(value)) {
- value = "1";
- } else if("FALSE".equals(value)) {
- value = "0";
- }
-
- mapOptions.put(arg.substring(1, 4), value);
- } else {
- isOption = false;
-
- if(arg.startsWith("-e=")) {
- lstLibraries.add(arg.substring(3));
- } else {
- lstSources.add(arg);
- }
- }
- }
-
- if(lstSources.isEmpty()) {
- printHelp();
- } else {
- ConsoleDecompiler decompiler = new ConsoleDecompiler(
- new PrintStreamLogger(IFernflowerLogger.INFO, System.out),
- mapOptions);
-
- for(String source : lstSources) {
- decompiler.addSpace(new File(source), true);
- }
-
- for(String library : lstLibraries) {
- decompiler.addSpace(new File(library), false);
- }
-
- decompiler.decompileContext(new File(args[args.length-1]));
- }
-
- } else {
- printHelp();
- }
-
- } catch(Exception ex) {
- ex.printStackTrace();
- }
-
- }
-
- private static void printHelp() {
- System.out.println("Usage: java ConsoleDecompiler ( -<option>=<value>)* (<source>)+ <destination>");
- System.out.println("Example: java ConsoleDecompiler -dgs=true c:\\mysource\\ c:\\my.jar d:\\decompiled\\");
- }
-
- public void addSpace(File file, boolean isOwn) throws IOException {
- fernflower.getStructcontext().addSpace(file, isOwn);
- }
-
- public void decompileContext(File root) {
- this.root = root;
- fernflower.decompileContext();
- }
-
- // *******************************************************************
- // Interface IBytecodeProvider
- // *******************************************************************
-
- public InputStream getBytecodeStream(String externPath, String internPath) {
-
- try {
- File file = new File(externPath);
-
- if(internPath == null) {
- return new FileInputStream(file);
- } else { // archive file
- ZipFile archive = new ZipFile(file);
-
- Enumeration<? extends ZipEntry> en = archive.entries();
- while(en.hasMoreElements()) {
- ZipEntry entr = en.nextElement();
-
- if(entr.getName().equals(internPath)) {
- return archive.getInputStream(entr);
- }
- }
- }
- } catch(IOException ex) {
- ex.printStackTrace();
- }
-
- return null;
- }
-
- // *******************************************************************
- // Interface IDecompilatSaver
- // *******************************************************************
-
- private String getAbsolutePath(String path) {
- return new File(root, path).getAbsolutePath();
- }
-
- private boolean addEntryName(String filename, String entry) {
- HashSet<String> set = mapArchiveEntries.get(filename);
- if(set == null) {
- mapArchiveEntries.put(filename, set = new HashSet<String>());
- }
-
- return set.add(entry);
- }
-
- public void copyEntry(String source, String destpath, String archivename, String entryName) {
-
- try {
- String filename = new File(getAbsolutePath(destpath), archivename).getAbsolutePath();
-
- if(!addEntryName(filename, entryName)) {
- DecompilerContext.getLogger().writeMessage("Zip entry already exists: "+
- destpath+","+archivename+","+entryName, IFernflowerLogger.WARNING);
- return;
- }
-
- ZipFile srcarchive = new ZipFile(new File(source));
-
- Enumeration<? extends ZipEntry> en = srcarchive.entries();
- while(en.hasMoreElements()) {
- ZipEntry entr = en.nextElement();
-
- if(entr.getName().equals(entryName)) {
- InputStream in = srcarchive.getInputStream(entr);
-
- ZipOutputStream out = mapArchiveStreams.get(filename);
- out.putNextEntry(new ZipEntry(entryName));
-
- InterpreterUtil.copyInputStream(in, out);
- in.close();
- }
- }
-
- srcarchive.close();
-
- } catch(IOException ex) {
- DecompilerContext.getLogger().writeMessage("Error copying zip file entry: "+source+","+destpath+","+archivename+","+entryName, IFernflowerLogger.WARNING);
- ex.printStackTrace();
- }
- }
-
- public void copyFile(String source, String destpath, String destfilename) {
- try {
- InterpreterUtil.copyFile(new File(source), new File(destfilename));
- } catch(IOException ex) {
- ex.printStackTrace();
- }
- }
-
- public void saveFile(String path, String filename, String content) {
- try {
- BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(getAbsolutePath(path), filename)), "UTF8"));
- out.write(content);
- out.flush();
- out.close();
- } catch(IOException ex) {
- ex.printStackTrace();
- }
- }
-
- public void createArchive(String path, String archivename, Manifest manifest) {
-
- try {
- File file = new File(getAbsolutePath(path), archivename);
- file.createNewFile();
-
- ZipOutputStream out;
- if(manifest != null) { // jar
- out = new JarOutputStream(new FileOutputStream(file), manifest);
- } else {
- out = new ZipOutputStream(new FileOutputStream(file));
- }
- mapArchiveStreams.put(file.getAbsolutePath(), out);
-
- } catch(IOException ex) {
- ex.printStackTrace();
- }
- }
-
- public void saveClassEntry(String path, String archivename,
- String qualifiedName, String entryName, String content) {
- saveEntry(path, archivename, entryName, content);
- }
-
- public void saveClassFile(String path, String qualifiedName, String entryName, String content) {
- saveFile(path, entryName, content);
- }
-
- public void saveEntry(String path, String archivename, String entryName,
- String content) {
-
- try {
- String filename = new File(getAbsolutePath(path), archivename).getAbsolutePath();
-
- if(!addEntryName(filename, entryName)) {
- DecompilerContext.getLogger().writeMessage("Zip entry already exists: "+
- path+","+archivename+","+entryName, IFernflowerLogger.WARNING);
- return;
- }
-
- ZipOutputStream out = mapArchiveStreams.get(filename);
- out.putNextEntry(new ZipEntry(entryName));
-
- if(content != null) {
- BufferedWriter outwriter = new BufferedWriter(new OutputStreamWriter(out, "UTF8"));
- outwriter.write(content);
- outwriter.flush();
- }
-
- } catch(IOException ex) {
- ex.printStackTrace();
- }
- }
-
- public void saveFolder(String path) {
- File f = new File(getAbsolutePath(path));
- f.mkdirs();
- }
-
-
- public void closeArchive(String path, String archivename) {
- try {
- String filename = new File(getAbsolutePath(path), archivename).getAbsolutePath();
-
- mapArchiveEntries.remove(filename);
- ZipOutputStream out = mapArchiveStreams.remove(filename);
-
- out.flush();
- out.close();
-
- } catch(IOException ex) {
- ex.printStackTrace();
- }
- }
-
-
+ private File root;
+
+ private Fernflower fernflower;
+
+ private HashMap<String, ZipOutputStream> mapArchiveStreams = new HashMap<String, ZipOutputStream>();
+
+ private HashMap<String, HashSet<String>> mapArchiveEntries = new HashMap<String, HashSet<String>>();
+
+ public ConsoleDecompiler() {
+ this(null);
+ }
+
+ public ConsoleDecompiler(HashMap<String, Object> propertiesCustom) {
+ this(new PrintStreamLogger(IFernflowerLogger.WARNING, System.out), propertiesCustom);
+ }
+
+ protected ConsoleDecompiler(IFernflowerLogger logger, HashMap<String, Object> propertiesCustom) {
+ fernflower = new Fernflower(this, this, propertiesCustom);
+ DecompilerContext.setLogger(logger);
+ }
+
+ public static void main(String[] args) {
+
+ try {
+
+ if (args != null && args.length > 1) {
+
+ HashMap<String, Object> mapOptions = new HashMap<String, Object>();
+
+ List<String> lstSources = new ArrayList<String>();
+ List<String> lstLibraries = new ArrayList<String>();
+
+ boolean isOption = true;
+ for (int i = 0; i < args.length - 1; ++i) { // last parameter - destination
+ String arg = args[i];
+
+ if (isOption && arg.startsWith("-") &&
+ arg.length() > 5 && arg.charAt(4) == '=') {
+ String value = arg.substring(5).toUpperCase();
+ if ("TRUE".equals(value)) {
+ value = "1";
+ }
+ else if ("FALSE".equals(value)) {
+ value = "0";
+ }
+
+ mapOptions.put(arg.substring(1, 4), value);
+ }
+ else {
+ isOption = false;
+
+ if (arg.startsWith("-e=")) {
+ lstLibraries.add(arg.substring(3));
+ }
+ else {
+ lstSources.add(arg);
+ }
+ }
+ }
+
+ if (lstSources.isEmpty()) {
+ printHelp();
+ }
+ else {
+ ConsoleDecompiler decompiler = new ConsoleDecompiler(
+ new PrintStreamLogger(IFernflowerLogger.INFO, System.out),
+ mapOptions);
+
+ for (String source : lstSources) {
+ decompiler.addSpace(new File(source), true);
+ }
+
+ for (String library : lstLibraries) {
+ decompiler.addSpace(new File(library), false);
+ }
+
+ decompiler.decompileContext(new File(args[args.length - 1]));
+ }
+ }
+ else {
+ printHelp();
+ }
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ private static void printHelp() {
+ System.out.println("Usage: java ConsoleDecompiler ( -<option>=<value>)* (<source>)+ <destination>");
+ System.out.println("Example: java ConsoleDecompiler -dgs=true c:\\mysource\\ c:\\my.jar d:\\decompiled\\");
+ }
+
+ public void addSpace(File file, boolean isOwn) throws IOException {
+ fernflower.getStructcontext().addSpace(file, isOwn);
+ }
+
+ public void decompileContext(File root) {
+ this.root = root;
+ fernflower.decompileContext();
+ }
+
+ // *******************************************************************
+ // Interface IBytecodeProvider
+ // *******************************************************************
+
+ public InputStream getBytecodeStream(String externPath, String internPath) {
+
+ try {
+ File file = new File(externPath);
+
+ if (internPath == null) {
+ return new FileInputStream(file);
+ }
+ else { // archive file
+ ZipFile archive = new ZipFile(file);
+
+ Enumeration<? extends ZipEntry> en = archive.entries();
+ while (en.hasMoreElements()) {
+ ZipEntry entr = en.nextElement();
+
+ if (entr.getName().equals(internPath)) {
+ return archive.getInputStream(entr);
+ }
+ }
+ }
+ }
+ catch (IOException ex) {
+ ex.printStackTrace();
+ }
+
+ return null;
+ }
+
+ // *******************************************************************
+ // Interface IDecompilatSaver
+ // *******************************************************************
+
+ private String getAbsolutePath(String path) {
+ return new File(root, path).getAbsolutePath();
+ }
+
+ private boolean addEntryName(String filename, String entry) {
+ HashSet<String> set = mapArchiveEntries.get(filename);
+ if (set == null) {
+ mapArchiveEntries.put(filename, set = new HashSet<String>());
+ }
+
+ return set.add(entry);
+ }
+
+ public void copyEntry(String source, String destpath, String archivename, String entryName) {
+
+ try {
+ String filename = new File(getAbsolutePath(destpath), archivename).getAbsolutePath();
+
+ if (!addEntryName(filename, entryName)) {
+ DecompilerContext.getLogger().writeMessage("Zip entry already exists: " +
+ destpath + "," + archivename + "," + entryName, IFernflowerLogger.WARNING);
+ return;
+ }
+
+ ZipFile srcarchive = new ZipFile(new File(source));
+
+ Enumeration<? extends ZipEntry> en = srcarchive.entries();
+ while (en.hasMoreElements()) {
+ ZipEntry entr = en.nextElement();
+
+ if (entr.getName().equals(entryName)) {
+ InputStream in = srcarchive.getInputStream(entr);
+
+ ZipOutputStream out = mapArchiveStreams.get(filename);
+ out.putNextEntry(new ZipEntry(entryName));
+
+ InterpreterUtil.copyInputStream(in, out);
+ in.close();
+ }
+ }
+
+ srcarchive.close();
+ }
+ catch (IOException ex) {
+ DecompilerContext.getLogger()
+ .writeMessage("Error copying zip file entry: " + source + "," + destpath + "," + archivename + "," + entryName,
+ IFernflowerLogger.WARNING);
+ ex.printStackTrace();
+ }
+ }
+
+ public void copyFile(String source, String destpath, String destfilename) {
+ try {
+ InterpreterUtil.copyFile(new File(source), new File(destfilename));
+ }
+ catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public void saveFile(String path, String filename, String content) {
+ try {
+ BufferedWriter out =
+ new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(getAbsolutePath(path), filename)), "UTF8"));
+ out.write(content);
+ out.flush();
+ out.close();
+ }
+ catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public void createArchive(String path, String archivename, Manifest manifest) {
+
+ try {
+ File file = new File(getAbsolutePath(path), archivename);
+ file.createNewFile();
+
+ ZipOutputStream out;
+ if (manifest != null) { // jar
+ out = new JarOutputStream(new FileOutputStream(file), manifest);
+ }
+ else {
+ out = new ZipOutputStream(new FileOutputStream(file));
+ }
+ mapArchiveStreams.put(file.getAbsolutePath(), out);
+ }
+ catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public void saveClassEntry(String path, String archivename,
+ String qualifiedName, String entryName, String content) {
+ saveEntry(path, archivename, entryName, content);
+ }
+
+ public void saveClassFile(String path, String qualifiedName, String entryName, String content) {
+ saveFile(path, entryName, content);
+ }
+
+ public void saveEntry(String path, String archivename, String entryName,
+ String content) {
+
+ try {
+ String filename = new File(getAbsolutePath(path), archivename).getAbsolutePath();
+
+ if (!addEntryName(filename, entryName)) {
+ DecompilerContext.getLogger().writeMessage("Zip entry already exists: " +
+ path + "," + archivename + "," + entryName, IFernflowerLogger.WARNING);
+ return;
+ }
+
+ ZipOutputStream out = mapArchiveStreams.get(filename);
+ out.putNextEntry(new ZipEntry(entryName));
+
+ if (content != null) {
+ BufferedWriter outwriter = new BufferedWriter(new OutputStreamWriter(out, "UTF8"));
+ outwriter.write(content);
+ outwriter.flush();
+ }
+ }
+ catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public void saveFolder(String path) {
+ File f = new File(getAbsolutePath(path));
+ f.mkdirs();
+ }
+
+
+ public void closeArchive(String path, String archivename) {
+ try {
+ String filename = new File(getAbsolutePath(path), archivename).getAbsolutePath();
+
+ mapArchiveEntries.remove(filename);
+ ZipOutputStream out = mapArchiveStreams.remove(filename);
+
+ out.flush();
+ out.close();
+ }
+ catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/decompiler/IdeDecompiler.java b/src/org/jetbrains/java/decompiler/main/decompiler/IdeDecompiler.java
index 07dd0f0..dab59e9 100644
--- a/src/org/jetbrains/java/decompiler/main/decompiler/IdeDecompiler.java
+++ b/src/org/jetbrains/java/decompiler/main/decompiler/IdeDecompiler.java
@@ -1,43 +1,43 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.decompiler;
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.Fernflower;
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+
public class IdeDecompiler {
- private Fernflower fernflower;
-
- public IdeDecompiler(IBytecodeProvider provider,
+ private Fernflower fernflower;
+
+ public IdeDecompiler(IBytecodeProvider provider,
IDecompilatSaver saver, IFernflowerLogger logger,
HashMap<String, Object> propertiesCustom) {
- fernflower = new Fernflower(provider, saver, propertiesCustom);
-
- DecompilerContext.setLogger(logger);
-
- }
+ fernflower = new Fernflower(provider, saver, propertiesCustom);
+
+ DecompilerContext.setLogger(logger);
+ }
public void addSpace(File file, boolean isOwn) throws IOException {
fernflower.getStructcontext().addSpace(file, isOwn);
@@ -46,9 +46,9 @@ public class IdeDecompiler {
public void decompileContext() {
try {
fernflower.decompileContext();
- } finally {
+ }
+ finally {
fernflower.clearContext();
}
}
-
}
diff --git a/src/org/jetbrains/java/decompiler/main/decompiler/WebDecompiler.java b/src/org/jetbrains/java/decompiler/main/decompiler/WebDecompiler.java
index 5f20c01..06e4c6f 100644
--- a/src/org/jetbrains/java/decompiler/main/decompiler/WebDecompiler.java
+++ b/src/org/jetbrains/java/decompiler/main/decompiler/WebDecompiler.java
@@ -1,78 +1,78 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.decompiler;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
-import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
-
public class WebDecompiler extends ConsoleDecompiler {
- private HashMap<String, File> mapInputFilenames = new HashMap<String, File>();
-
- private HashSet<String> setClassFiles = new HashSet<String>();
-
- private File root;
-
- public WebDecompiler(IFernflowerLogger logger, HashMap<String, Object> propertiesCustom) {
- super(logger, propertiesCustom);
- }
-
- @Override
- public void decompileContext(File root) {
- this.root = root;
- super.decompileContext(root);
- }
-
- @Override
- public void copyFile(String source, String destpath, String destfilename) {
- super.copyFile(source, destpath, destfilename);
- mapInputFilenames.put(destfilename, new File(getAbsolutePath(destpath), destfilename));
- }
-
- @Override
- public void saveFile(String path, String filename, String content) {
- super.saveFile(path, filename, content);
-
- mapInputFilenames.put(setClassFiles.contains(filename)?
- filename.substring(0, filename.lastIndexOf(".java"))+".class":
- filename, new File(getAbsolutePath(path), filename));
- }
-
- @Override
- public void saveClassFile(String path, String qualifiedName, String entryName, String content) {
- setClassFiles.add(entryName);
- saveFile(path, entryName, content);
- }
-
- @Override
- public void closeArchive(String path, String archivename) {
- super.closeArchive(path, archivename);
- mapInputFilenames.put(archivename, new File(getAbsolutePath(path), archivename));
- }
-
- private String getAbsolutePath(String path) {
- return new File(root, path).getAbsolutePath();
- }
-
- public HashMap<String, File> getMapInputFilenames() {
- return mapInputFilenames;
- }
-
+ private HashMap<String, File> mapInputFilenames = new HashMap<String, File>();
+
+ private HashSet<String> setClassFiles = new HashSet<String>();
+
+ private File root;
+
+ public WebDecompiler(IFernflowerLogger logger, HashMap<String, Object> propertiesCustom) {
+ super(logger, propertiesCustom);
+ }
+
+ @Override
+ public void decompileContext(File root) {
+ this.root = root;
+ super.decompileContext(root);
+ }
+
+ @Override
+ public void copyFile(String source, String destpath, String destfilename) {
+ super.copyFile(source, destpath, destfilename);
+ mapInputFilenames.put(destfilename, new File(getAbsolutePath(destpath), destfilename));
+ }
+
+ @Override
+ public void saveFile(String path, String filename, String content) {
+ super.saveFile(path, filename, content);
+
+ mapInputFilenames.put(setClassFiles.contains(filename) ?
+ filename.substring(0, filename.lastIndexOf(".java")) + ".class" :
+ filename, new File(getAbsolutePath(path), filename));
+ }
+
+ @Override
+ public void saveClassFile(String path, String qualifiedName, String entryName, String content) {
+ setClassFiles.add(entryName);
+ saveFile(path, entryName, content);
+ }
+
+ @Override
+ public void closeArchive(String path, String archivename) {
+ super.closeArchive(path, archivename);
+ mapInputFilenames.put(archivename, new File(getAbsolutePath(path), archivename));
+ }
+
+ private String getAbsolutePath(String path) {
+ return new File(root, path).getAbsolutePath();
+ }
+
+ public HashMap<String, File> getMapInputFilenames() {
+ return mapInputFilenames;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/decompiler/helper/PrintStreamLogger.java b/src/org/jetbrains/java/decompiler/main/decompiler/helper/PrintStreamLogger.java
index 6d03b34..3a6c7e8 100644
--- a/src/org/jetbrains/java/decompiler/main/decompiler/helper/PrintStreamLogger.java
+++ b/src/org/jetbrains/java/decompiler/main/decompiler/helper/PrintStreamLogger.java
@@ -1,83 +1,84 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.decompiler.helper;
-import java.io.PrintStream;
-
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.io.PrintStream;
+
public class PrintStreamLogger implements IFernflowerLogger {
- private int severity;
-
- private int indent;
-
- private PrintStream stream;
-
- public PrintStreamLogger(int severity, PrintStream stream) {
- this.severity = severity;
- this.indent = 0;
- this.stream = stream;
- }
-
-
- public void writeMessage(String message, int severity) {
- if (severity >= this.severity) {
- stream.println(InterpreterUtil.getIndentString(indent) + names[severity] + ": " + message);
- }
- }
-
- public void writeMessage(String message, Throwable t) {
- t.printStackTrace(stream);
- writeMessage(message, ERROR);
- }
-
- public void startClass(String classname) {
- stream.println(InterpreterUtil.getIndentString(indent++)+"Processing class "+classname+" ...");
- }
-
- public void endClass() {
- stream.println(InterpreterUtil.getIndentString(--indent)+"... proceeded.");
- }
-
- public void startWriteClass(String classname) {
- stream.println(InterpreterUtil.getIndentString(indent++)+"Writing class "+classname+" ...");
- }
-
- public void endWriteClass() {
- stream.println(InterpreterUtil.getIndentString(--indent)+"... written.");
- }
-
- public void startMethod(String method) {
- if(severity <= INFO) {
- stream.println(InterpreterUtil.getIndentString(indent)+"Processing method "+method+" ...");
- }
- }
-
- public void endMethod() {
- if(severity <= INFO) {
- stream.println(InterpreterUtil.getIndentString(indent)+"... proceeded.");
- }
- }
-
- public int getSeverity() {
- return severity;
- }
-
- public void setSeverity(int severity) {
- this.severity = severity;
- }
+ private int severity;
+
+ private int indent;
+
+ private PrintStream stream;
+
+ public PrintStreamLogger(int severity, PrintStream stream) {
+ this.severity = severity;
+ this.indent = 0;
+ this.stream = stream;
+ }
+
+
+ public void writeMessage(String message, int severity) {
+ if (severity >= this.severity) {
+ stream.println(InterpreterUtil.getIndentString(indent) + names[severity] + ": " + message);
+ }
+ }
+
+ public void writeMessage(String message, Throwable t) {
+ t.printStackTrace(stream);
+ writeMessage(message, ERROR);
+ }
+
+ public void startClass(String classname) {
+ stream.println(InterpreterUtil.getIndentString(indent++) + "Processing class " + classname + " ...");
+ }
+
+ public void endClass() {
+ stream.println(InterpreterUtil.getIndentString(--indent) + "... proceeded.");
+ }
+
+ public void startWriteClass(String classname) {
+ stream.println(InterpreterUtil.getIndentString(indent++) + "Writing class " + classname + " ...");
+ }
+
+ public void endWriteClass() {
+ stream.println(InterpreterUtil.getIndentString(--indent) + "... written.");
+ }
+
+ public void startMethod(String method) {
+ if (severity <= INFO) {
+ stream.println(InterpreterUtil.getIndentString(indent) + "Processing method " + method + " ...");
+ }
+ }
+
+ public void endMethod() {
+ if (severity <= INFO) {
+ stream.println(InterpreterUtil.getIndentString(indent) + "... proceeded.");
+ }
+ }
+
+ public int getSeverity() {
+ return severity;
+ }
+
+ public void setSeverity(int severity) {
+ this.severity = severity;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/extern/IBytecodeProvider.java b/src/org/jetbrains/java/decompiler/main/extern/IBytecodeProvider.java
index 6e13e51..7ff43fc 100644
--- a/src/org/jetbrains/java/decompiler/main/extern/IBytecodeProvider.java
+++ b/src/org/jetbrains/java/decompiler/main/extern/IBytecodeProvider.java
@@ -1,23 +1,23 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.extern;
import java.io.InputStream;
public interface IBytecodeProvider {
- public InputStream getBytecodeStream(String externPath, String internPath);
-
+ public InputStream getBytecodeStream(String externPath, String internPath);
}
diff --git a/src/org/jetbrains/java/decompiler/main/extern/IDecompilatSaver.java b/src/org/jetbrains/java/decompiler/main/extern/IDecompilatSaver.java
index 855f95c..0270b5e 100644
--- a/src/org/jetbrains/java/decompiler/main/extern/IDecompilatSaver.java
+++ b/src/org/jetbrains/java/decompiler/main/extern/IDecompilatSaver.java
@@ -1,39 +1,39 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.extern;
import java.util.jar.Manifest;
public interface IDecompilatSaver {
- public void copyFile(String source, String destpath, String destfilename);
+ public void copyFile(String source, String destpath, String destfilename);
+
+ public void saveFolder(String path);
+
+ public void saveClassFile(String path, String qualifiedName, String entryName, String content);
+
+ public void saveFile(String path, String filename, String content);
- public void saveFolder(String path);
-
- public void saveClassFile(String path, String qualifiedName, String entryName, String content);
+ public void createArchive(String path, String archivename, Manifest manifest);
- public void saveFile(String path, String filename, String content);
-
- public void createArchive(String path, String archivename, Manifest manifest);
+ public void saveClassEntry(String path, String archivename, String qualifiedName, String entryName, String content);
- public void saveClassEntry(String path, String archivename, String qualifiedName, String entryName, String content);
+ public void saveEntry(String path, String archivename, String entryName, String content);
- public void saveEntry(String path, String archivename, String entryName, String content);
+ public void copyEntry(String source, String destpath, String archivename, String entry);
- public void copyEntry(String source, String destpath, String archivename, String entry);
-
- public void closeArchive(String path, String archivename);
-
+ public void closeArchive(String path, String archivename);
}
diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerLogger.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerLogger.java
index eb1427c..c80039d 100644
--- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerLogger.java
+++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerLogger.java
@@ -1,56 +1,57 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.extern;
import java.util.HashMap;
public interface IFernflowerLogger {
- public static final int TRACE = 1;
- public static final int INFO = 2;
- public static final int WARNING = 3;
- public static final int ERROR = 4;
- public static final int IMMEDIATE = 5;
-
- public static final HashMap<String, Integer> mapLogLevel = new HashMap<String, Integer>() {{
- put("TRACE", 1);
- put("INFO", 2);
- put("WARN", 3);
- put("ERROR", 4);
- put("IMME", 5);
- }};
-
- public static final String[] names = new String[] {""/*DUMMY ENTRY*/, "TRACE", "INFO", "WARNING", "ERROR", ""/*IMMEDIATE*/};
-
- public void writeMessage(String message, int severity);
-
- public void writeMessage(String message, Throwable t);
-
- public void startClass(String classname);
-
- public void endClass();
-
- public void startWriteClass(String classname);
-
- public void endWriteClass();
-
- public void startMethod(String method);
-
- public void endMethod();
-
- public int getSeverity();
-
- public void setSeverity(int severity);
+ public static final int TRACE = 1;
+ public static final int INFO = 2;
+ public static final int WARNING = 3;
+ public static final int ERROR = 4;
+ public static final int IMMEDIATE = 5;
+
+ public static final HashMap<String, Integer> mapLogLevel = new HashMap<String, Integer>() {{
+ put("TRACE", 1);
+ put("INFO", 2);
+ put("WARN", 3);
+ put("ERROR", 4);
+ put("IMME", 5);
+ }};
+
+ public static final String[] names = new String[]{""/*DUMMY ENTRY*/, "TRACE", "INFO", "WARNING", "ERROR", ""/*IMMEDIATE*/};
+
+ public void writeMessage(String message, int severity);
+
+ public void writeMessage(String message, Throwable t);
+
+ public void startClass(String classname);
+
+ public void endClass();
+
+ public void startWriteClass(String classname);
+
+ public void endWriteClass();
+
+ public void startMethod(String method);
+
+ public void endMethod();
+
+ public int getSeverity();
+
+ public void setSeverity(int severity);
}
diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java
index 9f19127..2fcc5e1 100644
--- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java
+++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java
@@ -1,57 +1,58 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.extern;
public interface IFernflowerPreferences {
- public static final String REMOVE_BRIDGE = "rbr";
- public static final String REMOVE_SYNTHETIC = "rsy";
- public static final String DECOMPILE_INNER = "din";
- public static final String DECOMPILE_CLASS_1_4 = "dc4";
- public static final String DECOMPILE_ASSERTIONS = "das";
- public static final String HIDE_EMPTY_SUPER = "hes";
- public static final String HIDE_DEFAULT_CONSTRUCTOR = "hdc";
- public static final String DECOMPILE_GENERIC_SIGNATURES = "dgs";
- public static final String OUTPUT_COPYRIGHT_COMMENT = "occ";
- public static final String NO_EXCEPTIONS_RETURN = "ner";
- public static final String DECOMPILE_ENUM = "den";
- public static final String REMOVE_GETCLASS_NEW = "rgn";
- public static final String LITERALS_AS_IS = "lit";
- public static final String BOOLEAN_TRUE_ONE = "bto";
- public static final String SYNTHETIC_NOT_SET = "nns";
- public static final String UNDEFINED_PARAM_TYPE_OBJECT = "uto";
- public static final String USE_DEBUG_VARNAMES = "udv";
- public static final String MAX_PROCESSING_METHOD = "mpm";
- public static final String REMOVE_EMPTY_RANGES = "rer";
- public static final String ASCII_STRING_CHARACTERS = "asc";
-
- public static final String FINALLY_DEINLINE = "fdi";
-
- public static final String FINALLY_CATCHALL = "FINALLY_CATCHALL";
- public static final String FINALLY_SEMAPHOR = "FINALLY_SEMAPHOR";
-
- public static final String RENAME_ENTITIES = "ren";
- public static final String USER_RENAMER_CLASS = "urc";
-
- public static final String LOG_LEVEL = "log";
-
- public static final String NEW_LINE_SEPARATOR = "nls";
- public static final String IDEA_NOT_NULL_ANNOTATION = "inn";
- public static final String LAMBDA_TO_ANONYMOUS_CLASS = "lac";
+ public static final String REMOVE_BRIDGE = "rbr";
+ public static final String REMOVE_SYNTHETIC = "rsy";
+ public static final String DECOMPILE_INNER = "din";
+ public static final String DECOMPILE_CLASS_1_4 = "dc4";
+ public static final String DECOMPILE_ASSERTIONS = "das";
+ public static final String HIDE_EMPTY_SUPER = "hes";
+ public static final String HIDE_DEFAULT_CONSTRUCTOR = "hdc";
+ public static final String DECOMPILE_GENERIC_SIGNATURES = "dgs";
+ public static final String OUTPUT_COPYRIGHT_COMMENT = "occ";
+ public static final String NO_EXCEPTIONS_RETURN = "ner";
+ public static final String DECOMPILE_ENUM = "den";
+ public static final String REMOVE_GETCLASS_NEW = "rgn";
+ public static final String LITERALS_AS_IS = "lit";
+ public static final String BOOLEAN_TRUE_ONE = "bto";
+ public static final String SYNTHETIC_NOT_SET = "nns";
+ public static final String UNDEFINED_PARAM_TYPE_OBJECT = "uto";
+ public static final String USE_DEBUG_VARNAMES = "udv";
+ public static final String MAX_PROCESSING_METHOD = "mpm";
+ public static final String REMOVE_EMPTY_RANGES = "rer";
+ public static final String ASCII_STRING_CHARACTERS = "asc";
+
+ public static final String FINALLY_DEINLINE = "fdi";
+
+ public static final String FINALLY_CATCHALL = "FINALLY_CATCHALL";
+ public static final String FINALLY_SEMAPHOR = "FINALLY_SEMAPHOR";
+
+ public static final String RENAME_ENTITIES = "ren";
+ public static final String USER_RENAMER_CLASS = "urc";
+
+ public static final String LOG_LEVEL = "log";
+
+ public static final String NEW_LINE_SEPARATOR = "nls";
+ public static final String IDEA_NOT_NULL_ANNOTATION = "inn";
+ public static final String LAMBDA_TO_ANONYMOUS_CLASS = "lac";
public static final String INDENT_STRING = "ind";
- public static final String LINE_SEPARATOR_WIN = "\r\n";
- public static final String LINE_SEPARATOR_LIN = "\n";
+ public static final String LINE_SEPARATOR_WIN = "\r\n";
+ public static final String LINE_SEPARATOR_LIN = "\n";
}
diff --git a/src/org/jetbrains/java/decompiler/main/extern/IIdentifierRenamer.java b/src/org/jetbrains/java/decompiler/main/extern/IIdentifierRenamer.java
index f379da6..88b1ca4 100644
--- a/src/org/jetbrains/java/decompiler/main/extern/IIdentifierRenamer.java
+++ b/src/org/jetbrains/java/decompiler/main/extern/IIdentifierRenamer.java
@@ -1,20 +1,35 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.main.extern;
public interface IIdentifierRenamer {
- public static final int ELEMENT_CLASS = 1;
-
- public static final int ELEMENT_FIELD = 2;
+ public static final int ELEMENT_CLASS = 1;
- public static final int ELEMENT_METHOD = 3;
-
-
- public boolean toBeRenamed(int element_type, String classname, String element, String descriptor);
-
- public String getNextClassname(String fullname, String shortname);
-
- public String getNextFieldname(String classname, String field, String descriptor);
+ public static final int ELEMENT_FIELD = 2;
- public String getNextMethodname(String classname, String method, String descriptor);
+ public static final int ELEMENT_METHOD = 3;
+
+
+ public boolean toBeRenamed(int element_type, String classname, String element, String descriptor);
+
+ public String getNextClassname(String fullname, String shortname);
+
+ public String getNextFieldname(String classname, String field, String descriptor);
+
+ public String getNextMethodname(String classname, String method, String descriptor);
}
diff --git a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java
index dcbeaea..f0e8591 100644
--- a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java
+++ b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java
@@ -1,22 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.rels;
-import java.io.IOException;
-import java.util.HashSet;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
@@ -36,181 +34,191 @@ import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.io.IOException;
+import java.util.HashSet;
+
public class ClassWrapper {
- private StructClass classStruct;
-
- private HashSet<String> hideMembers = new HashSet<String>();
-
- private VBStyleCollection<Exprent, String> staticFieldInitializers = new VBStyleCollection<Exprent, String>();
-
- private VBStyleCollection<Exprent, String> dynamicFieldInitializers = new VBStyleCollection<Exprent, String>();
-
- private VBStyleCollection<MethodWrapper, String> methods = new VBStyleCollection<MethodWrapper, String>();
-
-
- public ClassWrapper(StructClass classStruct) {
- this.classStruct = classStruct;
- }
-
- @SuppressWarnings("deprecation")
- public void init() throws IOException {
-
- DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS, classStruct);
-
- DecompilerContext.getLogger().startClass(classStruct.qualifiedName);
-
- // collect field names
- HashSet<String> setFieldNames = new HashSet<String>();
- for(StructField fd: classStruct.getFields()) {
- setFieldNames.add(fd.getName());
- }
-
- for(StructMethod mt: classStruct.getMethods()) {
-
- DecompilerContext.getLogger().startMethod(mt.getName()+" "+mt.getDescriptor());
-
- VarNamesCollector vc = new VarNamesCollector();
- DecompilerContext.setVarncollector(vc);
-
- CounterContainer counter = new CounterContainer();
- DecompilerContext.setCountercontainer(counter);
-
- DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD, mt);
- DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR, MethodDescriptor.parseDescriptor(mt.getDescriptor()));
-
- VarProcessor varproc = new VarProcessor();
- DecompilerContext.setProperty(DecompilerContext.CURRENT_VAR_PROCESSOR, varproc);
-
- Thread mtthread = null;
- RootStatement root = null;
-
- boolean isError = false;
-
- try {
- if(mt.containsCode()) {
-
- int maxsec = 10 * Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());
-
- if(maxsec == 0) { // blocking wait
- root = MethodProcessorThread.codeToJava(mt, varproc);
- } else {
- MethodProcessorThread mtproc = new MethodProcessorThread(mt, varproc, DecompilerContext.getCurrentContext());
- mtthread = new Thread(mtproc);
-
- mtthread.start();
-
- int sec = 0;
- while(mtthread.isAlive()) {
-
- synchronized(mtproc) {
- mtproc.wait(100);
- }
-
- if(maxsec > 0 && ++sec > maxsec) {
- DecompilerContext.getLogger().writeMessage("Processing time limit ("+maxsec+" sec.) for method " +
- mt.getName()+" "+mt.getDescriptor()+ " exceeded, execution interrupted.", IFernflowerLogger.ERROR);
- mtthread.stop();
- isError = true;
- break;
- }
- }
-
- if(!isError) {
- if(mtproc.getError() != null) {
- throw mtproc.getError();
- } else {
- root = mtproc.getRoot();
- }
- }
- }
-
- } else {
- boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
-
- int paramcount = 0;
- if(thisvar) {
- varproc.getThisvars().put(new VarVersionPaar(0,0), classStruct.qualifiedName);
- paramcount = 1;
- }
- paramcount += md.params.length;
-
- int varindex = 0;
- for(int i=0;i<paramcount;i++) {
- varproc.setVarName(new VarVersionPaar(varindex, 0), vc.getFreeName(varindex));
-
- if(thisvar) {
- if(i==0) {
- varindex++;
- } else {
- varindex+=md.params[i-1].stack_size;
- }
- } else {
- varindex+=md.params[i].stack_size;
- }
- }
- }
-
- } catch(ThreadDeath ex) {
- try {
- if(mtthread != null) {
- mtthread.stop();
- }
- } catch(Throwable ignored) { }
-
- throw ex;
- } catch(Throwable ex) {
- DecompilerContext.getLogger().writeMessage("Method "+mt.getName()+" "+mt.getDescriptor()+" couldn't be decompiled.", ex);
- isError = true;
- }
-
- MethodWrapper meth = new MethodWrapper(root, varproc, mt, counter);
- meth.decompiledWithErrors = isError;
-
- methods.addWithKey(meth, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
-
- // rename vars so that no one has the same name as a field
- varproc.refreshVarNames(new VarNamesCollector(setFieldNames));
-
- // if debug information present and should be used
- if(DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VARNAMES)) {
- StructLocalVariableTableAttribute attr = (StructLocalVariableTableAttribute)mt.getAttributes().getWithKey(
- StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE);
-
- if(attr != null) {
- varproc.setDebugVarNames(attr.getMapVarNames());
- }
- }
-
- DecompilerContext.getLogger().endMethod();
- }
-
- DecompilerContext.getLogger().endClass();
- }
-
- public MethodWrapper getMethodWrapper(String name, String descriptor) {
- return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
- }
-
- public StructClass getClassStruct() {
- return classStruct;
- }
-
- public VBStyleCollection<MethodWrapper, String> getMethods() {
- return methods;
- }
-
- public HashSet<String> getHideMembers() {
- return hideMembers;
- }
-
- public VBStyleCollection<Exprent, String> getStaticFieldInitializers() {
- return staticFieldInitializers;
- }
-
- public VBStyleCollection<Exprent, String> getDynamicFieldInitializers() {
- return dynamicFieldInitializers;
- }
+ private StructClass classStruct;
+
+ private HashSet<String> hideMembers = new HashSet<String>();
+
+ private VBStyleCollection<Exprent, String> staticFieldInitializers = new VBStyleCollection<Exprent, String>();
+
+ private VBStyleCollection<Exprent, String> dynamicFieldInitializers = new VBStyleCollection<Exprent, String>();
+
+ private VBStyleCollection<MethodWrapper, String> methods = new VBStyleCollection<MethodWrapper, String>();
+
+
+ public ClassWrapper(StructClass classStruct) {
+ this.classStruct = classStruct;
+ }
+
+ @SuppressWarnings("deprecation")
+ public void init() throws IOException {
+
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS, classStruct);
+
+ DecompilerContext.getLogger().startClass(classStruct.qualifiedName);
+ // collect field names
+ HashSet<String> setFieldNames = new HashSet<String>();
+ for (StructField fd : classStruct.getFields()) {
+ setFieldNames.add(fd.getName());
+ }
+
+ for (StructMethod mt : classStruct.getMethods()) {
+
+ DecompilerContext.getLogger().startMethod(mt.getName() + " " + mt.getDescriptor());
+
+ VarNamesCollector vc = new VarNamesCollector();
+ DecompilerContext.setVarncollector(vc);
+
+ CounterContainer counter = new CounterContainer();
+ DecompilerContext.setCountercontainer(counter);
+
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD, mt);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR, MethodDescriptor.parseDescriptor(mt.getDescriptor()));
+
+ VarProcessor varproc = new VarProcessor();
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_VAR_PROCESSOR, varproc);
+
+ Thread mtthread = null;
+ RootStatement root = null;
+
+ boolean isError = false;
+
+ try {
+ if (mt.containsCode()) {
+
+ int maxsec = 10 * Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());
+
+ if (maxsec == 0) { // blocking wait
+ root = MethodProcessorThread.codeToJava(mt, varproc);
+ }
+ else {
+ MethodProcessorThread mtproc = new MethodProcessorThread(mt, varproc, DecompilerContext.getCurrentContext());
+ mtthread = new Thread(mtproc);
+
+ mtthread.start();
+
+ int sec = 0;
+ while (mtthread.isAlive()) {
+
+ synchronized (mtproc) {
+ mtproc.wait(100);
+ }
+
+ if (maxsec > 0 && ++sec > maxsec) {
+ DecompilerContext.getLogger().writeMessage("Processing time limit (" + maxsec + " sec.) for method " +
+ mt.getName() + " " + mt.getDescriptor() + " exceeded, execution interrupted.",
+ IFernflowerLogger.ERROR);
+ mtthread.stop();
+ isError = true;
+ break;
+ }
+ }
+
+ if (!isError) {
+ if (mtproc.getError() != null) {
+ throw mtproc.getError();
+ }
+ else {
+ root = mtproc.getRoot();
+ }
+ }
+ }
+ }
+ else {
+ boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int paramcount = 0;
+ if (thisvar) {
+ varproc.getThisvars().put(new VarVersionPaar(0, 0), classStruct.qualifiedName);
+ paramcount = 1;
+ }
+ paramcount += md.params.length;
+
+ int varindex = 0;
+ for (int i = 0; i < paramcount; i++) {
+ varproc.setVarName(new VarVersionPaar(varindex, 0), vc.getFreeName(varindex));
+
+ if (thisvar) {
+ if (i == 0) {
+ varindex++;
+ }
+ else {
+ varindex += md.params[i - 1].stack_size;
+ }
+ }
+ else {
+ varindex += md.params[i].stack_size;
+ }
+ }
+ }
+ }
+ catch (ThreadDeath ex) {
+ try {
+ if (mtthread != null) {
+ mtthread.stop();
+ }
+ }
+ catch (Throwable ignored) {
+ }
+
+ throw ex;
+ }
+ catch (Throwable ex) {
+ DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be decompiled.", ex);
+ isError = true;
+ }
+
+ MethodWrapper meth = new MethodWrapper(root, varproc, mt, counter);
+ meth.decompiledWithErrors = isError;
+
+ methods.addWithKey(meth, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
+
+ // rename vars so that no one has the same name as a field
+ varproc.refreshVarNames(new VarNamesCollector(setFieldNames));
+
+ // if debug information present and should be used
+ if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VARNAMES)) {
+ StructLocalVariableTableAttribute attr = (StructLocalVariableTableAttribute)mt.getAttributes().getWithKey(
+ StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE);
+
+ if (attr != null) {
+ varproc.setDebugVarNames(attr.getMapVarNames());
+ }
+ }
+
+ DecompilerContext.getLogger().endMethod();
+ }
+
+ DecompilerContext.getLogger().endClass();
+ }
+
+ public MethodWrapper getMethodWrapper(String name, String descriptor) {
+ return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
+ }
+
+ public StructClass getClassStruct() {
+ return classStruct;
+ }
+
+ public VBStyleCollection<MethodWrapper, String> getMethods() {
+ return methods;
+ }
+
+ public HashSet<String> getHideMembers() {
+ return hideMembers;
+ }
+
+ public VBStyleCollection<Exprent, String> getStaticFieldInitializers() {
+ return staticFieldInitializers;
+ }
+
+ public VBStyleCollection<Exprent, String> getDynamicFieldInitializers() {
+ return dynamicFieldInitializers;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java
index bf5f72f..3d42bda 100644
--- a/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java
+++ b/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java
@@ -1,12 +1,20 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.main.rels;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.code.Instruction;
import org.jetbrains.java.decompiler.code.InstructionSequence;
@@ -23,116 +31,121 @@ import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.io.IOException;
+import java.util.*;
+
public class LambdaProcessor {
- private static final String JAVAC_LAMBDA_CLASS = "java/lang/invoke/LambdaMetafactory";
- private static final String JAVAC_LAMBDA_METHOD = "metafactory";
- private static final String JAVAC_LAMBDA_METHOD_DESCRIPTOR = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;";
-
- public void processClass(ClassNode node) throws IOException {
-
- for(ClassNode child : node.nested) {
- processClass(child);
- }
-
- if(node.nested.isEmpty()) {
- hasLambda(node);
- }
- }
-
- public boolean hasLambda(ClassNode node) throws IOException {
-
- ClassesProcessor clprocessor = DecompilerContext.getClassprocessor();
- StructClass cl = node.classStruct;
-
- if(cl.getBytecodeVersion() < CodeConstants.BYTECODE_JAVA_8) { // lamda beginning with Java 8
- return false;
- }
-
- StructBootstrapMethodsAttribute bootstrap = (StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
- if(bootstrap == null || bootstrap.getMethodsNumber() == 0) {
- return false; // no bootstrap constants in pool
- }
-
- Set<Integer> lambda_methods = new HashSet<Integer>();
-
- // find lambda bootstrap constants
- for(int i = 0; i < bootstrap.getMethodsNumber(); ++i) {
- LinkConstant method_ref = bootstrap.getMethodReference(i); // method handle
-
- if(JAVAC_LAMBDA_CLASS.equals(method_ref.classname) &&
- JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) &&
- JAVAC_LAMBDA_METHOD_DESCRIPTOR.equals(method_ref.descriptor)) { // check for javac lambda structure. FIXME: extend for Eclipse etc. at some point
- lambda_methods.add(i);
- }
- }
-
- if(lambda_methods.isEmpty()) {
- return false; // no lambda bootstrap constant found
- }
-
- Map<String, String> mapMethodsLambda = new HashMap<String, String>();
-
- // iterate over code and find invocations of bootstrap methods. Replace them with anonymous classes.
- for(StructMethod mt: cl.getMethods()) {
- mt.expandData();
-
- InstructionSequence seq = mt.getInstructionSequence();
- if(seq != null && seq.length() > 0) {
- int len = seq.length();
-
- for(int i = 0; i < len; ++i) {
- Instruction instr = seq.getInstr(i);
-
- if(instr.opcode == CodeConstants.opc_invokedynamic) {
- LinkConstant invoke_dynamic = cl.getPool().getLinkConstant(instr.getOperand(0));
-
- if(lambda_methods.contains(invoke_dynamic.index1)) { // lambda invocation found
-
- List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_dynamic.index1);
- MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.descriptor);
-
- String lambda_class_name = md.ret.value;
- String lambda_method_name = invoke_dynamic.elementname;
- String lambda_method_descriptor = ((PrimitiveConstant)bootstrap_arguments.get(2)).getString(); // method type
-
- LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments.get(1);
-
- ClassNode node_lambda = clprocessor.new ClassNode(content_method_handle.classname, content_method_handle.elementname,
- content_method_handle.descriptor, content_method_handle.index1,
- lambda_class_name, lambda_method_name, lambda_method_descriptor, cl);
- node_lambda.simpleName = cl.qualifiedName + "##Lambda_" + invoke_dynamic.index1 + "_" + invoke_dynamic.index2;
- node_lambda.enclosingMethod = InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor());
-
- node.nested.add(node_lambda);
- node_lambda.parent = node;
-
- clprocessor.getMapRootClasses().put(node_lambda.simpleName, node_lambda);
- mapMethodsLambda.put(node_lambda.lambda_information.content_method_key, node_lambda.simpleName);
- }
- }
- }
- }
-
- mt.releaseResources();
- }
-
- // build class hierarchy on lambda
- for(ClassNode nd : node.nested) {
- if(nd.type == ClassNode.CLASS_LAMBDA) {
- String parent_class_name = mapMethodsLambda.get(nd.enclosingMethod);
- if(parent_class_name != null) {
- ClassNode parent_class = clprocessor.getMapRootClasses().get(parent_class_name);
-
- parent_class.nested.add(nd);
- nd.parent = parent_class;
- }
- }
- }
-
- // FIXME: mixed hierarchy?
-
- return false;
- }
-
+ private static final String JAVAC_LAMBDA_CLASS = "java/lang/invoke/LambdaMetafactory";
+ private static final String JAVAC_LAMBDA_METHOD = "metafactory";
+ private static final String JAVAC_LAMBDA_METHOD_DESCRIPTOR =
+ "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;";
+
+ public void processClass(ClassNode node) throws IOException {
+
+ for (ClassNode child : node.nested) {
+ processClass(child);
+ }
+
+ if (node.nested.isEmpty()) {
+ hasLambda(node);
+ }
+ }
+
+ public boolean hasLambda(ClassNode node) throws IOException {
+
+ ClassesProcessor clprocessor = DecompilerContext.getClassprocessor();
+ StructClass cl = node.classStruct;
+
+ if (cl.getBytecodeVersion() < CodeConstants.BYTECODE_JAVA_8) { // lamda beginning with Java 8
+ return false;
+ }
+
+ StructBootstrapMethodsAttribute bootstrap =
+ (StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
+ if (bootstrap == null || bootstrap.getMethodsNumber() == 0) {
+ return false; // no bootstrap constants in pool
+ }
+
+ Set<Integer> lambda_methods = new HashSet<Integer>();
+
+ // find lambda bootstrap constants
+ for (int i = 0; i < bootstrap.getMethodsNumber(); ++i) {
+ LinkConstant method_ref = bootstrap.getMethodReference(i); // method handle
+
+ if (JAVAC_LAMBDA_CLASS.equals(method_ref.classname) &&
+ JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) &&
+ JAVAC_LAMBDA_METHOD_DESCRIPTOR
+ .equals(method_ref.descriptor)) { // check for javac lambda structure. FIXME: extend for Eclipse etc. at some point
+ lambda_methods.add(i);
+ }
+ }
+
+ if (lambda_methods.isEmpty()) {
+ return false; // no lambda bootstrap constant found
+ }
+
+ Map<String, String> mapMethodsLambda = new HashMap<String, String>();
+
+ // iterate over code and find invocations of bootstrap methods. Replace them with anonymous classes.
+ for (StructMethod mt : cl.getMethods()) {
+ mt.expandData();
+
+ InstructionSequence seq = mt.getInstructionSequence();
+ if (seq != null && seq.length() > 0) {
+ int len = seq.length();
+
+ for (int i = 0; i < len; ++i) {
+ Instruction instr = seq.getInstr(i);
+
+ if (instr.opcode == CodeConstants.opc_invokedynamic) {
+ LinkConstant invoke_dynamic = cl.getPool().getLinkConstant(instr.getOperand(0));
+
+ if (lambda_methods.contains(invoke_dynamic.index1)) { // lambda invocation found
+
+ List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_dynamic.index1);
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.descriptor);
+
+ String lambda_class_name = md.ret.value;
+ String lambda_method_name = invoke_dynamic.elementname;
+ String lambda_method_descriptor = ((PrimitiveConstant)bootstrap_arguments.get(2)).getString(); // method type
+
+ LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments.get(1);
+
+ ClassNode node_lambda = clprocessor.new ClassNode(content_method_handle.classname, content_method_handle.elementname,
+ content_method_handle.descriptor, content_method_handle.index1,
+ lambda_class_name, lambda_method_name, lambda_method_descriptor, cl);
+ node_lambda.simpleName = cl.qualifiedName + "##Lambda_" + invoke_dynamic.index1 + "_" + invoke_dynamic.index2;
+ node_lambda.enclosingMethod = InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor());
+
+ node.nested.add(node_lambda);
+ node_lambda.parent = node;
+
+ clprocessor.getMapRootClasses().put(node_lambda.simpleName, node_lambda);
+ mapMethodsLambda.put(node_lambda.lambda_information.content_method_key, node_lambda.simpleName);
+ }
+ }
+ }
+ }
+
+ mt.releaseResources();
+ }
+
+ // build class hierarchy on lambda
+ for (ClassNode nd : node.nested) {
+ if (nd.type == ClassNode.CLASS_LAMBDA) {
+ String parent_class_name = mapMethodsLambda.get(nd.enclosingMethod);
+ if (parent_class_name != null) {
+ ClassNode parent_class = clprocessor.getMapRootClasses().get(parent_class_name);
+
+ parent_class.nested.add(nd);
+ nd.parent = parent_class;
+ }
+ }
+ }
+
+ // FIXME: mixed hierarchy?
+
+ return false;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorThread.java b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorThread.java
index c3c180b..038e057 100644
--- a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorThread.java
+++ b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorThread.java
@@ -1,21 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.rels;
-import java.io.IOException;
-
import org.jetbrains.java.decompiler.code.InstructionSequence;
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
import org.jetbrains.java.decompiler.main.DecompilerContext;
@@ -23,252 +22,239 @@ import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.ClearStructHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.DomHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.ExitHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
-import org.jetbrains.java.decompiler.modules.decompiler.FinallyProcessor;
-import org.jetbrains.java.decompiler.modules.decompiler.IdeaNotNullHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.IfHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.InlineSingleBlockHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.LabelHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.LoopExtractHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.MergeHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.PPandMMHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.SecondaryFunctionsHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.SequenceHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.StackVarsProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.*;
import org.jetbrains.java.decompiler.modules.decompiler.deobfuscator.ExceptionDeobfuscator;
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructMethod;
+import java.io.IOException;
+
public class MethodProcessorThread implements Runnable {
- private StructMethod method;
- private VarProcessor varproc;
- private DecompilerContext parentContext;
-
- private RootStatement root;
-
- private Throwable error;
-
- public MethodProcessorThread(StructMethod method, VarProcessor varproc,
- DecompilerContext parentContext) {
- this.method = method;
- this.varproc = varproc;
- this.parentContext = parentContext;
- }
-
- public void run() {
-
- DecompilerContext.setCurrentContext(parentContext);
-
- error = null;
- root = null;
-
- try {
- root = codeToJava(method, varproc);
-
- synchronized(this) {
- this.notify();
- }
-
- } catch(ThreadDeath ex) {
- ;
- } catch(Throwable ex) {
- error = ex;
- }
-
- }
-
- public static RootStatement codeToJava(StructMethod mt, VarProcessor varproc) throws IOException {
-
- StructClass cl = mt.getClassStruct();
-
- boolean isInitializer = "<clinit>".equals(mt.getName()); // for now static initializer only
-
- mt.expandData();
- InstructionSequence seq = mt.getInstructionSequence();
- ControlFlowGraph graph = new ControlFlowGraph(seq);
-
-// System.out.println(graph.toString());
-
-
-// if(mt.getName().endsWith("_getActiveServers")) {
-// System.out.println();
-// }
-
- //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern1.dot"), true);
-
- DeadCodeHelper.removeDeadBlocks(graph);
- graph.inlineJsr(mt);
-
-// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern4.dot"), true);
-
- // TODO: move to the start, before jsr inlining
- DeadCodeHelper.connectDummyExitBlock(graph);
-
- DeadCodeHelper.removeGotos(graph);
- ExceptionDeobfuscator.removeCircularRanges(graph);
- //DeadCodeHelper.removeCircularRanges(graph);
-
-
-// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
-
- ExceptionDeobfuscator.restorePopRanges(graph);
-
- if(DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) {
- ExceptionDeobfuscator.removeEmptyRanges(graph);
- }
-
-// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
-
- if(DecompilerContext.getOption(IFernflowerPreferences.NO_EXCEPTIONS_RETURN)) {
- // special case: single return instruction outside of a protected range
- DeadCodeHelper.incorporateValueReturns(graph);
- }
-
-// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
-
-// ExceptionDeobfuscator.restorePopRanges(graph);
- ExceptionDeobfuscator.insertEmptyExceptionHandlerBlocks(graph);
-
- DeadCodeHelper.mergeBasicBlocks(graph);
-
- DecompilerContext.getCountercontainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables());
-
- //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
- //System.out.println(graph.toString());
-
- if(ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
- DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.WARNING);
- }
-
- RootStatement root = DomHelper.parseGraph(graph);
-
- if(!DecompilerContext.getOption(IFernflowerPreferences.FINALLY_CATCHALL)) {
- FinallyProcessor fproc = new FinallyProcessor(varproc);
- while(fproc.iterateGraph(mt, root, graph)) {
-
- //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern2.dot"), true);
- //System.out.println(graph.toString());
-
- //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
-
- root = DomHelper.parseGraph(graph);
- }
- }
-
- // remove synchronized exception handler
- // not until now because of comparison between synchronized statements in the finally cycle
- DomHelper.removeSynchronizedHandler(root);
-
-// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
-// System.out.println(graph.toString());
-
-// LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
-
- SequenceHelper.condenseSequences(root);
-
- ClearStructHelper.clearStatements(root);
-
- ExprProcessor proc = new ExprProcessor();
- proc.processStatement(root, cl);
-
-// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
-// System.out.println(graph.toString());
-
- //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
-
- for(;;) {
- StackVarsProcessor stackproc = new StackVarsProcessor();
- stackproc.simplifyStackVars(root, mt, cl);
-
- //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
-
- varproc.setVarVersions(root);
-
-// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
-
- if(!new PPandMMHelper().findPPandMM(root)) {
- break;
- }
- }
-
- for(;;) {
-
- LabelHelper.cleanUpEdges(root);
-
- for(;;) {
-
- MergeHelper.enhanceLoops(root);
-
- if(LoopExtractHelper.extractLoops(root)) {
- continue;
- }
-
- if(!IfHelper.mergeAllIfs(root)) {
- break;
- }
- }
-
- if(DecompilerContext.getOption(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION)) {
-
- if(IdeaNotNullHelper.removeHardcodedChecks(root, mt)) {
-
- SequenceHelper.condenseSequences(root);
-
- StackVarsProcessor stackproc = new StackVarsProcessor();
- stackproc.simplifyStackVars(root, mt, cl);
-
- varproc.setVarVersions(root);
- }
- }
-
- LabelHelper.identifyLabels(root);
-
-// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
-
- if(InlineSingleBlockHelper.inlineSingleBlocks(root)) {
- continue;
- }
-
- // initializer may have at most one return point, so no transformation of method exits permitted
- if(isInitializer || !ExitHelper.condenseExits(root)) {
- break;
- }
-
- // FIXME: !!
-// if(!EliminateLoopsHelper.eliminateLoops(root)) {
-// break;
-// }
- }
-
- ExitHelper.removeRedundantReturns(root);
-
- SecondaryFunctionsHelper.identifySecondaryFunctions(root);
-
- varproc.setVarDefinitions(root);
-
- // must be the last invocation, because it makes the statement structure inconsistent
- // FIXME: new edge type needed
- LabelHelper.replaceContinueWithBreak(root);
-
- mt.releaseResources();
-
-// System.out.println("++++++++++++++++++++++/// \r\n"+root.toJava());
-
- return root;
- }
-
- public RootStatement getRoot() {
- return root;
- }
-
- public Throwable getError() {
- return error;
- }
-
+ private StructMethod method;
+ private VarProcessor varproc;
+ private DecompilerContext parentContext;
+
+ private RootStatement root;
+
+ private Throwable error;
+
+ public MethodProcessorThread(StructMethod method, VarProcessor varproc,
+ DecompilerContext parentContext) {
+ this.method = method;
+ this.varproc = varproc;
+ this.parentContext = parentContext;
+ }
+
+ public void run() {
+
+ DecompilerContext.setCurrentContext(parentContext);
+
+ error = null;
+ root = null;
+
+ try {
+ root = codeToJava(method, varproc);
+
+ synchronized (this) {
+ this.notify();
+ }
+ }
+ catch (ThreadDeath ex) {
+ ;
+ }
+ catch (Throwable ex) {
+ error = ex;
+ }
+ }
+
+ public static RootStatement codeToJava(StructMethod mt, VarProcessor varproc) throws IOException {
+
+ StructClass cl = mt.getClassStruct();
+
+ boolean isInitializer = "<clinit>".equals(mt.getName()); // for now static initializer only
+
+ mt.expandData();
+ InstructionSequence seq = mt.getInstructionSequence();
+ ControlFlowGraph graph = new ControlFlowGraph(seq);
+
+ // System.out.println(graph.toString());
+
+
+ // if(mt.getName().endsWith("_getActiveServers")) {
+ // System.out.println();
+ // }
+
+ //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern1.dot"), true);
+
+ DeadCodeHelper.removeDeadBlocks(graph);
+ graph.inlineJsr(mt);
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern4.dot"), true);
+
+ // TODO: move to the start, before jsr inlining
+ DeadCodeHelper.connectDummyExitBlock(graph);
+
+ DeadCodeHelper.removeGotos(graph);
+ ExceptionDeobfuscator.removeCircularRanges(graph);
+ //DeadCodeHelper.removeCircularRanges(graph);
+
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
+
+ ExceptionDeobfuscator.restorePopRanges(graph);
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) {
+ ExceptionDeobfuscator.removeEmptyRanges(graph);
+ }
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.NO_EXCEPTIONS_RETURN)) {
+ // special case: single return instruction outside of a protected range
+ DeadCodeHelper.incorporateValueReturns(graph);
+ }
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
+
+ // ExceptionDeobfuscator.restorePopRanges(graph);
+ ExceptionDeobfuscator.insertEmptyExceptionHandlerBlocks(graph);
+
+ DeadCodeHelper.mergeBasicBlocks(graph);
+
+ DecompilerContext.getCountercontainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables());
+
+ //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
+ //System.out.println(graph.toString());
+
+ if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
+ DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.WARNING);
+ }
+
+ RootStatement root = DomHelper.parseGraph(graph);
+
+ if (!DecompilerContext.getOption(IFernflowerPreferences.FINALLY_CATCHALL)) {
+ FinallyProcessor fproc = new FinallyProcessor(varproc);
+ while (fproc.iterateGraph(mt, root, graph)) {
+
+ //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern2.dot"), true);
+ //System.out.println(graph.toString());
+
+ //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ root = DomHelper.parseGraph(graph);
+ }
+ }
+
+ // remove synchronized exception handler
+ // not until now because of comparison between synchronized statements in the finally cycle
+ DomHelper.removeSynchronizedHandler(root);
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
+ // System.out.println(graph.toString());
+
+ // LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
+
+ SequenceHelper.condenseSequences(root);
+
+ ClearStructHelper.clearStatements(root);
+
+ ExprProcessor proc = new ExprProcessor();
+ proc.processStatement(root, cl);
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
+ // System.out.println(graph.toString());
+
+ //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ for (; ; ) {
+ StackVarsProcessor stackproc = new StackVarsProcessor();
+ stackproc.simplifyStackVars(root, mt, cl);
+
+ //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ varproc.setVarVersions(root);
+
+ // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ if (!new PPandMMHelper().findPPandMM(root)) {
+ break;
+ }
+ }
+
+ for (; ; ) {
+
+ LabelHelper.cleanUpEdges(root);
+
+ for (; ; ) {
+
+ MergeHelper.enhanceLoops(root);
+
+ if (LoopExtractHelper.extractLoops(root)) {
+ continue;
+ }
+
+ if (!IfHelper.mergeAllIfs(root)) {
+ break;
+ }
+ }
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION)) {
+
+ if (IdeaNotNullHelper.removeHardcodedChecks(root, mt)) {
+
+ SequenceHelper.condenseSequences(root);
+
+ StackVarsProcessor stackproc = new StackVarsProcessor();
+ stackproc.simplifyStackVars(root, mt, cl);
+
+ varproc.setVarVersions(root);
+ }
+ }
+
+ LabelHelper.identifyLabels(root);
+
+ // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ if (InlineSingleBlockHelper.inlineSingleBlocks(root)) {
+ continue;
+ }
+
+ // initializer may have at most one return point, so no transformation of method exits permitted
+ if (isInitializer || !ExitHelper.condenseExits(root)) {
+ break;
+ }
+
+ // FIXME: !!
+ // if(!EliminateLoopsHelper.eliminateLoops(root)) {
+ // break;
+ // }
+ }
+
+ ExitHelper.removeRedundantReturns(root);
+
+ SecondaryFunctionsHelper.identifySecondaryFunctions(root);
+
+ varproc.setVarDefinitions(root);
+
+ // must be the last invocation, because it makes the statement structure inconsistent
+ // FIXME: new edge type needed
+ LabelHelper.replaceContinueWithBreak(root);
+
+ mt.releaseResources();
+
+ // System.out.println("++++++++++++++++++++++/// \r\n"+root.toJava());
+
+ return root;
+ }
+
+ public RootStatement getRoot() {
+ return root;
+ }
+
+ public Throwable getError() {
+ return error;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/rels/MethodWrapper.java b/src/org/jetbrains/java/decompiler/main/rels/MethodWrapper.java
index 4f8d6f8..d36b8bc 100644
--- a/src/org/jetbrains/java/decompiler/main/rels/MethodWrapper.java
+++ b/src/org/jetbrains/java/decompiler/main/rels/MethodWrapper.java
@@ -1,22 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.rels;
-import java.util.HashSet;
-import java.util.List;
-
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper;
@@ -25,38 +23,40 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
import org.jetbrains.java.decompiler.struct.StructMethod;
+import java.util.HashSet;
+import java.util.List;
+
public class MethodWrapper {
- public RootStatement root;
-
- public VarProcessor varproc;
-
- public StructMethod methodStruct;
-
- public CounterContainer counter;
-
- public DirectGraph graph;
-
- public List<VarVersionPaar> signatureFields;
-
- public boolean decompiledWithErrors;
-
- public HashSet<String> setOuterVarNames = new HashSet<String>();
-
- public MethodWrapper(RootStatement root, VarProcessor varproc, StructMethod methodStruct, CounterContainer counter) {
- this.root = root;
- this.varproc = varproc;
- this.methodStruct = methodStruct;
- this.counter = counter;
- }
-
- public DirectGraph getOrBuildGraph() {
- if(graph == null && root != null) {
- FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
- graph = flatthelper.buildDirectGraph(root);
- }
- return graph;
- }
-
+ public RootStatement root;
+
+ public VarProcessor varproc;
+
+ public StructMethod methodStruct;
+
+ public CounterContainer counter;
+
+ public DirectGraph graph;
+
+ public List<VarVersionPaar> signatureFields;
+
+ public boolean decompiledWithErrors;
+
+ public HashSet<String> setOuterVarNames = new HashSet<String>();
+
+ public MethodWrapper(RootStatement root, VarProcessor varproc, StructMethod methodStruct, CounterContainer counter) {
+ this.root = root;
+ this.varproc = varproc;
+ this.methodStruct = methodStruct;
+ this.counter = counter;
+ }
+
+ public DirectGraph getOrBuildGraph() {
+ if (graph == null && root != null) {
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ graph = flatthelper.buildDirectGraph(root);
+ }
+ return graph;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java
index 1c962ec..9dba114 100644
--- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java
+++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java
@@ -1,41 +1,28 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.rels;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
@@ -51,970 +38,995 @@ import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.*;
+import java.util.Map.Entry;
+
public class NestedClassProcessor {
-
-
- public void processClass(ClassNode root, ClassNode node) {
-
- // hide synthetic lambda content methods
- if(node.type == ClassNode.CLASS_LAMBDA && !node.lambda_information.is_method_reference) {
- ClassNode node_content = DecompilerContext.getClassprocessor().getMapRootClasses().get(node.classStruct.qualifiedName);
- if(node_content != null && node_content.wrapper != null) {
- node_content.wrapper.getHideMembers().add(node.lambda_information.content_method_key);
- }
- }
-
- if(node.nested.isEmpty()) {
- return;
- }
-
- if(node.type != ClassNode.CLASS_LAMBDA) {
-
- computeLocalVarsAndDefinitions(node);
-
- // for each local or anonymous class ensure not empty enclosing method
- checkNotFoundClasses(root, node);
- }
-
- int nameless = 0, synthetics = 0;
- for(ClassNode child : node.nested) {
- // ensure not-empty class name
- if ((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_MEMBER) && child.simpleName == null) {
- StructClass cl = child.classStruct;
- if (((child.access | cl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic")) {
- child.simpleName = "SyntheticClass_" + (++synthetics);
- } else {
- DecompilerContext.getLogger().writeMessage("Nameless local or member class " + cl.qualifiedName + "!", IFernflowerLogger.WARNING);
- child.simpleName = "NamelessClass_" + (++nameless);
- }
- }
- }
-
- for(ClassNode child : node.nested) {
- if(child.type == ClassNode.CLASS_LAMBDA) {
- setLambdaVars(node, child);
- } else {
- if(child.type != ClassNode.CLASS_MEMBER || (child.access & CodeConstants.ACC_STATIC) == 0) {
- insertLocalVars(node, child);
-
- if(child.type == ClassNode.CLASS_LOCAL) {
- setLocalClassDefinition(node.wrapper.getMethods().getWithKey(child.enclosingMethod), child);
- }
- }
- }
- }
-
- for(ClassNode child : node.nested) {
- processClass(root, child);
- }
-
- }
-
- private void setLambdaVars(ClassNode parent, ClassNode child) {
-
- if(child.lambda_information.is_method_reference) { // method reference, no code and no parameters
- return;
- }
-
- final MethodWrapper meth = parent.wrapper.getMethods().getWithKey(child.lambda_information.content_method_key);
- final MethodWrapper encmeth = parent.wrapper.getMethods().getWithKey(child.enclosingMethod);
-
- MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(child.lambda_information.method_descriptor);
- final MethodDescriptor md_content = MethodDescriptor.parseDescriptor(child.lambda_information.content_method_descriptor);
-
- final int vars_count = md_content.params.length - md_lambda.params.length;
-// if(vars_count < 0) { // should not happen, but just in case...
-// vars_count = 0;
-// }
-
- final boolean is_static_lambda_content = child.lambda_information.is_content_method_static;
-
- final String parent_class_name = parent.wrapper.getClassStruct().qualifiedName;
- final String lambda_class_name = child.simpleName;
-
- final VarType lambda_class_type = new VarType(lambda_class_name, true);
-
- // this pointer
- if(!is_static_lambda_content && DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) {
- meth.varproc.getThisvars().put(new VarVersionPaar(0, 0), parent_class_name);
- meth.varproc.setVarName(new VarVersionPaar(0, 0), parent.simpleName + ".this");
- }
-
- // local variables
- DirectGraph graph = encmeth.getOrBuildGraph();
-
- final HashMap<VarVersionPaar, String> mapNewNames = new HashMap<VarVersionPaar, String>();
-
- graph.iterateExprents(new DirectGraph.ExprentIterator() {
- public int processExprent(Exprent exprent) {
-
- List<Exprent> lst = exprent.getAllExprents(true);
- lst.add(exprent);
-
- for(Exprent expr: lst) {
-
- if(expr.type == Exprent.EXPRENT_NEW) {
- NewExprent new_expr = (NewExprent)expr;
- if(new_expr.isLambda() && lambda_class_type.equals(new_expr.getNewtype())) {
-
- InvocationExprent inv_dynamic = new_expr.getConstructor();
-
- int param_index = is_static_lambda_content ? 0 : 1;;
- int varindex = is_static_lambda_content ? 0 : 1;
-
- for(int i = 0; i < vars_count; ++i) {
-
- Exprent param = inv_dynamic.getLstParameters().get(param_index + i);
-
- if(param.type == Exprent.EXPRENT_VAR) {
- VarVersionPaar enc_varpaar = new VarVersionPaar((VarExprent)param);
- String enc_varname = encmeth.varproc.getVarName(enc_varpaar);
-
- //meth.varproc.setVarName(new VarVersionPaar(varindex, 0), enc_varname);
- mapNewNames.put(new VarVersionPaar(varindex, 0), enc_varname);
- }
-
- varindex+=md_content.params[i].stack_size;
- }
-
- }
- }
- }
-
- return 0;
- }
- });
-
- // update names of local variables
- HashSet<String> setNewOuterNames = new HashSet<String>(mapNewNames.values());
- setNewOuterNames.removeAll(meth.setOuterVarNames);
-
- meth.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames));
- meth.setOuterVarNames.addAll(setNewOuterNames);
-
- for(Entry<VarVersionPaar, String> entr : mapNewNames.entrySet()) {
- meth.varproc.setVarName(entr.getKey(), entr.getValue());
- }
-
- }
-
- private void checkNotFoundClasses(ClassNode root, ClassNode node) {
-
- List<ClassNode> lstChildren = new ArrayList<ClassNode>(node.nested);
-
- for(ClassNode child : lstChildren) {
-
- if((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_ANONYMOUS) && child.enclosingMethod == null) {
-
- Set<String> setEnclosing = child.enclosingClasses;
-
- if(setEnclosing.size() == 1) {
- StructEnclosingMethodAttribute attr = (StructEnclosingMethodAttribute)child.classStruct.getAttributes().getWithKey("EnclosingMethod");
- if(attr != null && attr.getMethodName() != null) {
- if(node.classStruct.qualifiedName.equals(attr.getClassname()) &&
- node.classStruct.getMethod(attr.getMethodName(), attr.getMethodDescriptor()) != null) {
- child.enclosingMethod = InterpreterUtil.makeUniqueKey(attr.getMethodName(), attr.getMethodDescriptor());
- continue;
- }
- }
- }
-
- node.nested.remove(child);
- child.parent = null;
- setEnclosing.remove(node.classStruct.qualifiedName);
-
- boolean hasEnclosing = !setEnclosing.isEmpty();
- if(hasEnclosing) {
- hasEnclosing = insertNestedClass(root, child);
- }
-
- if(!hasEnclosing) {
- if(child.type == ClassNode.CLASS_ANONYMOUS) {
- DecompilerContext.getLogger().writeMessage("Unreferenced anonymous class "+child.classStruct.qualifiedName+"!", IFernflowerLogger.WARNING);
- } else if(child.type == ClassNode.CLASS_LOCAL) {
- DecompilerContext.getLogger().writeMessage("Unreferenced local class "+child.classStruct.qualifiedName+"!", IFernflowerLogger.WARNING);
- }
- }
- }
- }
- }
-
- private boolean insertNestedClass(ClassNode root, ClassNode child) {
-
- Set<String> setEnclosing = child.enclosingClasses;
-
- LinkedList<ClassNode> stack = new LinkedList<ClassNode>();
- stack.add(root);
-
- while(!stack.isEmpty()) {
-
- ClassNode node = stack.removeFirst();
-
- if(setEnclosing.contains(node.classStruct.qualifiedName)) {
- node.nested.add(child);
- child.parent = node;
-
- return true;
- }
-
- // note: ordered list
- stack.addAll(node.nested);
- }
-
- return false;
- }
-
-
- private void computeLocalVarsAndDefinitions(final ClassNode node) {
-
- // local var masks
- // class name, constructor descriptor, field mask
- final HashMap<String, HashMap<String, List<VarFieldPair>>> mapVarMasks = new HashMap<String, HashMap<String, List<VarFieldPair>>>();
-
- int cltypes = 0;
-
- for(ClassNode nd: node.nested) {
- if(nd.type != ClassNode.CLASS_LAMBDA) {
- if((nd.access & CodeConstants.ACC_STATIC) == 0 && (nd.access & CodeConstants.ACC_INTERFACE) == 0) {
-
- cltypes |= nd.type;
-
- HashMap<String, List<VarFieldPair>> mask = getMaskLocalVars(nd.wrapper);
- if(mask.isEmpty()) {
- DecompilerContext.getLogger().writeMessage("Nested class "+nd.classStruct.qualifiedName+" has no constructor!", IFernflowerLogger.WARNING);
- } else {
- mapVarMasks.put(nd.classStruct.qualifiedName, mask);
- }
- }
- }
- }
-
- // local var masks
- final HashMap<String, HashMap<String, List<VarFieldPair>>> mapVarFieldPairs = new HashMap<String, HashMap<String, List<VarFieldPair>>>();
-
- if(cltypes != ClassNode.CLASS_MEMBER) {
-
- // iterate enclosing class
- for(final MethodWrapper meth: node.wrapper.getMethods()) {
-
- if(meth.root != null) { // neither abstract, nor native
- DirectGraph graph = meth.getOrBuildGraph();
-
- graph.iterateExprents(new DirectGraph.ExprentIterator() {
- public int processExprent(Exprent exprent) {
- List<Exprent> lst = exprent.getAllExprents(true);
- lst.add(exprent);
-
- for(Exprent expr: lst) {
-
- if(expr.type == Exprent.EXPRENT_NEW) {
- InvocationExprent constr = ((NewExprent)expr).getConstructor();
-
- if(constr != null && mapVarMasks.containsKey(constr.getClassname())) { // non-static inner class constructor
-
- String refclname = constr.getClassname();
-
- ClassNode nestedClassNode = node.getClassNode(refclname);
-
- if(nestedClassNode.type != ClassNode.CLASS_MEMBER) {
-
- List<VarFieldPair> mask = mapVarMasks.get(refclname).get(constr.getStringDescriptor());
-
- if(!mapVarFieldPairs.containsKey(refclname)) {
- mapVarFieldPairs.put(refclname, new HashMap<String, List<VarFieldPair>>());
- }
-
- List<VarFieldPair> lstTemp = new ArrayList<VarFieldPair>();
-
- for(int i=0;i<mask.size();i++) {
- Exprent param = constr.getLstParameters().get(i);
- VarFieldPair pair = null;
-
- if(param.type == Exprent.EXPRENT_VAR && mask.get(i) != null) {
- VarVersionPaar varpaar = new VarVersionPaar((VarExprent)param);
-
- // FIXME: final flags of variables are wrong! Correct the entire final functionality.
-// if(meth.varproc.getVarFinal(varpaar) != VarTypeProcessor.VAR_NONFINAL) {
- pair = new VarFieldPair(mask.get(i).keyfield, varpaar);
-// }
- }
-
- lstTemp.add(pair);
- }
-
- List<VarFieldPair> pairmask = mapVarFieldPairs.get(refclname).get(constr.getStringDescriptor());
-
- if(pairmask == null) {
- pairmask = lstTemp;
- } else {
- for(int i=0;i<pairmask.size();i++) {
- if(!InterpreterUtil.equalObjects(pairmask.get(i), lstTemp.get(i))) {
- pairmask.set(i, null);
- }
- }
- }
-
- mapVarFieldPairs.get(refclname).put(constr.getStringDescriptor(), pairmask);
- nestedClassNode.enclosingMethod = InterpreterUtil.makeUniqueKey(meth.methodStruct.getName(), meth.methodStruct.getDescriptor());
- }
- }
- }
-
- }
- return 0;
- }
- });
- }
- }
- }
-
- // merge var masks
- for(Entry<String, HashMap<String, List<VarFieldPair>>> entcl : mapVarMasks.entrySet()) {
-
- ClassNode nestedNode = node.getClassNode(entcl.getKey());
-
- // intersection
- List<VarFieldPair> intrPairMask = null;
- // merge referenced constructors
- if(mapVarFieldPairs.containsKey(entcl.getKey())) {
- for(List<VarFieldPair> mask : mapVarFieldPairs.get(entcl.getKey()).values()) {
- if(intrPairMask == null) {
- intrPairMask = new ArrayList<VarFieldPair>(mask);
- } else {
- mergeListSignatures(intrPairMask, mask, false);
- }
- }
- }
-
- List<VarFieldPair> intrMask = null;
- // merge all constructors
- for(List<VarFieldPair> mask : entcl.getValue().values()) {
- if(intrMask == null) {
- intrMask = new ArrayList<VarFieldPair>(mask);
- } else {
- mergeListSignatures(intrMask, mask, false);
- }
- }
-
- if(intrPairMask == null) { // member or local and never instantiated
- intrPairMask = new ArrayList<VarFieldPair>(intrMask);
-
- boolean found = false;
-
- for(int i=0;i<intrPairMask.size();i++) {
- if(intrPairMask.get(i) != null) {
- if(found) {
- intrPairMask.set(i, null);
- }
- found = true;
- }
- }
- }
-
- mergeListSignatures(intrPairMask, intrMask, true);
-
- for(int i=0;i<intrPairMask.size();i++) {
- VarFieldPair pair = intrPairMask.get(i);
- if(pair != null && pair.keyfield.length() > 0) {
- nestedNode.mapFieldsToVars.put(pair.keyfield, pair.varpaar);
- }
- }
-
- // set resulting constructor signatures
- for(Entry<String, List<VarFieldPair>> entmt : entcl.getValue().entrySet()) {
- mergeListSignatures(entmt.getValue(), intrPairMask, false);
-
- MethodWrapper meth = nestedNode.wrapper.getMethodWrapper("<init>", entmt.getKey());
- meth.signatureFields = new ArrayList<VarVersionPaar>();
-
- for(VarFieldPair pair : entmt.getValue()) {
- meth.signatureFields.add(pair==null?null:pair.varpaar);
- }
- }
-
- }
-
- }
-
- private void insertLocalVars(final ClassNode parent, final ClassNode child) {
-
- // enclosing method, is null iff member class
- MethodWrapper encmeth = parent.wrapper.getMethods().getWithKey(child.enclosingMethod);
-
- // iterate all child methods
- for(final MethodWrapper meth : child.wrapper.getMethods()) {
-
- if(meth.root != null) { // neither abstract nor native
-
- // local var names
- HashMap<VarVersionPaar, String> mapNewNames = new HashMap<VarVersionPaar, String>();
- // local var types
- HashMap<VarVersionPaar, VarType> mapNewTypes = new HashMap<VarVersionPaar, VarType>();
-
- final HashMap<Integer, VarVersionPaar> mapParamsToNewVars = new HashMap<Integer, VarVersionPaar>();
- if(meth.signatureFields != null) {
- int index = 0;
- int varindex = 1;
- MethodDescriptor md = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor());
-
- for(VarVersionPaar paar : meth.signatureFields) {
- if(paar != null) {
- VarVersionPaar newvar = new VarVersionPaar(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);
-
- mapParamsToNewVars.put(varindex, newvar);
-
- String varname = null;
- VarType vartype = null;
-
- if(child.type != ClassNode.CLASS_MEMBER) {
- varname = encmeth.varproc.getVarName(paar);
- vartype = encmeth.varproc.getVarType(paar);
-
- encmeth.varproc.setVarFinal(paar, VarTypeProcessor.VAR_FINALEXPLICIT);
- }
-
- if(paar.var == -1 || "this".equals(varname)) {
- if(parent.simpleName == null) {
- // anonymous enclosing class, no access to this
- varname = VarExprent.VAR_NAMELESS_ENCLOSURE;
- } else {
- varname = parent.simpleName+".this";
- }
- meth.varproc.getThisvars().put(newvar, parent.classStruct.qualifiedName);
- }
-
- mapNewNames.put(newvar, varname);
- mapNewTypes.put(newvar, vartype);
- }
- varindex+=md.params[index++].stack_size;
- }
- }
-
- // new vars
- final HashMap<String, VarVersionPaar> mapFieldsToNewVars = new HashMap<String, VarVersionPaar>();
-
- for(ClassNode clnode = child; clnode != null; clnode = clnode.parent) {
-
- for(Entry<String, VarVersionPaar> entr : clnode.mapFieldsToVars.entrySet()) {
- VarVersionPaar newvar = new VarVersionPaar(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);
-
- mapFieldsToNewVars.put(InterpreterUtil.makeUniqueKey(clnode.classStruct.qualifiedName, entr.getKey()), newvar);
-
- String varname = null;
- VarType vartype = null;
-
- if(clnode.type != ClassNode.CLASS_MEMBER) {
-
- MethodWrapper enclosing_method = clnode.parent.wrapper.getMethods().getWithKey(clnode.enclosingMethod);
-
- varname = enclosing_method.varproc.getVarName(entr.getValue());
- vartype = enclosing_method.varproc.getVarType(entr.getValue());
-
- enclosing_method.varproc.setVarFinal(entr.getValue(), VarTypeProcessor.VAR_FINALEXPLICIT);
- }
-
- if(entr.getValue().var == -1 || "this".equals(varname)) {
- if(clnode.parent.simpleName == null) {
- // anonymous enclosing class, no access to this
- varname = VarExprent.VAR_NAMELESS_ENCLOSURE;
- } else {
- varname = clnode.parent.simpleName+".this";
- }
- meth.varproc.getThisvars().put(newvar, clnode.parent.classStruct.qualifiedName);
- }
-
- mapNewNames.put(newvar, varname);
- mapNewTypes.put(newvar, vartype);
-
- // hide synthetic field
- if(clnode == child) { // fields higher up the chain were already handled with their classes
- StructField fd = child.classStruct.getFields().getWithKey(entr.getKey());
- child.wrapper.getHideMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
- }
- }
- }
-
- HashSet<String> setNewOuterNames = new HashSet<String>(mapNewNames.values());
- setNewOuterNames.removeAll(meth.setOuterVarNames);
-
- meth.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames));
- meth.setOuterVarNames.addAll(setNewOuterNames);
-
- for(Entry<VarVersionPaar, String> entr : mapNewNames.entrySet()) {
- VarVersionPaar varpaar = entr.getKey();
- VarType vartype = mapNewTypes.get(varpaar);
-
- meth.varproc.setVarName(varpaar, entr.getValue());
- if(vartype != null) {
- meth.varproc.setVarType(varpaar, vartype);
- }
- }
-
- DirectGraph graph = meth.getOrBuildGraph();
-
- graph.iterateExprents(new DirectGraph.ExprentIterator() {
- public int processExprent(Exprent exprent) {
-
- if(exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent asexpr = (AssignmentExprent)exprent;
- if(asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
- FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
-
- if(fexpr.getClassname().equals(child.classStruct.qualifiedName) && // process this class only
- mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(child.classStruct.qualifiedName,
- InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString)))) {
- return 2;
- }
-
- //if(fexpr.getClassname().equals(child.classStruct.qualifiedName) &&
- // mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString))) {
- // return 2;
- //}
- }
- }
-
- if(child.type == ClassNode.CLASS_ANONYMOUS && "<init>".equals(meth.methodStruct.getName())
- && exprent.type == Exprent.EXPRENT_INVOCATION) {
- InvocationExprent invexpr = (InvocationExprent)exprent;
- if(invexpr.getFunctype() == InvocationExprent.TYP_INIT) {
- // invocation of the super constructor in an anonymous class
- child.superInvocation = invexpr; // FIXME: save original names of parameters
- return 2;
- }
- }
-
- replaceExprent(exprent);
-
- return 0;
- }
-
- private Exprent replaceExprent(Exprent exprent) {
-
- if(exprent.type == Exprent.EXPRENT_VAR) {
- int varindex = ((VarExprent)exprent).getIndex();
- if(mapParamsToNewVars.containsKey(varindex)) {
- VarVersionPaar newvar = mapParamsToNewVars.get(varindex);
- meth.varproc.getExternvars().add(newvar);
- return new VarExprent(newvar.var, meth.varproc.getVarType(newvar), meth.varproc);
- }
- } else if(exprent.type == Exprent.EXPRENT_FIELD) {
- FieldExprent fexpr = (FieldExprent)exprent;
-
- String keyField = InterpreterUtil.makeUniqueKey(fexpr.getClassname(), InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString));
-
- if(mapFieldsToNewVars.containsKey(keyField)) {
- //if(fexpr.getClassname().equals(child.classStruct.qualifiedName) &&
- // mapFieldsToNewVars.containsKey(keyField)) {
- VarVersionPaar newvar = mapFieldsToNewVars.get(keyField);
- meth.varproc.getExternvars().add(newvar);
- return new VarExprent(newvar.var, meth.varproc.getVarType(newvar), meth.varproc);
- }
- }
-
- boolean replaced = true;
- while(replaced) {
- replaced = false;
-
- for(Exprent expr: exprent.getAllExprents()) {
- Exprent retexpr = replaceExprent(expr);
- if(retexpr != null) {
- exprent.replaceExprent(expr, retexpr);
- replaced = true;
- break;
- }
- }
- }
-
- return null;
- }
- });
-
- }
- }
-
- }
-
- private HashMap<String, List<VarFieldPair>> getMaskLocalVars(ClassWrapper wrapper) {
-
- HashMap<String, List<VarFieldPair>> mapMasks = new HashMap<String, List<VarFieldPair>>();
-
- StructClass cl = wrapper.getClassStruct();
-
- // iterate over constructors
- for(StructMethod mt: cl.getMethods()) {
- if("<init>".equals(mt.getName())) {
-
- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
-
- MethodWrapper meth = wrapper.getMethodWrapper("<init>", mt.getDescriptor());
- DirectGraph graph = meth.getOrBuildGraph();
-
- if(graph != null) { // something gone wrong, should not be null
- List<VarFieldPair> fields = new ArrayList<VarFieldPair>();
-
- int varindex = 1;
- for(int i=0;i<md.params.length;i++) { // no static methods allowed
- String keyField = getEnclosingVarField(cl, meth, graph, varindex);
- fields.add(keyField==null?null:new VarFieldPair(keyField, new VarVersionPaar(-1, 0))); // TODO: null?
- varindex+=md.params[i].stack_size;
- }
- mapMasks.put(mt.getDescriptor(), fields);
- }
- }
- }
-
- return mapMasks;
- }
-
- private String getEnclosingVarField(StructClass cl, MethodWrapper meth, DirectGraph graph, final int index) {
-
- String field = "";
-
- // parameter variable final
- if(meth.varproc.getVarFinal(new VarVersionPaar(index, 0)) == VarTypeProcessor.VAR_NONFINAL) {
- return null;
- }
-
- boolean notsynth = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
-
- // no loop at the begin
- DirectNode firstnode = graph.first;
- if(firstnode.preds.isEmpty()) {
- // assignment to a final synthetic field?
- for(Exprent exprent: firstnode.exprents) {
- if(exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent asexpr = (AssignmentExprent)exprent;
- if(asexpr.getRight().type == Exprent.EXPRENT_VAR && ((VarExprent)asexpr.getRight()).getIndex() == index) {
- if(asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
-
- FieldExprent left = (FieldExprent)asexpr.getLeft();
- StructField fd = cl.getField(left.getName(), left.getDescriptor().descriptorString);
-
- if(fd != null) { // local (== not inherited) field
- if(cl.qualifiedName.equals(left.getClassname()) &&
- (fd.access_flags & CodeConstants.ACC_FINAL) != 0 &&
- ((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0 ||
- fd.getAttributes().containsKey("Synthetic") ||
- (notsynth && (fd.access_flags & CodeConstants.ACC_PRIVATE) != 0))) {
- field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString);
- break;
- }
- }
- }
- }
- }
- }
- }
-
- return field;
- }
-
- private void mergeListSignatures(List<VarFieldPair> first, List<VarFieldPair> second, boolean both) {
-
- int i=1;
- for(;;) {
- if(first.size() <= i || second.size() <= i) {
- break;
- }
-
- VarFieldPair fobj = first.get(first.size() - i);
- VarFieldPair sobj = second.get(second.size() - i);
-
- boolean eq = false;
- if(fobj == null || sobj == null) {
- eq = (fobj == sobj);
- } else {
- eq = true;
- if(fobj.keyfield.length()==0) {
- fobj.keyfield = sobj.keyfield;
- } else if(sobj.keyfield.length() == 0) {
- if(both) {
- sobj.keyfield = fobj.keyfield;
- }
- } else {
- eq = fobj.keyfield.equals(sobj.keyfield);
- }
- }
-
- if(!eq) {
- first.set(first.size() - i, null);
- if(both) {
- second.set(second.size() - i, null);
- }
- } else {
- if(fobj != null) {
- if(fobj.varpaar.var == -1) {
- fobj.varpaar = sobj.varpaar;
- } else {
- sobj.varpaar = fobj.varpaar;
- }
- }
- }
- i++;
- }
-
- for(int j=1;j<=first.size()-i;j++) {
- first.set(j, null);
- }
-
- if(both) {
- for(int j=1;j<=second.size()-i;j++) {
- second.set(j, null);
- }
- }
-
- // first
- if(first.isEmpty()) {
- if(!second.isEmpty() && both) {
- second.set(0, null);
- }
- } else if(second.isEmpty()) {
- first.set(0, null);
- } else {
- VarFieldPair fobj = first.get(0);
- VarFieldPair sobj = second.get(0);
-
- boolean eq = false;
- if(fobj == null || sobj == null) {
- eq = (fobj == sobj);
- } else {
- eq = true;
- if(fobj.keyfield.length()==0) {
- fobj.keyfield = sobj.keyfield;
- } else if(sobj.keyfield.length() == 0) {
- if(both) {
- sobj.keyfield = fobj.keyfield;
- }
- } else {
- eq = fobj.keyfield.equals(sobj.keyfield);
- }
- }
-
- if(!eq) {
- first.set(0, null);
- if(both) {
- second.set(0, null);
- }
- } else if(fobj != null) {
- if(fobj.varpaar.var == -1) {
- fobj.varpaar = sobj.varpaar;
- } else {
- sobj.varpaar = fobj.varpaar;
- }
- }
- }
-
- }
-
-
- private void setLocalClassDefinition(MethodWrapper meth, ClassNode node) {
-
- RootStatement root = meth.root;
-
- HashSet<Statement> setStats = new HashSet<Statement>();
- VarType classtype = new VarType(node.classStruct.qualifiedName, true);
-
- Statement stdef = getDefStatement(root, classtype, setStats);
- if(stdef == null) {
- // unreferenced local class
- stdef = root.getFirst();
- }
-
- Statement first = findFirstBlock(stdef, setStats);
-
- List<Exprent> lst;
- if(first == null) {
- lst = stdef.getVarDefinitions();
- } else if(first.getExprents() == null) {
- lst = first.getVarDefinitions();
- } else {
- lst = first.getExprents();
- }
-
-
- int addindex = 0;
- for(Exprent expr: lst) {
- if(searchForClass(expr, classtype)) {
- break;
- }
- addindex++;
- }
-
- VarExprent var = new VarExprent(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER),
- classtype, meth.varproc);
- var.setDefinition(true);
- var.setClassdef(true);
-
- lst.add(addindex, var);
-
- }
-
-
-
- private Statement findFirstBlock(Statement stat, HashSet<Statement> setStats) {
-
- LinkedList<Statement> stack = new LinkedList<Statement>();
- stack.add(stat);
-
- while(!stack.isEmpty()) {
- Statement st = stack.remove(0);
-
- if(stack.isEmpty() || setStats.contains(st)) {
-
- if(st.isLabeled() && !stack.isEmpty()) {
- return st;
- }
-
- if(st.getExprents() != null) {
- return st;
- } else {
- stack.clear();
-
- switch(st.type) {
- case Statement.TYPE_SEQUENCE:
- stack.addAll(0, st.getStats());
- break;
- case Statement.TYPE_IF:
- case Statement.TYPE_ROOT:
- case Statement.TYPE_SWITCH:
- case Statement.TYPE_SYNCRONIZED:
- stack.add(st.getFirst());
- break;
- default:
- return st;
- }
- }
- }
- }
-
- return null;
- }
-
-
- private Statement getDefStatement(Statement stat, VarType classtype, HashSet<Statement> setStats) {
-
- List<Exprent> condlst = new ArrayList<Exprent>();
- Statement retstat = null;
-
- if(stat.getExprents() == null) {
- int counter = 0;
-
- for(Object obj: stat.getSequentialObjects()) {
- if(obj instanceof Statement) {
- Statement st = (Statement)obj;
-
- Statement stTemp = getDefStatement(st, classtype, setStats);
-
- if(stTemp != null) {
- if(counter == 1) {
- retstat = stat;
- break;
- }
- retstat = stTemp;
- counter++;
- }
-
- if(st.type == DoStatement.TYPE_DO) {
- DoStatement dost = (DoStatement)st;
-
- condlst.addAll(dost.getInitExprentList());
- condlst.addAll(dost.getConditionExprentList());
- }
-
- } else if(obj instanceof Exprent) {
- condlst.add((Exprent)obj);
- }
- }
- } else {
- condlst = stat.getExprents();
- }
-
- if(retstat != stat) {
- for(Exprent exprent : condlst) {
- if(exprent!=null && searchForClass(exprent, classtype)) {
- retstat = stat;
- break;
- }
- }
- }
-
- if(retstat != null) {
- setStats.add(stat);
- }
-
- return retstat;
- }
-
- private boolean searchForClass(Exprent exprent, VarType classtype) {
-
- List<Exprent> lst = exprent.getAllExprents(true);
- lst.add(exprent);
-
- String classname = classtype.value;
-
- for(Exprent expr : lst) {
-
- boolean res = false;
-
- switch(expr.type) {
- case Exprent.EXPRENT_CONST:
- ConstExprent cexpr = (ConstExprent)expr;
- res = (VarType.VARTYPE_CLASS.equals(cexpr.getConsttype()) && classname.equals(cexpr.getValue()) ||
- classtype.equals(cexpr.getConsttype()));
- break;
- case Exprent.EXPRENT_FIELD:
- res = classname.equals(((FieldExprent)expr).getClassname());
- break;
- case Exprent.EXPRENT_INVOCATION:
- res = classname.equals(((InvocationExprent)expr).getClassname());
- break;
- case Exprent.EXPRENT_NEW:
- VarType newType = expr.getExprType();
- res = newType.type == CodeConstants.TYPE_OBJECT && classname.equals(newType.value);
- break;
- case Exprent.EXPRENT_VAR:
- VarExprent vexpr = (VarExprent)expr;
- if(vexpr.isDefinition()) {
- VarType vtype = vexpr.getVartype();
- if(classtype.equals(vtype) || (vtype.arraydim > 0 && classtype.value.equals(vtype.value))) {
- res = true;
- }
- }
- }
-
- if(res) {
- return true;
- }
- }
-
- return false;
- }
-
-
- private class VarFieldPair {
-
- public String keyfield = "";
- public VarVersionPaar varpaar;
-
- public VarFieldPair(String field, VarVersionPaar varpaar) {
- this.keyfield = field;
- this.varpaar = varpaar;
- }
-
- @Override
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof VarFieldPair)) return false;
-
- VarFieldPair pair = (VarFieldPair)o;
- return keyfield.equals(pair.keyfield) && varpaar.equals(pair.varpaar);
- }
-
- @Override
- public int hashCode() {
- return keyfield.hashCode()+varpaar.hashCode();
- }
-
- }
-
+
+
+ public void processClass(ClassNode root, ClassNode node) {
+
+ // hide synthetic lambda content methods
+ if (node.type == ClassNode.CLASS_LAMBDA && !node.lambda_information.is_method_reference) {
+ ClassNode node_content = DecompilerContext.getClassprocessor().getMapRootClasses().get(node.classStruct.qualifiedName);
+ if (node_content != null && node_content.wrapper != null) {
+ node_content.wrapper.getHideMembers().add(node.lambda_information.content_method_key);
+ }
+ }
+
+ if (node.nested.isEmpty()) {
+ return;
+ }
+
+ if (node.type != ClassNode.CLASS_LAMBDA) {
+
+ computeLocalVarsAndDefinitions(node);
+
+ // for each local or anonymous class ensure not empty enclosing method
+ checkNotFoundClasses(root, node);
+ }
+
+ int nameless = 0, synthetics = 0;
+ for (ClassNode child : node.nested) {
+ // ensure not-empty class name
+ if ((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_MEMBER) && child.simpleName == null) {
+ StructClass cl = child.classStruct;
+ if (((child.access | cl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic")) {
+ child.simpleName = "SyntheticClass_" + (++synthetics);
+ }
+ else {
+ DecompilerContext.getLogger().writeMessage("Nameless local or member class " + cl.qualifiedName + "!", IFernflowerLogger.WARNING);
+ child.simpleName = "NamelessClass_" + (++nameless);
+ }
+ }
+ }
+
+ for (ClassNode child : node.nested) {
+ if (child.type == ClassNode.CLASS_LAMBDA) {
+ setLambdaVars(node, child);
+ }
+ else {
+ if (child.type != ClassNode.CLASS_MEMBER || (child.access & CodeConstants.ACC_STATIC) == 0) {
+ insertLocalVars(node, child);
+
+ if (child.type == ClassNode.CLASS_LOCAL) {
+ setLocalClassDefinition(node.wrapper.getMethods().getWithKey(child.enclosingMethod), child);
+ }
+ }
+ }
+ }
+
+ for (ClassNode child : node.nested) {
+ processClass(root, child);
+ }
+ }
+
+ private void setLambdaVars(ClassNode parent, ClassNode child) {
+
+ if (child.lambda_information.is_method_reference) { // method reference, no code and no parameters
+ return;
+ }
+
+ final MethodWrapper meth = parent.wrapper.getMethods().getWithKey(child.lambda_information.content_method_key);
+ final MethodWrapper encmeth = parent.wrapper.getMethods().getWithKey(child.enclosingMethod);
+
+ MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(child.lambda_information.method_descriptor);
+ final MethodDescriptor md_content = MethodDescriptor.parseDescriptor(child.lambda_information.content_method_descriptor);
+
+ final int vars_count = md_content.params.length - md_lambda.params.length;
+ // if(vars_count < 0) { // should not happen, but just in case...
+ // vars_count = 0;
+ // }
+
+ final boolean is_static_lambda_content = child.lambda_information.is_content_method_static;
+
+ final String parent_class_name = parent.wrapper.getClassStruct().qualifiedName;
+ final String lambda_class_name = child.simpleName;
+
+ final VarType lambda_class_type = new VarType(lambda_class_name, true);
+
+ // this pointer
+ if (!is_static_lambda_content && DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) {
+ meth.varproc.getThisvars().put(new VarVersionPaar(0, 0), parent_class_name);
+ meth.varproc.setVarName(new VarVersionPaar(0, 0), parent.simpleName + ".this");
+ }
+
+ // local variables
+ DirectGraph graph = encmeth.getOrBuildGraph();
+
+ final HashMap<VarVersionPaar, String> mapNewNames = new HashMap<VarVersionPaar, String>();
+
+ graph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+
+ if (expr.type == Exprent.EXPRENT_NEW) {
+ NewExprent new_expr = (NewExprent)expr;
+ if (new_expr.isLambda() && lambda_class_type.equals(new_expr.getNewtype())) {
+
+ InvocationExprent inv_dynamic = new_expr.getConstructor();
+
+ int param_index = is_static_lambda_content ? 0 : 1;
+ ;
+ int varindex = is_static_lambda_content ? 0 : 1;
+
+ for (int i = 0; i < vars_count; ++i) {
+
+ Exprent param = inv_dynamic.getLstParameters().get(param_index + i);
+
+ if (param.type == Exprent.EXPRENT_VAR) {
+ VarVersionPaar enc_varpaar = new VarVersionPaar((VarExprent)param);
+ String enc_varname = encmeth.varproc.getVarName(enc_varpaar);
+
+ //meth.varproc.setVarName(new VarVersionPaar(varindex, 0), enc_varname);
+ mapNewNames.put(new VarVersionPaar(varindex, 0), enc_varname);
+ }
+
+ varindex += md_content.params[i].stack_size;
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+ });
+
+ // update names of local variables
+ HashSet<String> setNewOuterNames = new HashSet<String>(mapNewNames.values());
+ setNewOuterNames.removeAll(meth.setOuterVarNames);
+
+ meth.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames));
+ meth.setOuterVarNames.addAll(setNewOuterNames);
+
+ for (Entry<VarVersionPaar, String> entr : mapNewNames.entrySet()) {
+ meth.varproc.setVarName(entr.getKey(), entr.getValue());
+ }
+ }
+
+ private void checkNotFoundClasses(ClassNode root, ClassNode node) {
+
+ List<ClassNode> lstChildren = new ArrayList<ClassNode>(node.nested);
+
+ for (ClassNode child : lstChildren) {
+
+ if ((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_ANONYMOUS) && child.enclosingMethod == null) {
+
+ Set<String> setEnclosing = child.enclosingClasses;
+
+ if (setEnclosing.size() == 1) {
+ StructEnclosingMethodAttribute attr =
+ (StructEnclosingMethodAttribute)child.classStruct.getAttributes().getWithKey("EnclosingMethod");
+ if (attr != null && attr.getMethodName() != null) {
+ if (node.classStruct.qualifiedName.equals(attr.getClassname()) &&
+ node.classStruct.getMethod(attr.getMethodName(), attr.getMethodDescriptor()) != null) {
+ child.enclosingMethod = InterpreterUtil.makeUniqueKey(attr.getMethodName(), attr.getMethodDescriptor());
+ continue;
+ }
+ }
+ }
+
+ node.nested.remove(child);
+ child.parent = null;
+ setEnclosing.remove(node.classStruct.qualifiedName);
+
+ boolean hasEnclosing = !setEnclosing.isEmpty();
+ if (hasEnclosing) {
+ hasEnclosing = insertNestedClass(root, child);
+ }
+
+ if (!hasEnclosing) {
+ if (child.type == ClassNode.CLASS_ANONYMOUS) {
+ DecompilerContext.getLogger()
+ .writeMessage("Unreferenced anonymous class " + child.classStruct.qualifiedName + "!", IFernflowerLogger.WARNING);
+ }
+ else if (child.type == ClassNode.CLASS_LOCAL) {
+ DecompilerContext.getLogger()
+ .writeMessage("Unreferenced local class " + child.classStruct.qualifiedName + "!", IFernflowerLogger.WARNING);
+ }
+ }
+ }
+ }
+ }
+
+ private boolean insertNestedClass(ClassNode root, ClassNode child) {
+
+ Set<String> setEnclosing = child.enclosingClasses;
+
+ LinkedList<ClassNode> stack = new LinkedList<ClassNode>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+
+ ClassNode node = stack.removeFirst();
+
+ if (setEnclosing.contains(node.classStruct.qualifiedName)) {
+ node.nested.add(child);
+ child.parent = node;
+
+ return true;
+ }
+
+ // note: ordered list
+ stack.addAll(node.nested);
+ }
+
+ return false;
+ }
+
+
+ private void computeLocalVarsAndDefinitions(final ClassNode node) {
+
+ // local var masks
+ // class name, constructor descriptor, field mask
+ final HashMap<String, HashMap<String, List<VarFieldPair>>> mapVarMasks = new HashMap<String, HashMap<String, List<VarFieldPair>>>();
+
+ int cltypes = 0;
+
+ for (ClassNode nd : node.nested) {
+ if (nd.type != ClassNode.CLASS_LAMBDA) {
+ if ((nd.access & CodeConstants.ACC_STATIC) == 0 && (nd.access & CodeConstants.ACC_INTERFACE) == 0) {
+
+ cltypes |= nd.type;
+
+ HashMap<String, List<VarFieldPair>> mask = getMaskLocalVars(nd.wrapper);
+ if (mask.isEmpty()) {
+ DecompilerContext.getLogger()
+ .writeMessage("Nested class " + nd.classStruct.qualifiedName + " has no constructor!", IFernflowerLogger.WARNING);
+ }
+ else {
+ mapVarMasks.put(nd.classStruct.qualifiedName, mask);
+ }
+ }
+ }
+ }
+
+ // local var masks
+ final HashMap<String, HashMap<String, List<VarFieldPair>>> mapVarFieldPairs =
+ new HashMap<String, HashMap<String, List<VarFieldPair>>>();
+
+ if (cltypes != ClassNode.CLASS_MEMBER) {
+
+ // iterate enclosing class
+ for (final MethodWrapper meth : node.wrapper.getMethods()) {
+
+ if (meth.root != null) { // neither abstract, nor native
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ graph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+
+ if (expr.type == Exprent.EXPRENT_NEW) {
+ InvocationExprent constr = ((NewExprent)expr).getConstructor();
+
+ if (constr != null && mapVarMasks.containsKey(constr.getClassname())) { // non-static inner class constructor
+
+ String refclname = constr.getClassname();
+
+ ClassNode nestedClassNode = node.getClassNode(refclname);
+
+ if (nestedClassNode.type != ClassNode.CLASS_MEMBER) {
+
+ List<VarFieldPair> mask = mapVarMasks.get(refclname).get(constr.getStringDescriptor());
+
+ if (!mapVarFieldPairs.containsKey(refclname)) {
+ mapVarFieldPairs.put(refclname, new HashMap<String, List<VarFieldPair>>());
+ }
+
+ List<VarFieldPair> lstTemp = new ArrayList<VarFieldPair>();
+
+ for (int i = 0; i < mask.size(); i++) {
+ Exprent param = constr.getLstParameters().get(i);
+ VarFieldPair pair = null;
+
+ if (param.type == Exprent.EXPRENT_VAR && mask.get(i) != null) {
+ VarVersionPaar varpaar = new VarVersionPaar((VarExprent)param);
+
+ // FIXME: final flags of variables are wrong! Correct the entire final functionality.
+ // if(meth.varproc.getVarFinal(varpaar) != VarTypeProcessor.VAR_NONFINAL) {
+ pair = new VarFieldPair(mask.get(i).keyfield, varpaar);
+ // }
+ }
+
+ lstTemp.add(pair);
+ }
+
+ List<VarFieldPair> pairmask = mapVarFieldPairs.get(refclname).get(constr.getStringDescriptor());
+
+ if (pairmask == null) {
+ pairmask = lstTemp;
+ }
+ else {
+ for (int i = 0; i < pairmask.size(); i++) {
+ if (!InterpreterUtil.equalObjects(pairmask.get(i), lstTemp.get(i))) {
+ pairmask.set(i, null);
+ }
+ }
+ }
+
+ mapVarFieldPairs.get(refclname).put(constr.getStringDescriptor(), pairmask);
+ nestedClassNode.enclosingMethod =
+ InterpreterUtil.makeUniqueKey(meth.methodStruct.getName(), meth.methodStruct.getDescriptor());
+ }
+ }
+ }
+ }
+ return 0;
+ }
+ });
+ }
+ }
+ }
+
+ // merge var masks
+ for (Entry<String, HashMap<String, List<VarFieldPair>>> entcl : mapVarMasks.entrySet()) {
+
+ ClassNode nestedNode = node.getClassNode(entcl.getKey());
+
+ // intersection
+ List<VarFieldPair> intrPairMask = null;
+ // merge referenced constructors
+ if (mapVarFieldPairs.containsKey(entcl.getKey())) {
+ for (List<VarFieldPair> mask : mapVarFieldPairs.get(entcl.getKey()).values()) {
+ if (intrPairMask == null) {
+ intrPairMask = new ArrayList<VarFieldPair>(mask);
+ }
+ else {
+ mergeListSignatures(intrPairMask, mask, false);
+ }
+ }
+ }
+
+ List<VarFieldPair> intrMask = null;
+ // merge all constructors
+ for (List<VarFieldPair> mask : entcl.getValue().values()) {
+ if (intrMask == null) {
+ intrMask = new ArrayList<VarFieldPair>(mask);
+ }
+ else {
+ mergeListSignatures(intrMask, mask, false);
+ }
+ }
+
+ if (intrPairMask == null) { // member or local and never instantiated
+ intrPairMask = new ArrayList<VarFieldPair>(intrMask);
+
+ boolean found = false;
+
+ for (int i = 0; i < intrPairMask.size(); i++) {
+ if (intrPairMask.get(i) != null) {
+ if (found) {
+ intrPairMask.set(i, null);
+ }
+ found = true;
+ }
+ }
+ }
+
+ mergeListSignatures(intrPairMask, intrMask, true);
+
+ for (int i = 0; i < intrPairMask.size(); i++) {
+ VarFieldPair pair = intrPairMask.get(i);
+ if (pair != null && pair.keyfield.length() > 0) {
+ nestedNode.mapFieldsToVars.put(pair.keyfield, pair.varpaar);
+ }
+ }
+
+ // set resulting constructor signatures
+ for (Entry<String, List<VarFieldPair>> entmt : entcl.getValue().entrySet()) {
+ mergeListSignatures(entmt.getValue(), intrPairMask, false);
+
+ MethodWrapper meth = nestedNode.wrapper.getMethodWrapper("<init>", entmt.getKey());
+ meth.signatureFields = new ArrayList<VarVersionPaar>();
+
+ for (VarFieldPair pair : entmt.getValue()) {
+ meth.signatureFields.add(pair == null ? null : pair.varpaar);
+ }
+ }
+ }
+ }
+
+ private void insertLocalVars(final ClassNode parent, final ClassNode child) {
+
+ // enclosing method, is null iff member class
+ MethodWrapper encmeth = parent.wrapper.getMethods().getWithKey(child.enclosingMethod);
+
+ // iterate all child methods
+ for (final MethodWrapper meth : child.wrapper.getMethods()) {
+
+ if (meth.root != null) { // neither abstract nor native
+
+ // local var names
+ HashMap<VarVersionPaar, String> mapNewNames = new HashMap<VarVersionPaar, String>();
+ // local var types
+ HashMap<VarVersionPaar, VarType> mapNewTypes = new HashMap<VarVersionPaar, VarType>();
+
+ final HashMap<Integer, VarVersionPaar> mapParamsToNewVars = new HashMap<Integer, VarVersionPaar>();
+ if (meth.signatureFields != null) {
+ int index = 0;
+ int varindex = 1;
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor());
+
+ for (VarVersionPaar paar : meth.signatureFields) {
+ if (paar != null) {
+ VarVersionPaar newvar = new VarVersionPaar(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);
+
+ mapParamsToNewVars.put(varindex, newvar);
+
+ String varname = null;
+ VarType vartype = null;
+
+ if (child.type != ClassNode.CLASS_MEMBER) {
+ varname = encmeth.varproc.getVarName(paar);
+ vartype = encmeth.varproc.getVarType(paar);
+
+ encmeth.varproc.setVarFinal(paar, VarTypeProcessor.VAR_FINALEXPLICIT);
+ }
+
+ if (paar.var == -1 || "this".equals(varname)) {
+ if (parent.simpleName == null) {
+ // anonymous enclosing class, no access to this
+ varname = VarExprent.VAR_NAMELESS_ENCLOSURE;
+ }
+ else {
+ varname = parent.simpleName + ".this";
+ }
+ meth.varproc.getThisvars().put(newvar, parent.classStruct.qualifiedName);
+ }
+
+ mapNewNames.put(newvar, varname);
+ mapNewTypes.put(newvar, vartype);
+ }
+ varindex += md.params[index++].stack_size;
+ }
+ }
+
+ // new vars
+ final HashMap<String, VarVersionPaar> mapFieldsToNewVars = new HashMap<String, VarVersionPaar>();
+
+ for (ClassNode clnode = child; clnode != null; clnode = clnode.parent) {
+
+ for (Entry<String, VarVersionPaar> entr : clnode.mapFieldsToVars.entrySet()) {
+ VarVersionPaar newvar = new VarVersionPaar(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);
+
+ mapFieldsToNewVars.put(InterpreterUtil.makeUniqueKey(clnode.classStruct.qualifiedName, entr.getKey()), newvar);
+
+ String varname = null;
+ VarType vartype = null;
+
+ if (clnode.type != ClassNode.CLASS_MEMBER) {
+
+ MethodWrapper enclosing_method = clnode.parent.wrapper.getMethods().getWithKey(clnode.enclosingMethod);
+
+ varname = enclosing_method.varproc.getVarName(entr.getValue());
+ vartype = enclosing_method.varproc.getVarType(entr.getValue());
+
+ enclosing_method.varproc.setVarFinal(entr.getValue(), VarTypeProcessor.VAR_FINALEXPLICIT);
+ }
+
+ if (entr.getValue().var == -1 || "this".equals(varname)) {
+ if (clnode.parent.simpleName == null) {
+ // anonymous enclosing class, no access to this
+ varname = VarExprent.VAR_NAMELESS_ENCLOSURE;
+ }
+ else {
+ varname = clnode.parent.simpleName + ".this";
+ }
+ meth.varproc.getThisvars().put(newvar, clnode.parent.classStruct.qualifiedName);
+ }
+
+ mapNewNames.put(newvar, varname);
+ mapNewTypes.put(newvar, vartype);
+
+ // hide synthetic field
+ if (clnode == child) { // fields higher up the chain were already handled with their classes
+ StructField fd = child.classStruct.getFields().getWithKey(entr.getKey());
+ child.wrapper.getHideMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
+ }
+ }
+ }
+
+ HashSet<String> setNewOuterNames = new HashSet<String>(mapNewNames.values());
+ setNewOuterNames.removeAll(meth.setOuterVarNames);
+
+ meth.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames));
+ meth.setOuterVarNames.addAll(setNewOuterNames);
+
+ for (Entry<VarVersionPaar, String> entr : mapNewNames.entrySet()) {
+ VarVersionPaar varpaar = entr.getKey();
+ VarType vartype = mapNewTypes.get(varpaar);
+
+ meth.varproc.setVarName(varpaar, entr.getValue());
+ if (vartype != null) {
+ meth.varproc.setVarType(varpaar, vartype);
+ }
+ }
+
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ graph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
+ FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
+
+ if (fexpr.getClassname().equals(child.classStruct.qualifiedName) && // process this class only
+ mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(child.classStruct.qualifiedName,
+ InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr
+ .getDescriptor().descriptorString)))) {
+ return 2;
+ }
+
+ //if(fexpr.getClassname().equals(child.classStruct.qualifiedName) &&
+ // mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString))) {
+ // return 2;
+ //}
+ }
+ }
+
+ if (child.type == ClassNode.CLASS_ANONYMOUS && "<init>".equals(meth.methodStruct.getName())
+ && exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)exprent;
+ if (invexpr.getFunctype() == InvocationExprent.TYP_INIT) {
+ // invocation of the super constructor in an anonymous class
+ child.superInvocation = invexpr; // FIXME: save original names of parameters
+ return 2;
+ }
+ }
+
+ replaceExprent(exprent);
+
+ return 0;
+ }
+
+ private Exprent replaceExprent(Exprent exprent) {
+
+ if (exprent.type == Exprent.EXPRENT_VAR) {
+ int varindex = ((VarExprent)exprent).getIndex();
+ if (mapParamsToNewVars.containsKey(varindex)) {
+ VarVersionPaar newvar = mapParamsToNewVars.get(varindex);
+ meth.varproc.getExternvars().add(newvar);
+ return new VarExprent(newvar.var, meth.varproc.getVarType(newvar), meth.varproc);
+ }
+ }
+ else if (exprent.type == Exprent.EXPRENT_FIELD) {
+ FieldExprent fexpr = (FieldExprent)exprent;
+
+ String keyField = InterpreterUtil.makeUniqueKey(fexpr.getClassname(), InterpreterUtil
+ .makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString));
+
+ if (mapFieldsToNewVars.containsKey(keyField)) {
+ //if(fexpr.getClassname().equals(child.classStruct.qualifiedName) &&
+ // mapFieldsToNewVars.containsKey(keyField)) {
+ VarVersionPaar newvar = mapFieldsToNewVars.get(keyField);
+ meth.varproc.getExternvars().add(newvar);
+ return new VarExprent(newvar.var, meth.varproc.getVarType(newvar), meth.varproc);
+ }
+ }
+
+ boolean replaced = true;
+ while (replaced) {
+ replaced = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ Exprent retexpr = replaceExprent(expr);
+ if (retexpr != null) {
+ exprent.replaceExprent(expr, retexpr);
+ replaced = true;
+ break;
+ }
+ }
+ }
+
+ return null;
+ }
+ });
+ }
+ }
+ }
+
+ private HashMap<String, List<VarFieldPair>> getMaskLocalVars(ClassWrapper wrapper) {
+
+ HashMap<String, List<VarFieldPair>> mapMasks = new HashMap<String, List<VarFieldPair>>();
+
+ StructClass cl = wrapper.getClassStruct();
+
+ // iterate over constructors
+ for (StructMethod mt : cl.getMethods()) {
+ if ("<init>".equals(mt.getName())) {
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ MethodWrapper meth = wrapper.getMethodWrapper("<init>", mt.getDescriptor());
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ if (graph != null) { // something gone wrong, should not be null
+ List<VarFieldPair> fields = new ArrayList<VarFieldPair>();
+
+ int varindex = 1;
+ for (int i = 0; i < md.params.length; i++) { // no static methods allowed
+ String keyField = getEnclosingVarField(cl, meth, graph, varindex);
+ fields.add(keyField == null ? null : new VarFieldPair(keyField, new VarVersionPaar(-1, 0))); // TODO: null?
+ varindex += md.params[i].stack_size;
+ }
+ mapMasks.put(mt.getDescriptor(), fields);
+ }
+ }
+ }
+
+ return mapMasks;
+ }
+
+ private String getEnclosingVarField(StructClass cl, MethodWrapper meth, DirectGraph graph, final int index) {
+
+ String field = "";
+
+ // parameter variable final
+ if (meth.varproc.getVarFinal(new VarVersionPaar(index, 0)) == VarTypeProcessor.VAR_NONFINAL) {
+ return null;
+ }
+
+ boolean notsynth = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
+
+ // no loop at the begin
+ DirectNode firstnode = graph.first;
+ if (firstnode.preds.isEmpty()) {
+ // assignment to a final synthetic field?
+ for (Exprent exprent : firstnode.exprents) {
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ if (asexpr.getRight().type == Exprent.EXPRENT_VAR && ((VarExprent)asexpr.getRight()).getIndex() == index) {
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
+
+ FieldExprent left = (FieldExprent)asexpr.getLeft();
+ StructField fd = cl.getField(left.getName(), left.getDescriptor().descriptorString);
+
+ if (fd != null) { // local (== not inherited) field
+ if (cl.qualifiedName.equals(left.getClassname()) &&
+ (fd.access_flags & CodeConstants.ACC_FINAL) != 0 &&
+ ((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0 ||
+ fd.getAttributes().containsKey("Synthetic") ||
+ (notsynth && (fd.access_flags & CodeConstants.ACC_PRIVATE) != 0))) {
+ field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return field;
+ }
+
+ private void mergeListSignatures(List<VarFieldPair> first, List<VarFieldPair> second, boolean both) {
+
+ int i = 1;
+ for (; ; ) {
+ if (first.size() <= i || second.size() <= i) {
+ break;
+ }
+
+ VarFieldPair fobj = first.get(first.size() - i);
+ VarFieldPair sobj = second.get(second.size() - i);
+
+ boolean eq = false;
+ if (fobj == null || sobj == null) {
+ eq = (fobj == sobj);
+ }
+ else {
+ eq = true;
+ if (fobj.keyfield.length() == 0) {
+ fobj.keyfield = sobj.keyfield;
+ }
+ else if (sobj.keyfield.length() == 0) {
+ if (both) {
+ sobj.keyfield = fobj.keyfield;
+ }
+ }
+ else {
+ eq = fobj.keyfield.equals(sobj.keyfield);
+ }
+ }
+
+ if (!eq) {
+ first.set(first.size() - i, null);
+ if (both) {
+ second.set(second.size() - i, null);
+ }
+ }
+ else {
+ if (fobj != null) {
+ if (fobj.varpaar.var == -1) {
+ fobj.varpaar = sobj.varpaar;
+ }
+ else {
+ sobj.varpaar = fobj.varpaar;
+ }
+ }
+ }
+ i++;
+ }
+
+ for (int j = 1; j <= first.size() - i; j++) {
+ first.set(j, null);
+ }
+
+ if (both) {
+ for (int j = 1; j <= second.size() - i; j++) {
+ second.set(j, null);
+ }
+ }
+
+ // first
+ if (first.isEmpty()) {
+ if (!second.isEmpty() && both) {
+ second.set(0, null);
+ }
+ }
+ else if (second.isEmpty()) {
+ first.set(0, null);
+ }
+ else {
+ VarFieldPair fobj = first.get(0);
+ VarFieldPair sobj = second.get(0);
+
+ boolean eq = false;
+ if (fobj == null || sobj == null) {
+ eq = (fobj == sobj);
+ }
+ else {
+ eq = true;
+ if (fobj.keyfield.length() == 0) {
+ fobj.keyfield = sobj.keyfield;
+ }
+ else if (sobj.keyfield.length() == 0) {
+ if (both) {
+ sobj.keyfield = fobj.keyfield;
+ }
+ }
+ else {
+ eq = fobj.keyfield.equals(sobj.keyfield);
+ }
+ }
+
+ if (!eq) {
+ first.set(0, null);
+ if (both) {
+ second.set(0, null);
+ }
+ }
+ else if (fobj != null) {
+ if (fobj.varpaar.var == -1) {
+ fobj.varpaar = sobj.varpaar;
+ }
+ else {
+ sobj.varpaar = fobj.varpaar;
+ }
+ }
+ }
+ }
+
+
+ private void setLocalClassDefinition(MethodWrapper meth, ClassNode node) {
+
+ RootStatement root = meth.root;
+
+ HashSet<Statement> setStats = new HashSet<Statement>();
+ VarType classtype = new VarType(node.classStruct.qualifiedName, true);
+
+ Statement stdef = getDefStatement(root, classtype, setStats);
+ if (stdef == null) {
+ // unreferenced local class
+ stdef = root.getFirst();
+ }
+
+ Statement first = findFirstBlock(stdef, setStats);
+
+ List<Exprent> lst;
+ if (first == null) {
+ lst = stdef.getVarDefinitions();
+ }
+ else if (first.getExprents() == null) {
+ lst = first.getVarDefinitions();
+ }
+ else {
+ lst = first.getExprents();
+ }
+
+
+ int addindex = 0;
+ for (Exprent expr : lst) {
+ if (searchForClass(expr, classtype)) {
+ break;
+ }
+ addindex++;
+ }
+
+ VarExprent var = new VarExprent(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ classtype, meth.varproc);
+ var.setDefinition(true);
+ var.setClassdef(true);
+
+ lst.add(addindex, var);
+ }
+
+
+ private Statement findFirstBlock(Statement stat, HashSet<Statement> setStats) {
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(stat);
+
+ while (!stack.isEmpty()) {
+ Statement st = stack.remove(0);
+
+ if (stack.isEmpty() || setStats.contains(st)) {
+
+ if (st.isLabeled() && !stack.isEmpty()) {
+ return st;
+ }
+
+ if (st.getExprents() != null) {
+ return st;
+ }
+ else {
+ stack.clear();
+
+ switch (st.type) {
+ case Statement.TYPE_SEQUENCE:
+ stack.addAll(0, st.getStats());
+ break;
+ case Statement.TYPE_IF:
+ case Statement.TYPE_ROOT:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ stack.add(st.getFirst());
+ break;
+ default:
+ return st;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ private Statement getDefStatement(Statement stat, VarType classtype, HashSet<Statement> setStats) {
+
+ List<Exprent> condlst = new ArrayList<Exprent>();
+ Statement retstat = null;
+
+ if (stat.getExprents() == null) {
+ int counter = 0;
+
+ for (Object obj : stat.getSequentialObjects()) {
+ if (obj instanceof Statement) {
+ Statement st = (Statement)obj;
+
+ Statement stTemp = getDefStatement(st, classtype, setStats);
+
+ if (stTemp != null) {
+ if (counter == 1) {
+ retstat = stat;
+ break;
+ }
+ retstat = stTemp;
+ counter++;
+ }
+
+ if (st.type == DoStatement.TYPE_DO) {
+ DoStatement dost = (DoStatement)st;
+
+ condlst.addAll(dost.getInitExprentList());
+ condlst.addAll(dost.getConditionExprentList());
+ }
+ }
+ else if (obj instanceof Exprent) {
+ condlst.add((Exprent)obj);
+ }
+ }
+ }
+ else {
+ condlst = stat.getExprents();
+ }
+
+ if (retstat != stat) {
+ for (Exprent exprent : condlst) {
+ if (exprent != null && searchForClass(exprent, classtype)) {
+ retstat = stat;
+ break;
+ }
+ }
+ }
+
+ if (retstat != null) {
+ setStats.add(stat);
+ }
+
+ return retstat;
+ }
+
+ private boolean searchForClass(Exprent exprent, VarType classtype) {
+
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ String classname = classtype.value;
+
+ for (Exprent expr : lst) {
+
+ boolean res = false;
+
+ switch (expr.type) {
+ case Exprent.EXPRENT_CONST:
+ ConstExprent cexpr = (ConstExprent)expr;
+ res = (VarType.VARTYPE_CLASS.equals(cexpr.getConsttype()) && classname.equals(cexpr.getValue()) ||
+ classtype.equals(cexpr.getConsttype()));
+ break;
+ case Exprent.EXPRENT_FIELD:
+ res = classname.equals(((FieldExprent)expr).getClassname());
+ break;
+ case Exprent.EXPRENT_INVOCATION:
+ res = classname.equals(((InvocationExprent)expr).getClassname());
+ break;
+ case Exprent.EXPRENT_NEW:
+ VarType newType = expr.getExprType();
+ res = newType.type == CodeConstants.TYPE_OBJECT && classname.equals(newType.value);
+ break;
+ case Exprent.EXPRENT_VAR:
+ VarExprent vexpr = (VarExprent)expr;
+ if (vexpr.isDefinition()) {
+ VarType vtype = vexpr.getVartype();
+ if (classtype.equals(vtype) || (vtype.arraydim > 0 && classtype.value.equals(vtype.value))) {
+ res = true;
+ }
+ }
+ }
+
+ if (res) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ private class VarFieldPair {
+
+ public String keyfield = "";
+ public VarVersionPaar varpaar;
+
+ public VarFieldPair(String field, VarVersionPaar varpaar) {
+ this.keyfield = field;
+ this.varpaar = varpaar;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof VarFieldPair)) return false;
+
+ VarFieldPair pair = (VarFieldPair)o;
+ return keyfield.equals(pair.keyfield) && varpaar.equals(pair.varpaar);
+ }
+
+ @Override
+ public int hashCode() {
+ return keyfield.hashCode() + varpaar.hashCode();
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java b/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java
index 3eda632..e81a69e 100644
--- a/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java
+++ b/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java
@@ -1,35 +1,27 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.main.rels;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
@@ -37,421 +29,426 @@ import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+
public class NestedMemberAccess {
-
- private static final int METHOD_ACCESS_NORMAL = 1;
- private static final int METHOD_ACCESS_FIELDGET = 2;
- private static final int METHOD_ACCESS_FIELDSET = 3;
- private static final int METHOD_ACCESS_METHOD = 4;
-
- private boolean notSetSync;
-
- private HashMap<MethodWrapper, Integer> mapMethodType = new HashMap<MethodWrapper, Integer>();
-
-
- public void propagateMemberAccess(ClassNode root) {
-
- if(root.nested.isEmpty()) {
- return;
- }
-
- notSetSync = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
-
- computeMethodTypes(root);
-
- eliminateStaticAccess(root);
- }
-
-
- private void computeMethodTypes(ClassNode node) {
-
- if(node.type == ClassNode.CLASS_LAMBDA) {
- return;
- }
-
- for(ClassNode nd : node.nested) {
- computeMethodTypes(nd);
- }
-
- for(MethodWrapper meth : node.wrapper.getMethods()) {
- computeMethodType(node, meth);
- }
-
- }
-
- private void computeMethodType(ClassNode node, MethodWrapper meth) {
-
- int type = METHOD_ACCESS_NORMAL;
-
- if(meth.root != null) {
-
- DirectGraph graph = meth.getOrBuildGraph();
-
- int flags = meth.methodStruct.getAccessFlags();
- if(((flags & CodeConstants.ACC_SYNTHETIC) != 0 || meth.methodStruct.getAttributes().containsKey("Synthetic") || notSetSync) &&
- (flags & CodeConstants.ACC_STATIC) != 0) {
- if(graph.nodes.size() == 2) { // incl. dummy exit node
- if(graph.first.exprents.size() == 1) {
- Exprent exprent = graph.first.exprents.get(0);
-
- MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor());
- int parcount = mtdesc.params.length;
-
- Exprent exprCore = exprent;
-
- if(exprent.type == Exprent.EXPRENT_EXIT) {
- ExitExprent exexpr = (ExitExprent)exprent;
- if(exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
- exprCore = exexpr.getValue();
- }
- }
-
- switch(exprCore.type) {
- case Exprent.EXPRENT_FIELD:
- FieldExprent fexpr = (FieldExprent)exprCore;
- if((parcount == 1 && !fexpr.isStatic()) ||
- (parcount == 0 && fexpr.isStatic())) {
- if(fexpr.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
- if(fexpr.isStatic() || (fexpr.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpr.getInstance()).getIndex() == 0)) {
- type = METHOD_ACCESS_FIELDGET;
- }
- }
- }
- break;
- case Exprent.EXPRENT_VAR: // qualified this
- if(parcount == 1) {
- // this or final variable
- if(((VarExprent)exprCore).getIndex() != 0) {
- type = METHOD_ACCESS_FIELDGET;
- }
- }
-
- break;
- case Exprent.EXPRENT_INVOCATION:
- type = METHOD_ACCESS_METHOD;
- break;
- case Exprent.EXPRENT_ASSIGNMENT:
- AssignmentExprent asexpr = (AssignmentExprent)exprCore;
- if(asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
- FieldExprent fexpras = (FieldExprent)asexpr.getLeft();
- if((parcount == 2 && !fexpras.isStatic()) ||
- (parcount == 1 && fexpras.isStatic())) {
- if(fexpras.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
- if(fexpras.isStatic() || (fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) {
- if(((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
- type = METHOD_ACCESS_FIELDSET;
- }
- }
- }
- }
- }
- }
-
-
- if(type == METHOD_ACCESS_METHOD) { // FIXME: check for private flag of the method
-
- type = METHOD_ACCESS_NORMAL;
-
- InvocationExprent invexpr = (InvocationExprent)exprCore;
-
- if((invexpr.isStatic() && invexpr.getLstParameters().size() == parcount) || (!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR
- && ((VarExprent)invexpr.getInstance()).getIndex() == 0 && invexpr.getLstParameters().size() == parcount-1)) {
-
- boolean equalpars = true;
-
- for(int i=0;i<invexpr.getLstParameters().size();i++) {
- Exprent parexpr = invexpr.getLstParameters().get(i);
- if(parexpr.type != Exprent.EXPRENT_VAR ||
- ((VarExprent)parexpr).getIndex() != i + (invexpr.isStatic()?0:1)) {
- equalpars = false;
- break;
- }
- }
-
- if(equalpars) {
- type = METHOD_ACCESS_METHOD;
- }
- }
- }
- } else if(graph.first.exprents.size() == 2) {
- Exprent exprentFirst = graph.first.exprents.get(0);
- Exprent exprentSecond = graph.first.exprents.get(1);
-
- if(exprentFirst.type == Exprent.EXPRENT_ASSIGNMENT &&
- exprentSecond.type == Exprent.EXPRENT_EXIT) {
-
- MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor());
- int parcount = mtdesc.params.length;
-
- AssignmentExprent asexpr = (AssignmentExprent)exprentFirst;
- if(asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
- FieldExprent fexpras = (FieldExprent)asexpr.getLeft();
- if((parcount == 2 && !fexpras.isStatic()) ||
- (parcount == 1 && fexpras.isStatic())) {
- if(fexpras.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
- if(fexpras.isStatic() || (fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) {
- if(((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
-
- ExitExprent exexpr = (ExitExprent)exprentSecond;
- if(exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
- if(exexpr.getValue().type == Exprent.EXPRENT_VAR &&
- ((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
- type = METHOD_ACCESS_FIELDSET;
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
-
- }
- }
- }
-
- if(type != METHOD_ACCESS_NORMAL) {
- mapMethodType.put(meth, type);
- } else {
- mapMethodType.remove(meth);
- }
- }
-
-
-
- private void eliminateStaticAccess(ClassNode node) {
-
- if(node.type == ClassNode.CLASS_LAMBDA) {
- return;
- }
-
- for(MethodWrapper meth : node.wrapper.getMethods()) {
-
- if(meth.root != null) {
-
- boolean replaced = false;
-
- DirectGraph graph = meth.getOrBuildGraph();
-
- HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
- LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
- stack.add(graph.first);
-
- while(!stack.isEmpty()) { // TODO: replace with interface iterator?
-
- DirectNode nd = stack.removeFirst();
-
- if(setVisited.contains(nd)) {
- continue;
- }
- setVisited.add(nd);
-
- for(int i=0;i<nd.exprents.size();i++) {
- Exprent exprent = nd.exprents.get(i);
-
- replaced |= replaceInvocations(node, meth, exprent);
-
- if(exprent.type == Exprent.EXPRENT_INVOCATION) {
- Exprent ret = replaceAccessExprent(node, meth, (InvocationExprent)exprent);
-
- if(ret != null) {
- nd.exprents.set(i, ret);
- replaced = true;
- }
- }
- }
-
- for(DirectNode ndx: nd.succs) {
- stack.add(ndx);
- }
- }
-
- if(replaced) {
- computeMethodType(node, meth);
- }
-
- }
- }
-
- for(ClassNode child : node.nested) {
- eliminateStaticAccess(child);
- }
-
- }
-
-
- private boolean replaceInvocations(ClassNode caller, MethodWrapper meth, Exprent exprent) {
-
- boolean res = false;
-
- for(Exprent expr : exprent.getAllExprents()) {
- res |= replaceInvocations(caller, meth, expr);
- }
-
- for(;;) {
-
- boolean found = false;
-
- for(Exprent expr : exprent.getAllExprents()) {
- if(expr.type == Exprent.EXPRENT_INVOCATION) {
- Exprent newexpr = replaceAccessExprent(caller, meth, (InvocationExprent)expr);
- if(newexpr != null) {
- exprent.replaceExprent(expr, newexpr);
- found = true;
- res = true;
- break;
- }
- }
- }
-
- if(!found) {
- break;
- }
- }
-
- return res;
- }
-
- private boolean sameTree(ClassNode caller, ClassNode callee) {
-
- if(caller.classStruct.qualifiedName.equals(callee.classStruct.qualifiedName)) {
- return false;
- }
-
- while(caller.parent != null) {
- caller = caller.parent;
- }
-
- while(callee.parent != null) {
- callee = callee.parent;
- }
-
- return caller == callee;
- }
-
- private Exprent replaceAccessExprent(ClassNode caller, MethodWrapper methdest, InvocationExprent invexpr) {
-
- ClassNode node = DecompilerContext.getClassprocessor().getMapRootClasses().get(invexpr.getClassname());
-
- MethodWrapper methsource = null;
- if(node != null && node.wrapper != null) {
- methsource = node.wrapper.getMethodWrapper(invexpr.getName(), invexpr.getStringDescriptor());
- }
-
- if(methsource == null || !mapMethodType.containsKey(methsource)) {
- return null;
- }
-
- // if same method, return
- if(node.classStruct.qualifiedName.equals(caller.classStruct.qualifiedName) &&
- methsource.methodStruct.getName().equals(methdest.methodStruct.getName()) &&
- methsource.methodStruct.getDescriptor().equals(methdest.methodStruct.getDescriptor())) {
- // no recursive invocations permitted!
- return null;
- }
-
- int type = mapMethodType.get(methsource);
-
-// // FIXME: impossible case. METHOD_ACCESS_NORMAL is not saved in the map
-// if(type == METHOD_ACCESS_NORMAL) {
-// return null;
-// }
-
- if(!sameTree(caller, node)) {
- return null;
- }
-
- DirectGraph graph = methsource.getOrBuildGraph();
- Exprent source = graph.first.exprents.get(0);
-
- Exprent retexprent = null;
-
- switch(type) {
- case METHOD_ACCESS_FIELDGET:
- ExitExprent exsource = (ExitExprent)source;
- if(exsource.getValue().type == Exprent.EXPRENT_VAR) { // qualified this
- VarExprent var = (VarExprent)exsource.getValue();
- String varname = methsource.varproc.getVarName(new VarVersionPaar(var));
-
- if(!methdest.setOuterVarNames.contains(varname)) {
- VarNamesCollector vnc = new VarNamesCollector();
- vnc.addName(varname);
-
- methdest.varproc.refreshVarNames(vnc);
- methdest.setOuterVarNames.add(varname);
- }
-
- int index = methdest.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER);
- VarExprent ret = new VarExprent(index, var.getVartype(), methdest.varproc);
- methdest.varproc.setVarName(new VarVersionPaar(index, 0), varname);
-
- retexprent = ret;
- } else { // field
- FieldExprent ret = (FieldExprent)exsource.getValue().copy();
- if(!ret.isStatic()) {
- ret.replaceExprent(ret.getInstance(), invexpr.getLstParameters().get(0));
- }
- retexprent = ret;
- }
- break;
- case METHOD_ACCESS_FIELDSET:
- AssignmentExprent ret;
- if(source.type == Exprent.EXPRENT_EXIT) {
- ExitExprent extex = (ExitExprent)source;
- ret = (AssignmentExprent)((AssignmentExprent)extex.getValue()).copy();
- } else {
- ret = (AssignmentExprent)((AssignmentExprent)source).copy();
- }
- FieldExprent fexpr = (FieldExprent)ret.getLeft();
-
- if(fexpr.isStatic()) {
- ret.replaceExprent(ret.getRight(), invexpr.getLstParameters().get(0));
- } else {
- ret.replaceExprent(ret.getRight(), invexpr.getLstParameters().get(1));
- fexpr.replaceExprent(fexpr.getInstance(), invexpr.getLstParameters().get(0));
- }
- retexprent = ret;
- break;
- case METHOD_ACCESS_METHOD:
- if(source.type == Exprent.EXPRENT_EXIT) {
- source = ((ExitExprent)source).getValue();
- }
-
- InvocationExprent invret = (InvocationExprent)source.copy();
-
- int index = 0;
- if(!invret.isStatic()) {
- invret.replaceExprent(invret.getInstance(), invexpr.getLstParameters().get(0));
- index = 1;
- }
-
- for(int i=0;i<invret.getLstParameters().size();i++) {
- invret.replaceExprent(invret.getLstParameters().get(i), invexpr.getLstParameters().get(i + index));
- }
-
- retexprent = invret;
- }
-
-
- if(retexprent != null) {
- // hide synthetic access method
- boolean hide = true;
-
- if(node.type == ClassNode.CLASS_ROOT || (node.access & CodeConstants.ACC_STATIC) != 0) {
- StructMethod mt = methsource.methodStruct;
- if((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) == 0 && !mt.getAttributes().containsKey("Synthetic")) {
- hide = false;
- }
- }
- if(hide) {
- node.wrapper.getHideMembers().add(InterpreterUtil.makeUniqueKey(invexpr.getName(), invexpr.getStringDescriptor()));
- }
- }
-
- return retexprent;
- }
-
-
+
+ private static final int METHOD_ACCESS_NORMAL = 1;
+ private static final int METHOD_ACCESS_FIELDGET = 2;
+ private static final int METHOD_ACCESS_FIELDSET = 3;
+ private static final int METHOD_ACCESS_METHOD = 4;
+
+ private boolean notSetSync;
+
+ private HashMap<MethodWrapper, Integer> mapMethodType = new HashMap<MethodWrapper, Integer>();
+
+
+ public void propagateMemberAccess(ClassNode root) {
+
+ if (root.nested.isEmpty()) {
+ return;
+ }
+
+ notSetSync = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
+
+ computeMethodTypes(root);
+
+ eliminateStaticAccess(root);
+ }
+
+
+ private void computeMethodTypes(ClassNode node) {
+
+ if (node.type == ClassNode.CLASS_LAMBDA) {
+ return;
+ }
+
+ for (ClassNode nd : node.nested) {
+ computeMethodTypes(nd);
+ }
+
+ for (MethodWrapper meth : node.wrapper.getMethods()) {
+ computeMethodType(node, meth);
+ }
+ }
+
+ private void computeMethodType(ClassNode node, MethodWrapper meth) {
+
+ int type = METHOD_ACCESS_NORMAL;
+
+ if (meth.root != null) {
+
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ int flags = meth.methodStruct.getAccessFlags();
+ if (((flags & CodeConstants.ACC_SYNTHETIC) != 0 || meth.methodStruct.getAttributes().containsKey("Synthetic") || notSetSync) &&
+ (flags & CodeConstants.ACC_STATIC) != 0) {
+ if (graph.nodes.size() == 2) { // incl. dummy exit node
+ if (graph.first.exprents.size() == 1) {
+ Exprent exprent = graph.first.exprents.get(0);
+
+ MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor());
+ int parcount = mtdesc.params.length;
+
+ Exprent exprCore = exprent;
+
+ if (exprent.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exexpr = (ExitExprent)exprent;
+ if (exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
+ exprCore = exexpr.getValue();
+ }
+ }
+
+ switch (exprCore.type) {
+ case Exprent.EXPRENT_FIELD:
+ FieldExprent fexpr = (FieldExprent)exprCore;
+ if ((parcount == 1 && !fexpr.isStatic()) ||
+ (parcount == 0 && fexpr.isStatic())) {
+ if (fexpr.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
+ if (fexpr.isStatic() ||
+ (fexpr.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpr.getInstance()).getIndex() == 0)) {
+ type = METHOD_ACCESS_FIELDGET;
+ }
+ }
+ }
+ break;
+ case Exprent.EXPRENT_VAR: // qualified this
+ if (parcount == 1) {
+ // this or final variable
+ if (((VarExprent)exprCore).getIndex() != 0) {
+ type = METHOD_ACCESS_FIELDGET;
+ }
+ }
+
+ break;
+ case Exprent.EXPRENT_INVOCATION:
+ type = METHOD_ACCESS_METHOD;
+ break;
+ case Exprent.EXPRENT_ASSIGNMENT:
+ AssignmentExprent asexpr = (AssignmentExprent)exprCore;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
+ FieldExprent fexpras = (FieldExprent)asexpr.getLeft();
+ if ((parcount == 2 && !fexpras.isStatic()) ||
+ (parcount == 1 && fexpras.isStatic())) {
+ if (fexpras.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
+ if (fexpras.isStatic() ||
+ (fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) {
+ if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
+ type = METHOD_ACCESS_FIELDSET;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ if (type == METHOD_ACCESS_METHOD) { // FIXME: check for private flag of the method
+
+ type = METHOD_ACCESS_NORMAL;
+
+ InvocationExprent invexpr = (InvocationExprent)exprCore;
+
+ if ((invexpr.isStatic() && invexpr.getLstParameters().size() == parcount) ||
+ (!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR
+ && ((VarExprent)invexpr.getInstance()).getIndex() == 0 && invexpr.getLstParameters().size() == parcount - 1)) {
+
+ boolean equalpars = true;
+
+ for (int i = 0; i < invexpr.getLstParameters().size(); i++) {
+ Exprent parexpr = invexpr.getLstParameters().get(i);
+ if (parexpr.type != Exprent.EXPRENT_VAR ||
+ ((VarExprent)parexpr).getIndex() != i + (invexpr.isStatic() ? 0 : 1)) {
+ equalpars = false;
+ break;
+ }
+ }
+
+ if (equalpars) {
+ type = METHOD_ACCESS_METHOD;
+ }
+ }
+ }
+ }
+ else if (graph.first.exprents.size() == 2) {
+ Exprent exprentFirst = graph.first.exprents.get(0);
+ Exprent exprentSecond = graph.first.exprents.get(1);
+
+ if (exprentFirst.type == Exprent.EXPRENT_ASSIGNMENT &&
+ exprentSecond.type == Exprent.EXPRENT_EXIT) {
+
+ MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor());
+ int parcount = mtdesc.params.length;
+
+ AssignmentExprent asexpr = (AssignmentExprent)exprentFirst;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
+ FieldExprent fexpras = (FieldExprent)asexpr.getLeft();
+ if ((parcount == 2 && !fexpras.isStatic()) ||
+ (parcount == 1 && fexpras.isStatic())) {
+ if (fexpras.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
+ if (fexpras.isStatic() ||
+ (fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) {
+ if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
+
+ ExitExprent exexpr = (ExitExprent)exprentSecond;
+ if (exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
+ if (exexpr.getValue().type == Exprent.EXPRENT_VAR &&
+ ((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
+ type = METHOD_ACCESS_FIELDSET;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (type != METHOD_ACCESS_NORMAL) {
+ mapMethodType.put(meth, type);
+ }
+ else {
+ mapMethodType.remove(meth);
+ }
+ }
+
+
+ private void eliminateStaticAccess(ClassNode node) {
+
+ if (node.type == ClassNode.CLASS_LAMBDA) {
+ return;
+ }
+
+ for (MethodWrapper meth : node.wrapper.getMethods()) {
+
+ if (meth.root != null) {
+
+ boolean replaced = false;
+
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ stack.add(graph.first);
+
+ while (!stack.isEmpty()) { // TODO: replace with interface iterator?
+
+ DirectNode nd = stack.removeFirst();
+
+ if (setVisited.contains(nd)) {
+ continue;
+ }
+ setVisited.add(nd);
+
+ for (int i = 0; i < nd.exprents.size(); i++) {
+ Exprent exprent = nd.exprents.get(i);
+
+ replaced |= replaceInvocations(node, meth, exprent);
+
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ Exprent ret = replaceAccessExprent(node, meth, (InvocationExprent)exprent);
+
+ if (ret != null) {
+ nd.exprents.set(i, ret);
+ replaced = true;
+ }
+ }
+ }
+
+ for (DirectNode ndx : nd.succs) {
+ stack.add(ndx);
+ }
+ }
+
+ if (replaced) {
+ computeMethodType(node, meth);
+ }
+ }
+ }
+
+ for (ClassNode child : node.nested) {
+ eliminateStaticAccess(child);
+ }
+ }
+
+
+ private boolean replaceInvocations(ClassNode caller, MethodWrapper meth, Exprent exprent) {
+
+ boolean res = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ res |= replaceInvocations(caller, meth, expr);
+ }
+
+ for (; ; ) {
+
+ boolean found = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ if (expr.type == Exprent.EXPRENT_INVOCATION) {
+ Exprent newexpr = replaceAccessExprent(caller, meth, (InvocationExprent)expr);
+ if (newexpr != null) {
+ exprent.replaceExprent(expr, newexpr);
+ found = true;
+ res = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ return res;
+ }
+
+ private boolean sameTree(ClassNode caller, ClassNode callee) {
+
+ if (caller.classStruct.qualifiedName.equals(callee.classStruct.qualifiedName)) {
+ return false;
+ }
+
+ while (caller.parent != null) {
+ caller = caller.parent;
+ }
+
+ while (callee.parent != null) {
+ callee = callee.parent;
+ }
+
+ return caller == callee;
+ }
+
+ private Exprent replaceAccessExprent(ClassNode caller, MethodWrapper methdest, InvocationExprent invexpr) {
+
+ ClassNode node = DecompilerContext.getClassprocessor().getMapRootClasses().get(invexpr.getClassname());
+
+ MethodWrapper methsource = null;
+ if (node != null && node.wrapper != null) {
+ methsource = node.wrapper.getMethodWrapper(invexpr.getName(), invexpr.getStringDescriptor());
+ }
+
+ if (methsource == null || !mapMethodType.containsKey(methsource)) {
+ return null;
+ }
+
+ // if same method, return
+ if (node.classStruct.qualifiedName.equals(caller.classStruct.qualifiedName) &&
+ methsource.methodStruct.getName().equals(methdest.methodStruct.getName()) &&
+ methsource.methodStruct.getDescriptor().equals(methdest.methodStruct.getDescriptor())) {
+ // no recursive invocations permitted!
+ return null;
+ }
+
+ int type = mapMethodType.get(methsource);
+
+ // // FIXME: impossible case. METHOD_ACCESS_NORMAL is not saved in the map
+ // if(type == METHOD_ACCESS_NORMAL) {
+ // return null;
+ // }
+
+ if (!sameTree(caller, node)) {
+ return null;
+ }
+
+ DirectGraph graph = methsource.getOrBuildGraph();
+ Exprent source = graph.first.exprents.get(0);
+
+ Exprent retexprent = null;
+
+ switch (type) {
+ case METHOD_ACCESS_FIELDGET:
+ ExitExprent exsource = (ExitExprent)source;
+ if (exsource.getValue().type == Exprent.EXPRENT_VAR) { // qualified this
+ VarExprent var = (VarExprent)exsource.getValue();
+ String varname = methsource.varproc.getVarName(new VarVersionPaar(var));
+
+ if (!methdest.setOuterVarNames.contains(varname)) {
+ VarNamesCollector vnc = new VarNamesCollector();
+ vnc.addName(varname);
+
+ methdest.varproc.refreshVarNames(vnc);
+ methdest.setOuterVarNames.add(varname);
+ }
+
+ int index = methdest.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER);
+ VarExprent ret = new VarExprent(index, var.getVartype(), methdest.varproc);
+ methdest.varproc.setVarName(new VarVersionPaar(index, 0), varname);
+
+ retexprent = ret;
+ }
+ else { // field
+ FieldExprent ret = (FieldExprent)exsource.getValue().copy();
+ if (!ret.isStatic()) {
+ ret.replaceExprent(ret.getInstance(), invexpr.getLstParameters().get(0));
+ }
+ retexprent = ret;
+ }
+ break;
+ case METHOD_ACCESS_FIELDSET:
+ AssignmentExprent ret;
+ if (source.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent extex = (ExitExprent)source;
+ ret = (AssignmentExprent)((AssignmentExprent)extex.getValue()).copy();
+ }
+ else {
+ ret = (AssignmentExprent)((AssignmentExprent)source).copy();
+ }
+ FieldExprent fexpr = (FieldExprent)ret.getLeft();
+
+ if (fexpr.isStatic()) {
+ ret.replaceExprent(ret.getRight(), invexpr.getLstParameters().get(0));
+ }
+ else {
+ ret.replaceExprent(ret.getRight(), invexpr.getLstParameters().get(1));
+ fexpr.replaceExprent(fexpr.getInstance(), invexpr.getLstParameters().get(0));
+ }
+ retexprent = ret;
+ break;
+ case METHOD_ACCESS_METHOD:
+ if (source.type == Exprent.EXPRENT_EXIT) {
+ source = ((ExitExprent)source).getValue();
+ }
+
+ InvocationExprent invret = (InvocationExprent)source.copy();
+
+ int index = 0;
+ if (!invret.isStatic()) {
+ invret.replaceExprent(invret.getInstance(), invexpr.getLstParameters().get(0));
+ index = 1;
+ }
+
+ for (int i = 0; i < invret.getLstParameters().size(); i++) {
+ invret.replaceExprent(invret.getLstParameters().get(i), invexpr.getLstParameters().get(i + index));
+ }
+
+ retexprent = invret;
+ }
+
+
+ if (retexprent != null) {
+ // hide synthetic access method
+ boolean hide = true;
+
+ if (node.type == ClassNode.CLASS_ROOT || (node.access & CodeConstants.ACC_STATIC) != 0) {
+ StructMethod mt = methsource.methodStruct;
+ if ((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) == 0 && !mt.getAttributes().containsKey("Synthetic")) {
+ hide = false;
+ }
+ }
+ if (hide) {
+ node.wrapper.getHideMembers().add(InterpreterUtil.makeUniqueKey(invexpr.getName(), invexpr.getStringDescriptor()));
+ }
+ }
+
+ return retexprent;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java b/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java
index 4d39e68..386f6ae 100644
--- a/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java
@@ -1,24 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.code;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.code.Instruction;
import org.jetbrains.java.decompiler.code.InstructionSequence;
@@ -28,411 +24,416 @@ import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+
public class DeadCodeHelper {
- public static void removeDeadBlocks(ControlFlowGraph graph) {
-
- LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
- HashSet<BasicBlock> setStacked = new HashSet<BasicBlock>();
-
- stack.add(graph.getFirst());
- setStacked.add(graph.getFirst());
-
- while(!stack.isEmpty()) {
- BasicBlock block = stack.removeFirst();
-
- List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
- lstSuccs.addAll(block.getSuccExceptions());
-
- for(BasicBlock succ : lstSuccs) {
- if(!setStacked.contains(succ)) {
- stack.add(succ);
- setStacked.add(succ);
- }
- }
- }
-
- HashSet<BasicBlock> setAllBlocks = new HashSet<BasicBlock>(graph.getBlocks());
- setAllBlocks.removeAll(setStacked);
-
- for(BasicBlock block : setAllBlocks) {
- graph.removeBlock(block);
- }
- }
-
- public static void removeEmptyBlocks(ControlFlowGraph graph) {
-
- List<BasicBlock> blocks = graph.getBlocks();
-
- boolean cont;
- do {
- cont = false;
-
- for(int i=blocks.size()-1;i>=0;i--) {
- BasicBlock block = (BasicBlock)blocks.get(i);
-
- if(removeEmptyBlock(graph, block, false)) {
- cont = true;
- break;
- }
- }
-
- } while(cont);
- }
-
- private static boolean removeEmptyBlock(ControlFlowGraph graph, BasicBlock block, boolean merging) {
-
- boolean deletedRanges = false;
-
- if(block.getSeq().isEmpty()) {
-
- if(block.getSuccs().size() > 1) {
- if(block.getPreds().size()>1) {
- // ambiguous block
- throw new RuntimeException("ERROR: empty block with multiple predecessors and successors found");
- } else if(!merging) {
- throw new RuntimeException("ERROR: empty block with multiple successors found");
- }
- }
-
- HashSet<BasicBlock> setExits = new HashSet<BasicBlock>(graph.getLast().getPreds());
-
- if(block.getPredExceptions().isEmpty() &&
- (!setExits.contains(block) || block.getPreds().size() == 1)) {
-
- if(setExits.contains(block)) {
- BasicBlock pred = block.getPreds().get(0);
-
- // FIXME: flag in the basic block
- if(pred.getSuccs().size() != 1 || (!pred.getSeq().isEmpty()
- && pred.getSeq().getLastInstr().group == CodeConstants.GROUP_SWITCH)) {
- return false;
- }
- }
-
- HashSet<BasicBlock> setPreds = new HashSet<BasicBlock>(block.getPreds());
- HashSet<BasicBlock> setSuccs = new HashSet<BasicBlock>(block.getSuccs());
-
- // collect common exception ranges of predecessors and successors
- HashSet<BasicBlock> setCommonExceptionHandlers = null;
- for(int i = 0; i < 2; ++i) {
- for(BasicBlock pred : i == 0 ? setPreds : setSuccs) {
- if(setCommonExceptionHandlers == null) {
- setCommonExceptionHandlers = new HashSet<BasicBlock>(pred.getSuccExceptions());
- } else {
- setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
- }
- }
- }
-
- // check the block to be in each of the common ranges
- if(setCommonExceptionHandlers != null && !setCommonExceptionHandlers.isEmpty()) {
- for(BasicBlock handler : setCommonExceptionHandlers) {
- if(!block.getSuccExceptions().contains(handler)) {
- return false;
- }
- }
- }
-
- // remove ranges consisting of this one block
- List<ExceptionRangeCFG> lstRanges = graph.getExceptions();
- for(int i=lstRanges.size()-1;i>=0;i--) {
- ExceptionRangeCFG range = lstRanges.get(i);
- List<BasicBlock> lst = range.getProtectedRange();
-
- if(lst.size() == 1 && lst.get(0) == block) {
- if(DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) {
- block.removeSuccessorException(range.getHandler());
- lstRanges.remove(i);
-
- deletedRanges = true;
- } else {
- return false;
- }
- }
- }
-
-
- // connect remaining nodes
- if(merging) {
- BasicBlock pred = block.getPreds().get(0);
- pred.removeSuccessor(block);
-
- List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
- for(BasicBlock succ : lstSuccs) {
- block.removeSuccessor(succ);
- pred.addSuccessor(succ);
- }
-
- } else {
- for(BasicBlock pred : setPreds) {
- for(BasicBlock succ : setSuccs) {
- pred.replaceSuccessor(block, succ);
- }
- }
- }
-
- // finally exit edges
- HashSet<BasicBlock> setFinallyExits = graph.getFinallyExits();
- if(setFinallyExits.contains(block)) {
- setFinallyExits.remove(block);
- setFinallyExits.add(setPreds.iterator().next());
- }
-
- // replace first if necessary
- if(graph.getFirst() == block) {
- if(setSuccs.size() != 1) {
- throw new RuntimeException("multiple or no entry blocks!");
- } else {
- graph.setFirst(setSuccs.iterator().next());
- }
- }
-
- // remove this block
- graph.removeBlock(block);
-
- if(deletedRanges) {
- DeadCodeHelper.removeDeadBlocks(graph);
- }
- }
- }
-
- return deletedRanges;
- }
-
-
- public static boolean isDominator(ControlFlowGraph graph, BasicBlock block, BasicBlock dom) {
-
- HashSet<BasicBlock> marked = new HashSet<BasicBlock>();
-
- if(block == dom) {
- return true;
- }
-
- LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
- lstNodes.add(block);
-
- while(!lstNodes.isEmpty()) {
-
- BasicBlock node = (BasicBlock)lstNodes.remove(0);
- if(marked.contains(node)) {
- continue;
- } else {
- marked.add(node);
- }
-
- if(node == graph.getFirst()) {
- return false;
- }
-
- for(int i=0;i<node.getPreds().size();i++) {
- BasicBlock pred = (BasicBlock)node.getPreds().get(i);
- if(!marked.contains(pred) && pred != dom) {
- lstNodes.add(pred);
- }
- }
-
- for(int i=0;i<node.getPredExceptions().size();i++) {
- BasicBlock pred = (BasicBlock)node.getPredExceptions().get(i);
- if(!marked.contains(pred) && pred != dom) {
- lstNodes.add(pred);
- }
- }
- }
-
- return true;
- }
-
- public static void removeGotos(ControlFlowGraph graph) {
-
- for(BasicBlock block : graph.getBlocks()) {
- Instruction instr = block.getLastInstruction();
-
- if(instr!=null && instr.opcode == CodeConstants.opc_goto) {
- block.getSeq().removeInstruction(block.getSeq().length()-1);
- }
- }
-
- DeadCodeHelper.removeEmptyBlocks(graph);
- }
-
- public static void connectDummyExitBlock(ControlFlowGraph graph) {
-
- BasicBlock exit = graph.getLast();
- for(BasicBlock block : new HashSet<BasicBlock>(exit.getPreds())) {
- exit.removePredecessor(block);
- block.addSuccessor(exit);
- }
- }
-
- public static void incorporateValueReturns(ControlFlowGraph graph) {
-
- for(BasicBlock block: graph.getBlocks()) {
- InstructionSequence seq = block.getSeq();
-
- int len = seq.length();
- if(len > 0 && len < 3) {
-
- boolean ok = false;
-
- if(seq.getLastInstr().opcode >= CodeConstants.opc_ireturn && seq.getLastInstr().opcode <= CodeConstants.opc_return) {
- if(len == 1) {
- ok = true;
- } else if(seq.getLastInstr().opcode != CodeConstants.opc_return){
- switch(seq.getInstr(0).opcode) {
- case CodeConstants.opc_iload:
- case CodeConstants.opc_lload:
- case CodeConstants.opc_fload:
- case CodeConstants.opc_dload:
- case CodeConstants.opc_aload:
- case CodeConstants.opc_aconst_null:
- case CodeConstants.opc_bipush:
- case CodeConstants.opc_sipush:
- case CodeConstants.opc_lconst_0:
- case CodeConstants.opc_lconst_1:
- case CodeConstants.opc_fconst_0:
- case CodeConstants.opc_fconst_1:
- case CodeConstants.opc_fconst_2:
- case CodeConstants.opc_dconst_0:
- case CodeConstants.opc_dconst_1:
- case CodeConstants.opc_ldc:
- case CodeConstants.opc_ldc_w:
- case CodeConstants.opc_ldc2_w:
- ok = true;
- }
- }
- }
-
- if(ok) {
-
- if(!block.getPreds().isEmpty()) {
-
- HashSet<BasicBlock> setPredHandlersUnion = new HashSet<BasicBlock>();
- HashSet<BasicBlock> setPredHandlersIntersection = new HashSet<BasicBlock>();
-
- boolean firstpred = true;
- for(BasicBlock pred : block.getPreds()) {
- if(firstpred) {
- setPredHandlersIntersection.addAll(pred.getSuccExceptions());
- firstpred = false;
- } else {
- setPredHandlersIntersection.retainAll(pred.getSuccExceptions());
- }
-
- setPredHandlersUnion.addAll(pred.getSuccExceptions());
- }
-
- // add exception ranges from predecessors
- setPredHandlersIntersection.removeAll(block.getSuccExceptions());
- BasicBlock predecessor = block.getPreds().get(0);
-
- for(BasicBlock handler : setPredHandlersIntersection) {
- ExceptionRangeCFG range = graph.getExceptionRange(handler, predecessor);
-
- range.getProtectedRange().add(block);
- block.addSuccessorException(handler);
- }
-
- // remove redundant ranges
- HashSet<BasicBlock> setRangesToBeRemoved = new HashSet<BasicBlock>(block.getSuccExceptions());
- setRangesToBeRemoved.removeAll(setPredHandlersUnion);
-
- for(BasicBlock handler : setRangesToBeRemoved) {
- ExceptionRangeCFG range = graph.getExceptionRange(handler, block);
-
- if(range.getProtectedRange().size() > 1) {
- range.getProtectedRange().remove(block);
- block.removeSuccessorException(handler);
- }
- }
- }
-
-
- if(block.getPreds().size() == 1 && block.getPredExceptions().isEmpty()) {
-
- BasicBlock bpred = block.getPreds().get(0);
- if(bpred.getSuccs().size() == 1) {
-
- // add exception ranges of predecessor
- for(BasicBlock succ : bpred.getSuccExceptions()) {
- if(!block.getSuccExceptions().contains(succ)) {
- ExceptionRangeCFG range = graph.getExceptionRange(succ, bpred);
-
- range.getProtectedRange().add(block);
- block.addSuccessorException(succ);
- }
- }
-
- // remove superfluous ranges from successors
- for(BasicBlock succ : new HashSet<BasicBlock>(block.getSuccExceptions())) {
- if(!bpred.getSuccExceptions().contains(succ)) {
- ExceptionRangeCFG range = graph.getExceptionRange(succ, block);
-
- if(range.getProtectedRange().size() > 1) {
- range.getProtectedRange().remove(block);
- block.removeSuccessorException(succ);
- }
- }
- }
- }
- }
-
- }
- }
-
- }
-
- }
-
-
- public static void mergeBasicBlocks(ControlFlowGraph graph) {
-
- for(;;) {
-
- boolean merged = false;
-
- for(BasicBlock block: graph.getBlocks()) {
-
- InstructionSequence seq = block.getSeq();
-
- if(block.getSuccs().size() == 1) {
- BasicBlock next = block.getSuccs().get(0);
-
- if(next != graph.getLast() && (seq.isEmpty() || seq.getLastInstr().group != CodeConstants.GROUP_SWITCH)) {
-
- if(next.getPreds().size() == 1 && next.getPredExceptions().isEmpty()
- && next != graph.getFirst()) {
- // TODO: implement a dummy start block
- boolean sameRanges = true;
- for(ExceptionRangeCFG range : graph.getExceptions()) {
- if(range.getProtectedRange().contains(block) ^
- range.getProtectedRange().contains(next)) {
- sameRanges = false;
- break;
- }
- }
-
- if(sameRanges) {
- seq.addSequence(next.getSeq());
- next.getSeq().clear();
-
- removeEmptyBlock(graph, next, true);
-
- merged = true;
- break;
- }
- }
- }
- }
-
- }
-
- if(!merged) {
- break;
- }
- }
-
- }
-
-
+ public static void removeDeadBlocks(ControlFlowGraph graph) {
+
+ LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
+ HashSet<BasicBlock> setStacked = new HashSet<BasicBlock>();
+
+ stack.add(graph.getFirst());
+ setStacked.add(graph.getFirst());
+
+ while (!stack.isEmpty()) {
+ BasicBlock block = stack.removeFirst();
+
+ List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
+ lstSuccs.addAll(block.getSuccExceptions());
+
+ for (BasicBlock succ : lstSuccs) {
+ if (!setStacked.contains(succ)) {
+ stack.add(succ);
+ setStacked.add(succ);
+ }
+ }
+ }
+
+ HashSet<BasicBlock> setAllBlocks = new HashSet<BasicBlock>(graph.getBlocks());
+ setAllBlocks.removeAll(setStacked);
+
+ for (BasicBlock block : setAllBlocks) {
+ graph.removeBlock(block);
+ }
+ }
+
+ public static void removeEmptyBlocks(ControlFlowGraph graph) {
+
+ List<BasicBlock> blocks = graph.getBlocks();
+
+ boolean cont;
+ do {
+ cont = false;
+
+ for (int i = blocks.size() - 1; i >= 0; i--) {
+ BasicBlock block = (BasicBlock)blocks.get(i);
+
+ if (removeEmptyBlock(graph, block, false)) {
+ cont = true;
+ break;
+ }
+ }
+ }
+ while (cont);
+ }
+
+ private static boolean removeEmptyBlock(ControlFlowGraph graph, BasicBlock block, boolean merging) {
+
+ boolean deletedRanges = false;
+
+ if (block.getSeq().isEmpty()) {
+
+ if (block.getSuccs().size() > 1) {
+ if (block.getPreds().size() > 1) {
+ // ambiguous block
+ throw new RuntimeException("ERROR: empty block with multiple predecessors and successors found");
+ }
+ else if (!merging) {
+ throw new RuntimeException("ERROR: empty block with multiple successors found");
+ }
+ }
+
+ HashSet<BasicBlock> setExits = new HashSet<BasicBlock>(graph.getLast().getPreds());
+
+ if (block.getPredExceptions().isEmpty() &&
+ (!setExits.contains(block) || block.getPreds().size() == 1)) {
+
+ if (setExits.contains(block)) {
+ BasicBlock pred = block.getPreds().get(0);
+
+ // FIXME: flag in the basic block
+ if (pred.getSuccs().size() != 1 || (!pred.getSeq().isEmpty()
+ && pred.getSeq().getLastInstr().group == CodeConstants.GROUP_SWITCH)) {
+ return false;
+ }
+ }
+
+ HashSet<BasicBlock> setPreds = new HashSet<BasicBlock>(block.getPreds());
+ HashSet<BasicBlock> setSuccs = new HashSet<BasicBlock>(block.getSuccs());
+
+ // collect common exception ranges of predecessors and successors
+ HashSet<BasicBlock> setCommonExceptionHandlers = null;
+ for (int i = 0; i < 2; ++i) {
+ for (BasicBlock pred : i == 0 ? setPreds : setSuccs) {
+ if (setCommonExceptionHandlers == null) {
+ setCommonExceptionHandlers = new HashSet<BasicBlock>(pred.getSuccExceptions());
+ }
+ else {
+ setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
+ }
+ }
+ }
+
+ // check the block to be in each of the common ranges
+ if (setCommonExceptionHandlers != null && !setCommonExceptionHandlers.isEmpty()) {
+ for (BasicBlock handler : setCommonExceptionHandlers) {
+ if (!block.getSuccExceptions().contains(handler)) {
+ return false;
+ }
+ }
+ }
+
+ // remove ranges consisting of this one block
+ List<ExceptionRangeCFG> lstRanges = graph.getExceptions();
+ for (int i = lstRanges.size() - 1; i >= 0; i--) {
+ ExceptionRangeCFG range = lstRanges.get(i);
+ List<BasicBlock> lst = range.getProtectedRange();
+
+ if (lst.size() == 1 && lst.get(0) == block) {
+ if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) {
+ block.removeSuccessorException(range.getHandler());
+ lstRanges.remove(i);
+
+ deletedRanges = true;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+
+
+ // connect remaining nodes
+ if (merging) {
+ BasicBlock pred = block.getPreds().get(0);
+ pred.removeSuccessor(block);
+
+ List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
+ for (BasicBlock succ : lstSuccs) {
+ block.removeSuccessor(succ);
+ pred.addSuccessor(succ);
+ }
+ }
+ else {
+ for (BasicBlock pred : setPreds) {
+ for (BasicBlock succ : setSuccs) {
+ pred.replaceSuccessor(block, succ);
+ }
+ }
+ }
+
+ // finally exit edges
+ HashSet<BasicBlock> setFinallyExits = graph.getFinallyExits();
+ if (setFinallyExits.contains(block)) {
+ setFinallyExits.remove(block);
+ setFinallyExits.add(setPreds.iterator().next());
+ }
+
+ // replace first if necessary
+ if (graph.getFirst() == block) {
+ if (setSuccs.size() != 1) {
+ throw new RuntimeException("multiple or no entry blocks!");
+ }
+ else {
+ graph.setFirst(setSuccs.iterator().next());
+ }
+ }
+
+ // remove this block
+ graph.removeBlock(block);
+
+ if (deletedRanges) {
+ DeadCodeHelper.removeDeadBlocks(graph);
+ }
+ }
+ }
+
+ return deletedRanges;
+ }
+
+
+ public static boolean isDominator(ControlFlowGraph graph, BasicBlock block, BasicBlock dom) {
+
+ HashSet<BasicBlock> marked = new HashSet<BasicBlock>();
+
+ if (block == dom) {
+ return true;
+ }
+
+ LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
+ lstNodes.add(block);
+
+ while (!lstNodes.isEmpty()) {
+
+ BasicBlock node = (BasicBlock)lstNodes.remove(0);
+ if (marked.contains(node)) {
+ continue;
+ }
+ else {
+ marked.add(node);
+ }
+
+ if (node == graph.getFirst()) {
+ return false;
+ }
+
+ for (int i = 0; i < node.getPreds().size(); i++) {
+ BasicBlock pred = (BasicBlock)node.getPreds().get(i);
+ if (!marked.contains(pred) && pred != dom) {
+ lstNodes.add(pred);
+ }
+ }
+
+ for (int i = 0; i < node.getPredExceptions().size(); i++) {
+ BasicBlock pred = (BasicBlock)node.getPredExceptions().get(i);
+ if (!marked.contains(pred) && pred != dom) {
+ lstNodes.add(pred);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static void removeGotos(ControlFlowGraph graph) {
+
+ for (BasicBlock block : graph.getBlocks()) {
+ Instruction instr = block.getLastInstruction();
+
+ if (instr != null && instr.opcode == CodeConstants.opc_goto) {
+ block.getSeq().removeInstruction(block.getSeq().length() - 1);
+ }
+ }
+
+ DeadCodeHelper.removeEmptyBlocks(graph);
+ }
+
+ public static void connectDummyExitBlock(ControlFlowGraph graph) {
+
+ BasicBlock exit = graph.getLast();
+ for (BasicBlock block : new HashSet<BasicBlock>(exit.getPreds())) {
+ exit.removePredecessor(block);
+ block.addSuccessor(exit);
+ }
+ }
+
+ public static void incorporateValueReturns(ControlFlowGraph graph) {
+
+ for (BasicBlock block : graph.getBlocks()) {
+ InstructionSequence seq = block.getSeq();
+
+ int len = seq.length();
+ if (len > 0 && len < 3) {
+
+ boolean ok = false;
+
+ if (seq.getLastInstr().opcode >= CodeConstants.opc_ireturn && seq.getLastInstr().opcode <= CodeConstants.opc_return) {
+ if (len == 1) {
+ ok = true;
+ }
+ else if (seq.getLastInstr().opcode != CodeConstants.opc_return) {
+ switch (seq.getInstr(0).opcode) {
+ case CodeConstants.opc_iload:
+ case CodeConstants.opc_lload:
+ case CodeConstants.opc_fload:
+ case CodeConstants.opc_dload:
+ case CodeConstants.opc_aload:
+ case CodeConstants.opc_aconst_null:
+ case CodeConstants.opc_bipush:
+ case CodeConstants.opc_sipush:
+ case CodeConstants.opc_lconst_0:
+ case CodeConstants.opc_lconst_1:
+ case CodeConstants.opc_fconst_0:
+ case CodeConstants.opc_fconst_1:
+ case CodeConstants.opc_fconst_2:
+ case CodeConstants.opc_dconst_0:
+ case CodeConstants.opc_dconst_1:
+ case CodeConstants.opc_ldc:
+ case CodeConstants.opc_ldc_w:
+ case CodeConstants.opc_ldc2_w:
+ ok = true;
+ }
+ }
+ }
+
+ if (ok) {
+
+ if (!block.getPreds().isEmpty()) {
+
+ HashSet<BasicBlock> setPredHandlersUnion = new HashSet<BasicBlock>();
+ HashSet<BasicBlock> setPredHandlersIntersection = new HashSet<BasicBlock>();
+
+ boolean firstpred = true;
+ for (BasicBlock pred : block.getPreds()) {
+ if (firstpred) {
+ setPredHandlersIntersection.addAll(pred.getSuccExceptions());
+ firstpred = false;
+ }
+ else {
+ setPredHandlersIntersection.retainAll(pred.getSuccExceptions());
+ }
+
+ setPredHandlersUnion.addAll(pred.getSuccExceptions());
+ }
+
+ // add exception ranges from predecessors
+ setPredHandlersIntersection.removeAll(block.getSuccExceptions());
+ BasicBlock predecessor = block.getPreds().get(0);
+
+ for (BasicBlock handler : setPredHandlersIntersection) {
+ ExceptionRangeCFG range = graph.getExceptionRange(handler, predecessor);
+
+ range.getProtectedRange().add(block);
+ block.addSuccessorException(handler);
+ }
+
+ // remove redundant ranges
+ HashSet<BasicBlock> setRangesToBeRemoved = new HashSet<BasicBlock>(block.getSuccExceptions());
+ setRangesToBeRemoved.removeAll(setPredHandlersUnion);
+
+ for (BasicBlock handler : setRangesToBeRemoved) {
+ ExceptionRangeCFG range = graph.getExceptionRange(handler, block);
+
+ if (range.getProtectedRange().size() > 1) {
+ range.getProtectedRange().remove(block);
+ block.removeSuccessorException(handler);
+ }
+ }
+ }
+
+
+ if (block.getPreds().size() == 1 && block.getPredExceptions().isEmpty()) {
+
+ BasicBlock bpred = block.getPreds().get(0);
+ if (bpred.getSuccs().size() == 1) {
+
+ // add exception ranges of predecessor
+ for (BasicBlock succ : bpred.getSuccExceptions()) {
+ if (!block.getSuccExceptions().contains(succ)) {
+ ExceptionRangeCFG range = graph.getExceptionRange(succ, bpred);
+
+ range.getProtectedRange().add(block);
+ block.addSuccessorException(succ);
+ }
+ }
+
+ // remove superfluous ranges from successors
+ for (BasicBlock succ : new HashSet<BasicBlock>(block.getSuccExceptions())) {
+ if (!bpred.getSuccExceptions().contains(succ)) {
+ ExceptionRangeCFG range = graph.getExceptionRange(succ, block);
+
+ if (range.getProtectedRange().size() > 1) {
+ range.getProtectedRange().remove(block);
+ block.removeSuccessorException(succ);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ public static void mergeBasicBlocks(ControlFlowGraph graph) {
+
+ for (; ; ) {
+
+ boolean merged = false;
+
+ for (BasicBlock block : graph.getBlocks()) {
+
+ InstructionSequence seq = block.getSeq();
+
+ if (block.getSuccs().size() == 1) {
+ BasicBlock next = block.getSuccs().get(0);
+
+ if (next != graph.getLast() && (seq.isEmpty() || seq.getLastInstr().group != CodeConstants.GROUP_SWITCH)) {
+
+ if (next.getPreds().size() == 1 && next.getPredExceptions().isEmpty()
+ && next != graph.getFirst()) {
+ // TODO: implement a dummy start block
+ boolean sameRanges = true;
+ for (ExceptionRangeCFG range : graph.getExceptions()) {
+ if (range.getProtectedRange().contains(block) ^
+ range.getProtectedRange().contains(next)) {
+ sameRanges = false;
+ break;
+ }
+ }
+
+ if (sameRanges) {
+ seq.addSequence(next.getSeq());
+ next.getSeq().clear();
+
+ removeEmptyBlock(graph, next, true);
+
+ merged = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!merged) {
+ break;
+ }
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ClearStructHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ClearStructHelper.java
index aedca91..c6495e6 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/ClearStructHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ClearStructHelper.java
@@ -1,41 +1,40 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.LinkedList;
-
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import java.util.LinkedList;
+
public class ClearStructHelper {
- public static void clearStatements(RootStatement root) {
-
- LinkedList<Statement> stack = new LinkedList<Statement>();
- stack.add(root);
-
- while(!stack.isEmpty()) {
-
- Statement stat = stack.removeFirst();
-
- stat.clearTempInformation();
-
- stack.addAll(stat.getStats());
- }
-
- }
-
+ public static void clearStatements(RootStatement root) {
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+
+ Statement stat = stack.removeFirst();
+
+ stat.clearTempInformation();
+
+ stack.addAll(stat.getStats());
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java
index a07346b..db67902 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java
@@ -1,213 +1,209 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.List;
-
-
import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
+import java.util.ArrayList;
+import java.util.List;
+
public class ConcatenationHelper {
-
- private static final String builderClass = "java/lang/StringBuilder";
- private static final String bufferClass = "java/lang/StringBuffer";
- private static final String stringClass = "java/lang/String";
-
- private static final VarType builderType = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/StringBuilder");
- private static final VarType bufferType = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/StringBuffer");
-
-
- public static Exprent contractStringConcat(Exprent expr) {
-
- Exprent exprTmp = null;
- VarType cltype = null;
-
- // first quick test
- if(expr.type == Exprent.EXPRENT_INVOCATION) {
- InvocationExprent iex = (InvocationExprent)expr;
- if("toString".equals(iex.getName())) {
- if(builderClass.equals(iex.getClassname())) {
- cltype = builderType;
- } else if(bufferClass.equals(iex.getClassname())) {
- cltype = bufferType;
- }
- if(cltype!=null) {
- exprTmp = iex.getInstance();
- }
- }
- }
-
- if(exprTmp == null) {
- return expr;
- }
-
-
- // iterate in depth, collecting possible operands
- List<Exprent> lstOperands = new ArrayList<Exprent>();
-
- for(;;) {
-
- int found = 0;
-
- switch(exprTmp.type) {
- case Exprent.EXPRENT_INVOCATION:
- InvocationExprent iex = (InvocationExprent)exprTmp;
- if(isAppendConcat(iex, cltype)) {
- lstOperands.add(0, iex.getLstParameters().get(0));
- exprTmp = iex.getInstance();
- found = 1;
- }
- break;
- case Exprent.EXPRENT_NEW:
- NewExprent nex = (NewExprent)exprTmp;
- if(isNewConcat(nex, cltype)) {
- VarType[] params = nex.getConstructor().getDescriptor().params;
- if(params.length == 1) {
- lstOperands.add(0, nex.getConstructor().getLstParameters().get(0));
- }
- found = 2;
- }
- }
-
- if(found == 0) {
- return expr;
- } else if(found == 2) {
- break;
- }
- }
-
- int first2str = 0;
- int index=0;
- while(index<lstOperands.size() && index<2) {
- if(lstOperands.get(index).getExprType().equals(VarType.VARTYPE_STRING)) {
- first2str |= (index+1);
- }
- index++;
- }
-
- if(first2str == 0) {
- lstOperands.add(0, new ConstExprent(VarType.VARTYPE_STRING, ""));
- }
-
- // remove redundant String.valueOf
- for(int i=0;i<lstOperands.size();i++) {
- Exprent rep = removeStringValueOf(lstOperands.get(i));
-
- boolean ok = (i>1);
- if(!ok) {
- boolean isstr = rep.getExprType().equals(VarType.VARTYPE_STRING);
- ok = isstr || first2str != i+1;
-
- if(i == 0) {
- first2str &= 2;
- }
- }
-
- if(ok) {
- lstOperands.set(i, rep);
- }
- }
-
- // build exprent to return
- Exprent func = lstOperands.get(0);
-
- for(int i=1;i<lstOperands.size();i++) {
- List<Exprent> lstTmp = new ArrayList<Exprent>();
- lstTmp.add(func);
- lstTmp.add(lstOperands.get(i));
- func = new FunctionExprent(FunctionExprent.FUNCTION_STRCONCAT, lstTmp);
- }
-
- return func;
-
- }
-
- private static boolean isAppendConcat(InvocationExprent expr, VarType cltype) {
-
- if("append".equals(expr.getName())) {
- MethodDescriptor md = expr.getDescriptor();
- if(md.ret.equals(cltype) && md.params.length == 1) {
- VarType param = md.params[0];
- switch(param.type) {
- case CodeConstants.TYPE_OBJECT:
- if(!param.equals(VarType.VARTYPE_STRING) &&
- !param.equals(VarType.VARTYPE_OBJECT)) {
- break;
- }
- case CodeConstants.TYPE_BOOLEAN:
- case CodeConstants.TYPE_CHAR:
- case CodeConstants.TYPE_DOUBLE:
- case CodeConstants.TYPE_FLOAT:
- case CodeConstants.TYPE_INT:
- case CodeConstants.TYPE_LONG:
- return true;
- default:
- }
- }
- }
-
- return false;
- }
-
- private static boolean isNewConcat(NewExprent expr, VarType cltype) {
-
- if(expr.getNewtype().equals(cltype)) {
- VarType[] params = expr.getConstructor().getDescriptor().params;
- if(params.length == 0 || (params.length == 1 &&
- params[0].equals(VarType.VARTYPE_STRING))) {
- return true;
- }
- }
-
- return false;
- }
-
- private static Exprent removeStringValueOf(Exprent exprent) {
-
- if(exprent.type == Exprent.EXPRENT_INVOCATION) {
- InvocationExprent iex = (InvocationExprent)exprent;
- if("valueOf".equals(iex.getName()) && stringClass.equals(iex.getClassname())) {
- MethodDescriptor md = iex.getDescriptor();
- if(md.params.length == 1) {
- VarType param = md.params[0];
- switch(param.type) {
- case CodeConstants.TYPE_OBJECT:
- if(!param.equals(VarType.VARTYPE_OBJECT)) {
- break;
- }
- case CodeConstants.TYPE_BOOLEAN:
- case CodeConstants.TYPE_CHAR:
- case CodeConstants.TYPE_DOUBLE:
- case CodeConstants.TYPE_FLOAT:
- case CodeConstants.TYPE_INT:
- case CodeConstants.TYPE_LONG:
- return iex.getLstParameters().get(0);
- }
- }
- }
- }
-
- return exprent;
- }
-
+
+ private static final String builderClass = "java/lang/StringBuilder";
+ private static final String bufferClass = "java/lang/StringBuffer";
+ private static final String stringClass = "java/lang/String";
+
+ private static final VarType builderType = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/StringBuilder");
+ private static final VarType bufferType = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/StringBuffer");
+
+
+ public static Exprent contractStringConcat(Exprent expr) {
+
+ Exprent exprTmp = null;
+ VarType cltype = null;
+
+ // first quick test
+ if (expr.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent iex = (InvocationExprent)expr;
+ if ("toString".equals(iex.getName())) {
+ if (builderClass.equals(iex.getClassname())) {
+ cltype = builderType;
+ }
+ else if (bufferClass.equals(iex.getClassname())) {
+ cltype = bufferType;
+ }
+ if (cltype != null) {
+ exprTmp = iex.getInstance();
+ }
+ }
+ }
+
+ if (exprTmp == null) {
+ return expr;
+ }
+
+
+ // iterate in depth, collecting possible operands
+ List<Exprent> lstOperands = new ArrayList<Exprent>();
+
+ for (; ; ) {
+
+ int found = 0;
+
+ switch (exprTmp.type) {
+ case Exprent.EXPRENT_INVOCATION:
+ InvocationExprent iex = (InvocationExprent)exprTmp;
+ if (isAppendConcat(iex, cltype)) {
+ lstOperands.add(0, iex.getLstParameters().get(0));
+ exprTmp = iex.getInstance();
+ found = 1;
+ }
+ break;
+ case Exprent.EXPRENT_NEW:
+ NewExprent nex = (NewExprent)exprTmp;
+ if (isNewConcat(nex, cltype)) {
+ VarType[] params = nex.getConstructor().getDescriptor().params;
+ if (params.length == 1) {
+ lstOperands.add(0, nex.getConstructor().getLstParameters().get(0));
+ }
+ found = 2;
+ }
+ }
+
+ if (found == 0) {
+ return expr;
+ }
+ else if (found == 2) {
+ break;
+ }
+ }
+
+ int first2str = 0;
+ int index = 0;
+ while (index < lstOperands.size() && index < 2) {
+ if (lstOperands.get(index).getExprType().equals(VarType.VARTYPE_STRING)) {
+ first2str |= (index + 1);
+ }
+ index++;
+ }
+
+ if (first2str == 0) {
+ lstOperands.add(0, new ConstExprent(VarType.VARTYPE_STRING, ""));
+ }
+
+ // remove redundant String.valueOf
+ for (int i = 0; i < lstOperands.size(); i++) {
+ Exprent rep = removeStringValueOf(lstOperands.get(i));
+
+ boolean ok = (i > 1);
+ if (!ok) {
+ boolean isstr = rep.getExprType().equals(VarType.VARTYPE_STRING);
+ ok = isstr || first2str != i + 1;
+
+ if (i == 0) {
+ first2str &= 2;
+ }
+ }
+
+ if (ok) {
+ lstOperands.set(i, rep);
+ }
+ }
+
+ // build exprent to return
+ Exprent func = lstOperands.get(0);
+
+ for (int i = 1; i < lstOperands.size(); i++) {
+ List<Exprent> lstTmp = new ArrayList<Exprent>();
+ lstTmp.add(func);
+ lstTmp.add(lstOperands.get(i));
+ func = new FunctionExprent(FunctionExprent.FUNCTION_STRCONCAT, lstTmp);
+ }
+
+ return func;
+ }
+
+ private static boolean isAppendConcat(InvocationExprent expr, VarType cltype) {
+
+ if ("append".equals(expr.getName())) {
+ MethodDescriptor md = expr.getDescriptor();
+ if (md.ret.equals(cltype) && md.params.length == 1) {
+ VarType param = md.params[0];
+ switch (param.type) {
+ case CodeConstants.TYPE_OBJECT:
+ if (!param.equals(VarType.VARTYPE_STRING) &&
+ !param.equals(VarType.VARTYPE_OBJECT)) {
+ break;
+ }
+ case CodeConstants.TYPE_BOOLEAN:
+ case CodeConstants.TYPE_CHAR:
+ case CodeConstants.TYPE_DOUBLE:
+ case CodeConstants.TYPE_FLOAT:
+ case CodeConstants.TYPE_INT:
+ case CodeConstants.TYPE_LONG:
+ return true;
+ default:
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isNewConcat(NewExprent expr, VarType cltype) {
+
+ if (expr.getNewtype().equals(cltype)) {
+ VarType[] params = expr.getConstructor().getDescriptor().params;
+ if (params.length == 0 || (params.length == 1 &&
+ params[0].equals(VarType.VARTYPE_STRING))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static Exprent removeStringValueOf(Exprent exprent) {
+
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent iex = (InvocationExprent)exprent;
+ if ("valueOf".equals(iex.getName()) && stringClass.equals(iex.getClassname())) {
+ MethodDescriptor md = iex.getDescriptor();
+ if (md.params.length == 1) {
+ VarType param = md.params[0];
+ switch (param.type) {
+ case CodeConstants.TYPE_OBJECT:
+ if (!param.equals(VarType.VARTYPE_OBJECT)) {
+ break;
+ }
+ case CodeConstants.TYPE_BOOLEAN:
+ case CodeConstants.TYPE_CHAR:
+ case CodeConstants.TYPE_DOUBLE:
+ case CodeConstants.TYPE_FLOAT:
+ case CodeConstants.TYPE_INT:
+ case CodeConstants.TYPE_LONG:
+ return iex.getLstParameters().get(0);
+ }
+ }
+ }
+ }
+
+ return exprent;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java
index ea8823a..ec1fada 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java
@@ -1,217 +1,221 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import java.util.*;
+
public class DecHelper {
-
- public static boolean checkStatementExceptions(List<Statement> lst) {
-
- Set<Statement> all = new HashSet<Statement>(lst);
-
- Set<Statement> handlers = new HashSet<Statement>();
- Set<Statement> intersection = null;
-
- for(Statement stat : lst) {
- Set<Statement> setNew = stat.getNeighboursSet(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD);
-
- if(intersection == null) {
- intersection = setNew;
- } else {
- HashSet<Statement> interclone = new HashSet<Statement>(intersection);
- interclone.removeAll(setNew);
-
- intersection.retainAll(setNew);
-
- setNew.removeAll(intersection);
-
- handlers.addAll(interclone);
- handlers.addAll(setNew);
- }
- }
-
- for(Statement stat : handlers) {
- if(!all.contains(stat) || !all.containsAll(stat.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD))) {
- return false;
- }
- }
-
- // check for other handlers (excluding head)
- for(int i=1;i<lst.size();i++) {
- Statement stat = lst.get(i);
- if(!stat.getPredecessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty() && !handlers.contains(stat)) {
- return false;
- }
- }
-
- return true;
- }
-
- public static boolean isChoiceStatement(Statement head, List<Statement> lst) {
-
- Statement post = null;
-
- Set<Statement> setDest = head.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD);
-
- if(setDest.contains(head)) {
- return false;
- }
-
- for(;;) {
-
- lst.clear();
-
- boolean repeat = false;
-
- setDest.remove(post);
- Iterator<Statement> it = setDest.iterator();
-
- while(it.hasNext()) {
- Statement stat = it.next();
-
- if(stat.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) {
- if(post == null) {
- post = stat;
- repeat = true;
- break;
- } else {
- return false;
- }
- }
-
- // preds
- Set<Statement> setPred = stat.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
- setPred.remove(head);
- if(setPred.contains(stat)) {
- return false;
- }
-
- if(!setDest.containsAll(setPred) || setPred.size()>1) {
- if(post == null) {
- post = stat;
- repeat = true;
- break;
- } else {
- return false;
- }
- } else if(setPred.size() == 1) {
- Statement pred = setPred.iterator().next();
- while(lst.contains(pred)) {
- Set<Statement> setPredTemp = pred.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
- setPredTemp.remove(head);
-
- if(!setPredTemp.isEmpty()) { // at most 1 predecessor
- pred = setPredTemp.iterator().next();
- if(pred == stat) {
- return false; // loop found
- }
- } else {
- break;
- }
- }
- }
-
- // succs
- List<StatEdge> lstEdges = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
- if(lstEdges.size() > 1) {
- Set<Statement> setSucc = stat.getNeighboursSet(Statement.STATEDGE_DIRECT_ALL, Statement.DIRECTION_FORWARD);
- setSucc.retainAll(setDest);
-
- if(setSucc.size()>0) {
- return false;
- } else {
- if(post == null) {
- post = stat;
- repeat = true;
- break;
- } else {
- return false;
- }
- }
- } else if(lstEdges.size() == 1) {
-
- StatEdge edge = lstEdges.get(0);
- if(edge.getType() == StatEdge.TYPE_REGULAR) {
- Statement statd = edge.getDestination();
- if(head == statd) {
- return false;
- }
- if(!setDest.contains(statd) && post!=statd) {
- if(post!=null) {
- return false;
- } else {
- Set<Statement> set = statd.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
- if(set.size()>1){
- post = statd;
- repeat = true;
- break;
- } else {
- return false;
- }
- }
- }
- }
- }
-
- lst.add(stat);
- }
-
- if(!repeat) {
- break;
- }
-
- }
-
- lst.add(head);
- lst.remove(post);
-
- lst.add(0, post);
-
- return true;
-
- }
-
-
- public static HashSet<Statement> getUniquePredExceptions(Statement head) {
-
- HashSet<Statement> setHandlers = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
-
- Iterator<Statement> it = setHandlers.iterator();
- while(it.hasNext()) {
- if(it.next().getPredecessorEdges(StatEdge.TYPE_EXCEPTION).size()>1) {
- it.remove();
- }
- }
- return setHandlers;
- }
-
- public static List<Exprent> copyExprentList(List<Exprent> lst) {
- List<Exprent> ret = new ArrayList<Exprent>();
- for(Exprent expr: lst) {
- ret.add(expr.copy());
- }
- return ret;
- }
-
+
+ public static boolean checkStatementExceptions(List<Statement> lst) {
+
+ Set<Statement> all = new HashSet<Statement>(lst);
+
+ Set<Statement> handlers = new HashSet<Statement>();
+ Set<Statement> intersection = null;
+
+ for (Statement stat : lst) {
+ Set<Statement> setNew = stat.getNeighboursSet(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD);
+
+ if (intersection == null) {
+ intersection = setNew;
+ }
+ else {
+ HashSet<Statement> interclone = new HashSet<Statement>(intersection);
+ interclone.removeAll(setNew);
+
+ intersection.retainAll(setNew);
+
+ setNew.removeAll(intersection);
+
+ handlers.addAll(interclone);
+ handlers.addAll(setNew);
+ }
+ }
+
+ for (Statement stat : handlers) {
+ if (!all.contains(stat) || !all.containsAll(stat.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD))) {
+ return false;
+ }
+ }
+
+ // check for other handlers (excluding head)
+ for (int i = 1; i < lst.size(); i++) {
+ Statement stat = lst.get(i);
+ if (!stat.getPredecessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty() && !handlers.contains(stat)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean isChoiceStatement(Statement head, List<Statement> lst) {
+
+ Statement post = null;
+
+ Set<Statement> setDest = head.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD);
+
+ if (setDest.contains(head)) {
+ return false;
+ }
+
+ for (; ; ) {
+
+ lst.clear();
+
+ boolean repeat = false;
+
+ setDest.remove(post);
+ Iterator<Statement> it = setDest.iterator();
+
+ while (it.hasNext()) {
+ Statement stat = it.next();
+
+ if (stat.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) {
+ if (post == null) {
+ post = stat;
+ repeat = true;
+ break;
+ }
+ else {
+ return false;
+ }
+ }
+
+ // preds
+ Set<Statement> setPred = stat.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
+ setPred.remove(head);
+ if (setPred.contains(stat)) {
+ return false;
+ }
+
+ if (!setDest.containsAll(setPred) || setPred.size() > 1) {
+ if (post == null) {
+ post = stat;
+ repeat = true;
+ break;
+ }
+ else {
+ return false;
+ }
+ }
+ else if (setPred.size() == 1) {
+ Statement pred = setPred.iterator().next();
+ while (lst.contains(pred)) {
+ Set<Statement> setPredTemp = pred.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
+ setPredTemp.remove(head);
+
+ if (!setPredTemp.isEmpty()) { // at most 1 predecessor
+ pred = setPredTemp.iterator().next();
+ if (pred == stat) {
+ return false; // loop found
+ }
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ // succs
+ List<StatEdge> lstEdges = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
+ if (lstEdges.size() > 1) {
+ Set<Statement> setSucc = stat.getNeighboursSet(Statement.STATEDGE_DIRECT_ALL, Statement.DIRECTION_FORWARD);
+ setSucc.retainAll(setDest);
+
+ if (setSucc.size() > 0) {
+ return false;
+ }
+ else {
+ if (post == null) {
+ post = stat;
+ repeat = true;
+ break;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+ else if (lstEdges.size() == 1) {
+
+ StatEdge edge = lstEdges.get(0);
+ if (edge.getType() == StatEdge.TYPE_REGULAR) {
+ Statement statd = edge.getDestination();
+ if (head == statd) {
+ return false;
+ }
+ if (!setDest.contains(statd) && post != statd) {
+ if (post != null) {
+ return false;
+ }
+ else {
+ Set<Statement> set = statd.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
+ if (set.size() > 1) {
+ post = statd;
+ repeat = true;
+ break;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ lst.add(stat);
+ }
+
+ if (!repeat) {
+ break;
+ }
+ }
+
+ lst.add(head);
+ lst.remove(post);
+
+ lst.add(0, post);
+
+ return true;
+ }
+
+
+ public static HashSet<Statement> getUniquePredExceptions(Statement head) {
+
+ HashSet<Statement> setHandlers = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
+
+ Iterator<Statement> it = setHandlers.iterator();
+ while (it.hasNext()) {
+ if (it.next().getPredecessorEdges(StatEdge.TYPE_EXCEPTION).size() > 1) {
+ it.remove();
+ }
+ }
+ return setHandlers;
+ }
+
+ public static List<Exprent> copyExprentList(List<Exprent> lst) {
+ List<Exprent> ret = new ArrayList<Exprent>();
+ for (Exprent expr : lst) {
+ ret.add(expr.copy());
+ }
+ return ret;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java
index ba6f839..79bea88 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java
@@ -1,30 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
@@ -32,689 +22,690 @@ import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.modules.decompiler.decompose.FastExtendedPostdominanceHelper;
import org.jetbrains.java.decompiler.modules.decompiler.deobfuscator.IrreducibleCFGDeobfuscator;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.GeneralStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SwitchStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
import org.jetbrains.java.decompiler.util.FastFixedSetFactory;
+import org.jetbrains.java.decompiler.util.FastFixedSetFactory.FastFixedSet;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
-import org.jetbrains.java.decompiler.util.FastFixedSetFactory.FastFixedSet;
+
+import java.util.*;
public class DomHelper {
-
-
- private static RootStatement graphToStatement(ControlFlowGraph graph) {
-
- VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<Statement, Integer>();
- VBStyleCollection<BasicBlock, Integer> blocks = graph.getBlocks();
-
- for(BasicBlock block: blocks) {
- stats.addWithKey(new BasicBlockStatement(block), block.id);
- }
-
- BasicBlock firstblock = graph.getFirst();
- // head statement
- Statement firstst = stats.getWithKey(firstblock.id);
- // dummy exit statement
- Statement dummyexit = new Statement();
- dummyexit.type = Statement.TYPE_DUMMYEXIT;
-
- Statement general;
- if(stats.size() > 1 || firstblock.isSuccessor(firstblock)) { // multiple basic blocks or an infinite loop of one block
- general = new GeneralStatement(firstst, stats, null);
- } else { // one straightforward basic block
- RootStatement root = new RootStatement(firstst, dummyexit);
- firstst.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, firstst, dummyexit, root));
-
- return root;
- }
-
- for(BasicBlock block: blocks) {
- Statement stat = stats.getWithKey(block.id);
-
- for(BasicBlock succ: block.getSuccs()) {
- Statement stsucc = stats.getWithKey(succ.id);
-
- int type;
- if(stsucc==firstst) {
- type = StatEdge.TYPE_CONTINUE;
- } else if(graph.getFinallyExits().contains(block)) {
- type = StatEdge.TYPE_FINALLYEXIT;
- stsucc = dummyexit;
- } else if(succ.id == graph.getLast().id) {
- type = StatEdge.TYPE_BREAK;
- stsucc = dummyexit;
- } else {
- type = StatEdge.TYPE_REGULAR;
- }
-
- stat.addSuccessor(new StatEdge(type, stat, (type == StatEdge.TYPE_CONTINUE)?general:stsucc,
- (type == StatEdge.TYPE_REGULAR)?null:general));
- }
-
- // exceptions edges
- for(BasicBlock succex: block.getSuccExceptions()) {
- Statement stsuccex = stats.getWithKey(succex.id);
-
- ExceptionRangeCFG range = graph.getExceptionRange(succex, block);
- if(!range.isCircular()) {
- stat.addSuccessor(new StatEdge(stat, stsuccex, range.getExceptionTypes()));
- }
- }
-
- }
-
- general.buildContinueSet();
- general.buildMonitorFlags();
- return new RootStatement(general, dummyexit);
- }
-
- public static VBStyleCollection<List<Integer>, Integer> calcPostDominators(Statement container) {
-
- HashMap<Statement, FastFixedSet<Statement>> lists = new HashMap<Statement, FastFixedSet<Statement>>();
-
- StrongConnectivityHelper schelper = new StrongConnectivityHelper(container);
- List<List<Statement>> components = schelper.getComponents();
-
- List<Statement> lstStats = container.getPostReversePostOrderList(StrongConnectivityHelper.getExitReps(components));
-
- FastFixedSetFactory<Statement> factory = new FastFixedSetFactory<Statement>(lstStats);
-
- FastFixedSet<Statement> setFlagNodes = factory.spawnEmptySet();
- setFlagNodes.setAllElements();
-
- FastFixedSet<Statement> initSet = factory.spawnEmptySet();
- initSet.setAllElements();
-
- for(List<Statement> lst: components) {
- FastFixedSet<Statement> tmpSet;
-
- if(StrongConnectivityHelper.isExitComponent(lst)) {
- tmpSet = factory.spawnEmptySet();
- tmpSet.addAll(lst);
- } else {
- tmpSet = initSet.getCopy();
- }
-
- for(Statement stat : lst) {
- lists.put(stat, tmpSet);
- }
- }
-
- do {
-
- for(Statement stat : lstStats) {
-
- if(!setFlagNodes.contains(stat)) {
- continue;
- }
- setFlagNodes.remove(stat);
-
- FastFixedSet<Statement> doms = lists.get(stat);
- FastFixedSet<Statement> domsSuccs = factory.spawnEmptySet();
-
- List<Statement> lstSuccs = stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD);
- for(int j=0;j<lstSuccs.size();j++) {
- Statement succ = lstSuccs.get(j);
- FastFixedSet<Statement> succlst = lists.get(succ);
-
- if(j == 0) {
- domsSuccs.union(succlst);
- } else {
- domsSuccs.intersection(succlst);
- }
- }
-
- if(!domsSuccs.contains(stat)) {
- domsSuccs.add(stat);
- }
-
- if(!InterpreterUtil.equalObjects(domsSuccs, doms)) {
-
- lists.put(stat, domsSuccs);
-
- List<Statement> lstPreds = stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
- for(Statement pred : lstPreds) {
- setFlagNodes.add(pred);
- }
- }
- }
-
- } while(!setFlagNodes.isEmpty());
-
- VBStyleCollection<List<Integer>, Integer> ret = new VBStyleCollection<List<Integer>, Integer>();
- List<Statement> lstRevPost = container.getReversePostOrderList(); // sort order crucial!
-
- final HashMap<Integer, Integer> mapSortOrder = new HashMap<Integer, Integer>();
- for(int i=0;i<lstRevPost.size();i++) {
- mapSortOrder.put(lstRevPost.get(i).id, i);
- }
-
- for(Statement st: lstStats) {
-
- List<Integer> lstPosts = new ArrayList<Integer>();
- for(Statement stt : lists.get(st)) {
- lstPosts.add(stt.id);
- }
-
- Collections.sort(lstPosts, new Comparator<Integer>() {
- public int compare(Integer o1, Integer o2) {
- return mapSortOrder.get(o1).compareTo(mapSortOrder.get(o2));
- }
- });
-
- if(lstPosts.size() > 1 && lstPosts.get(0).intValue() == st.id) {
- lstPosts.add(lstPosts.remove(0));
- }
-
- ret.addWithKey(lstPosts, st.id);
- }
-
- return ret;
- }
-
- public static RootStatement parseGraph(ControlFlowGraph graph) {
-
- RootStatement root = graphToStatement(graph);
-
- if(!processStatement(root, new HashMap<Integer, Set<Integer>>())) {
- DecompilerContext.getLogger().writeMessage("parsing failure!", IFernflowerLogger.ERROR);
-
-// try {
-// DotExporter.toDotFile(root.getFirst().getStats().get(13), new File("c:\\Temp\\stat1.dot"));
-// } catch (Exception ex) {
-// ex.printStackTrace();
-// }
- throw new RuntimeException("parsing failure!");
- }
-
- LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
-
- SequenceHelper.condenseSequences(root);
- root.buildMonitorFlags();
-
- // build synchronized statements
- buildSynchronized(root);
-
- return root;
- }
-
- public static void removeSynchronizedHandler(Statement stat) {
-
- for(Statement st : stat.getStats()) {
- removeSynchronizedHandler(st);
- }
-
- if(stat.type == Statement.TYPE_SYNCRONIZED) {
- ((SynchronizedStatement)stat).removeExc();
- }
- }
-
-
- private static void buildSynchronized(Statement stat) {
-
- for(Statement st : stat.getStats()) {
- buildSynchronized(st);
- }
-
- if(stat.type == Statement.TYPE_SEQUENCE) {
-
- for(;;) {
-
- boolean found = false;
-
- List<Statement> lst = stat.getStats();
- for(int i=0;i<lst.size()-1;i++) {
- Statement current = lst.get(i); // basic block
-
- if(current.isMonitorEnter()) {
-
- Statement next = lst.get(i+1);
- Statement nextDirect = next;
-
- while(next.type == Statement.TYPE_SEQUENCE) {
- next = next.getFirst();
- }
-
- if(next.type == Statement.TYPE_CATCHALL) {
-
- CatchAllStatement ca = (CatchAllStatement)next;
-
- if(ca.getFirst().isContainsMonitorExit() && ca.getHandler().isContainsMonitorExit()) {
-
- // remove the head block from sequence
- current.removeSuccessor(current.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0));
-
- for(StatEdge edge: current.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
- current.removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, nextDirect);
- nextDirect.addPredecessor(edge);
- }
-
- stat.getStats().removeWithKey(current.id);
- stat.setFirst(stat.getStats().get(0));
-
- // new statement
- SynchronizedStatement sync = new SynchronizedStatement(current, ca.getFirst(), ca.getHandler());
- sync.setAllParent();
-
- for(StatEdge edge : new HashSet<StatEdge>(ca.getLabelEdges())) {
- sync.addLabeledEdge(edge);
- }
-
- current.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, current, ca.getFirst()));
-
- ca.getParent().replaceStatement(ca, sync);
- found = true;
- break;
- }
- }
- }
- }
-
- if(!found) {
- break;
- }
- }
-
- }
-
- }
-
- private static boolean processStatement(Statement general, HashMap<Integer, Set<Integer>> mapExtPost) {
-
- if(general.type == Statement.TYPE_ROOT) {
- Statement stat = general.getFirst();
- if(stat.type != Statement.TYPE_GENERAL) {
- return true;
- } else {
- boolean complete = processStatement(stat, mapExtPost);
- if(complete) {
- // replace general purpose statement with simple one
- general.replaceStatement(stat, stat.getFirst());
- }
- return complete;
- }
- }
-
- boolean mapRefreshed = mapExtPost.isEmpty();
-
- for(int mapstage = 0; mapstage < 2; mapstage++) {
-
- for(int reducibility=0; reducibility < 5; reducibility++) { // FIXME: implement proper node splitting. For now up to 5 nodes in sequence are splitted.
-
- if(reducibility > 0) {
-
-// try {
-// DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
-// } catch(Exception ex) {ex.printStackTrace();}
-
- // take care of irreducible control flow graphs
- if(IrreducibleCFGDeobfuscator.isStatementIrreducible(general)) {
- if(!IrreducibleCFGDeobfuscator.splitIrreducibleNode(general)) {
- DecompilerContext.getLogger().writeMessage("Irreducible statement cannot be decomposed!", IFernflowerLogger.ERROR);
- break;
- }
- } else {
- if(mapstage == 2 || mapRefreshed) { // last chance lost
- DecompilerContext.getLogger().writeMessage("Statement cannot be decomposed although reducible!", IFernflowerLogger.ERROR);
- }
- break;
- }
-
-// try {
-// DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
-// } catch(Exception ex) {ex.printStackTrace();}
-
- mapExtPost = new HashMap<Integer, Set<Integer>>();
- mapRefreshed = true;
- }
-
- for(int i=0;i<2;i++) {
-
- boolean forceall = i!=0;
-
- for(;;) {
-
- if(findSimpleStatements(general, mapExtPost)) {
- reducibility = 0;
- }
-
- if(general.type == Statement.TYPE_PLACEHOLDER) {
- return true;
- }
-
- Statement stat = findGeneralStatement(general, forceall, mapExtPost);
-
- if(stat!=null) {
- boolean complete = processStatement(stat, general.getFirst() == stat?mapExtPost:new HashMap<Integer, Set<Integer>>());
-
- if(complete) {
- // replace general purpose statement with simple one
- general.replaceStatement(stat, stat.getFirst());
- } else {
- return false;
- }
-
- mapExtPost = new HashMap<Integer, Set<Integer>>();
- mapRefreshed = true;
- reducibility = 0;
-
- } else {
- break;
- }
- }
- }
-
-// try {
-// DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
-// } catch (Exception ex) {
-// ex.printStackTrace();
-// }
- }
-
- if(mapRefreshed) {
- break;
- } else {
- mapExtPost = new HashMap<Integer, Set<Integer>>();
- }
- }
-
- return false;
- }
-
- private static Statement findGeneralStatement(Statement stat, boolean forceall, HashMap<Integer, Set<Integer>> mapExtPost) {
-
- VBStyleCollection<Statement, Integer> stats = stat.getStats();
- VBStyleCollection<List<Integer>, Integer> vbPost;
-
- if(mapExtPost.isEmpty()) {
- FastExtendedPostdominanceHelper extpost = new FastExtendedPostdominanceHelper();
- mapExtPost.putAll(extpost.getExtendedPostdominators(stat));
- }
-
- if(forceall) {
- vbPost = new VBStyleCollection<List<Integer>, Integer>();
- List<Statement> lstAll = stat.getPostReversePostOrderList();
-
- for(Statement st: lstAll) {
- Set<Integer> set = mapExtPost.get(st.id);
- if(set != null) {
- vbPost.addWithKey(new ArrayList<Integer>(set), st.id); // FIXME: sort order!!
- }
- }
-
- // tail statements
- Set<Integer> setFirst = mapExtPost.get(stat.getFirst().id);
- if(setFirst != null) {
- for(Integer id : setFirst) {
- List<Integer> lst = vbPost.getWithKey(id);
- if(lst == null) {
- vbPost.addWithKey(lst = new ArrayList<Integer>(), id);
- }
- lst.add(id);
- }
- }
-
- } else {
- vbPost = calcPostDominators(stat);
- }
-
- for(int k=0;k<vbPost.size();k++) {
-
- Integer headid = vbPost.getKey(k);
- List<Integer> posts = vbPost.get(k);
-
- if(!mapExtPost.containsKey(headid) &&
- !(posts.size() == 1 && posts.get(0).equals(headid))) {
- continue;
- }
-
- Statement head = stats.getWithKey(headid);
-
- Set<Integer> setExtPosts = mapExtPost.get(headid);
-
- for(int i=0;i<posts.size();i++) {
-
- Integer postid = posts.get(i);
- if(!postid.equals(headid) && !setExtPosts.contains(postid)) {
- continue;
- }
-
- Statement post = stats.getWithKey(postid);
-
- if(post == null) { // possible in case of an inherited postdominance set
- continue;
- }
-
- boolean same = (post == head);
-
- HashSet<Statement> setNodes = new HashSet<Statement>();
- HashSet<Statement> setPreds = new HashSet<Statement>();
-
- // collect statement nodes
- HashSet<Statement> setHandlers = new HashSet<Statement>();
- setHandlers.add(head);
- for(;;) {
-
- boolean hdfound = false;
- Iterator<Statement> itHandlers = setHandlers.iterator();
- while(itHandlers.hasNext()) {
- Statement handler = itHandlers.next();
-
- if(setNodes.contains(handler)) {
- continue;
- }
-
- boolean addhd = (setNodes.size() == 0); // first handler == head
- if(!addhd) {
- List<Statement> hdsupp = handler.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD);
- addhd = (setNodes.containsAll(hdsupp) && (setNodes.size() > hdsupp.size()
- || setNodes.size() == 1)); // strict subset
- }
-
- if(addhd) {
- LinkedList<Statement> lstStack = new LinkedList<Statement>();
- lstStack.add(handler);
-
- while(!lstStack.isEmpty()) {
- Statement st = lstStack.remove(0);
-
- if(!(setNodes.contains(st) || (!same && st == post))) {
- setNodes.add(st);
- if(st != head) {
- // record predeccessors except for the head
- setPreds.addAll(st.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD));
- }
-
- // put successors on the stack
- lstStack.addAll(st.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD));
-
- // exception edges
- setHandlers.addAll(st.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
- }
- }
-
- hdfound = true;
- setHandlers.remove(handler);
- break;
- }
- }
-
- if(!hdfound) {
- break;
- }
- }
-
- // check exception handlers
- setHandlers.clear();
- for(Statement st : setNodes) {
- setHandlers.addAll(st.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
- }
- setHandlers.removeAll(setNodes);
-
- boolean excok = true;
- Iterator<Statement> itt = setHandlers.iterator();
- while(itt.hasNext()) {
- Statement handler = itt.next();
- if(!handler.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD).containsAll(setNodes)) {
- excok = false;
- break;
- }
- }
-
- // build statement and return
- if(excok) {
- Statement res = null;
-
- setPreds.removeAll(setNodes);
- if(setPreds.size() == 0) {
- if((setNodes.size() > 1 ||
- head.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD).contains(head))
- && setNodes.size() < stats.size()) {
- if(checkSynchronizedCompleteness(head, setNodes)) {
- res = new GeneralStatement(head, setNodes, same?null:post);
- stat.collapseNodesToStatement(res);
-
- return res;
- }
- }
- }
- }
- }
- }
-
- return null;
- }
-
- private static boolean checkSynchronizedCompleteness(Statement head, HashSet<Statement> setNodes) {
-
- // check exit nodes
- for(Statement stat : setNodes) {
- if(stat.isMonitorEnter()) {
- List<StatEdge> lstSuccs = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
- if(lstSuccs.size() != 1 || lstSuccs.get(0).getType() != StatEdge.TYPE_REGULAR) {
- return false;
- }
-
- if(!setNodes.contains(lstSuccs.get(0).getDestination())) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- private static boolean findSimpleStatements(Statement stat, HashMap<Integer, Set<Integer>> mapExtPost) {
-
- boolean found, success = false;
-
- do {
- found = false;
-
- List<Statement> lstStats = stat.getPostReversePostOrderList();
- for(Statement st: lstStats) {
-
- Statement result = detectStatement(st);
-
- if(result != null) {
-
- if(stat.type == Statement.TYPE_GENERAL && result.getFirst() == stat.getFirst() &&
- stat.getStats().size() == result.getStats().size()) {
- // mark general statement
- stat.type = Statement.TYPE_PLACEHOLDER;
- }
-
- stat.collapseNodesToStatement(result);
-
- // update the postdominator map
- if(!mapExtPost.isEmpty()) {
- HashSet<Integer> setOldNodes = new HashSet<Integer>();
- for(Statement old : result.getStats()) {
- setOldNodes.add(old.id);
- }
-
- Integer newid = result.id;
-
- for(Integer key : new ArrayList<Integer>(mapExtPost.keySet())) {
- Set<Integer> set = mapExtPost.get(key);
-
- int oldsize = set.size();
- set.removeAll(setOldNodes);
-
- if(setOldNodes.contains(key)) {
- Set<Integer> setNew = mapExtPost.get(newid);
- if(setNew == null) {
- mapExtPost.put(newid, setNew = new HashSet<Integer>());
- }
- setNew.addAll(set);
-
- mapExtPost.remove(key);
- } else {
- if(set.size() < oldsize) {
- set.add(newid);
- }
- }
- }
- }
-
-
- found = true;
- break;
- }
- }
-
- if(found) {
- success = true;
- }
-
- } while(found);
-
- return success;
- }
-
-
- private static Statement detectStatement(Statement head) {
-
- Statement res;
-
- if((res = DoStatement.isHead(head)) != null) {
- return res;
- }
-
- if((res = SwitchStatement.isHead(head)) != null) {
- return res;
- }
-
- if((res = IfStatement.isHead(head)) != null) {
- return res;
- }
-
- // synchronized statements will be identified later
- // right now they are recognized as catchall
-
- if((res = SequenceStatement.isHead2Block(head)) != null) {
- return res;
- }
-
- if((res = CatchStatement.isHead(head)) != null) {
- return res;
- }
-
- if((res = CatchAllStatement.isHead(head)) != null) {
- return res;
- }
-
- return null;
- }
-
+
+
+ private static RootStatement graphToStatement(ControlFlowGraph graph) {
+
+ VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<Statement, Integer>();
+ VBStyleCollection<BasicBlock, Integer> blocks = graph.getBlocks();
+
+ for (BasicBlock block : blocks) {
+ stats.addWithKey(new BasicBlockStatement(block), block.id);
+ }
+
+ BasicBlock firstblock = graph.getFirst();
+ // head statement
+ Statement firstst = stats.getWithKey(firstblock.id);
+ // dummy exit statement
+ Statement dummyexit = new Statement();
+ dummyexit.type = Statement.TYPE_DUMMYEXIT;
+
+ Statement general;
+ if (stats.size() > 1 || firstblock.isSuccessor(firstblock)) { // multiple basic blocks or an infinite loop of one block
+ general = new GeneralStatement(firstst, stats, null);
+ }
+ else { // one straightforward basic block
+ RootStatement root = new RootStatement(firstst, dummyexit);
+ firstst.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, firstst, dummyexit, root));
+
+ return root;
+ }
+
+ for (BasicBlock block : blocks) {
+ Statement stat = stats.getWithKey(block.id);
+
+ for (BasicBlock succ : block.getSuccs()) {
+ Statement stsucc = stats.getWithKey(succ.id);
+
+ int type;
+ if (stsucc == firstst) {
+ type = StatEdge.TYPE_CONTINUE;
+ }
+ else if (graph.getFinallyExits().contains(block)) {
+ type = StatEdge.TYPE_FINALLYEXIT;
+ stsucc = dummyexit;
+ }
+ else if (succ.id == graph.getLast().id) {
+ type = StatEdge.TYPE_BREAK;
+ stsucc = dummyexit;
+ }
+ else {
+ type = StatEdge.TYPE_REGULAR;
+ }
+
+ stat.addSuccessor(new StatEdge(type, stat, (type == StatEdge.TYPE_CONTINUE) ? general : stsucc,
+ (type == StatEdge.TYPE_REGULAR) ? null : general));
+ }
+
+ // exceptions edges
+ for (BasicBlock succex : block.getSuccExceptions()) {
+ Statement stsuccex = stats.getWithKey(succex.id);
+
+ ExceptionRangeCFG range = graph.getExceptionRange(succex, block);
+ if (!range.isCircular()) {
+ stat.addSuccessor(new StatEdge(stat, stsuccex, range.getExceptionTypes()));
+ }
+ }
+ }
+
+ general.buildContinueSet();
+ general.buildMonitorFlags();
+ return new RootStatement(general, dummyexit);
+ }
+
+ public static VBStyleCollection<List<Integer>, Integer> calcPostDominators(Statement container) {
+
+ HashMap<Statement, FastFixedSet<Statement>> lists = new HashMap<Statement, FastFixedSet<Statement>>();
+
+ StrongConnectivityHelper schelper = new StrongConnectivityHelper(container);
+ List<List<Statement>> components = schelper.getComponents();
+
+ List<Statement> lstStats = container.getPostReversePostOrderList(StrongConnectivityHelper.getExitReps(components));
+
+ FastFixedSetFactory<Statement> factory = new FastFixedSetFactory<Statement>(lstStats);
+
+ FastFixedSet<Statement> setFlagNodes = factory.spawnEmptySet();
+ setFlagNodes.setAllElements();
+
+ FastFixedSet<Statement> initSet = factory.spawnEmptySet();
+ initSet.setAllElements();
+
+ for (List<Statement> lst : components) {
+ FastFixedSet<Statement> tmpSet;
+
+ if (StrongConnectivityHelper.isExitComponent(lst)) {
+ tmpSet = factory.spawnEmptySet();
+ tmpSet.addAll(lst);
+ }
+ else {
+ tmpSet = initSet.getCopy();
+ }
+
+ for (Statement stat : lst) {
+ lists.put(stat, tmpSet);
+ }
+ }
+
+ do {
+
+ for (Statement stat : lstStats) {
+
+ if (!setFlagNodes.contains(stat)) {
+ continue;
+ }
+ setFlagNodes.remove(stat);
+
+ FastFixedSet<Statement> doms = lists.get(stat);
+ FastFixedSet<Statement> domsSuccs = factory.spawnEmptySet();
+
+ List<Statement> lstSuccs = stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD);
+ for (int j = 0; j < lstSuccs.size(); j++) {
+ Statement succ = lstSuccs.get(j);
+ FastFixedSet<Statement> succlst = lists.get(succ);
+
+ if (j == 0) {
+ domsSuccs.union(succlst);
+ }
+ else {
+ domsSuccs.intersection(succlst);
+ }
+ }
+
+ if (!domsSuccs.contains(stat)) {
+ domsSuccs.add(stat);
+ }
+
+ if (!InterpreterUtil.equalObjects(domsSuccs, doms)) {
+
+ lists.put(stat, domsSuccs);
+
+ List<Statement> lstPreds = stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
+ for (Statement pred : lstPreds) {
+ setFlagNodes.add(pred);
+ }
+ }
+ }
+ }
+ while (!setFlagNodes.isEmpty());
+
+ VBStyleCollection<List<Integer>, Integer> ret = new VBStyleCollection<List<Integer>, Integer>();
+ List<Statement> lstRevPost = container.getReversePostOrderList(); // sort order crucial!
+
+ final HashMap<Integer, Integer> mapSortOrder = new HashMap<Integer, Integer>();
+ for (int i = 0; i < lstRevPost.size(); i++) {
+ mapSortOrder.put(lstRevPost.get(i).id, i);
+ }
+
+ for (Statement st : lstStats) {
+
+ List<Integer> lstPosts = new ArrayList<Integer>();
+ for (Statement stt : lists.get(st)) {
+ lstPosts.add(stt.id);
+ }
+
+ Collections.sort(lstPosts, new Comparator<Integer>() {
+ public int compare(Integer o1, Integer o2) {
+ return mapSortOrder.get(o1).compareTo(mapSortOrder.get(o2));
+ }
+ });
+
+ if (lstPosts.size() > 1 && lstPosts.get(0).intValue() == st.id) {
+ lstPosts.add(lstPosts.remove(0));
+ }
+
+ ret.addWithKey(lstPosts, st.id);
+ }
+
+ return ret;
+ }
+
+ public static RootStatement parseGraph(ControlFlowGraph graph) {
+
+ RootStatement root = graphToStatement(graph);
+
+ if (!processStatement(root, new HashMap<Integer, Set<Integer>>())) {
+ DecompilerContext.getLogger().writeMessage("parsing failure!", IFernflowerLogger.ERROR);
+
+ // try {
+ // DotExporter.toDotFile(root.getFirst().getStats().get(13), new File("c:\\Temp\\stat1.dot"));
+ // } catch (Exception ex) {
+ // ex.printStackTrace();
+ // }
+ throw new RuntimeException("parsing failure!");
+ }
+
+ LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
+
+ SequenceHelper.condenseSequences(root);
+ root.buildMonitorFlags();
+
+ // build synchronized statements
+ buildSynchronized(root);
+
+ return root;
+ }
+
+ public static void removeSynchronizedHandler(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ removeSynchronizedHandler(st);
+ }
+
+ if (stat.type == Statement.TYPE_SYNCRONIZED) {
+ ((SynchronizedStatement)stat).removeExc();
+ }
+ }
+
+
+ private static void buildSynchronized(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ buildSynchronized(st);
+ }
+
+ if (stat.type == Statement.TYPE_SEQUENCE) {
+
+ for (; ; ) {
+
+ boolean found = false;
+
+ List<Statement> lst = stat.getStats();
+ for (int i = 0; i < lst.size() - 1; i++) {
+ Statement current = lst.get(i); // basic block
+
+ if (current.isMonitorEnter()) {
+
+ Statement next = lst.get(i + 1);
+ Statement nextDirect = next;
+
+ while (next.type == Statement.TYPE_SEQUENCE) {
+ next = next.getFirst();
+ }
+
+ if (next.type == Statement.TYPE_CATCHALL) {
+
+ CatchAllStatement ca = (CatchAllStatement)next;
+
+ if (ca.getFirst().isContainsMonitorExit() && ca.getHandler().isContainsMonitorExit()) {
+
+ // remove the head block from sequence
+ current.removeSuccessor(current.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0));
+
+ for (StatEdge edge : current.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
+ current.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, nextDirect);
+ nextDirect.addPredecessor(edge);
+ }
+
+ stat.getStats().removeWithKey(current.id);
+ stat.setFirst(stat.getStats().get(0));
+
+ // new statement
+ SynchronizedStatement sync = new SynchronizedStatement(current, ca.getFirst(), ca.getHandler());
+ sync.setAllParent();
+
+ for (StatEdge edge : new HashSet<StatEdge>(ca.getLabelEdges())) {
+ sync.addLabeledEdge(edge);
+ }
+
+ current.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, current, ca.getFirst()));
+
+ ca.getParent().replaceStatement(ca, sync);
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+ }
+ }
+
+ private static boolean processStatement(Statement general, HashMap<Integer, Set<Integer>> mapExtPost) {
+
+ if (general.type == Statement.TYPE_ROOT) {
+ Statement stat = general.getFirst();
+ if (stat.type != Statement.TYPE_GENERAL) {
+ return true;
+ }
+ else {
+ boolean complete = processStatement(stat, mapExtPost);
+ if (complete) {
+ // replace general purpose statement with simple one
+ general.replaceStatement(stat, stat.getFirst());
+ }
+ return complete;
+ }
+ }
+
+ boolean mapRefreshed = mapExtPost.isEmpty();
+
+ for (int mapstage = 0; mapstage < 2; mapstage++) {
+
+ for (int reducibility = 0;
+ reducibility < 5;
+ reducibility++) { // FIXME: implement proper node splitting. For now up to 5 nodes in sequence are splitted.
+
+ if (reducibility > 0) {
+
+ // try {
+ // DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
+ // take care of irreducible control flow graphs
+ if (IrreducibleCFGDeobfuscator.isStatementIrreducible(general)) {
+ if (!IrreducibleCFGDeobfuscator.splitIrreducibleNode(general)) {
+ DecompilerContext.getLogger().writeMessage("Irreducible statement cannot be decomposed!", IFernflowerLogger.ERROR);
+ break;
+ }
+ }
+ else {
+ if (mapstage == 2 || mapRefreshed) { // last chance lost
+ DecompilerContext.getLogger().writeMessage("Statement cannot be decomposed although reducible!", IFernflowerLogger.ERROR);
+ }
+ break;
+ }
+
+ // try {
+ // DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
+ mapExtPost = new HashMap<Integer, Set<Integer>>();
+ mapRefreshed = true;
+ }
+
+ for (int i = 0; i < 2; i++) {
+
+ boolean forceall = i != 0;
+
+ for (; ; ) {
+
+ if (findSimpleStatements(general, mapExtPost)) {
+ reducibility = 0;
+ }
+
+ if (general.type == Statement.TYPE_PLACEHOLDER) {
+ return true;
+ }
+
+ Statement stat = findGeneralStatement(general, forceall, mapExtPost);
+
+ if (stat != null) {
+ boolean complete = processStatement(stat, general.getFirst() == stat ? mapExtPost : new HashMap<Integer, Set<Integer>>());
+
+ if (complete) {
+ // replace general purpose statement with simple one
+ general.replaceStatement(stat, stat.getFirst());
+ }
+ else {
+ return false;
+ }
+
+ mapExtPost = new HashMap<Integer, Set<Integer>>();
+ mapRefreshed = true;
+ reducibility = 0;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ // try {
+ // DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
+ // } catch (Exception ex) {
+ // ex.printStackTrace();
+ // }
+ }
+
+ if (mapRefreshed) {
+ break;
+ }
+ else {
+ mapExtPost = new HashMap<Integer, Set<Integer>>();
+ }
+ }
+
+ return false;
+ }
+
+ private static Statement findGeneralStatement(Statement stat, boolean forceall, HashMap<Integer, Set<Integer>> mapExtPost) {
+
+ VBStyleCollection<Statement, Integer> stats = stat.getStats();
+ VBStyleCollection<List<Integer>, Integer> vbPost;
+
+ if (mapExtPost.isEmpty()) {
+ FastExtendedPostdominanceHelper extpost = new FastExtendedPostdominanceHelper();
+ mapExtPost.putAll(extpost.getExtendedPostdominators(stat));
+ }
+
+ if (forceall) {
+ vbPost = new VBStyleCollection<List<Integer>, Integer>();
+ List<Statement> lstAll = stat.getPostReversePostOrderList();
+
+ for (Statement st : lstAll) {
+ Set<Integer> set = mapExtPost.get(st.id);
+ if (set != null) {
+ vbPost.addWithKey(new ArrayList<Integer>(set), st.id); // FIXME: sort order!!
+ }
+ }
+
+ // tail statements
+ Set<Integer> setFirst = mapExtPost.get(stat.getFirst().id);
+ if (setFirst != null) {
+ for (Integer id : setFirst) {
+ List<Integer> lst = vbPost.getWithKey(id);
+ if (lst == null) {
+ vbPost.addWithKey(lst = new ArrayList<Integer>(), id);
+ }
+ lst.add(id);
+ }
+ }
+ }
+ else {
+ vbPost = calcPostDominators(stat);
+ }
+
+ for (int k = 0; k < vbPost.size(); k++) {
+
+ Integer headid = vbPost.getKey(k);
+ List<Integer> posts = vbPost.get(k);
+
+ if (!mapExtPost.containsKey(headid) &&
+ !(posts.size() == 1 && posts.get(0).equals(headid))) {
+ continue;
+ }
+
+ Statement head = stats.getWithKey(headid);
+
+ Set<Integer> setExtPosts = mapExtPost.get(headid);
+
+ for (int i = 0; i < posts.size(); i++) {
+
+ Integer postid = posts.get(i);
+ if (!postid.equals(headid) && !setExtPosts.contains(postid)) {
+ continue;
+ }
+
+ Statement post = stats.getWithKey(postid);
+
+ if (post == null) { // possible in case of an inherited postdominance set
+ continue;
+ }
+
+ boolean same = (post == head);
+
+ HashSet<Statement> setNodes = new HashSet<Statement>();
+ HashSet<Statement> setPreds = new HashSet<Statement>();
+
+ // collect statement nodes
+ HashSet<Statement> setHandlers = new HashSet<Statement>();
+ setHandlers.add(head);
+ for (; ; ) {
+
+ boolean hdfound = false;
+ Iterator<Statement> itHandlers = setHandlers.iterator();
+ while (itHandlers.hasNext()) {
+ Statement handler = itHandlers.next();
+
+ if (setNodes.contains(handler)) {
+ continue;
+ }
+
+ boolean addhd = (setNodes.size() == 0); // first handler == head
+ if (!addhd) {
+ List<Statement> hdsupp = handler.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD);
+ addhd = (setNodes.containsAll(hdsupp) && (setNodes.size() > hdsupp.size()
+ || setNodes.size() == 1)); // strict subset
+ }
+
+ if (addhd) {
+ LinkedList<Statement> lstStack = new LinkedList<Statement>();
+ lstStack.add(handler);
+
+ while (!lstStack.isEmpty()) {
+ Statement st = lstStack.remove(0);
+
+ if (!(setNodes.contains(st) || (!same && st == post))) {
+ setNodes.add(st);
+ if (st != head) {
+ // record predeccessors except for the head
+ setPreds.addAll(st.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD));
+ }
+
+ // put successors on the stack
+ lstStack.addAll(st.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD));
+
+ // exception edges
+ setHandlers.addAll(st.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
+ }
+ }
+
+ hdfound = true;
+ setHandlers.remove(handler);
+ break;
+ }
+ }
+
+ if (!hdfound) {
+ break;
+ }
+ }
+
+ // check exception handlers
+ setHandlers.clear();
+ for (Statement st : setNodes) {
+ setHandlers.addAll(st.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
+ }
+ setHandlers.removeAll(setNodes);
+
+ boolean excok = true;
+ Iterator<Statement> itt = setHandlers.iterator();
+ while (itt.hasNext()) {
+ Statement handler = itt.next();
+ if (!handler.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD).containsAll(setNodes)) {
+ excok = false;
+ break;
+ }
+ }
+
+ // build statement and return
+ if (excok) {
+ Statement res = null;
+
+ setPreds.removeAll(setNodes);
+ if (setPreds.size() == 0) {
+ if ((setNodes.size() > 1 ||
+ head.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD).contains(head))
+ && setNodes.size() < stats.size()) {
+ if (checkSynchronizedCompleteness(head, setNodes)) {
+ res = new GeneralStatement(head, setNodes, same ? null : post);
+ stat.collapseNodesToStatement(res);
+
+ return res;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean checkSynchronizedCompleteness(Statement head, HashSet<Statement> setNodes) {
+
+ // check exit nodes
+ for (Statement stat : setNodes) {
+ if (stat.isMonitorEnter()) {
+ List<StatEdge> lstSuccs = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
+ if (lstSuccs.size() != 1 || lstSuccs.get(0).getType() != StatEdge.TYPE_REGULAR) {
+ return false;
+ }
+
+ if (!setNodes.contains(lstSuccs.get(0).getDestination())) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private static boolean findSimpleStatements(Statement stat, HashMap<Integer, Set<Integer>> mapExtPost) {
+
+ boolean found, success = false;
+
+ do {
+ found = false;
+
+ List<Statement> lstStats = stat.getPostReversePostOrderList();
+ for (Statement st : lstStats) {
+
+ Statement result = detectStatement(st);
+
+ if (result != null) {
+
+ if (stat.type == Statement.TYPE_GENERAL && result.getFirst() == stat.getFirst() &&
+ stat.getStats().size() == result.getStats().size()) {
+ // mark general statement
+ stat.type = Statement.TYPE_PLACEHOLDER;
+ }
+
+ stat.collapseNodesToStatement(result);
+
+ // update the postdominator map
+ if (!mapExtPost.isEmpty()) {
+ HashSet<Integer> setOldNodes = new HashSet<Integer>();
+ for (Statement old : result.getStats()) {
+ setOldNodes.add(old.id);
+ }
+
+ Integer newid = result.id;
+
+ for (Integer key : new ArrayList<Integer>(mapExtPost.keySet())) {
+ Set<Integer> set = mapExtPost.get(key);
+
+ int oldsize = set.size();
+ set.removeAll(setOldNodes);
+
+ if (setOldNodes.contains(key)) {
+ Set<Integer> setNew = mapExtPost.get(newid);
+ if (setNew == null) {
+ mapExtPost.put(newid, setNew = new HashSet<Integer>());
+ }
+ setNew.addAll(set);
+
+ mapExtPost.remove(key);
+ }
+ else {
+ if (set.size() < oldsize) {
+ set.add(newid);
+ }
+ }
+ }
+ }
+
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ success = true;
+ }
+ }
+ while (found);
+
+ return success;
+ }
+
+
+ private static Statement detectStatement(Statement head) {
+
+ Statement res;
+
+ if ((res = DoStatement.isHead(head)) != null) {
+ return res;
+ }
+
+ if ((res = SwitchStatement.isHead(head)) != null) {
+ return res;
+ }
+
+ if ((res = IfStatement.isHead(head)) != null) {
+ return res;
+ }
+
+ // synchronized statements will be identified later
+ // right now they are recognized as catchall
+
+ if ((res = SequenceStatement.isHead2Block(head)) != null) {
+ return res;
+ }
+
+ if ((res = CatchStatement.isHead(head)) != null) {
+ return res;
+ }
+
+ if ((res = CatchAllStatement.isHead(head)) != null) {
+ return res;
+ }
+
+ return null;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java
index 6854cd3..16f7da0 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java
@@ -1,214 +1,214 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
-
public class EliminateLoopsHelper {
-
-// public static boolean eliminateLoops(Statement root) {
-//
-// boolean ret = eliminateLoopsRec(root);
-//
-// if(ret) {
-// SequenceHelper.condenseSequences(root);
-//
-// HashSet<Integer> setReorderedIfs = new HashSet<Integer>();
-//
-// SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(false);
-// while(sehelper.simplifyStackVarsStatement(root, setReorderedIfs, null)) {
-// SequenceHelper.condenseSequences(root);
-// }
-// }
-//
-// return ret;
-// }
-
- private static boolean eliminateLoopsRec(Statement stat) {
-
- for(Statement st: stat.getStats()) {
- if(eliminateLoopsRec(st)) {
- return true;
- }
- }
-
- if(stat.type == Statement.TYPE_DO && isLoopRedundant((DoStatement)stat)) {
- return true;
- }
-
- return false;
- }
-
- private static boolean isLoopRedundant(DoStatement loop) {
-
- if(loop.getLooptype() != DoStatement.LOOP_DO) {
- return false;
- }
-
- // get parent loop if exists
- Statement parentloop = loop.getParent();
- while(parentloop != null && parentloop.type != Statement.TYPE_DO) {
- parentloop = parentloop.getParent();
- }
-
- if(parentloop == null || parentloop.getBasichead() != loop.getBasichead()) {
- return false;
- }
-
- // collect relevant break edges
- List<StatEdge> lstBreakEdges = new ArrayList<StatEdge>();
- for(StatEdge edge: loop.getLabelEdges()) {
- if(edge.getType() == StatEdge.TYPE_BREAK) { // all break edges are explicit because of LOOP_DO type
- lstBreakEdges.add(edge);
- }
- }
-
-
- Statement loopcontent = loop.getFirst();
-
- boolean firstok = loopcontent.getAllSuccessorEdges().isEmpty();
- if(!firstok) {
- StatEdge edge = loopcontent.getAllSuccessorEdges().get(0);
- firstok = (edge.closure == loop && edge.getType() == StatEdge.TYPE_BREAK);
- if(firstok) {
- lstBreakEdges.remove(edge);
- }
- }
-
-
- if(!lstBreakEdges.isEmpty()) {
- if(firstok) {
-
- HashMap<Integer, Boolean> statLabeled = new HashMap<Integer, Boolean>();
- List<Statement> lstEdgeClosures = new ArrayList<Statement>();
-
- for(StatEdge edge: lstBreakEdges) {
- Statement minclosure = LowBreakHelper.getMinClosure(loopcontent, edge.getSource());
- lstEdgeClosures.add(minclosure);
- }
-
- int precount = loop.isLabeled()?1:0;
- for(Statement st: lstEdgeClosures) {
- if(!statLabeled.containsKey(st.id)) {
- boolean btemp = st.isLabeled();
- precount+=btemp?1:0;
- statLabeled.put(st.id, btemp);
- }
- }
-
- for(int i=0;i<lstBreakEdges.size();i++) {
- Statement st = lstEdgeClosures.get(i);
- statLabeled.put(st.id, LowBreakHelper.isBreakEdgeLabeled(lstBreakEdges.get(i).getSource(), st) | statLabeled.get(st.id));
- }
-
- for(int i=0;i<lstBreakEdges.size();i++) {
- lstEdgeClosures.set(i, getMaxBreakLift(lstEdgeClosures.get(i), lstBreakEdges.get(i), statLabeled, loop));
- }
-
- statLabeled.clear();
- for(Statement st: lstEdgeClosures) {
- statLabeled.put(st.id, st.isLabeled());
- }
-
- for(int i=0;i<lstBreakEdges.size();i++) {
- Statement st = lstEdgeClosures.get(i);
- statLabeled.put(st.id, LowBreakHelper.isBreakEdgeLabeled(lstBreakEdges.get(i).getSource(), st) | statLabeled.get(st.id));
- }
-
- int postcount = 0;
- for(Boolean val: statLabeled.values()) {
- postcount+=val?1:0;
- }
-
- if(precount <= postcount) {
- return false;
- } else {
- for(int i=0;i<lstBreakEdges.size();i++) {
- lstEdgeClosures.get(i).addLabeledEdge(lstBreakEdges.get(i));
- }
- }
-
- } else {
- return false;
- }
- }
-
- eliminateLoop(loop, parentloop);
-
- return true;
- }
-
- private static Statement getMaxBreakLift(Statement stat, StatEdge edge, HashMap<Integer, Boolean> statLabeled, Statement max) {
-
- Statement closure = stat;
- Statement newclosure = stat;
-
- while((newclosure = getNextBreakLift(newclosure, edge, statLabeled, max)) != null) {
- closure = newclosure;
- }
-
- return closure;
- }
-
- private static Statement getNextBreakLift(Statement stat, StatEdge edge, HashMap<Integer, Boolean> statLabeled, Statement max) {
-
- Statement closure = stat.getParent();
-
- while(closure!=null && closure!=max && !closure.containsStatementStrict(edge.getDestination())) {
-
- boolean edge_labeled = LowBreakHelper.isBreakEdgeLabeled(edge.getSource(), closure);
- boolean stat_labeled = statLabeled.containsKey(closure.id)?statLabeled.get(closure.id):closure.isLabeled();
-
- if(stat_labeled || !edge_labeled) {
- return closure;
- }
-
- closure = closure.getParent();
- }
-
- return null;
- }
-
- private static void eliminateLoop(Statement loop, Statement parentloop) {
-
- // move continue edges to the parent loop
- List<StatEdge> lst = new ArrayList<StatEdge>(loop.getLabelEdges());
- for(StatEdge edge: lst) {
- loop.removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, parentloop);
- parentloop.addPredecessor(edge);
-
- parentloop.addLabeledEdge(edge);
- }
-
- // remove the last break edge, if exists
- Statement loopcontent = loop.getFirst();
- if(!loopcontent.getAllSuccessorEdges().isEmpty()) {
- loopcontent.removeSuccessor(loopcontent.getAllSuccessorEdges().get(0));
- }
-
- // replace loop with its content
- loop.getParent().replaceStatement(loop, loopcontent);
- }
-
+
+ // public static boolean eliminateLoops(Statement root) {
+ //
+ // boolean ret = eliminateLoopsRec(root);
+ //
+ // if(ret) {
+ // SequenceHelper.condenseSequences(root);
+ //
+ // HashSet<Integer> setReorderedIfs = new HashSet<Integer>();
+ //
+ // SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(false);
+ // while(sehelper.simplifyStackVarsStatement(root, setReorderedIfs, null)) {
+ // SequenceHelper.condenseSequences(root);
+ // }
+ // }
+ //
+ // return ret;
+ // }
+
+ private static boolean eliminateLoopsRec(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ if (eliminateLoopsRec(st)) {
+ return true;
+ }
+ }
+
+ if (stat.type == Statement.TYPE_DO && isLoopRedundant((DoStatement)stat)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static boolean isLoopRedundant(DoStatement loop) {
+
+ if (loop.getLooptype() != DoStatement.LOOP_DO) {
+ return false;
+ }
+
+ // get parent loop if exists
+ Statement parentloop = loop.getParent();
+ while (parentloop != null && parentloop.type != Statement.TYPE_DO) {
+ parentloop = parentloop.getParent();
+ }
+
+ if (parentloop == null || parentloop.getBasichead() != loop.getBasichead()) {
+ return false;
+ }
+
+ // collect relevant break edges
+ List<StatEdge> lstBreakEdges = new ArrayList<StatEdge>();
+ for (StatEdge edge : loop.getLabelEdges()) {
+ if (edge.getType() == StatEdge.TYPE_BREAK) { // all break edges are explicit because of LOOP_DO type
+ lstBreakEdges.add(edge);
+ }
+ }
+
+
+ Statement loopcontent = loop.getFirst();
+
+ boolean firstok = loopcontent.getAllSuccessorEdges().isEmpty();
+ if (!firstok) {
+ StatEdge edge = loopcontent.getAllSuccessorEdges().get(0);
+ firstok = (edge.closure == loop && edge.getType() == StatEdge.TYPE_BREAK);
+ if (firstok) {
+ lstBreakEdges.remove(edge);
+ }
+ }
+
+
+ if (!lstBreakEdges.isEmpty()) {
+ if (firstok) {
+
+ HashMap<Integer, Boolean> statLabeled = new HashMap<Integer, Boolean>();
+ List<Statement> lstEdgeClosures = new ArrayList<Statement>();
+
+ for (StatEdge edge : lstBreakEdges) {
+ Statement minclosure = LowBreakHelper.getMinClosure(loopcontent, edge.getSource());
+ lstEdgeClosures.add(minclosure);
+ }
+
+ int precount = loop.isLabeled() ? 1 : 0;
+ for (Statement st : lstEdgeClosures) {
+ if (!statLabeled.containsKey(st.id)) {
+ boolean btemp = st.isLabeled();
+ precount += btemp ? 1 : 0;
+ statLabeled.put(st.id, btemp);
+ }
+ }
+
+ for (int i = 0; i < lstBreakEdges.size(); i++) {
+ Statement st = lstEdgeClosures.get(i);
+ statLabeled.put(st.id, LowBreakHelper.isBreakEdgeLabeled(lstBreakEdges.get(i).getSource(), st) | statLabeled.get(st.id));
+ }
+
+ for (int i = 0; i < lstBreakEdges.size(); i++) {
+ lstEdgeClosures.set(i, getMaxBreakLift(lstEdgeClosures.get(i), lstBreakEdges.get(i), statLabeled, loop));
+ }
+
+ statLabeled.clear();
+ for (Statement st : lstEdgeClosures) {
+ statLabeled.put(st.id, st.isLabeled());
+ }
+
+ for (int i = 0; i < lstBreakEdges.size(); i++) {
+ Statement st = lstEdgeClosures.get(i);
+ statLabeled.put(st.id, LowBreakHelper.isBreakEdgeLabeled(lstBreakEdges.get(i).getSource(), st) | statLabeled.get(st.id));
+ }
+
+ int postcount = 0;
+ for (Boolean val : statLabeled.values()) {
+ postcount += val ? 1 : 0;
+ }
+
+ if (precount <= postcount) {
+ return false;
+ }
+ else {
+ for (int i = 0; i < lstBreakEdges.size(); i++) {
+ lstEdgeClosures.get(i).addLabeledEdge(lstBreakEdges.get(i));
+ }
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ eliminateLoop(loop, parentloop);
+
+ return true;
+ }
+
+ private static Statement getMaxBreakLift(Statement stat, StatEdge edge, HashMap<Integer, Boolean> statLabeled, Statement max) {
+
+ Statement closure = stat;
+ Statement newclosure = stat;
+
+ while ((newclosure = getNextBreakLift(newclosure, edge, statLabeled, max)) != null) {
+ closure = newclosure;
+ }
+
+ return closure;
+ }
+
+ private static Statement getNextBreakLift(Statement stat, StatEdge edge, HashMap<Integer, Boolean> statLabeled, Statement max) {
+
+ Statement closure = stat.getParent();
+
+ while (closure != null && closure != max && !closure.containsStatementStrict(edge.getDestination())) {
+
+ boolean edge_labeled = LowBreakHelper.isBreakEdgeLabeled(edge.getSource(), closure);
+ boolean stat_labeled = statLabeled.containsKey(closure.id) ? statLabeled.get(closure.id) : closure.isLabeled();
+
+ if (stat_labeled || !edge_labeled) {
+ return closure;
+ }
+
+ closure = closure.getParent();
+ }
+
+ return null;
+ }
+
+ private static void eliminateLoop(Statement loop, Statement parentloop) {
+
+ // move continue edges to the parent loop
+ List<StatEdge> lst = new ArrayList<StatEdge>(loop.getLabelEdges());
+ for (StatEdge edge : lst) {
+ loop.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, parentloop);
+ parentloop.addPredecessor(edge);
+
+ parentloop.addLabeledEdge(edge);
+ }
+
+ // remove the last break edge, if exists
+ Statement loopcontent = loop.getFirst();
+ if (!loopcontent.getAllSuccessorEdges().isEmpty()) {
+ loopcontent.removeSuccessor(loopcontent.getAllSuccessorEdges().get(0));
+ }
+
+ // replace loop with its content
+ loop.getParent().replaceStatement(loop, loopcontent);
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java
index 352415a..cddbc21 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java
@@ -1,348 +1,345 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
public class ExitHelper {
-
- public static boolean condenseExits(RootStatement root) {
-
- int changed = integrateExits(root);
-
- if(changed > 0) {
-
- cleanUpUnreachableBlocks(root);
-
- SequenceHelper.condenseSequences(root);
- }
-
- return (changed > 0);
- }
-
-
- private static void cleanUpUnreachableBlocks(Statement stat) {
-
- boolean found;
- do {
-
- found = false;
-
- for(int i=0;i<stat.getStats().size();i++) {
-
- Statement st = stat.getStats().get(i);
-
- cleanUpUnreachableBlocks(st);
-
- if(st.type == Statement.TYPE_SEQUENCE && st.getStats().size() > 1) {
-
- Statement last = st.getStats().getLast();
- Statement secondlast = st.getStats().get(st.getStats().size()-2);
-
- if(last.getExprents() == null || !last.getExprents().isEmpty()) {
- if(!secondlast.hasBasicSuccEdge()) {
-
- Set<Statement> set = last.getNeighboursSet(Statement.STATEDGE_DIRECT_ALL, Statement.DIRECTION_BACKWARD);
- set.remove(secondlast);
-
- if(set.isEmpty()) {
- last.setExprents(new ArrayList<Exprent>());
- found = true;
- break;
- }
- }
- }
- }
- }
-
- } while(found);
-
- }
-
-
- private static int integrateExits(Statement stat) {
-
- int ret = 0;
- Statement dest = null;
-
- if(stat.getExprents() == null) {
-
- for(;;) {
-
- int changed = 0;
-
- for(Statement st: stat.getStats()) {
- changed = integrateExits(st);
- if(changed > 0) {
- ret = 1;
- break;
- }
- }
-
- if(changed == 0) {
- break;
- }
- }
-
-
- switch(stat.type) {
- case Statement.TYPE_IF:
- IfStatement ifst = (IfStatement)stat;
- if(ifst.getIfstat() == null) {
- StatEdge ifedge = ifst.getIfEdge();
- dest = isExitEdge(ifedge);
- if(dest != null) {
- BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
- DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
- bstat.setExprents(DecHelper.copyExprentList(dest.getExprents()));
-
- ifst.getFirst().removeSuccessor(ifedge);
- StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, ifst.getFirst(), bstat);
- ifst.getFirst().addSuccessor(newedge);
- ifst.setIfEdge(newedge);
- ifst.setIfstat(bstat);
- ifst.getStats().addWithKey(bstat, bstat.id);
- bstat.setParent(ifst);
-
- StatEdge oldexitedge = dest.getAllSuccessorEdges().get(0);
- StatEdge newexitedge = new StatEdge(StatEdge.TYPE_BREAK, bstat, oldexitedge.getDestination());
- bstat.addSuccessor(newexitedge);
- oldexitedge.closure.addLabeledEdge(newexitedge);
- ret = 1;
- }
- }
- }
- }
-
-
- if(stat.getAllSuccessorEdges().size() == 1 && stat.getAllSuccessorEdges().get(0).getType() == StatEdge.TYPE_BREAK && stat.getLabelEdges().isEmpty()) {
- Statement parent = stat.getParent();
- if(stat != parent.getFirst() || (parent.type != Statement.TYPE_IF &&
- parent.type != Statement.TYPE_SWITCH)) {
-
- StatEdge destedge = stat.getAllSuccessorEdges().get(0);
- dest = isExitEdge(destedge);
- if(dest != null) {
- stat.removeSuccessor(destedge);
-
- BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
- DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
- bstat.setExprents(DecHelper.copyExprentList(dest.getExprents()));
-
- StatEdge oldexitedge = dest.getAllSuccessorEdges().get(0);
- StatEdge newexitedge = new StatEdge(StatEdge.TYPE_BREAK, bstat, oldexitedge.getDestination());
- bstat.addSuccessor(newexitedge);
- oldexitedge.closure.addLabeledEdge(newexitedge);
-
- SequenceStatement block = new SequenceStatement(Arrays.asList(new Statement[] {stat, bstat}));
- block.setAllParent();
-
- parent.replaceStatement(stat, block);
- // LabelHelper.lowContinueLabels not applicable because of forward continue edges
- // LabelHelper.lowContinueLabels(block, new HashSet<StatEdge>());
- // do it by hand
- for(StatEdge prededge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
-
- block.removePredecessor(prededge);
- prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, stat);
- stat.addPredecessor(prededge);
-
- stat.addLabeledEdge(prededge);
- }
-
-
- stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, bstat));
-
- for(StatEdge edge : dest.getAllPredecessorEdges()) {
- if(!edge.explicit && stat.containsStatementStrict(edge.getSource()) &&
- MergeHelper.isDirectPath(edge.getSource().getParent(), bstat)) {
-
- dest.removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, bstat);
- bstat.addPredecessor(edge);
-
- if(!stat.containsStatementStrict(edge.closure)) {
- stat.addLabeledEdge(edge);
- }
- }
- }
-
- ret = 2;
- }
- }
- }
-
- return ret;
- }
-
- private static Statement isExitEdge(StatEdge edge) {
-
- Statement dest = edge.getDestination();
-
- if(edge.getType() == StatEdge.TYPE_BREAK && dest.type == Statement.TYPE_BASICBLOCK
- && edge.explicit && (edge.labeled || isOnlyEdge(edge))) {
- List<Exprent> data = dest.getExprents();
-
- if(data != null && data.size() == 1) {
- if(data.get(0).type == Exprent.EXPRENT_EXIT) {
- return dest;
- }
- }
- }
-
- return null;
- }
-
- private static boolean isOnlyEdge(StatEdge edge) {
-
- Statement stat = edge.getDestination();
-
- for(StatEdge ed: stat.getAllPredecessorEdges()) {
- if(ed != edge) {
- if(ed.getType() == StatEdge.TYPE_REGULAR) {
- Statement source = ed.getSource();
-
- if(source.type == Statement.TYPE_BASICBLOCK || (source.type == Statement.TYPE_IF &&
- ((IfStatement)source).iftype == IfStatement.IFTYPE_IF) ||
- (source.type == Statement.TYPE_DO && ((DoStatement)source).getLooptype() != DoStatement.LOOP_DO)) {
- return false;
- }
- } else {
- return false;
- }
- }
- }
-
- return true;
- }
-
- public static boolean removeRedundantReturns(RootStatement root) {
-
- boolean res = false;
-
- for(StatEdge edge: root.getDummyExit().getAllPredecessorEdges()) {
- if(!edge.explicit) {
- Statement source = edge.getSource();
+
+ public static boolean condenseExits(RootStatement root) {
+
+ int changed = integrateExits(root);
+
+ if (changed > 0) {
+
+ cleanUpUnreachableBlocks(root);
+
+ SequenceHelper.condenseSequences(root);
+ }
+
+ return (changed > 0);
+ }
+
+
+ private static void cleanUpUnreachableBlocks(Statement stat) {
+
+ boolean found;
+ do {
+
+ found = false;
+
+ for (int i = 0; i < stat.getStats().size(); i++) {
+
+ Statement st = stat.getStats().get(i);
+
+ cleanUpUnreachableBlocks(st);
+
+ if (st.type == Statement.TYPE_SEQUENCE && st.getStats().size() > 1) {
+
+ Statement last = st.getStats().getLast();
+ Statement secondlast = st.getStats().get(st.getStats().size() - 2);
+
+ if (last.getExprents() == null || !last.getExprents().isEmpty()) {
+ if (!secondlast.hasBasicSuccEdge()) {
+
+ Set<Statement> set = last.getNeighboursSet(Statement.STATEDGE_DIRECT_ALL, Statement.DIRECTION_BACKWARD);
+ set.remove(secondlast);
+
+ if (set.isEmpty()) {
+ last.setExprents(new ArrayList<Exprent>());
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ while (found);
+ }
+
+
+ private static int integrateExits(Statement stat) {
+
+ int ret = 0;
+ Statement dest = null;
+
+ if (stat.getExprents() == null) {
+
+ for (; ; ) {
+
+ int changed = 0;
+
+ for (Statement st : stat.getStats()) {
+ changed = integrateExits(st);
+ if (changed > 0) {
+ ret = 1;
+ break;
+ }
+ }
+
+ if (changed == 0) {
+ break;
+ }
+ }
+
+
+ switch (stat.type) {
+ case Statement.TYPE_IF:
+ IfStatement ifst = (IfStatement)stat;
+ if (ifst.getIfstat() == null) {
+ StatEdge ifedge = ifst.getIfEdge();
+ dest = isExitEdge(ifedge);
+ if (dest != null) {
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ bstat.setExprents(DecHelper.copyExprentList(dest.getExprents()));
+
+ ifst.getFirst().removeSuccessor(ifedge);
+ StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, ifst.getFirst(), bstat);
+ ifst.getFirst().addSuccessor(newedge);
+ ifst.setIfEdge(newedge);
+ ifst.setIfstat(bstat);
+ ifst.getStats().addWithKey(bstat, bstat.id);
+ bstat.setParent(ifst);
+
+ StatEdge oldexitedge = dest.getAllSuccessorEdges().get(0);
+ StatEdge newexitedge = new StatEdge(StatEdge.TYPE_BREAK, bstat, oldexitedge.getDestination());
+ bstat.addSuccessor(newexitedge);
+ oldexitedge.closure.addLabeledEdge(newexitedge);
+ ret = 1;
+ }
+ }
+ }
+ }
+
+
+ if (stat.getAllSuccessorEdges().size() == 1 &&
+ stat.getAllSuccessorEdges().get(0).getType() == StatEdge.TYPE_BREAK &&
+ stat.getLabelEdges().isEmpty()) {
+ Statement parent = stat.getParent();
+ if (stat != parent.getFirst() || (parent.type != Statement.TYPE_IF &&
+ parent.type != Statement.TYPE_SWITCH)) {
+
+ StatEdge destedge = stat.getAllSuccessorEdges().get(0);
+ dest = isExitEdge(destedge);
+ if (dest != null) {
+ stat.removeSuccessor(destedge);
+
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ bstat.setExprents(DecHelper.copyExprentList(dest.getExprents()));
+
+ StatEdge oldexitedge = dest.getAllSuccessorEdges().get(0);
+ StatEdge newexitedge = new StatEdge(StatEdge.TYPE_BREAK, bstat, oldexitedge.getDestination());
+ bstat.addSuccessor(newexitedge);
+ oldexitedge.closure.addLabeledEdge(newexitedge);
+
+ SequenceStatement block = new SequenceStatement(Arrays.asList(new Statement[]{stat, bstat}));
+ block.setAllParent();
+
+ parent.replaceStatement(stat, block);
+ // LabelHelper.lowContinueLabels not applicable because of forward continue edges
+ // LabelHelper.lowContinueLabels(block, new HashSet<StatEdge>());
+ // do it by hand
+ for (StatEdge prededge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
+
+ block.removePredecessor(prededge);
+ prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, stat);
+ stat.addPredecessor(prededge);
+
+ stat.addLabeledEdge(prededge);
+ }
+
+
+ stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, bstat));
+
+ for (StatEdge edge : dest.getAllPredecessorEdges()) {
+ if (!edge.explicit && stat.containsStatementStrict(edge.getSource()) &&
+ MergeHelper.isDirectPath(edge.getSource().getParent(), bstat)) {
+
+ dest.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, bstat);
+ bstat.addPredecessor(edge);
+
+ if (!stat.containsStatementStrict(edge.closure)) {
+ stat.addLabeledEdge(edge);
+ }
+ }
+ }
+
+ ret = 2;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ private static Statement isExitEdge(StatEdge edge) {
+
+ Statement dest = edge.getDestination();
+
+ if (edge.getType() == StatEdge.TYPE_BREAK && dest.type == Statement.TYPE_BASICBLOCK
+ && edge.explicit && (edge.labeled || isOnlyEdge(edge))) {
+ List<Exprent> data = dest.getExprents();
+
+ if (data != null && data.size() == 1) {
+ if (data.get(0).type == Exprent.EXPRENT_EXIT) {
+ return dest;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isOnlyEdge(StatEdge edge) {
+
+ Statement stat = edge.getDestination();
+
+ for (StatEdge ed : stat.getAllPredecessorEdges()) {
+ if (ed != edge) {
+ if (ed.getType() == StatEdge.TYPE_REGULAR) {
+ Statement source = ed.getSource();
+
+ if (source.type == Statement.TYPE_BASICBLOCK || (source.type == Statement.TYPE_IF &&
+ ((IfStatement)source).iftype == IfStatement.IFTYPE_IF) ||
+ (source.type == Statement.TYPE_DO && ((DoStatement)source).getLooptype() != DoStatement.LOOP_DO)) {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean removeRedundantReturns(RootStatement root) {
+
+ boolean res = false;
+
+ for (StatEdge edge : root.getDummyExit().getAllPredecessorEdges()) {
+ if (!edge.explicit) {
+ Statement source = edge.getSource();
List<Exprent> lstExpr = source.getExprents();
- if(lstExpr != null && !lstExpr.isEmpty()) {
- Exprent expr = lstExpr.get(lstExpr.size() - 1);
- if(expr.type == Exprent.EXPRENT_EXIT) {
- ExitExprent ex = (ExitExprent)expr;
- if(ex.getExittype() == ExitExprent.EXIT_RETURN && ex.getValue() == null) {
- // remove redundant return
- lstExpr.remove(lstExpr.size() - 1);
- res = true;
- }
- }
- }
- }
- }
-
- return res;
- }
-
- public static boolean handleReturnFromInitializer(RootStatement root) {
-
- boolean res = false;
-
- Statement exit = root.getDummyExit();
- Statement top = root.getFirst();
- Statement newret = null;
-
- boolean sharedcreated = false;
-
- for(StatEdge edge: exit.getAllPredecessorEdges()) {
- if(edge.explicit) {
-
- if(!sharedcreated) {
- newret = addSharedInitializerReturn(root);
- sharedcreated = true;
- }
-
- Statement source = edge.getSource();
+ if (lstExpr != null && !lstExpr.isEmpty()) {
+ Exprent expr = lstExpr.get(lstExpr.size() - 1);
+ if (expr.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent ex = (ExitExprent)expr;
+ if (ex.getExittype() == ExitExprent.EXIT_RETURN && ex.getValue() == null) {
+ // remove redundant return
+ lstExpr.remove(lstExpr.size() - 1);
+ res = true;
+ }
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public static boolean handleReturnFromInitializer(RootStatement root) {
+
+ boolean res = false;
+
+ Statement exit = root.getDummyExit();
+ Statement top = root.getFirst();
+ Statement newret = null;
+
+ boolean sharedcreated = false;
+
+ for (StatEdge edge : exit.getAllPredecessorEdges()) {
+ if (edge.explicit) {
+
+ if (!sharedcreated) {
+ newret = addSharedInitializerReturn(root);
+ sharedcreated = true;
+ }
+
+ Statement source = edge.getSource();
List<Exprent> lstExpr = source.getExprents();
- if(lstExpr != null && !lstExpr.isEmpty()) {
- Exprent expr = lstExpr.get(lstExpr.size() - 1);
- if(expr.type == Exprent.EXPRENT_EXIT) {
- ExitExprent ex = (ExitExprent)expr;
- if(ex.getExittype() == ExitExprent.EXIT_RETURN && ex.getValue() == null) {
- lstExpr.remove(lstExpr.size() - 1);
-
- source.removeSuccessor(edge);
- source.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, source, newret, top));
-
- res = true;
- }
- }
- }
- }
- }
-
- return res;
- }
-
- private static Statement addSharedInitializerReturn(RootStatement root) {
-
- Statement exit = root.getDummyExit();
- Statement top = root.getFirst();
-
- // build a new statement with the single instruction 'return'
- BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
- DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
-
- ExitExprent retexpr = new ExitExprent(ExitExprent.EXIT_RETURN, null,
- ((MethodDescriptor)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR)).ret);
- // a changeable list needed
- bstat.setExprents(new ArrayList<Exprent>(Arrays.asList(new Exprent[]{retexpr})));
-
- // build sequence to replace the former top statement
- SequenceStatement seq = new SequenceStatement(Arrays.asList(new Statement[]{top, bstat}));
- top.setParent(seq);
- bstat.setParent(seq);
- seq.setParent(root);
-
- root.getStats().removeWithKey(top.id);
- root.getStats().addWithKeyAndIndex(0, seq, seq.id);
- root.setFirst(seq);
-
- for(StatEdge succedge : top.getAllSuccessorEdges()) {
- top.removeSuccessor(succedge);
- }
-
- top.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, top, bstat));
- bstat.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, bstat, exit, seq));
-
- return bstat;
- }
-
-
+ if (lstExpr != null && !lstExpr.isEmpty()) {
+ Exprent expr = lstExpr.get(lstExpr.size() - 1);
+ if (expr.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent ex = (ExitExprent)expr;
+ if (ex.getExittype() == ExitExprent.EXIT_RETURN && ex.getValue() == null) {
+ lstExpr.remove(lstExpr.size() - 1);
+
+ source.removeSuccessor(edge);
+ source.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, source, newret, top));
+
+ res = true;
+ }
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+ private static Statement addSharedInitializerReturn(RootStatement root) {
+
+ Statement exit = root.getDummyExit();
+ Statement top = root.getFirst();
+
+ // build a new statement with the single instruction 'return'
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+
+ ExitExprent retexpr = new ExitExprent(ExitExprent.EXIT_RETURN, null,
+ ((MethodDescriptor)DecompilerContext
+ .getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR)).ret);
+ // a changeable list needed
+ bstat.setExprents(new ArrayList<Exprent>(Arrays.asList(new Exprent[]{retexpr})));
+
+ // build sequence to replace the former top statement
+ SequenceStatement seq = new SequenceStatement(Arrays.asList(new Statement[]{top, bstat}));
+ top.setParent(seq);
+ bstat.setParent(seq);
+ seq.setParent(root);
+
+ root.getStats().removeWithKey(top.id);
+ root.getStats().addWithKeyAndIndex(0, seq, seq.id);
+ root.setFirst(seq);
+
+ for (StatEdge succedge : top.getAllSuccessorEdges()) {
+ top.removeSuccessor(succedge);
+ }
+
+ top.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, top, bstat));
+ bstat.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, bstat, exit, seq));
+
+ return bstat;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java
index 362e1a2..3b35d36 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java
@@ -1,54 +1,31 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.code.Instruction;
import org.jetbrains.java.decompiler.code.InstructionSequence;
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
import org.jetbrains.java.decompiler.main.DecompilerContext;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ArrayExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.MonitorExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.SwitchExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper.FinallyPathWrapper;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.attr.StructBootstrapMethodsAttribute;
@@ -61,826 +38,876 @@ import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.*;
+
public class ExprProcessor implements CodeConstants {
- public static final String UNDEFINED_TYPE_STRING = "<undefinedtype>";
- public static final String UNKNOWN_TYPE_STRING = "<unknown>";
- public static final String NULL_TYPE_STRING = "<null>";
-
- private static final HashMap<Integer, Integer> mapConsts = new HashMap<Integer, Integer>();
+ public static final String UNDEFINED_TYPE_STRING = "<undefinedtype>";
+ public static final String UNKNOWN_TYPE_STRING = "<unknown>";
+ public static final String NULL_TYPE_STRING = "<null>";
+
+ private static final HashMap<Integer, Integer> mapConsts = new HashMap<Integer, Integer>();
+
+ static {
+
+ // mapConsts.put(new Integer(opc_i2l), new
+ // Integer(FunctionExprent.FUNCTION_I2L));
+ // mapConsts.put(new Integer(opc_i2f), new
+ // Integer(FunctionExprent.FUNCTION_I2F));
+ // mapConsts.put(new Integer(opc_i2d), new
+ // Integer(FunctionExprent.FUNCTION_I2D));
+ // mapConsts.put(new Integer(opc_l2i), new
+ // Integer(FunctionExprent.FUNCTION_L2I));
+ // mapConsts.put(new Integer(opc_l2f), new
+ // Integer(FunctionExprent.FUNCTION_L2F));
+ // mapConsts.put(new Integer(opc_l2d), new
+ // Integer(FunctionExprent.FUNCTION_L2D));
+ // mapConsts.put(new Integer(opc_f2i), new
+ // Integer(FunctionExprent.FUNCTION_F2I));
+ // mapConsts.put(new Integer(opc_f2l), new
+ // Integer(FunctionExprent.FUNCTION_F2L));
+ // mapConsts.put(new Integer(opc_f2d), new
+ // Integer(FunctionExprent.FUNCTION_F2D));
+ // mapConsts.put(new Integer(opc_d2i), new
+ // Integer(FunctionExprent.FUNCTION_D2I));
+ // mapConsts.put(new Integer(opc_d2l), new
+ // Integer(FunctionExprent.FUNCTION_D2L));
+ // mapConsts.put(new Integer(opc_d2f), new
+ // Integer(FunctionExprent.FUNCTION_D2F));
+ // mapConsts.put(new Integer(opc_i2b), new
+ // Integer(FunctionExprent.FUNCTION_I2B));
+ // mapConsts.put(new Integer(opc_i2c), new
+ // Integer(FunctionExprent.FUNCTION_I2C));
+ // mapConsts.put(new Integer(opc_i2s), new
+ // Integer(FunctionExprent.FUNCTION_I2S));
+
+ mapConsts.put(new Integer(opc_arraylength), new Integer(FunctionExprent.FUNCTION_ARRAYLENGTH));
+ mapConsts.put(new Integer(opc_checkcast), new Integer(FunctionExprent.FUNCTION_CAST));
+ mapConsts.put(new Integer(opc_instanceof), new Integer(FunctionExprent.FUNCTION_INSTANCEOF));
+ }
+
+ private static final VarType[] consts =
+ new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_CLASS,
+ VarType.VARTYPE_STRING};
+
+ private static final VarType[] vartypes =
+ new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT};
+
+ private static final VarType[] arrtypes =
+ new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT,
+ VarType.VARTYPE_BOOLEAN, VarType.VARTYPE_CHAR, VarType.VARTYPE_SHORT};
+
+ private static final int[] func1 =
+ new int[]{FunctionExprent.FUNCTION_ADD, FunctionExprent.FUNCTION_SUB, FunctionExprent.FUNCTION_MUL, FunctionExprent.FUNCTION_DIV,
+ FunctionExprent.FUNCTION_REM};
+
+ private static final int[] func2 =
+ new int[]{FunctionExprent.FUNCTION_SHL, FunctionExprent.FUNCTION_SHR, FunctionExprent.FUNCTION_USHR, FunctionExprent.FUNCTION_AND,
+ FunctionExprent.FUNCTION_OR, FunctionExprent.FUNCTION_XOR};
+
+ private static final int[] func3 =
+ new int[]{FunctionExprent.FUNCTION_I2L, FunctionExprent.FUNCTION_I2F, FunctionExprent.FUNCTION_I2D, FunctionExprent.FUNCTION_L2I,
+ FunctionExprent.FUNCTION_L2F, FunctionExprent.FUNCTION_L2D, FunctionExprent.FUNCTION_F2I, FunctionExprent.FUNCTION_F2L,
+ FunctionExprent.FUNCTION_F2D,
+ FunctionExprent.FUNCTION_D2I, FunctionExprent.FUNCTION_D2L, FunctionExprent.FUNCTION_D2F, FunctionExprent.FUNCTION_I2B,
+ FunctionExprent.FUNCTION_I2C,
+ FunctionExprent.FUNCTION_I2S};
+
+ private static final int[] func4 =
+ new int[]{FunctionExprent.FUNCTION_LCMP, FunctionExprent.FUNCTION_FCMPL, FunctionExprent.FUNCTION_FCMPG, FunctionExprent.FUNCTION_DCMPL,
+ FunctionExprent.FUNCTION_DCMPG};
+
+ private static final int[] func5 =
+ new int[]{IfExprent.IF_EQ, IfExprent.IF_NE, IfExprent.IF_LT, IfExprent.IF_GE, IfExprent.IF_GT, IfExprent.IF_LE};
+
+ private static final int[] func6 =
+ new int[]{IfExprent.IF_ICMPEQ, IfExprent.IF_ICMPNE, IfExprent.IF_ICMPLT, IfExprent.IF_ICMPGE, IfExprent.IF_ICMPGT, IfExprent.IF_ICMPLE,
+ IfExprent.IF_ACMPEQ, IfExprent.IF_ACMPNE};
+
+ private static final int[] func7 = new int[]{IfExprent.IF_NULL, IfExprent.IF_NONNULL};
+
+ private static final int[] func8 = new int[]{MonitorExprent.MONITOR_ENTER, MonitorExprent.MONITOR_EXIT};
+
+ private static final int[] arr_type =
+ new int[]{CodeConstants.TYPE_BOOLEAN, CodeConstants.TYPE_CHAR, CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_DOUBLE,
+ CodeConstants.TYPE_BYTE, CodeConstants.TYPE_SHORT, CodeConstants.TYPE_INT, CodeConstants.TYPE_LONG};
+
+ private static final int[] negifs =
+ new int[]{IfExprent.IF_NE, IfExprent.IF_EQ, IfExprent.IF_GE, IfExprent.IF_LT, IfExprent.IF_LE, IfExprent.IF_GT, IfExprent.IF_NONNULL,
+ IfExprent.IF_NULL, IfExprent.IF_ICMPNE, IfExprent.IF_ICMPEQ, IfExprent.IF_ICMPGE, IfExprent.IF_ICMPLT, IfExprent.IF_ICMPLE,
+ IfExprent.IF_ICMPGT, IfExprent.IF_ACMPNE,
+ IfExprent.IF_ACMPEQ};
+
+ private static final String[] typeNames = new String[]{"byte", "char", "double", "float", "int", "long", "short", "boolean",};
+
+ private VarProcessor varProcessor = (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR);
+
+ public void processStatement(RootStatement root, StructClass cl) {
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
+ // } catch (Exception ex) {
+ // ex.printStackTrace();
+ // }
+
+ // collect finally entry points
+ Set<String> setFinallyShortRangeEntryPoints = new HashSet<String>();
+ for (List<FinallyPathWrapper> lst : dgraph.mapShortRangeFinallyPaths.values()) {
+ for (FinallyPathWrapper finwrap : lst) {
+ setFinallyShortRangeEntryPoints.add(finwrap.entry);
+ }
+ }
+
+ Set<String> setFinallyLongRangeEntryPaths = new HashSet<String>();
+ for (List<FinallyPathWrapper> lst : dgraph.mapLongRangeFinallyPaths.values()) {
+ for (FinallyPathWrapper finwrap : lst) {
+ setFinallyLongRangeEntryPaths.add(finwrap.source + "##" + finwrap.entry);
+ }
+ }
- static {
-
- // mapConsts.put(new Integer(opc_i2l), new
- // Integer(FunctionExprent.FUNCTION_I2L));
- // mapConsts.put(new Integer(opc_i2f), new
- // Integer(FunctionExprent.FUNCTION_I2F));
- // mapConsts.put(new Integer(opc_i2d), new
- // Integer(FunctionExprent.FUNCTION_I2D));
- // mapConsts.put(new Integer(opc_l2i), new
- // Integer(FunctionExprent.FUNCTION_L2I));
- // mapConsts.put(new Integer(opc_l2f), new
- // Integer(FunctionExprent.FUNCTION_L2F));
- // mapConsts.put(new Integer(opc_l2d), new
- // Integer(FunctionExprent.FUNCTION_L2D));
- // mapConsts.put(new Integer(opc_f2i), new
- // Integer(FunctionExprent.FUNCTION_F2I));
- // mapConsts.put(new Integer(opc_f2l), new
- // Integer(FunctionExprent.FUNCTION_F2L));
- // mapConsts.put(new Integer(opc_f2d), new
- // Integer(FunctionExprent.FUNCTION_F2D));
- // mapConsts.put(new Integer(opc_d2i), new
- // Integer(FunctionExprent.FUNCTION_D2I));
- // mapConsts.put(new Integer(opc_d2l), new
- // Integer(FunctionExprent.FUNCTION_D2L));
- // mapConsts.put(new Integer(opc_d2f), new
- // Integer(FunctionExprent.FUNCTION_D2F));
- // mapConsts.put(new Integer(opc_i2b), new
- // Integer(FunctionExprent.FUNCTION_I2B));
- // mapConsts.put(new Integer(opc_i2c), new
- // Integer(FunctionExprent.FUNCTION_I2C));
- // mapConsts.put(new Integer(opc_i2s), new
- // Integer(FunctionExprent.FUNCTION_I2S));
-
- mapConsts.put(new Integer(opc_arraylength), new Integer(FunctionExprent.FUNCTION_ARRAYLENGTH));
- mapConsts.put(new Integer(opc_checkcast), new Integer(FunctionExprent.FUNCTION_CAST));
- mapConsts.put(new Integer(opc_instanceof), new Integer(FunctionExprent.FUNCTION_INSTANCEOF));
-
- }
-
- private static final VarType[] consts = new VarType[] { VarType.VARTYPE_INT, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_CLASS,
- VarType.VARTYPE_STRING };
+ Map<String, VarExprent> mapCatch = new HashMap<String, VarExprent>();
+ collectCatchVars(root, flatthelper, mapCatch);
+
+ Map<DirectNode, Map<String, PrimitiveExprsList>> mapData = new HashMap<DirectNode, Map<String, PrimitiveExprsList>>();
+
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ LinkedList<LinkedList<String>> stackEntryPoint = new LinkedList<LinkedList<String>>();
+
+ stack.add(dgraph.first);
+ stackEntryPoint.add(new LinkedList<String>());
+
+ Map<String, PrimitiveExprsList> map = new HashMap<String, PrimitiveExprsList>();
+ map.put(null, new PrimitiveExprsList());
+ mapData.put(dgraph.first, map);
+
+ while (!stack.isEmpty()) {
+
+ DirectNode node = stack.removeFirst();
+ LinkedList<String> entrypoints = stackEntryPoint.removeFirst();
+
+ PrimitiveExprsList data;
+ if (mapCatch.containsKey(node.id)) {
+ data = getExpressionData(mapCatch.get(node.id));
+ }
+ else {
+ data = mapData.get(node).get(buildEntryPointKey(entrypoints));
+ }
+
+ BasicBlockStatement block = node.block;
+ if (block != null) {
+ processBlock(block, data, cl);
+ block.setExprents(data.getLstExprents());
+ }
+
+ String currentEntrypoint = entrypoints.isEmpty() ? null : entrypoints.getLast();
+
+ for (DirectNode nd : node.succs) {
+
+ boolean isSuccessor = true;
+ if (currentEntrypoint != null && dgraph.mapLongRangeFinallyPaths.containsKey(node.id)) {
+ isSuccessor = false;
+ for (FinallyPathWrapper finwraplong : dgraph.mapLongRangeFinallyPaths.get(node.id)) {
+ if (finwraplong.source.equals(currentEntrypoint) && finwraplong.destination.equals(nd.id)) {
+ isSuccessor = true;
+ break;
+ }
+ }
+ }
+
+ if (isSuccessor) {
+
+ Map<String, PrimitiveExprsList> mapSucc = mapData.get(nd);
+ if (mapSucc == null) {
+ mapData.put(nd, mapSucc = new HashMap<String, PrimitiveExprsList>());
+ }
+
+ LinkedList<String> ndentrypoints = new LinkedList<String>(entrypoints);
+
+ if (setFinallyLongRangeEntryPaths.contains(node.id + "##" + nd.id)) {
+ ndentrypoints.addLast(node.id);
+ }
+ else if (!setFinallyShortRangeEntryPoints.contains(nd.id) && dgraph.mapLongRangeFinallyPaths.containsKey(node.id)) {
+ ndentrypoints.removeLast(); // currentEntrypoint should
+ // not be null at this point
+ }
+
+ // handling of entry point loops
+ int succ_entry_index = ndentrypoints.indexOf(nd.id);
+ if (succ_entry_index >=
+ 0) { // we are in a loop (e.g. continue in a finally block), drop all entry points in the list beginning with succ_entry_index
+ for (int elements_to_remove = ndentrypoints.size() - succ_entry_index; elements_to_remove > 0; elements_to_remove--) {
+ ndentrypoints.removeLast();
+ }
+ }
+
+ String ndentrykey = buildEntryPointKey(ndentrypoints);
+ if (!mapSucc.containsKey(ndentrykey)) {
+
+ mapSucc.put(ndentrykey, copyVarExprents(data.copyStack()));
+
+ stack.add(nd);
+ stackEntryPoint.add(ndentrypoints);
+ }
+ }
+ }
+ }
+
+ initStatementExprents(root);
+ }
+
+ // FIXME: Ugly code, to be rewritten. A tuple class is needed.
+ private String buildEntryPointKey(LinkedList<String> entrypoints) {
+ if (entrypoints.isEmpty()) {
+ return null;
+ }
+ else {
+ StringBuilder buffer = new StringBuilder();
+ for (String point : entrypoints) {
+ buffer.append(point);
+ buffer.append(":");
+ }
+ return buffer.toString();
+ }
+ }
- private static final VarType[] vartypes = new VarType[] { VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT };
+ private PrimitiveExprsList copyVarExprents(PrimitiveExprsList data) {
+ ExprentStack stack = data.getStack();
+ for (int i = 0; i < stack.size(); i++) {
+ stack.set(i, stack.get(i).copy());
+ }
+ return data;
+ }
+
+ private void collectCatchVars(Statement stat, FlattenStatementsHelper flatthelper, Map<String, VarExprent> map) {
+
+ List<VarExprent> lst = null;
+
+ if (stat.type == Statement.TYPE_CATCHALL) {
+ CatchAllStatement catchall = (CatchAllStatement)stat;
+ if (!catchall.isFinally()) {
+ lst = catchall.getVars();
+ }
+ }
+ else if (stat.type == Statement.TYPE_TRYCATCH) {
+ lst = ((CatchStatement)stat).getVars();
+ }
+
+ if (lst != null) {
+ for (int i = 1; i < stat.getStats().size(); i++) {
+ map.put(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0], lst.get(i - 1));
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ collectCatchVars(st, flatthelper, map);
+ }
+ }
- private static final VarType[] arrtypes = new VarType[] { VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT,
- VarType.VARTYPE_BOOLEAN, VarType.VARTYPE_CHAR, VarType.VARTYPE_SHORT };
+ private void initStatementExprents(Statement stat) {
+ stat.initExprents();
- private static final int[] func1 = new int[] { FunctionExprent.FUNCTION_ADD, FunctionExprent.FUNCTION_SUB, FunctionExprent.FUNCTION_MUL, FunctionExprent.FUNCTION_DIV,
- FunctionExprent.FUNCTION_REM };
-
- private static final int[] func2 = new int[] { FunctionExprent.FUNCTION_SHL, FunctionExprent.FUNCTION_SHR, FunctionExprent.FUNCTION_USHR, FunctionExprent.FUNCTION_AND,
- FunctionExprent.FUNCTION_OR, FunctionExprent.FUNCTION_XOR };
-
- private static final int[] func3 = new int[] { FunctionExprent.FUNCTION_I2L, FunctionExprent.FUNCTION_I2F, FunctionExprent.FUNCTION_I2D, FunctionExprent.FUNCTION_L2I,
- FunctionExprent.FUNCTION_L2F, FunctionExprent.FUNCTION_L2D, FunctionExprent.FUNCTION_F2I, FunctionExprent.FUNCTION_F2L, FunctionExprent.FUNCTION_F2D,
- FunctionExprent.FUNCTION_D2I, FunctionExprent.FUNCTION_D2L, FunctionExprent.FUNCTION_D2F, FunctionExprent.FUNCTION_I2B, FunctionExprent.FUNCTION_I2C,
- FunctionExprent.FUNCTION_I2S };
-
- private static final int[] func4 = new int[] { FunctionExprent.FUNCTION_LCMP, FunctionExprent.FUNCTION_FCMPL, FunctionExprent.FUNCTION_FCMPG, FunctionExprent.FUNCTION_DCMPL,
- FunctionExprent.FUNCTION_DCMPG };
-
- private static final int[] func5 = new int[] { IfExprent.IF_EQ, IfExprent.IF_NE, IfExprent.IF_LT, IfExprent.IF_GE, IfExprent.IF_GT, IfExprent.IF_LE };
-
- private static final int[] func6 = new int[] { IfExprent.IF_ICMPEQ, IfExprent.IF_ICMPNE, IfExprent.IF_ICMPLT, IfExprent.IF_ICMPGE, IfExprent.IF_ICMPGT, IfExprent.IF_ICMPLE,
- IfExprent.IF_ACMPEQ, IfExprent.IF_ACMPNE };
-
- private static final int[] func7 = new int[] { IfExprent.IF_NULL, IfExprent.IF_NONNULL };
-
- private static final int[] func8 = new int[] { MonitorExprent.MONITOR_ENTER, MonitorExprent.MONITOR_EXIT };
-
- private static final int[] arr_type = new int[] { CodeConstants.TYPE_BOOLEAN, CodeConstants.TYPE_CHAR, CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_DOUBLE,
- CodeConstants.TYPE_BYTE, CodeConstants.TYPE_SHORT, CodeConstants.TYPE_INT, CodeConstants.TYPE_LONG };
-
- private static final int[] negifs = new int[] { IfExprent.IF_NE, IfExprent.IF_EQ, IfExprent.IF_GE, IfExprent.IF_LT, IfExprent.IF_LE, IfExprent.IF_GT, IfExprent.IF_NONNULL,
- IfExprent.IF_NULL, IfExprent.IF_ICMPNE, IfExprent.IF_ICMPEQ, IfExprent.IF_ICMPGE, IfExprent.IF_ICMPLT, IfExprent.IF_ICMPLE, IfExprent.IF_ICMPGT, IfExprent.IF_ACMPNE,
- IfExprent.IF_ACMPEQ };
-
- private static final String[] typeNames = new String[] { "byte", "char", "double", "float", "int", "long", "short", "boolean", };
-
- private VarProcessor varProcessor = (VarProcessor) DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR);
-
- public void processStatement(RootStatement root, StructClass cl) {
-
- FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
- DirectGraph dgraph = flatthelper.buildDirectGraph(root);
-
-// try {
-// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
-// } catch (Exception ex) {
-// ex.printStackTrace();
-// }
-
- // collect finally entry points
- Set<String> setFinallyShortRangeEntryPoints = new HashSet<String>();
- for (List<FinallyPathWrapper> lst : dgraph.mapShortRangeFinallyPaths.values()) {
- for (FinallyPathWrapper finwrap : lst) {
- setFinallyShortRangeEntryPoints.add(finwrap.entry);
- }
- }
-
- Set<String> setFinallyLongRangeEntryPaths = new HashSet<String>();
- for (List<FinallyPathWrapper> lst : dgraph.mapLongRangeFinallyPaths.values()) {
- for (FinallyPathWrapper finwrap : lst) {
- setFinallyLongRangeEntryPaths.add(finwrap.source + "##" + finwrap.entry);
- }
- }
-
- Map<String, VarExprent> mapCatch = new HashMap<String, VarExprent>();
- collectCatchVars(root, flatthelper, mapCatch);
-
- Map<DirectNode, Map<String, PrimitiveExprsList>> mapData = new HashMap<DirectNode, Map<String, PrimitiveExprsList>>();
-
- LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
- LinkedList<LinkedList<String>> stackEntryPoint = new LinkedList<LinkedList<String>>();
-
- stack.add(dgraph.first);
- stackEntryPoint.add(new LinkedList<String>());
-
- Map<String, PrimitiveExprsList> map = new HashMap<String, PrimitiveExprsList>();
- map.put(null, new PrimitiveExprsList());
- mapData.put(dgraph.first, map);
-
- while (!stack.isEmpty()) {
-
- DirectNode node = stack.removeFirst();
- LinkedList<String> entrypoints = stackEntryPoint.removeFirst();
-
- PrimitiveExprsList data;
- if (mapCatch.containsKey(node.id)) {
- data = getExpressionData(mapCatch.get(node.id));
- } else {
- data = mapData.get(node).get(buildEntryPointKey(entrypoints));
- }
-
- BasicBlockStatement block = node.block;
- if (block != null) {
- processBlock(block, data, cl);
- block.setExprents(data.getLstExprents());
- }
-
- String currentEntrypoint = entrypoints.isEmpty() ? null : entrypoints.getLast();
-
- for (DirectNode nd : node.succs) {
-
- boolean isSuccessor = true;
- if (currentEntrypoint != null && dgraph.mapLongRangeFinallyPaths.containsKey(node.id)) {
- isSuccessor = false;
- for (FinallyPathWrapper finwraplong : dgraph.mapLongRangeFinallyPaths.get(node.id)) {
- if (finwraplong.source.equals(currentEntrypoint) && finwraplong.destination.equals(nd.id)) {
- isSuccessor = true;
- break;
- }
- }
- }
-
- if (isSuccessor) {
-
- Map<String, PrimitiveExprsList> mapSucc = mapData.get(nd);
- if (mapSucc == null) {
- mapData.put(nd, mapSucc = new HashMap<String, PrimitiveExprsList>());
- }
-
- LinkedList<String> ndentrypoints = new LinkedList<String>(entrypoints);
-
- if (setFinallyLongRangeEntryPaths.contains(node.id + "##" + nd.id)) {
- ndentrypoints.addLast(node.id);
- } else if (!setFinallyShortRangeEntryPoints.contains(nd.id) && dgraph.mapLongRangeFinallyPaths.containsKey(node.id)) {
- ndentrypoints.removeLast(); // currentEntrypoint should
- // not be null at this point
- }
-
- // handling of entry point loops
- int succ_entry_index = ndentrypoints.indexOf(nd.id);
- if(succ_entry_index >= 0) { // we are in a loop (e.g. continue in a finally block), drop all entry points in the list beginning with succ_entry_index
- for(int elements_to_remove = ndentrypoints.size() - succ_entry_index; elements_to_remove > 0; elements_to_remove--) {
- ndentrypoints.removeLast();
- }
- }
-
- String ndentrykey = buildEntryPointKey(ndentrypoints);
- if (!mapSucc.containsKey(ndentrykey)) {
-
- mapSucc.put(ndentrykey, copyVarExprents(data.copyStack()));
-
- stack.add(nd);
- stackEntryPoint.add(ndentrypoints);
- }
- }
- }
- }
-
- initStatementExprents(root);
- }
-
- // FIXME: Ugly code, to be rewritten. A tuple class is needed.
- private String buildEntryPointKey(LinkedList<String> entrypoints) {
- if (entrypoints.isEmpty()) {
- return null;
- } else {
- StringBuilder buffer = new StringBuilder();
- for (String point : entrypoints) {
- buffer.append(point);
- buffer.append(":");
- }
- return buffer.toString();
- }
- }
-
- private PrimitiveExprsList copyVarExprents(PrimitiveExprsList data) {
- ExprentStack stack = data.getStack();
- for (int i = 0; i < stack.size(); i++) {
- stack.set(i, stack.get(i).copy());
- }
- return data;
- }
-
- private void collectCatchVars(Statement stat, FlattenStatementsHelper flatthelper, Map<String, VarExprent> map) {
-
- List<VarExprent> lst = null;
-
- if (stat.type == Statement.TYPE_CATCHALL) {
- CatchAllStatement catchall = (CatchAllStatement) stat;
- if (!catchall.isFinally()) {
- lst = catchall.getVars();
- }
- } else if (stat.type == Statement.TYPE_TRYCATCH) {
- lst = ((CatchStatement) stat).getVars();
- }
-
- if (lst != null) {
- for (int i = 1; i < stat.getStats().size(); i++) {
- map.put(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0], lst.get(i - 1));
- }
- }
-
- for (Statement st : stat.getStats()) {
- collectCatchVars(st, flatthelper, map);
- }
- }
-
- private void initStatementExprents(Statement stat) {
- stat.initExprents();
-
- for (Statement st : stat.getStats()) {
- initStatementExprents(st);
- }
- }
-
- public void processBlock(BasicBlockStatement stat, PrimitiveExprsList data, StructClass cl) {
-
- ConstantPool pool = cl.getPool();
- StructBootstrapMethodsAttribute bootstrap = (StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
-
- BasicBlock block = stat.getBlock();
-
- ExprentStack stack = data.getStack();
- List<Exprent> exprlist = data.getLstExprents();
-
- InstructionSequence seq = block.getSeq();
-
- for (int i = 0; i < seq.length(); i++) {
-
- Instruction instr = seq.getInstr(i);
-
- switch (instr.opcode) {
- case opc_aconst_null:
- pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_NULL, null));
- break;
- case opc_bipush:
- case opc_sipush:
- pushEx(stack, exprlist, new ConstExprent(instr.getOperand(0), true));
- break;
- case opc_lconst_0:
- case opc_lconst_1:
- pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_LONG, new Long(instr.opcode - opc_lconst_0)));
- break;
- case opc_fconst_0:
- case opc_fconst_1:
- case opc_fconst_2:
- pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_FLOAT, new Float(instr.opcode - opc_fconst_0)));
- break;
- case opc_dconst_0:
- case opc_dconst_1:
- pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(instr.opcode - opc_dconst_0)));
- break;
- case opc_ldc:
- case opc_ldc_w:
- case opc_ldc2_w:
- PrimitiveConstant cn = pool.getPrimitiveConstant(instr.getOperand(0));
- pushEx(stack, exprlist, new ConstExprent(consts[cn.type - CONSTANT_Integer], cn.value));
- break;
- case opc_iload:
- case opc_lload:
- case opc_fload:
- case opc_dload:
- case opc_aload:
- pushEx(stack, exprlist, new VarExprent(instr.getOperand(0), vartypes[instr.opcode - opc_iload], varProcessor));
- break;
- case opc_iaload:
- case opc_laload:
- case opc_faload:
- case opc_daload:
- case opc_aaload:
- case opc_baload:
- case opc_caload:
- case opc_saload:
- Exprent index = stack.pop();
- Exprent arr = stack.pop();
-
- VarType vartype = null;
- switch (instr.opcode) {
- case opc_laload:
- vartype = VarType.VARTYPE_LONG;
- break;
- case opc_daload:
- vartype = VarType.VARTYPE_DOUBLE;
- }
- pushEx(stack, exprlist, new ArrayExprent(arr, index, arrtypes[instr.opcode - opc_iaload]), vartype);
- break;
- case opc_istore:
- case opc_lstore:
- case opc_fstore:
- case opc_dstore:
- case opc_astore:
- Exprent top = stack.pop();
- int varindex = instr.getOperand(0);
- AssignmentExprent assign = new AssignmentExprent(new VarExprent(varindex, vartypes[instr.opcode - opc_istore], varProcessor), top);
- exprlist.add(assign);
- break;
- case opc_iastore:
- case opc_lastore:
- case opc_fastore:
- case opc_dastore:
- case opc_aastore:
- case opc_bastore:
- case opc_castore:
- case opc_sastore:
- Exprent value = stack.pop();
- Exprent index_store = stack.pop();
- Exprent arr_store = stack.pop();
- AssignmentExprent arrassign = new AssignmentExprent(new ArrayExprent(arr_store, index_store, arrtypes[instr.opcode - opc_iastore]), value);
- exprlist.add(arrassign);
- break;
- case opc_iadd:
- case opc_ladd:
- case opc_fadd:
- case opc_dadd:
- case opc_isub:
- case opc_lsub:
- case opc_fsub:
- case opc_dsub:
- case opc_imul:
- case opc_lmul:
- case opc_fmul:
- case opc_dmul:
- case opc_idiv:
- case opc_ldiv:
- case opc_fdiv:
- case opc_ddiv:
- case opc_irem:
- case opc_lrem:
- case opc_frem:
- case opc_drem:
- pushEx(stack, exprlist, new FunctionExprent(func1[(instr.opcode - opc_iadd) / 4], stack));
- break;
- case opc_ishl:
- case opc_lshl:
- case opc_ishr:
- case opc_lshr:
- case opc_iushr:
- case opc_lushr:
- case opc_iand:
- case opc_land:
- case opc_ior:
- case opc_lor:
- case opc_ixor:
- case opc_lxor:
- pushEx(stack, exprlist, new FunctionExprent(func2[(instr.opcode - opc_ishl) / 2], stack));
- break;
- case opc_ineg:
- case opc_lneg:
- case opc_fneg:
- case opc_dneg:
- pushEx(stack, exprlist, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack));
- break;
- case opc_iinc:
- VarExprent vevar = new VarExprent(instr.getOperand(0), VarType.VARTYPE_INT, varProcessor);
- exprlist.add(new AssignmentExprent(vevar, new FunctionExprent(instr.getOperand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD, Arrays
- .asList(new Exprent[] { vevar.copy(), new ConstExprent(VarType.VARTYPE_INT, new Integer(Math.abs(instr.getOperand(1)))) }))));
- break;
- case opc_i2l:
- case opc_i2f:
- case opc_i2d:
- case opc_l2i:
- case opc_l2f:
- case opc_l2d:
- case opc_f2i:
- case opc_f2l:
- case opc_f2d:
- case opc_d2i:
- case opc_d2l:
- case opc_d2f:
- case opc_i2b:
- case opc_i2c:
- case opc_i2s:
- pushEx(stack, exprlist, new FunctionExprent(func3[instr.opcode - opc_i2l], stack));
- break;
- case opc_lcmp:
- case opc_fcmpl:
- case opc_fcmpg:
- case opc_dcmpl:
- case opc_dcmpg:
- pushEx(stack, exprlist, new FunctionExprent(func4[instr.opcode - opc_lcmp], stack));
- break;
- case opc_ifeq:
- case opc_ifne:
- case opc_iflt:
- case opc_ifge:
- case opc_ifgt:
- case opc_ifle:
- exprlist.add(new IfExprent(negifs[func5[instr.opcode - opc_ifeq]], stack));
- break;
- case opc_if_icmpeq:
- case opc_if_icmpne:
- case opc_if_icmplt:
- case opc_if_icmpge:
- case opc_if_icmpgt:
- case opc_if_icmple:
- case opc_if_acmpeq:
- case opc_if_acmpne:
- exprlist.add(new IfExprent(negifs[func6[instr.opcode - opc_if_icmpeq]], stack));
- break;
- case opc_ifnull:
- case opc_ifnonnull:
- exprlist.add(new IfExprent(negifs[func7[instr.opcode - opc_ifnull]], stack));
- break;
- case opc_tableswitch:
- case opc_lookupswitch:
- exprlist.add(new SwitchExprent(stack.pop()));
- break;
- case opc_ireturn:
- case opc_lreturn:
- case opc_freturn:
- case opc_dreturn:
- case opc_areturn:
- case opc_return:
- case opc_athrow:
- exprlist.add(new ExitExprent(instr.opcode == opc_athrow ? ExitExprent.EXIT_THROW : ExitExprent.EXIT_RETURN, instr.opcode == opc_return ? null : stack.pop(),
- instr.opcode == opc_athrow ? null : ((MethodDescriptor) DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR)).ret));
- break;
- case opc_monitorenter:
- case opc_monitorexit:
- exprlist.add(new MonitorExprent(func8[instr.opcode - opc_monitorenter], stack.pop()));
- break;
- case opc_checkcast:
- case opc_instanceof:
- stack.push(new ConstExprent(new VarType(pool.getPrimitiveConstant(instr.getOperand(0)).getString(), true), null));
- case opc_arraylength:
- pushEx(stack, exprlist, new FunctionExprent(mapConsts.get(instr.opcode).intValue(), stack));
- break;
- case opc_getstatic:
- case opc_getfield:
- pushEx(stack, exprlist, new FieldExprent(pool.getLinkConstant(instr.getOperand(0)), instr.opcode == opc_getstatic ? null : stack.pop()));
- break;
- case opc_putstatic:
- case opc_putfield:
- Exprent valfield = stack.pop();
- Exprent exprfield = new FieldExprent(pool.getLinkConstant(instr.getOperand(0)), instr.opcode == opc_putstatic ? null : stack.pop());
- exprlist.add(new AssignmentExprent(exprfield, valfield));
- break;
- case opc_invokevirtual:
- case opc_invokespecial:
- case opc_invokestatic:
- case opc_invokeinterface:
- case opc_invokedynamic:
- if(instr.opcode != opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
-
- LinkConstant invoke_constant = pool.getLinkConstant(instr.getOperand(0));
- int dynamic_invokation_type = -1;
-
- if(instr.opcode == opc_invokedynamic && bootstrap != null) {
- List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.index1);
- LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments.get(1);
-
- dynamic_invokation_type = content_method_handle.index1;
- }
-
- InvocationExprent exprinv = new InvocationExprent(instr.opcode, invoke_constant, stack, dynamic_invokation_type);
- if (exprinv.getDescriptor().ret.type == CodeConstants.TYPE_VOID) {
- exprlist.add(exprinv);
- } else {
- pushEx(stack, exprlist, exprinv);
- }
- }
- break;
- case opc_new:
- case opc_anewarray:
- case opc_multianewarray:
- int arrdims = (instr.opcode == opc_new) ? 0 : (instr.opcode == opc_anewarray) ? 1 : instr.getOperand(1);
- VarType arrtype = new VarType(pool.getPrimitiveConstant(instr.getOperand(0)).getString(), true);
- if (instr.opcode != opc_multianewarray) {
- arrtype.arraydim += arrdims;
- }
- pushEx(stack, exprlist, new NewExprent(arrtype, stack, arrdims));
- break;
- case opc_newarray:
- pushEx(stack, exprlist, new NewExprent(new VarType(arr_type[instr.getOperand(0) - 4], 1), stack, 1));
- break;
- case opc_dup:
- pushEx(stack, exprlist, stack.getByOffset(-1).copy());
- break;
- case opc_dup_x1:
- insertByOffsetEx(-2, stack, exprlist, -1);
- break;
- case opc_dup_x2:
- if (stack.getByOffset(-2).getExprType().stack_size == 2) {
- insertByOffsetEx(-2, stack, exprlist, -1);
- } else {
- insertByOffsetEx(-3, stack, exprlist, -1);
- }
- break;
- case opc_dup2:
- if (stack.getByOffset(-1).getExprType().stack_size == 2) {
- pushEx(stack, exprlist, stack.getByOffset(-1).copy());
- } else {
- pushEx(stack, exprlist, stack.getByOffset(-2).copy());
- pushEx(stack, exprlist, stack.getByOffset(-2).copy());
- }
- break;
- case opc_dup2_x1:
- if (stack.getByOffset(-1).getExprType().stack_size == 2) {
- insertByOffsetEx(-2, stack, exprlist, -1);
- } else {
- insertByOffsetEx(-3, stack, exprlist, -2);
- insertByOffsetEx(-3, stack, exprlist, -1);
- }
- break;
- case opc_dup2_x2:
- if (stack.getByOffset(-1).getExprType().stack_size == 2) {
- if (stack.getByOffset(-2).getExprType().stack_size == 2) {
- insertByOffsetEx(-2, stack, exprlist, -1);
- } else {
- insertByOffsetEx(-3, stack, exprlist, -1);
- }
- } else {
- if (stack.getByOffset(-3).getExprType().stack_size == 2) {
- insertByOffsetEx(-3, stack, exprlist, -2);
- insertByOffsetEx(-3, stack, exprlist, -1);
- } else {
- insertByOffsetEx(-4, stack, exprlist, -2);
- insertByOffsetEx(-4, stack, exprlist, -1);
- }
- }
- break;
- case opc_swap:
- insertByOffsetEx(-2, stack, exprlist, -1);
- stack.pop();
- break;
- case opc_pop:
- case opc_pop2:
- stack.pop();
- }
-
- }
-
- }
-
- private void pushEx(ExprentStack stack, List<Exprent> exprlist, Exprent exprent) {
- pushEx(stack, exprlist, exprent, null);
- }
-
- private void pushEx(ExprentStack stack, List<Exprent> exprlist, Exprent exprent, VarType vartype) {
- int varindex = VarExprent.STACK_BASE + stack.size();
- VarExprent var = new VarExprent(varindex, vartype == null ? exprent.getExprType() : vartype, varProcessor);
- var.setStack(true);
-
- exprlist.add(new AssignmentExprent(var, exprent));
- stack.push(var.copy());
- }
-
- private void insertByOffsetEx(int offset, ExprentStack stack, List<Exprent> exprlist, int copyoffset) {
-
- int base = VarExprent.STACK_BASE + stack.size();
-
- LinkedList<VarExprent> lst = new LinkedList<VarExprent>();
-
- for (int i = -1; i >= offset; i--) {
- Exprent varex = stack.pop();
- VarExprent varnew = new VarExprent(base + i + 1, varex.getExprType(), varProcessor);
- varnew.setStack(true);
- exprlist.add(new AssignmentExprent(varnew, varex));
- lst.add(0, (VarExprent) varnew.copy());
- }
-
- Exprent exprent = lst.get(lst.size() + copyoffset).copy();
- VarExprent var = new VarExprent(base + offset, exprent.getExprType(), varProcessor);
- var.setStack(true);
- exprlist.add(new AssignmentExprent(var, exprent));
- lst.add(0, (VarExprent) var.copy());
-
- for (VarExprent expr : lst) {
- stack.push(expr);
- }
-
- }
-
- public static String getTypeName(VarType type) {
- return getTypeName(type, true);
- }
-
- public static String getTypeName(VarType type, boolean getShort) {
-
- int tp = type.type;
- if (tp <= CodeConstants.TYPE_BOOLEAN) {
- return typeNames[tp];
- } else if (tp == CodeConstants.TYPE_UNKNOWN) {
- return UNKNOWN_TYPE_STRING; // INFO: should not occur
- } else if (tp == CodeConstants.TYPE_NULL) {
- return NULL_TYPE_STRING; // INFO: should not occur
- } else if (tp == CodeConstants.TYPE_VOID) {
- return "void";
- } else if (tp == CodeConstants.TYPE_OBJECT) {
- String ret = ExprProcessor.buildJavaClassName(type.value);
- if (getShort) {
- ret = DecompilerContext.getImpcollector().getShortName(ret);
- }
-
- if (ret == null) {
- // FIXME: a warning should be logged
- ret = UNDEFINED_TYPE_STRING;
- }
- return ret;
- }
-
- throw new RuntimeException("invalid type");
- }
-
- public static String getCastTypeName(VarType type) {
- return getCastTypeName(type, true);
- }
-
- public static String getCastTypeName(VarType type, boolean getShort) {
- String s = getTypeName(type, getShort);
- int dim = type.arraydim;
- while (dim-- > 0) {
- s += "[]";
- }
- return s;
- }
-
- public static PrimitiveExprsList getExpressionData(VarExprent var) {
- PrimitiveExprsList prlst = new PrimitiveExprsList();
- VarExprent vartmp = new VarExprent(VarExprent.STACK_BASE, var.getExprType(), var.getProcessor());
- vartmp.setStack(true);
-
- prlst.getLstExprents().add(new AssignmentExprent(vartmp, var.copy()));
- prlst.getStack().push(vartmp.copy());
- return prlst;
- }
-
- public static boolean endsWithSemikolon(Exprent expr) {
- int type = expr.type;
- return !(type == Exprent.EXPRENT_SWITCH || type == Exprent.EXPRENT_MONITOR || type == Exprent.EXPRENT_IF || (type == Exprent.EXPRENT_VAR && ((VarExprent) expr)
- .isClassdef()));
- }
-
- public static String jmpWrapper(Statement stat, int indent, boolean semicolon) {
- StringBuffer buf = new StringBuffer(stat.toJava(indent));
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- List<StatEdge> lstSuccs = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
- if (lstSuccs.size() == 1) {
- StatEdge edge = lstSuccs.get(0);
- if (edge.getType() != StatEdge.TYPE_REGULAR && edge.explicit == true && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
- buf.append(InterpreterUtil.getIndentString(indent));
-
- switch (edge.getType()) {
- case StatEdge.TYPE_BREAK:
- buf.append("break");
- break;
- case StatEdge.TYPE_CONTINUE:
- buf.append("continue");
- }
-
- if (edge.labeled) {
- buf.append(" label" + edge.closure.id);
- }
- buf.append(";" + new_line_separator);
- }
- }
-
- if (buf.length() == 0 && semicolon) {
- buf.append(InterpreterUtil.getIndentString(indent) + ";" + new_line_separator);
- }
-
- return buf.toString();
- }
-
- public static String buildJavaClassName(String name) {
- String res = name.replace('/', '.');
-
- if (res.indexOf("$") >= 0) { // attempt to invoke foreign member
- // classes correctly
- StructClass cl = DecompilerContext.getStructcontext().getClass(name);
- if (cl == null || !cl.isOwn()) {
- res = res.replace('$', '.');
- }
- }
-
- return res;
- }
-
- public static String listToJava(List<Exprent> lst, int indent) {
+ for (Statement st : stat.getStats()) {
+ initStatementExprents(st);
+ }
+ }
+
+ public void processBlock(BasicBlockStatement stat, PrimitiveExprsList data, StructClass cl) {
+
+ ConstantPool pool = cl.getPool();
+ StructBootstrapMethodsAttribute bootstrap =
+ (StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
+
+ BasicBlock block = stat.getBlock();
+
+ ExprentStack stack = data.getStack();
+ List<Exprent> exprlist = data.getLstExprents();
+
+ InstructionSequence seq = block.getSeq();
+
+ for (int i = 0; i < seq.length(); i++) {
+
+ Instruction instr = seq.getInstr(i);
+
+ switch (instr.opcode) {
+ case opc_aconst_null:
+ pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_NULL, null));
+ break;
+ case opc_bipush:
+ case opc_sipush:
+ pushEx(stack, exprlist, new ConstExprent(instr.getOperand(0), true));
+ break;
+ case opc_lconst_0:
+ case opc_lconst_1:
+ pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_LONG, new Long(instr.opcode - opc_lconst_0)));
+ break;
+ case opc_fconst_0:
+ case opc_fconst_1:
+ case opc_fconst_2:
+ pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_FLOAT, new Float(instr.opcode - opc_fconst_0)));
+ break;
+ case opc_dconst_0:
+ case opc_dconst_1:
+ pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(instr.opcode - opc_dconst_0)));
+ break;
+ case opc_ldc:
+ case opc_ldc_w:
+ case opc_ldc2_w:
+ PrimitiveConstant cn = pool.getPrimitiveConstant(instr.getOperand(0));
+ pushEx(stack, exprlist, new ConstExprent(consts[cn.type - CONSTANT_Integer], cn.value));
+ break;
+ case opc_iload:
+ case opc_lload:
+ case opc_fload:
+ case opc_dload:
+ case opc_aload:
+ pushEx(stack, exprlist, new VarExprent(instr.getOperand(0), vartypes[instr.opcode - opc_iload], varProcessor));
+ break;
+ case opc_iaload:
+ case opc_laload:
+ case opc_faload:
+ case opc_daload:
+ case opc_aaload:
+ case opc_baload:
+ case opc_caload:
+ case opc_saload:
+ Exprent index = stack.pop();
+ Exprent arr = stack.pop();
+
+ VarType vartype = null;
+ switch (instr.opcode) {
+ case opc_laload:
+ vartype = VarType.VARTYPE_LONG;
+ break;
+ case opc_daload:
+ vartype = VarType.VARTYPE_DOUBLE;
+ }
+ pushEx(stack, exprlist, new ArrayExprent(arr, index, arrtypes[instr.opcode - opc_iaload]), vartype);
+ break;
+ case opc_istore:
+ case opc_lstore:
+ case opc_fstore:
+ case opc_dstore:
+ case opc_astore:
+ Exprent top = stack.pop();
+ int varindex = instr.getOperand(0);
+ AssignmentExprent assign =
+ new AssignmentExprent(new VarExprent(varindex, vartypes[instr.opcode - opc_istore], varProcessor), top);
+ exprlist.add(assign);
+ break;
+ case opc_iastore:
+ case opc_lastore:
+ case opc_fastore:
+ case opc_dastore:
+ case opc_aastore:
+ case opc_bastore:
+ case opc_castore:
+ case opc_sastore:
+ Exprent value = stack.pop();
+ Exprent index_store = stack.pop();
+ Exprent arr_store = stack.pop();
+ AssignmentExprent arrassign =
+ new AssignmentExprent(new ArrayExprent(arr_store, index_store, arrtypes[instr.opcode - opc_iastore]), value);
+ exprlist.add(arrassign);
+ break;
+ case opc_iadd:
+ case opc_ladd:
+ case opc_fadd:
+ case opc_dadd:
+ case opc_isub:
+ case opc_lsub:
+ case opc_fsub:
+ case opc_dsub:
+ case opc_imul:
+ case opc_lmul:
+ case opc_fmul:
+ case opc_dmul:
+ case opc_idiv:
+ case opc_ldiv:
+ case opc_fdiv:
+ case opc_ddiv:
+ case opc_irem:
+ case opc_lrem:
+ case opc_frem:
+ case opc_drem:
+ pushEx(stack, exprlist, new FunctionExprent(func1[(instr.opcode - opc_iadd) / 4], stack));
+ break;
+ case opc_ishl:
+ case opc_lshl:
+ case opc_ishr:
+ case opc_lshr:
+ case opc_iushr:
+ case opc_lushr:
+ case opc_iand:
+ case opc_land:
+ case opc_ior:
+ case opc_lor:
+ case opc_ixor:
+ case opc_lxor:
+ pushEx(stack, exprlist, new FunctionExprent(func2[(instr.opcode - opc_ishl) / 2], stack));
+ break;
+ case opc_ineg:
+ case opc_lneg:
+ case opc_fneg:
+ case opc_dneg:
+ pushEx(stack, exprlist, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack));
+ break;
+ case opc_iinc:
+ VarExprent vevar = new VarExprent(instr.getOperand(0), VarType.VARTYPE_INT, varProcessor);
+ exprlist.add(new AssignmentExprent(vevar, new FunctionExprent(
+ instr.getOperand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD, Arrays
+ .asList(new Exprent[]{vevar.copy(), new ConstExprent(VarType.VARTYPE_INT, new Integer(Math.abs(instr.getOperand(1))))}))));
+ break;
+ case opc_i2l:
+ case opc_i2f:
+ case opc_i2d:
+ case opc_l2i:
+ case opc_l2f:
+ case opc_l2d:
+ case opc_f2i:
+ case opc_f2l:
+ case opc_f2d:
+ case opc_d2i:
+ case opc_d2l:
+ case opc_d2f:
+ case opc_i2b:
+ case opc_i2c:
+ case opc_i2s:
+ pushEx(stack, exprlist, new FunctionExprent(func3[instr.opcode - opc_i2l], stack));
+ break;
+ case opc_lcmp:
+ case opc_fcmpl:
+ case opc_fcmpg:
+ case opc_dcmpl:
+ case opc_dcmpg:
+ pushEx(stack, exprlist, new FunctionExprent(func4[instr.opcode - opc_lcmp], stack));
+ break;
+ case opc_ifeq:
+ case opc_ifne:
+ case opc_iflt:
+ case opc_ifge:
+ case opc_ifgt:
+ case opc_ifle:
+ exprlist.add(new IfExprent(negifs[func5[instr.opcode - opc_ifeq]], stack));
+ break;
+ case opc_if_icmpeq:
+ case opc_if_icmpne:
+ case opc_if_icmplt:
+ case opc_if_icmpge:
+ case opc_if_icmpgt:
+ case opc_if_icmple:
+ case opc_if_acmpeq:
+ case opc_if_acmpne:
+ exprlist.add(new IfExprent(negifs[func6[instr.opcode - opc_if_icmpeq]], stack));
+ break;
+ case opc_ifnull:
+ case opc_ifnonnull:
+ exprlist.add(new IfExprent(negifs[func7[instr.opcode - opc_ifnull]], stack));
+ break;
+ case opc_tableswitch:
+ case opc_lookupswitch:
+ exprlist.add(new SwitchExprent(stack.pop()));
+ break;
+ case opc_ireturn:
+ case opc_lreturn:
+ case opc_freturn:
+ case opc_dreturn:
+ case opc_areturn:
+ case opc_return:
+ case opc_athrow:
+ exprlist.add(new ExitExprent(instr.opcode == opc_athrow ? ExitExprent.EXIT_THROW : ExitExprent.EXIT_RETURN,
+ instr.opcode == opc_return ? null : stack.pop(),
+ instr.opcode == opc_athrow
+ ? null
+ : ((MethodDescriptor)DecompilerContext
+ .getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR)).ret));
+ break;
+ case opc_monitorenter:
+ case opc_monitorexit:
+ exprlist.add(new MonitorExprent(func8[instr.opcode - opc_monitorenter], stack.pop()));
+ break;
+ case opc_checkcast:
+ case opc_instanceof:
+ stack.push(new ConstExprent(new VarType(pool.getPrimitiveConstant(instr.getOperand(0)).getString(), true), null));
+ case opc_arraylength:
+ pushEx(stack, exprlist, new FunctionExprent(mapConsts.get(instr.opcode).intValue(), stack));
+ break;
+ case opc_getstatic:
+ case opc_getfield:
+ pushEx(stack, exprlist,
+ new FieldExprent(pool.getLinkConstant(instr.getOperand(0)), instr.opcode == opc_getstatic ? null : stack.pop()));
+ break;
+ case opc_putstatic:
+ case opc_putfield:
+ Exprent valfield = stack.pop();
+ Exprent exprfield =
+ new FieldExprent(pool.getLinkConstant(instr.getOperand(0)), instr.opcode == opc_putstatic ? null : stack.pop());
+ exprlist.add(new AssignmentExprent(exprfield, valfield));
+ break;
+ case opc_invokevirtual:
+ case opc_invokespecial:
+ case opc_invokestatic:
+ case opc_invokeinterface:
+ case opc_invokedynamic:
+ if (instr.opcode != opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
+
+ LinkConstant invoke_constant = pool.getLinkConstant(instr.getOperand(0));
+ int dynamic_invokation_type = -1;
+
+ if (instr.opcode == opc_invokedynamic && bootstrap != null) {
+ List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.index1);
+ LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments.get(1);
+
+ dynamic_invokation_type = content_method_handle.index1;
+ }
+
+ InvocationExprent exprinv = new InvocationExprent(instr.opcode, invoke_constant, stack, dynamic_invokation_type);
+ if (exprinv.getDescriptor().ret.type == CodeConstants.TYPE_VOID) {
+ exprlist.add(exprinv);
+ }
+ else {
+ pushEx(stack, exprlist, exprinv);
+ }
+ }
+ break;
+ case opc_new:
+ case opc_anewarray:
+ case opc_multianewarray:
+ int arrdims = (instr.opcode == opc_new) ? 0 : (instr.opcode == opc_anewarray) ? 1 : instr.getOperand(1);
+ VarType arrtype = new VarType(pool.getPrimitiveConstant(instr.getOperand(0)).getString(), true);
+ if (instr.opcode != opc_multianewarray) {
+ arrtype.arraydim += arrdims;
+ }
+ pushEx(stack, exprlist, new NewExprent(arrtype, stack, arrdims));
+ break;
+ case opc_newarray:
+ pushEx(stack, exprlist, new NewExprent(new VarType(arr_type[instr.getOperand(0) - 4], 1), stack, 1));
+ break;
+ case opc_dup:
+ pushEx(stack, exprlist, stack.getByOffset(-1).copy());
+ break;
+ case opc_dup_x1:
+ insertByOffsetEx(-2, stack, exprlist, -1);
+ break;
+ case opc_dup_x2:
+ if (stack.getByOffset(-2).getExprType().stack_size == 2) {
+ insertByOffsetEx(-2, stack, exprlist, -1);
+ }
+ else {
+ insertByOffsetEx(-3, stack, exprlist, -1);
+ }
+ break;
+ case opc_dup2:
+ if (stack.getByOffset(-1).getExprType().stack_size == 2) {
+ pushEx(stack, exprlist, stack.getByOffset(-1).copy());
+ }
+ else {
+ pushEx(stack, exprlist, stack.getByOffset(-2).copy());
+ pushEx(stack, exprlist, stack.getByOffset(-2).copy());
+ }
+ break;
+ case opc_dup2_x1:
+ if (stack.getByOffset(-1).getExprType().stack_size == 2) {
+ insertByOffsetEx(-2, stack, exprlist, -1);
+ }
+ else {
+ insertByOffsetEx(-3, stack, exprlist, -2);
+ insertByOffsetEx(-3, stack, exprlist, -1);
+ }
+ break;
+ case opc_dup2_x2:
+ if (stack.getByOffset(-1).getExprType().stack_size == 2) {
+ if (stack.getByOffset(-2).getExprType().stack_size == 2) {
+ insertByOffsetEx(-2, stack, exprlist, -1);
+ }
+ else {
+ insertByOffsetEx(-3, stack, exprlist, -1);
+ }
+ }
+ else {
+ if (stack.getByOffset(-3).getExprType().stack_size == 2) {
+ insertByOffsetEx(-3, stack, exprlist, -2);
+ insertByOffsetEx(-3, stack, exprlist, -1);
+ }
+ else {
+ insertByOffsetEx(-4, stack, exprlist, -2);
+ insertByOffsetEx(-4, stack, exprlist, -1);
+ }
+ }
+ break;
+ case opc_swap:
+ insertByOffsetEx(-2, stack, exprlist, -1);
+ stack.pop();
+ break;
+ case opc_pop:
+ case opc_pop2:
+ stack.pop();
+ }
+ }
+ }
+
+ private void pushEx(ExprentStack stack, List<Exprent> exprlist, Exprent exprent) {
+ pushEx(stack, exprlist, exprent, null);
+ }
+
+ private void pushEx(ExprentStack stack, List<Exprent> exprlist, Exprent exprent, VarType vartype) {
+ int varindex = VarExprent.STACK_BASE + stack.size();
+ VarExprent var = new VarExprent(varindex, vartype == null ? exprent.getExprType() : vartype, varProcessor);
+ var.setStack(true);
+
+ exprlist.add(new AssignmentExprent(var, exprent));
+ stack.push(var.copy());
+ }
+
+ private void insertByOffsetEx(int offset, ExprentStack stack, List<Exprent> exprlist, int copyoffset) {
+
+ int base = VarExprent.STACK_BASE + stack.size();
+
+ LinkedList<VarExprent> lst = new LinkedList<VarExprent>();
+
+ for (int i = -1; i >= offset; i--) {
+ Exprent varex = stack.pop();
+ VarExprent varnew = new VarExprent(base + i + 1, varex.getExprType(), varProcessor);
+ varnew.setStack(true);
+ exprlist.add(new AssignmentExprent(varnew, varex));
+ lst.add(0, (VarExprent)varnew.copy());
+ }
+
+ Exprent exprent = lst.get(lst.size() + copyoffset).copy();
+ VarExprent var = new VarExprent(base + offset, exprent.getExprType(), varProcessor);
+ var.setStack(true);
+ exprlist.add(new AssignmentExprent(var, exprent));
+ lst.add(0, (VarExprent)var.copy());
+
+ for (VarExprent expr : lst) {
+ stack.push(expr);
+ }
+ }
+
+ public static String getTypeName(VarType type) {
+ return getTypeName(type, true);
+ }
+
+ public static String getTypeName(VarType type, boolean getShort) {
+
+ int tp = type.type;
+ if (tp <= CodeConstants.TYPE_BOOLEAN) {
+ return typeNames[tp];
+ }
+ else if (tp == CodeConstants.TYPE_UNKNOWN) {
+ return UNKNOWN_TYPE_STRING; // INFO: should not occur
+ }
+ else if (tp == CodeConstants.TYPE_NULL) {
+ return NULL_TYPE_STRING; // INFO: should not occur
+ }
+ else if (tp == CodeConstants.TYPE_VOID) {
+ return "void";
+ }
+ else if (tp == CodeConstants.TYPE_OBJECT) {
+ String ret = ExprProcessor.buildJavaClassName(type.value);
+ if (getShort) {
+ ret = DecompilerContext.getImpcollector().getShortName(ret);
+ }
+
+ if (ret == null) {
+ // FIXME: a warning should be logged
+ ret = UNDEFINED_TYPE_STRING;
+ }
+ return ret;
+ }
+
+ throw new RuntimeException("invalid type");
+ }
+
+ public static String getCastTypeName(VarType type) {
+ return getCastTypeName(type, true);
+ }
+
+ public static String getCastTypeName(VarType type, boolean getShort) {
+ String s = getTypeName(type, getShort);
+ int dim = type.arraydim;
+ while (dim-- > 0) {
+ s += "[]";
+ }
+ return s;
+ }
+
+ public static PrimitiveExprsList getExpressionData(VarExprent var) {
+ PrimitiveExprsList prlst = new PrimitiveExprsList();
+ VarExprent vartmp = new VarExprent(VarExprent.STACK_BASE, var.getExprType(), var.getProcessor());
+ vartmp.setStack(true);
+
+ prlst.getLstExprents().add(new AssignmentExprent(vartmp, var.copy()));
+ prlst.getStack().push(vartmp.copy());
+ return prlst;
+ }
+
+ public static boolean endsWithSemikolon(Exprent expr) {
+ int type = expr.type;
+ return !(type == Exprent.EXPRENT_SWITCH ||
+ type == Exprent.EXPRENT_MONITOR ||
+ type == Exprent.EXPRENT_IF ||
+ (type == Exprent.EXPRENT_VAR && ((VarExprent)expr)
+ .isClassdef()));
+ }
+
+ public static String jmpWrapper(Statement stat, int indent, boolean semicolon) {
+ StringBuffer buf = new StringBuffer(stat.toJava(indent));
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ List<StatEdge> lstSuccs = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
+ if (lstSuccs.size() == 1) {
+ StatEdge edge = lstSuccs.get(0);
+ if (edge.getType() != StatEdge.TYPE_REGULAR && edge.explicit == true && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
+ buf.append(InterpreterUtil.getIndentString(indent));
+
+ switch (edge.getType()) {
+ case StatEdge.TYPE_BREAK:
+ buf.append("break");
+ break;
+ case StatEdge.TYPE_CONTINUE:
+ buf.append("continue");
+ }
+
+ if (edge.labeled) {
+ buf.append(" label" + edge.closure.id);
+ }
+ buf.append(";" + new_line_separator);
+ }
+ }
+
+ if (buf.length() == 0 && semicolon) {
+ buf.append(InterpreterUtil.getIndentString(indent) + ";" + new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public static String buildJavaClassName(String name) {
+ String res = name.replace('/', '.');
+
+ if (res.indexOf("$") >= 0) { // attempt to invoke foreign member
+ // classes correctly
+ StructClass cl = DecompilerContext.getStructcontext().getClass(name);
+ if (cl == null || !cl.isOwn()) {
+ res = res.replace('$', '.');
+ }
+ }
+
+ return res;
+ }
+
+ public static String listToJava(List<Exprent> lst, int indent) {
if (lst == null || lst.isEmpty()) {
return "";
}
- String indstr = InterpreterUtil.getIndentString(indent);
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- StringBuffer buf = new StringBuffer();
-
- for (Exprent expr : lst) {
- String content = expr.toJava(indent);
- if (content.length() > 0) {
- if (expr.type != Exprent.EXPRENT_VAR || !((VarExprent) expr).isClassdef()) {
- buf.append(indstr);
- }
- buf.append(content);
- if (expr.type == Exprent.EXPRENT_MONITOR && ((MonitorExprent) expr).getMontype() == MonitorExprent.MONITOR_ENTER) {
- buf.append("{}"); // empty synchronized block
- }
- if (ExprProcessor.endsWithSemikolon(expr)) {
- buf.append(";");
- }
- buf.append(new_line_separator);
- }
- }
-
- return buf.toString();
- }
-
- public static ConstExprent getDefaultArrayValue(VarType arrtype) {
-
- ConstExprent defaultval;
- if (arrtype.type == CodeConstants.TYPE_OBJECT || arrtype.arraydim > 0) {
- defaultval = new ConstExprent(VarType.VARTYPE_NULL, null);
- } else if (arrtype.type == CodeConstants.TYPE_FLOAT) {
- defaultval = new ConstExprent(VarType.VARTYPE_FLOAT, new Float(0));
- } else if (arrtype.type == CodeConstants.TYPE_LONG) {
- defaultval = new ConstExprent(VarType.VARTYPE_LONG, new Long(0));
- } else if (arrtype.type == CodeConstants.TYPE_DOUBLE) {
- defaultval = new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(0));
- } else { // integer types
- defaultval = new ConstExprent(0, true);
- }
-
- return defaultval;
- }
-
- public static boolean getCastedExprent(Exprent exprent, VarType leftType, StringBuilder buffer, int indent, boolean castNull) {
- return getCastedExprent(exprent, leftType, buffer, indent, castNull, false);
- }
-
- public static boolean getCastedExprent(Exprent exprent, VarType leftType, StringBuilder buffer, int indent, boolean castNull, boolean castAlways) {
-
- boolean ret = false;
- VarType rightType = exprent.getExprType();
-
- String res = exprent.toJava(indent);
-
- boolean cast = !leftType.isSuperset(rightType) && (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT);
- cast |= castAlways;
-
- if (!cast && castNull && rightType.type == CodeConstants.TYPE_NULL) {
- // check for a nameless anonymous class
- cast = !UNDEFINED_TYPE_STRING.equals(getTypeName(leftType));
- }
- if (!cast) {
- cast = isIntConstant(exprent) && VarType.VARTYPE_INT.isStrictSuperset(leftType);
- }
-
- if (cast) {
- if (exprent.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
- res = "(" + res + ")";
- }
-
- res = "(" + ExprProcessor.getCastTypeName(leftType) + ")" + res;
- ret = true;
- }
-
- buffer.append(res);
-
- return ret;
- }
-
- private static boolean isIntConstant(Exprent exprent) {
-
- if (exprent.type == Exprent.EXPRENT_CONST) {
- ConstExprent cexpr = (ConstExprent) exprent;
- switch (cexpr.getConsttype().type) {
- case CodeConstants.TYPE_BYTE:
- case CodeConstants.TYPE_BYTECHAR:
- case CodeConstants.TYPE_SHORT:
- case CodeConstants.TYPE_SHORTCHAR:
- case CodeConstants.TYPE_INT:
- return true;
- }
- }
-
- return false;
- }
+ String indstr = InterpreterUtil.getIndentString(indent);
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuffer buf = new StringBuffer();
+
+ for (Exprent expr : lst) {
+ String content = expr.toJava(indent);
+ if (content.length() > 0) {
+ if (expr.type != Exprent.EXPRENT_VAR || !((VarExprent)expr).isClassdef()) {
+ buf.append(indstr);
+ }
+ buf.append(content);
+ if (expr.type == Exprent.EXPRENT_MONITOR && ((MonitorExprent)expr).getMontype() == MonitorExprent.MONITOR_ENTER) {
+ buf.append("{}"); // empty synchronized block
+ }
+ if (ExprProcessor.endsWithSemikolon(expr)) {
+ buf.append(";");
+ }
+ buf.append(new_line_separator);
+ }
+ }
+
+ return buf.toString();
+ }
+
+ public static ConstExprent getDefaultArrayValue(VarType arrtype) {
+
+ ConstExprent defaultval;
+ if (arrtype.type == CodeConstants.TYPE_OBJECT || arrtype.arraydim > 0) {
+ defaultval = new ConstExprent(VarType.VARTYPE_NULL, null);
+ }
+ else if (arrtype.type == CodeConstants.TYPE_FLOAT) {
+ defaultval = new ConstExprent(VarType.VARTYPE_FLOAT, new Float(0));
+ }
+ else if (arrtype.type == CodeConstants.TYPE_LONG) {
+ defaultval = new ConstExprent(VarType.VARTYPE_LONG, new Long(0));
+ }
+ else if (arrtype.type == CodeConstants.TYPE_DOUBLE) {
+ defaultval = new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(0));
+ }
+ else { // integer types
+ defaultval = new ConstExprent(0, true);
+ }
+
+ return defaultval;
+ }
+
+ public static boolean getCastedExprent(Exprent exprent, VarType leftType, StringBuilder buffer, int indent, boolean castNull) {
+ return getCastedExprent(exprent, leftType, buffer, indent, castNull, false);
+ }
+
+ public static boolean getCastedExprent(Exprent exprent,
+ VarType leftType,
+ StringBuilder buffer,
+ int indent,
+ boolean castNull,
+ boolean castAlways) {
+
+ boolean ret = false;
+ VarType rightType = exprent.getExprType();
+
+ String res = exprent.toJava(indent);
+
+ boolean cast =
+ !leftType.isSuperset(rightType) && (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT);
+ cast |= castAlways;
+
+ if (!cast && castNull && rightType.type == CodeConstants.TYPE_NULL) {
+ // check for a nameless anonymous class
+ cast = !UNDEFINED_TYPE_STRING.equals(getTypeName(leftType));
+ }
+ if (!cast) {
+ cast = isIntConstant(exprent) && VarType.VARTYPE_INT.isStrictSuperset(leftType);
+ }
+
+ if (cast) {
+ if (exprent.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
+ res = "(" + res + ")";
+ }
+
+ res = "(" + ExprProcessor.getCastTypeName(leftType) + ")" + res;
+ ret = true;
+ }
+
+ buffer.append(res);
+
+ return ret;
+ }
+
+ private static boolean isIntConstant(Exprent exprent) {
+
+ if (exprent.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cexpr = (ConstExprent)exprent;
+ switch (cexpr.getConsttype().type) {
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_BYTECHAR:
+ case CodeConstants.TYPE_SHORT:
+ case CodeConstants.TYPE_SHORTCHAR:
+ case CodeConstants.TYPE_INT:
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprentStack.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprentStack.java
index 468dc41..dafc655 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprentStack.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprentStack.java
@@ -1,46 +1,47 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.util.ListStack;
public class ExprentStack extends ListStack<Exprent> {
-
- public ExprentStack() {}
-
- public ExprentStack(ListStack<Exprent> list) {
- super(list);
- pointer = list.getPointer();
- }
-
- public Exprent push(Exprent item) {
- super.push(item);
-
- return item;
- }
-
- public Exprent pop() {
-
- Exprent o = this.remove(--pointer);
-
- return o;
- }
-
- public ExprentStack clone() {
- return new ExprentStack(this);
- }
-
+
+ public ExprentStack() {
+ }
+
+ public ExprentStack(ListStack<Exprent> list) {
+ super(list);
+ pointer = list.getPointer();
+ }
+
+ public Exprent push(Exprent item) {
+ super.push(item);
+
+ return item;
+ }
+
+ public Exprent pop() {
+
+ Exprent o = this.remove(--pointer);
+
+ return o;
+ }
+
+ public ExprentStack clone() {
+ return new ExprentStack(this);
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java
index 3631090..a56c0f2 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java
@@ -1,31 +1,21 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map.Entry;
-
-import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.code.ConstantsUtil;
-import org.jetbrains.java.decompiler.code.Instruction;
-import org.jetbrains.java.decompiler.code.InstructionSequence;
-import org.jetbrains.java.decompiler.code.SimpleInstructionSequence;
+import org.jetbrains.java.decompiler.code.*;
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
@@ -51,981 +41,1028 @@ import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.*;
+import java.util.Map.Entry;
+
public class FinallyProcessor {
-
-
- private HashMap<Integer, Integer> finallyBlockIDs = new HashMap<Integer, Integer>();
- private HashMap<Integer, Integer> catchallBlockIDs = new HashMap<Integer, Integer>();
-
- private VarProcessor varprocessor;
-
- public FinallyProcessor(VarProcessor varprocessor) {
- this.varprocessor = varprocessor;
- }
-
- public boolean iterateGraph(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
-// return processStatement(mt, root, graph, root);
- return processStatementEx(mt, root, graph);
- }
-
- private boolean processStatementEx(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
-
- int bytecode_version = mt.getClassStruct().getBytecodeVersion();
-
- LinkedList<Statement> stack = new LinkedList<Statement>();
- stack.add(root);
-
- while(!stack.isEmpty()) {
-
- Statement stat = stack.removeLast();
-
- Statement parent = stat.getParent();
- if(parent != null && parent.type == Statement.TYPE_CATCHALL &&
- stat == parent.getFirst() && !parent.isCopied()) {
-
- CatchAllStatement fin = (CatchAllStatement)parent;
- BasicBlock head = fin.getBasichead().getBlock();
- BasicBlock handler = fin.getHandler().getBasichead().getBlock();
-
- if(catchallBlockIDs.containsKey(handler.id)) {
- ; // do nothing
- }else if(finallyBlockIDs.containsKey(handler.id)) {
-
- fin.setFinally(true);
-
- Integer var = finallyBlockIDs.get(handler.id);
- fin.setMonitor(var==null?null:new VarExprent(var.intValue(), VarType.VARTYPE_INT, varprocessor));
-
- } else {
-
- Object[] inf = getFinallyInformation(mt, root, fin);
-
- if(inf == null) { // inconsistent finally
- catchallBlockIDs.put(handler.id, null);
- } else {
-
- if(DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && verifyFinallyEx(graph, fin, inf)) {
- finallyBlockIDs.put(handler.id, null);
- } else {
-
- int varindex = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
- insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf, bytecode_version);
-
- finallyBlockIDs.put(handler.id, varindex);
- }
-
- DeadCodeHelper.removeDeadBlocks(graph); // e.g. multiple return blocks after a nested finally
- DeadCodeHelper.removeEmptyBlocks(graph);
- DeadCodeHelper.mergeBasicBlocks(graph);
- }
-
- return true;
- }
- }
-
- stack.addAll(stat.getStats());
- }
-
- return false;
- }
-
-
-
-// private boolean processStatement(StructMethod mt, RootStatement root, ControlFlowGraph graph, Statement stat) {
-//
-// boolean res = false;
-//
-// for(int i=stat.getStats().size()-1;i>=0;i--) {
-// if(processStatement(mt, root, graph, stat.getStats().get(i))) {
-// return true;
-// }
-// }
-//
-//
-// if(stat.type == Statement.TYPE_CATCHALL && !stat.isCopied()) {
-//
-// CatchAllStatement fin = (CatchAllStatement)stat;
-// BasicBlock head = fin.getBasichead().getBlock();
-// BasicBlock handler = fin.getHandler().getBasichead().getBlock();
-//
-// if(catchallBlockIDs.containsKey(handler.id)) {
-// ; // do nothing
-// }else if(finallyBlockIDs.containsKey(handler.id)) {
-//
-// fin.setFinally(true);
-//
-// Integer var = finallyBlockIDs.get(handler.id);
-// fin.setMonitor(var==null?null:new VarExprent(var.intValue(), VarType.VARTYPE_INT, varprocessor));
-//
-// } else {
-//
-// Object[] inf = getFinallyInformation(mt, root, fin);
-//
-// if(inf == null) { // inconsistent finally
-// catchallBlockIDs.put(handler.id, null);
-// } else {
-//
-// if(DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && verifyFinallyEx(graph, fin, inf)) {
-// finallyBlockIDs.put(handler.id, null);
-// } else {
-//
-// int varindex = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
-// insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf);
-//
-// finallyBlockIDs.put(handler.id, varindex);
-// }
-//
-// DeadCodeHelper.removeEmptyBlocks(graph);
-// DeadCodeHelper.mergeBasicBlocks(graph);
-// }
-//
-// res = true;
-// }
-// }
-//
-// return res;
-// }
-
-
- private Object[] getFinallyInformation(StructMethod mt, RootStatement root, CatchAllStatement fstat) {
-
- HashMap<BasicBlock, Boolean> mapLast = new HashMap<BasicBlock, Boolean>();
-
- BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead();
- BasicBlock firstBasicBlock = firstBlockStatement.getBlock();
- Instruction instrFirst = firstBasicBlock.getInstruction(0);
-
- int firstcode = 0;
-
- switch(instrFirst.opcode) {
- case CodeConstants.opc_pop:
- firstcode = 1;
- break;
- case CodeConstants.opc_astore:
- firstcode = 2;
- }
-
- ExprProcessor proc = new ExprProcessor();
- proc.processStatement(root, mt.getClassStruct());
-
- SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
- ssa.splitVariables(root, mt);
-
- List<Exprent> lstExprents = firstBlockStatement.getExprents();
-
- VarVersionPaar varpaar = new VarVersionPaar((VarExprent)((AssignmentExprent)lstExprents.get(firstcode==2?1:0)).getLeft());
-
- FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
- DirectGraph dgraph = flatthelper.buildDirectGraph(root);
-
- LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
- stack.add(dgraph.first);
-
- HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
-
- while(!stack.isEmpty()) {
-
- DirectNode node = stack.removeFirst();
-
- if(setVisited.contains(node)) {
- continue;
- }
- setVisited.add(node);
-
- BasicBlockStatement blockStatement = null;
- if(node.block != null) {
- blockStatement = node.block;
- } else if(node.preds.size() == 1) {
- blockStatement = node.preds.get(0).block;
- }
-
- boolean isTrueExit = true;
-
- if(firstcode != 1) {
-
- isTrueExit = false;
-
- for(int i=0;i<node.exprents.size();i++) {
- Exprent exprent = node.exprents.get(i);
-
- if(firstcode == 0) {
- List<Exprent> lst = exprent.getAllExprents();
- lst.add(exprent);
-
- boolean found = false;
- for(Exprent expr : lst) {
- if(expr.type == Exprent.EXPRENT_VAR && new VarVersionPaar((VarExprent)expr).equals(varpaar)) {
- found = true;
- break;
- }
- }
-
- if(found) {
- found = false;
- if(exprent.type == Exprent.EXPRENT_EXIT) {
- ExitExprent exexpr = (ExitExprent)exprent;
- if(exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_VAR) {
- found = true;
- }
- }
-
- if(!found) {
- return null;
- } else {
- isTrueExit = true;
- }
- }
- } else if(firstcode == 2) {
- // search for a load instruction
- if(exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent assexpr = (AssignmentExprent)exprent;
- if(assexpr.getRight().type == Exprent.EXPRENT_VAR &&
- new VarVersionPaar((VarExprent)assexpr.getRight()).equals(varpaar)) {
-
- Exprent next = null;
- if(i == node.exprents.size()-1) {
- if(node.succs.size() == 1) {
- DirectNode nd = node.succs.get(0);
- if(!nd.exprents.isEmpty()) {
- next = nd.exprents.get(0);
- }
- }
- } else {
- next = node.exprents.get(i+1);
- }
-
- boolean found = false;
- if(next != null && next.type == Exprent.EXPRENT_EXIT) {
- ExitExprent exexpr = (ExitExprent)next;
- if(exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_VAR
- && assexpr.getLeft().equals(exexpr.getValue())) {
- found = true;
- }
- }
-
- if(!found) {
- return null;
- } else {
- isTrueExit = true;
- }
- }
- }
- }
- }
- }
-
- // find finally exits
- if(blockStatement != null && blockStatement.getBlock() != null) {
- Statement handler = fstat.getHandler();
- for(StatEdge edge : blockStatement.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
- if(edge.getType() != StatEdge.TYPE_REGULAR && handler.containsStatement(blockStatement)
- && !handler.containsStatement(edge.getDestination())) {
- Boolean existingFlag = mapLast.get(blockStatement.getBlock());
- // note: the dummy node is also processed!
- if(existingFlag == null || !existingFlag) {
- mapLast.put(blockStatement.getBlock(), isTrueExit);
- break;
- }
- }
- }
- }
-
- stack.addAll(node.succs);
- }
-
- // empty finally block?
- if(fstat.getHandler().type == Statement.TYPE_BASICBLOCK) {
-
- boolean isEmpty = false;
- boolean isFirstLast = mapLast.containsKey(firstBasicBlock);
- InstructionSequence seq = firstBasicBlock.getSeq();
-
- switch(firstcode) {
- case 0:
- isEmpty = isFirstLast && seq.length() == 1;
- break;
- case 1:
- isEmpty = seq.length() == 1;
- break;
- case 2:
- isEmpty = isFirstLast?seq.length()==3:seq.length()==1;
- }
-
- if(isEmpty) {
- firstcode = 3;
- }
- }
-
- return new Object[] {firstcode, mapLast};
- }
-
- private void insertSemaphore(ControlFlowGraph graph, HashSet<BasicBlock> setTry, BasicBlock head, BasicBlock handler, int var, Object[] information, int bytecode_version) {
-
- HashSet<BasicBlock> setCopy = new HashSet<BasicBlock>(setTry);
-
- int finallytype = (Integer)information[0];
- HashMap<BasicBlock, Boolean> mapLast = (HashMap<BasicBlock, Boolean>)information[1];
-
- // first and last statements
- removeExceptionInstructionsEx(handler, 1, finallytype);
- for(Entry<BasicBlock, Boolean> entry : mapLast.entrySet()) {
- BasicBlock last = entry.getKey();
-
- if(entry.getValue()) {
- removeExceptionInstructionsEx(last, 2, finallytype);
- graph.getFinallyExits().add(last);
- }
- }
-
- // disable semaphore at statement exit points
- for(BasicBlock block: setTry) {
-
- List<BasicBlock> lstSucc = block.getSuccs();
- for(BasicBlock dest : lstSucc) {
-
- // break out
- if(!setCopy.contains(dest) && dest != graph.getLast()) {
- // disable semaphore
- SimpleInstructionSequence seq = new SimpleInstructionSequence();
-
- seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}) , -1);
- seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}) , -1);
-
- // build a separate block
- BasicBlock newblock = new BasicBlock(++graph.last_id);
- newblock.setSeq(seq);
-
- // insert between block and dest
- block.replaceSuccessor(dest, newblock);
- newblock.addSuccessor(dest);
- setCopy.add(newblock);
- graph.getBlocks().addWithKey(newblock, newblock.id);
-
- // exception ranges
- // FIXME: special case synchronized
-
- // copy exception edges and extend protected ranges
- for(int j=0;j<block.getSuccExceptions().size();j++) {
- BasicBlock hd = block.getSuccExceptions().get(j);
- newblock.addSuccessorException(hd);
-
- ExceptionRangeCFG range = graph.getExceptionRange(hd, block);
- range.getProtectedRange().add(newblock);
- }
- }
- }
- }
-
- // enable semaphor at the statement entrance
- SimpleInstructionSequence seq = new SimpleInstructionSequence();
- seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{1}) , -1);
- seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}) , -1);
-
- BasicBlock newhead = new BasicBlock(++graph.last_id);
- newhead.setSeq(seq);
-
- insertBlockBefore(graph, head, newhead);
-
- // initialize semaphor with false
- seq = new SimpleInstructionSequence();
- seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}) , -1);
- seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}) , -1);
-
- BasicBlock newheadinit = new BasicBlock(++graph.last_id);
- newheadinit.setSeq(seq);
-
- insertBlockBefore(graph, newhead, newheadinit);
-
- setCopy.add(newhead);
- setCopy.add(newheadinit);
-
- for(BasicBlock hd: new HashSet<BasicBlock>(newheadinit.getSuccExceptions())) {
- ExceptionRangeCFG range = graph.getExceptionRange(hd, newheadinit);
-
- if(setCopy.containsAll(range.getProtectedRange())) {
- newheadinit.removeSuccessorException(hd);
- range.getProtectedRange().remove(newheadinit);
- }
- }
-
- return;
- }
-
-
- private void insertBlockBefore(ControlFlowGraph graph, BasicBlock oldblock, BasicBlock newblock) {
-
- List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
- lstTemp.addAll(oldblock.getPreds());
- lstTemp.addAll(oldblock.getPredExceptions());
-
- // replace predecessors
- for(BasicBlock pred: lstTemp) {
- pred.replaceSuccessor(oldblock, newblock);
- }
-
- // copy exception edges and extend protected ranges
- for(BasicBlock hd: oldblock.getSuccExceptions()) {
- newblock.addSuccessorException(hd);
-
- ExceptionRangeCFG range = graph.getExceptionRange(hd, oldblock);
- range.getProtectedRange().add(newblock);
- }
-
- // replace handler
- for(ExceptionRangeCFG range: graph.getExceptions()) {
- if(range.getHandler() == oldblock) {
- range.setHandler(newblock);
- }
- }
-
- newblock.addSuccessor(oldblock);
- graph.getBlocks().addWithKey(newblock, newblock.id);
- if(graph.getFirst() == oldblock) {
- graph.setFirst(newblock);
- }
-
- }
-
- private HashSet<BasicBlock> getAllBasicBlocks(Statement stat) {
-
- List<Statement> lst = new LinkedList<Statement>();
- lst.add(stat);
-
- int index = 0;
- do {
- Statement st = lst.get(index);
-
- if(st.type == Statement.TYPE_BASICBLOCK) {
- index++;
- } else {
- lst.addAll(st.getStats());
- lst.remove(index);
- }
- } while(index<lst.size());
-
- HashSet<BasicBlock> res = new HashSet<BasicBlock>();
-
- for(Statement st: lst) {
- res.add(((BasicBlockStatement)st).getBlock());
- }
-
- return res;
- }
-
-
- private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, Object[] information) {
-
- HashSet<BasicBlock> tryBlocks = getAllBasicBlocks(fstat.getFirst());
- HashSet<BasicBlock> catchBlocks = getAllBasicBlocks(fstat.getHandler());
-
- int finallytype = (Integer)information[0];
- HashMap<BasicBlock, Boolean> mapLast = (HashMap<BasicBlock, Boolean>)information[1];
-
- BasicBlock first = fstat.getHandler().getBasichead().getBlock();
- boolean skippedFirst = false;
-
- if(finallytype == 3) {
- // empty finally
- removeExceptionInstructionsEx(first, 3, finallytype);
-
- if(mapLast.containsKey(first)) {
- graph.getFinallyExits().add(first);
- }
-
- return true;
- } else {
- if(first.getSeq().length() == 1 && finallytype>0) {
- BasicBlock firstsuc = first.getSuccs().get(0);
- if(catchBlocks.contains(firstsuc)) {
- first = firstsuc;
- skippedFirst = true;
- }
- }
- }
-
- // identify start blocks
- HashSet<BasicBlock> startBlocks = new HashSet<BasicBlock>();
- for(BasicBlock block: tryBlocks) {
- startBlocks.addAll(block.getSuccs());
- }
- // throw in the try body will point directly to the dummy exit
- // so remove dummy exit
- startBlocks.remove(graph.getLast());
- startBlocks.removeAll(tryBlocks);
-
- List<Object[]> lstAreas = new ArrayList<Object[]>();
-
- for(BasicBlock start: startBlocks) {
-
- Object[] arr = compareSubgraphsEx(graph, start, catchBlocks, first, finallytype, mapLast, skippedFirst);
- if(arr == null) {
- return false;
- }
-
- lstAreas.add(new Object[] {start, arr[0], arr[1]});
- }
-
-// try {
-// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
-// } catch(Exception ex){ex.printStackTrace();}
-
- // delete areas
- for(Object[] area: lstAreas) {
- deleteArea(graph, area);
- }
-
-// try {
-// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
-// } catch(Exception ex){ex.printStackTrace();}
-
- // INFO: empty basic blocks may remain in the graph!
- for(Entry<BasicBlock, Boolean> entry : mapLast.entrySet()) {
- BasicBlock last = entry.getKey();
-
- if(entry.getValue()) {
- removeExceptionInstructionsEx(last, 2, finallytype);
- graph.getFinallyExits().add(last);
- }
- }
-
- removeExceptionInstructionsEx(fstat.getHandler().getBasichead().getBlock(), 1, finallytype);
-
- return true;
- }
-
- private Object[] compareSubgraphsEx(ControlFlowGraph graph, BasicBlock startSample, HashSet<BasicBlock> catchBlocks, BasicBlock startCatch,
- int finallytype, HashMap<BasicBlock, Boolean> mapLast, boolean skippedFirst) {
-
- class BlockStackEntry {
- public BasicBlock blockCatch;
- public BasicBlock blockSample;
-
- // TODO: correct handling (merging) of multiple paths
- public List<int[]> lstStoreVars;
-
- public BlockStackEntry(BasicBlock blockCatch, BasicBlock blockSample, List<int[]> lstStoreVars) {
- this.blockCatch = blockCatch;
- this.blockSample = blockSample;
- this.lstStoreVars = new ArrayList<int[]>(lstStoreVars);
- }
- }
-
- List<BlockStackEntry> stack = new LinkedList<BlockStackEntry>();
-
- HashSet<BasicBlock> setSample = new HashSet<BasicBlock>();
-
- HashMap<String, BasicBlock[]> mapNext = new HashMap<String, BasicBlock[]>();
-
- stack.add(new BlockStackEntry(startCatch, startSample, new ArrayList<int[]>()));
-
- while(!stack.isEmpty()) {
-
- BlockStackEntry entry = stack.remove(0);
- BasicBlock blockCatch = entry.blockCatch;
- BasicBlock blockSample = entry.blockSample;
-
- boolean isFirstBlock = !skippedFirst && blockCatch == startCatch;
- boolean isLastBlock = mapLast.containsKey(blockCatch);
- boolean isTrueLastBlock = isLastBlock && mapLast.get(blockCatch);
-
- if(!compareBasicBlocksEx(graph, blockCatch, blockSample, (isFirstBlock?1:0) | (isTrueLastBlock?2:0), finallytype, entry.lstStoreVars)) {
- return null;
- }
-
- if(blockSample.getSuccs().size() != blockCatch.getSuccs().size()) {
- return null;
- }
-
- setSample.add(blockSample);
-
- // direct successors
- for(int i=0;i<blockCatch.getSuccs().size();i++) {
- BasicBlock sucCatch = blockCatch.getSuccs().get(i);
- BasicBlock sucSample = blockSample.getSuccs().get(i);
-
- if(catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) {
- stack.add(new BlockStackEntry(sucCatch, sucSample, entry.lstStoreVars));
- }
- }
-
-
- // exception successors
- if(isLastBlock && blockSample.getSeq().isEmpty()) {
- ; // do nothing, blockSample will be removed anyway
- } else {
- if(blockCatch.getSuccExceptions().size() == blockSample.getSuccExceptions().size()) {
- for(int i=0;i<blockCatch.getSuccExceptions().size();i++) {
- BasicBlock sucCatch = blockCatch.getSuccExceptions().get(i);
- BasicBlock sucSample = blockSample.getSuccExceptions().get(i);
-
- String excCatch = graph.getExceptionRange(sucCatch, blockCatch).getUniqueExceptionsString();
- String excSample = graph.getExceptionRange(sucSample, blockSample).getUniqueExceptionsString();
-
- // FIXME: compare handlers if possible
- boolean equalexc = excCatch == null?excSample == null:excCatch.equals(excSample);
-
- if(equalexc) {
- if(catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) {
-
- List<int[]> lst = entry.lstStoreVars;
-
- if(sucCatch.getSeq().length() > 0 && sucSample.getSeq().length() > 0) {
- Instruction instrCatch = sucCatch.getSeq().getInstr(0);
- Instruction instrSample = sucSample.getSeq().getInstr(0);
-
- if(instrCatch.opcode == CodeConstants.opc_astore &&
- instrSample.opcode == CodeConstants.opc_astore) {
- lst = new ArrayList<int[]>(lst);
- lst.add(new int[]{instrCatch.getOperand(0), instrSample.getOperand(0)});
- }
- }
-
- stack.add(new BlockStackEntry(sucCatch, sucSample, lst));
- }
- } else {
- return null;
- }
- }
- } else {
- return null;
- }
- }
-
- if(isLastBlock) {
- HashSet<BasicBlock> setSuccs = new HashSet<BasicBlock>(blockSample.getSuccs());
- setSuccs.removeAll(setSample);
-
- for(BlockStackEntry stackent : stack) {
- setSuccs.remove(stackent.blockSample);
- }
-
- for(BasicBlock succ : setSuccs) {
- if(graph.getLast() != succ) { // FIXME: why?
- mapNext.put(blockSample.id+"#"+succ.id, new BasicBlock[] {blockSample, succ, isTrueLastBlock?succ:null});
- }
- }
- }
- }
-
- return new Object[]{setSample, getUniqueNext(graph, new HashSet<BasicBlock[]>(mapNext.values()))};
- }
-
- private BasicBlock getUniqueNext(ControlFlowGraph graph, HashSet<BasicBlock[]> setNext) {
-
- // precondition: there is at most one true exit path in a finally statement
-
- BasicBlock next = null;
- boolean multiple = false;
-
- for(BasicBlock[] arr : setNext) {
-
- if(arr[2] != null) {
- next = arr[1];
- multiple = false;
- break;
- } else {
- if(next == null) {
- next = arr[1];
- } else if(next != arr[1]) {
- multiple = true;
- }
-
- if(arr[1].getPreds().size() == 1) {
- next = arr[1];
- }
- }
- }
-
- if(multiple) { // TODO: generic solution
- for(BasicBlock[] arr : setNext) {
- BasicBlock block = arr[1];
-
- if(block != next) {
- if(InterpreterUtil.equalSets(next.getSuccs(), block.getSuccs())) {
- InstructionSequence seqNext = next.getSeq();
- InstructionSequence seqBlock = block.getSeq();
-
- if(seqNext.length() == seqBlock.length()) {
- for(int i=0;i<seqNext.length();i++) {
- Instruction instrNext = seqNext.getInstr(i);
- Instruction instrBlock = seqBlock.getInstr(i);
-
- if(instrNext.opcode != instrBlock.opcode || instrNext.wide != instrBlock.wide
- || instrNext.operandsCount() != instrBlock.operandsCount()) {
- return null;
- }
-
- for(int j=0;i<instrNext.getOperands().length;j++) {
- if(instrNext.getOperand(j) != instrBlock.getOperand(j)) {
- return null;
- }
- }
- }
- } else {
- return null;
- }
- } else {
- return null;
- }
- }
- }
-
-// try {
-// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
-// } catch(IOException ex) {
-// ex.printStackTrace();
-// }
-
- for(BasicBlock[] arr : setNext) {
- if(arr[1] != next) {
- // FIXME: exception edge possible?
- arr[0].removeSuccessor(arr[1]);
- arr[0].addSuccessor(next);
- }
- }
-
- DeadCodeHelper.removeDeadBlocks(graph);
-
- }
-
- return next;
- }
-
- private boolean compareBasicBlocksEx(ControlFlowGraph graph, BasicBlock pattern, BasicBlock sample, int type, int finallytype, List<int[]> lstStoreVars) {
-
- InstructionSequence seqPattern = pattern.getSeq();
- InstructionSequence seqSample = sample.getSeq();
-
- if(type!=0) {
- seqPattern = seqPattern.clone();
-
- if((type & 1) > 0) { // first
- if(finallytype > 0) {
- seqPattern.removeInstruction(0);
- }
- }
-
- if((type & 2) > 0) { // last
- if(finallytype == 0 || finallytype == 2) {
- seqPattern.removeInstruction(seqPattern.length()-1);
- }
-
- if(finallytype == 2) {
- seqPattern.removeInstruction(seqPattern.length()-1);
- }
- }
- }
-
- if(seqPattern.length() > seqSample.length()) {
- return false;
- }
-
- for(int i=0;i<seqPattern.length();i++) {
- Instruction instrPattern = seqPattern.getInstr(i);
- Instruction instrSample = seqSample.getInstr(i);
-
- // compare instructions with respect to jumps
- if(!equalInstructions(instrPattern, instrSample, lstStoreVars)) {
- return false;
- }
- }
-
- if(seqPattern.length() < seqSample.length()) { // split in two blocks
-
- SimpleInstructionSequence seq = new SimpleInstructionSequence();
- for(int i=seqSample.length()-1;i>=seqPattern.length();i--) {
- seq.addInstruction(0, seqSample.getInstr(i), -1);
- seqSample.removeInstruction(i);
- }
-
- BasicBlock newblock = new BasicBlock(++graph.last_id);
- newblock.setSeq(seq);
-
- List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
- lstTemp.addAll(sample.getSuccs());
-
- // move successors
- for(BasicBlock suc: lstTemp) {
- sample.removeSuccessor(suc);
- newblock.addSuccessor(suc);
- }
-
- sample.addSuccessor(newblock);
-
- graph.getBlocks().addWithKey(newblock, newblock.id);
-
- HashSet<BasicBlock> setFinallyExits = graph.getFinallyExits();
- if(setFinallyExits.contains(sample)) {
- setFinallyExits.remove(sample);
- setFinallyExits.add(newblock);
- }
-
- // copy exception edges and extend protected ranges
- for(int j=0;j<sample.getSuccExceptions().size();j++) {
- BasicBlock hd = sample.getSuccExceptions().get(j);
- newblock.addSuccessorException(hd);
-
- ExceptionRangeCFG range = graph.getExceptionRange(hd, sample);
- range.getProtectedRange().add(newblock);
- }
- }
-
- return true;
- }
-
- public boolean equalInstructions(Instruction first, Instruction second, List<int[]> lstStoreVars) {
- if(first.opcode != second.opcode || first.wide != second.wide
- || first.operandsCount() != second.operandsCount()) {
- return false;
- }
-
- if(first.group != CodeConstants.GROUP_JUMP && first.getOperands() != null) { // FIXME: switch comparison
- for(int i=0;i<first.getOperands().length;i++) {
-
- int firstOp = first.getOperand(i);
- int secondOp = second.getOperand(i);
-
- if(firstOp != secondOp) {
-
- // a-load/store instructions
- if(first.opcode == CodeConstants.opc_aload || first.opcode == CodeConstants.opc_astore) {
- for(int[] arr : lstStoreVars) {
- if(arr[0] == firstOp && arr[1] == secondOp) {
- return true;
- }
- }
- }
-
- return false;
- }
- }
- }
-
- return true;
- }
-
- private void deleteArea(ControlFlowGraph graph, Object[] area) {
-
- BasicBlock start = (BasicBlock)area[0];
- BasicBlock next = (BasicBlock)area[2];
-
- if(start == next) {
- return;
- }
-
- if(next == null) {
- // dummy exit block
- next = graph.getLast();
- }
-
- // collect common exception ranges of predecessors and successors
- HashSet<BasicBlock> setCommonExceptionHandlers = new HashSet<BasicBlock>(next.getSuccExceptions());
- for(BasicBlock pred : start.getPreds()) {
- setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
- }
-
- boolean is_outside_range = false;
-
- HashSet<BasicBlock> setPredecessors = new HashSet<BasicBlock>(start.getPreds());
-
- // replace start with next
- for(BasicBlock pred: setPredecessors) {
- pred.replaceSuccessor(start, next);
- }
-
- HashSet<BasicBlock> setBlocks = (HashSet<BasicBlock>)area[1];
-
- HashSet<ExceptionRangeCFG> setCommonRemovedExceptionRanges = null;
-
- // remove all the blocks inbetween
- for(BasicBlock block: setBlocks) {
-
- // artificial basic blocks (those resulted from splitting)
- // can belong to more than one area
- if(graph.getBlocks().containsKey(block.id)) {
-
- if(!block.getSuccExceptions().containsAll(setCommonExceptionHandlers)) {
- is_outside_range = true;
- }
-
- HashSet<ExceptionRangeCFG> setRemovedExceptionRanges = new HashSet<ExceptionRangeCFG>();
- for(BasicBlock handler : block.getSuccExceptions()) {
- setRemovedExceptionRanges.add(graph.getExceptionRange(handler, block));
- }
-
- if(setCommonRemovedExceptionRanges == null) {
- setCommonRemovedExceptionRanges = setRemovedExceptionRanges;
- } else {
- setCommonRemovedExceptionRanges.retainAll(setRemovedExceptionRanges);
- }
-
- // shift extern edges on splitted blocks
- if(block.getSeq().isEmpty() && block.getSuccs().size() == 1) {
- BasicBlock succs = block.getSuccs().get(0);
- for(BasicBlock pred : new ArrayList<BasicBlock>(block.getPreds())) {
- if(!setBlocks.contains(pred)) {
- pred.replaceSuccessor(block, succs);
- }
- }
-
- if(graph.getFirst() == block) {
- graph.setFirst(succs);
- }
- }
-
- graph.removeBlock(block);
- }
- }
-
- if(is_outside_range) {
-
- // new empty block
- BasicBlock emptyblock = new BasicBlock(++graph.last_id);
- emptyblock.setSeq(new SimpleInstructionSequence());
- graph.getBlocks().addWithKey(emptyblock, emptyblock.id);
-
- // add to ranges if necessary
- if(setCommonRemovedExceptionRanges != null) {
- for(ExceptionRangeCFG range : setCommonRemovedExceptionRanges) {
- emptyblock.addSuccessorException(range.getHandler());
- range.getProtectedRange().add(emptyblock);
- }
- }
-
- // insert between predecessors and next
- emptyblock.addSuccessor(next);
- for(BasicBlock pred: setPredecessors) {
- pred.replaceSuccessor(next, emptyblock);
- }
- }
- }
-
- private void removeExceptionInstructionsEx(BasicBlock block, int blocktype, int finallytype) {
-
- InstructionSequence seq = block.getSeq();
-
- if(finallytype == 3) { // empty finally handler
- for(int i=seq.length()-1;i>=0;i--) {
- seq.removeInstruction(i);
- }
-
- } else {
- if((blocktype & 1) > 0) { // first
- if(finallytype == 2 || finallytype == 1) { // astore or pop
- seq.removeInstruction(0);
- }
- }
-
- if((blocktype & 2) > 0) { // last
- if(finallytype == 2 || finallytype == 0) {
- seq.removeInstruction(seq.length()-1);
- }
-
- if(finallytype == 2) { // astore
- seq.removeInstruction(seq.length()-1);
- }
- }
- }
- }
-
+
+
+ private HashMap<Integer, Integer> finallyBlockIDs = new HashMap<Integer, Integer>();
+ private HashMap<Integer, Integer> catchallBlockIDs = new HashMap<Integer, Integer>();
+
+ private VarProcessor varprocessor;
+
+ public FinallyProcessor(VarProcessor varprocessor) {
+ this.varprocessor = varprocessor;
+ }
+
+ public boolean iterateGraph(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
+ // return processStatement(mt, root, graph, root);
+ return processStatementEx(mt, root, graph);
+ }
+
+ private boolean processStatementEx(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
+
+ int bytecode_version = mt.getClassStruct().getBytecodeVersion();
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+
+ Statement stat = stack.removeLast();
+
+ Statement parent = stat.getParent();
+ if (parent != null && parent.type == Statement.TYPE_CATCHALL &&
+ stat == parent.getFirst() && !parent.isCopied()) {
+
+ CatchAllStatement fin = (CatchAllStatement)parent;
+ BasicBlock head = fin.getBasichead().getBlock();
+ BasicBlock handler = fin.getHandler().getBasichead().getBlock();
+
+ if (catchallBlockIDs.containsKey(handler.id)) {
+ ; // do nothing
+ }
+ else if (finallyBlockIDs.containsKey(handler.id)) {
+
+ fin.setFinally(true);
+
+ Integer var = finallyBlockIDs.get(handler.id);
+ fin.setMonitor(var == null ? null : new VarExprent(var.intValue(), VarType.VARTYPE_INT, varprocessor));
+ }
+ else {
+
+ Object[] inf = getFinallyInformation(mt, root, fin);
+
+ if (inf == null) { // inconsistent finally
+ catchallBlockIDs.put(handler.id, null);
+ }
+ else {
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && verifyFinallyEx(graph, fin, inf)) {
+ finallyBlockIDs.put(handler.id, null);
+ }
+ else {
+
+ int varindex = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
+ insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf, bytecode_version);
+
+ finallyBlockIDs.put(handler.id, varindex);
+ }
+
+ DeadCodeHelper.removeDeadBlocks(graph); // e.g. multiple return blocks after a nested finally
+ DeadCodeHelper.removeEmptyBlocks(graph);
+ DeadCodeHelper.mergeBasicBlocks(graph);
+ }
+
+ return true;
+ }
+ }
+
+ stack.addAll(stat.getStats());
+ }
+
+ return false;
+ }
+
+
+ // private boolean processStatement(StructMethod mt, RootStatement root, ControlFlowGraph graph, Statement stat) {
+ //
+ // boolean res = false;
+ //
+ // for(int i=stat.getStats().size()-1;i>=0;i--) {
+ // if(processStatement(mt, root, graph, stat.getStats().get(i))) {
+ // return true;
+ // }
+ // }
+ //
+ //
+ // if(stat.type == Statement.TYPE_CATCHALL && !stat.isCopied()) {
+ //
+ // CatchAllStatement fin = (CatchAllStatement)stat;
+ // BasicBlock head = fin.getBasichead().getBlock();
+ // BasicBlock handler = fin.getHandler().getBasichead().getBlock();
+ //
+ // if(catchallBlockIDs.containsKey(handler.id)) {
+ // ; // do nothing
+ // }else if(finallyBlockIDs.containsKey(handler.id)) {
+ //
+ // fin.setFinally(true);
+ //
+ // Integer var = finallyBlockIDs.get(handler.id);
+ // fin.setMonitor(var==null?null:new VarExprent(var.intValue(), VarType.VARTYPE_INT, varprocessor));
+ //
+ // } else {
+ //
+ // Object[] inf = getFinallyInformation(mt, root, fin);
+ //
+ // if(inf == null) { // inconsistent finally
+ // catchallBlockIDs.put(handler.id, null);
+ // } else {
+ //
+ // if(DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && verifyFinallyEx(graph, fin, inf)) {
+ // finallyBlockIDs.put(handler.id, null);
+ // } else {
+ //
+ // int varindex = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
+ // insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf);
+ //
+ // finallyBlockIDs.put(handler.id, varindex);
+ // }
+ //
+ // DeadCodeHelper.removeEmptyBlocks(graph);
+ // DeadCodeHelper.mergeBasicBlocks(graph);
+ // }
+ //
+ // res = true;
+ // }
+ // }
+ //
+ // return res;
+ // }
+
+
+ private Object[] getFinallyInformation(StructMethod mt, RootStatement root, CatchAllStatement fstat) {
+
+ HashMap<BasicBlock, Boolean> mapLast = new HashMap<BasicBlock, Boolean>();
+
+ BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead();
+ BasicBlock firstBasicBlock = firstBlockStatement.getBlock();
+ Instruction instrFirst = firstBasicBlock.getInstruction(0);
+
+ int firstcode = 0;
+
+ switch (instrFirst.opcode) {
+ case CodeConstants.opc_pop:
+ firstcode = 1;
+ break;
+ case CodeConstants.opc_astore:
+ firstcode = 2;
+ }
+
+ ExprProcessor proc = new ExprProcessor();
+ proc.processStatement(root, mt.getClassStruct());
+
+ SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
+ ssa.splitVariables(root, mt);
+
+ List<Exprent> lstExprents = firstBlockStatement.getExprents();
+
+ VarVersionPaar varpaar = new VarVersionPaar((VarExprent)((AssignmentExprent)lstExprents.get(firstcode == 2 ? 1 : 0)).getLeft());
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ stack.add(dgraph.first);
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+
+ while (!stack.isEmpty()) {
+
+ DirectNode node = stack.removeFirst();
+
+ if (setVisited.contains(node)) {
+ continue;
+ }
+ setVisited.add(node);
+
+ BasicBlockStatement blockStatement = null;
+ if (node.block != null) {
+ blockStatement = node.block;
+ }
+ else if (node.preds.size() == 1) {
+ blockStatement = node.preds.get(0).block;
+ }
+
+ boolean isTrueExit = true;
+
+ if (firstcode != 1) {
+
+ isTrueExit = false;
+
+ for (int i = 0; i < node.exprents.size(); i++) {
+ Exprent exprent = node.exprents.get(i);
+
+ if (firstcode == 0) {
+ List<Exprent> lst = exprent.getAllExprents();
+ lst.add(exprent);
+
+ boolean found = false;
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR && new VarVersionPaar((VarExprent)expr).equals(varpaar)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ found = false;
+ if (exprent.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exexpr = (ExitExprent)exprent;
+ if (exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_VAR) {
+ found = true;
+ }
+ }
+
+ if (!found) {
+ return null;
+ }
+ else {
+ isTrueExit = true;
+ }
+ }
+ }
+ else if (firstcode == 2) {
+ // search for a load instruction
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent assexpr = (AssignmentExprent)exprent;
+ if (assexpr.getRight().type == Exprent.EXPRENT_VAR &&
+ new VarVersionPaar((VarExprent)assexpr.getRight()).equals(varpaar)) {
+
+ Exprent next = null;
+ if (i == node.exprents.size() - 1) {
+ if (node.succs.size() == 1) {
+ DirectNode nd = node.succs.get(0);
+ if (!nd.exprents.isEmpty()) {
+ next = nd.exprents.get(0);
+ }
+ }
+ }
+ else {
+ next = node.exprents.get(i + 1);
+ }
+
+ boolean found = false;
+ if (next != null && next.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exexpr = (ExitExprent)next;
+ if (exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_VAR
+ && assexpr.getLeft().equals(exexpr.getValue())) {
+ found = true;
+ }
+ }
+
+ if (!found) {
+ return null;
+ }
+ else {
+ isTrueExit = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // find finally exits
+ if (blockStatement != null && blockStatement.getBlock() != null) {
+ Statement handler = fstat.getHandler();
+ for (StatEdge edge : blockStatement.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
+ if (edge.getType() != StatEdge.TYPE_REGULAR && handler.containsStatement(blockStatement)
+ && !handler.containsStatement(edge.getDestination())) {
+ Boolean existingFlag = mapLast.get(blockStatement.getBlock());
+ // note: the dummy node is also processed!
+ if (existingFlag == null || !existingFlag) {
+ mapLast.put(blockStatement.getBlock(), isTrueExit);
+ break;
+ }
+ }
+ }
+ }
+
+ stack.addAll(node.succs);
+ }
+
+ // empty finally block?
+ if (fstat.getHandler().type == Statement.TYPE_BASICBLOCK) {
+
+ boolean isEmpty = false;
+ boolean isFirstLast = mapLast.containsKey(firstBasicBlock);
+ InstructionSequence seq = firstBasicBlock.getSeq();
+
+ switch (firstcode) {
+ case 0:
+ isEmpty = isFirstLast && seq.length() == 1;
+ break;
+ case 1:
+ isEmpty = seq.length() == 1;
+ break;
+ case 2:
+ isEmpty = isFirstLast ? seq.length() == 3 : seq.length() == 1;
+ }
+
+ if (isEmpty) {
+ firstcode = 3;
+ }
+ }
+
+ return new Object[]{firstcode, mapLast};
+ }
+
+ private void insertSemaphore(ControlFlowGraph graph,
+ HashSet<BasicBlock> setTry,
+ BasicBlock head,
+ BasicBlock handler,
+ int var,
+ Object[] information,
+ int bytecode_version) {
+
+ HashSet<BasicBlock> setCopy = new HashSet<BasicBlock>(setTry);
+
+ int finallytype = (Integer)information[0];
+ HashMap<BasicBlock, Boolean> mapLast = (HashMap<BasicBlock, Boolean>)information[1];
+
+ // first and last statements
+ removeExceptionInstructionsEx(handler, 1, finallytype);
+ for (Entry<BasicBlock, Boolean> entry : mapLast.entrySet()) {
+ BasicBlock last = entry.getKey();
+
+ if (entry.getValue()) {
+ removeExceptionInstructionsEx(last, 2, finallytype);
+ graph.getFinallyExits().add(last);
+ }
+ }
+
+ // disable semaphore at statement exit points
+ for (BasicBlock block : setTry) {
+
+ List<BasicBlock> lstSucc = block.getSuccs();
+ for (BasicBlock dest : lstSucc) {
+
+ // break out
+ if (!setCopy.contains(dest) && dest != graph.getLast()) {
+ // disable semaphore
+ SimpleInstructionSequence seq = new SimpleInstructionSequence();
+
+ seq.addInstruction(ConstantsUtil
+ .getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version,
+ new int[]{0}), -1);
+ seq.addInstruction(ConstantsUtil
+ .getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version,
+ new int[]{var}), -1);
+
+ // build a separate block
+ BasicBlock newblock = new BasicBlock(++graph.last_id);
+ newblock.setSeq(seq);
+
+ // insert between block and dest
+ block.replaceSuccessor(dest, newblock);
+ newblock.addSuccessor(dest);
+ setCopy.add(newblock);
+ graph.getBlocks().addWithKey(newblock, newblock.id);
+
+ // exception ranges
+ // FIXME: special case synchronized
+
+ // copy exception edges and extend protected ranges
+ for (int j = 0; j < block.getSuccExceptions().size(); j++) {
+ BasicBlock hd = block.getSuccExceptions().get(j);
+ newblock.addSuccessorException(hd);
+
+ ExceptionRangeCFG range = graph.getExceptionRange(hd, block);
+ range.getProtectedRange().add(newblock);
+ }
+ }
+ }
+ }
+
+ // enable semaphor at the statement entrance
+ SimpleInstructionSequence seq = new SimpleInstructionSequence();
+ seq.addInstruction(
+ ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{1}),
+ -1);
+ seq.addInstruction(
+ ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}),
+ -1);
+
+ BasicBlock newhead = new BasicBlock(++graph.last_id);
+ newhead.setSeq(seq);
+
+ insertBlockBefore(graph, head, newhead);
+
+ // initialize semaphor with false
+ seq = new SimpleInstructionSequence();
+ seq.addInstruction(
+ ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}),
+ -1);
+ seq.addInstruction(
+ ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}),
+ -1);
+
+ BasicBlock newheadinit = new BasicBlock(++graph.last_id);
+ newheadinit.setSeq(seq);
+
+ insertBlockBefore(graph, newhead, newheadinit);
+
+ setCopy.add(newhead);
+ setCopy.add(newheadinit);
+
+ for (BasicBlock hd : new HashSet<BasicBlock>(newheadinit.getSuccExceptions())) {
+ ExceptionRangeCFG range = graph.getExceptionRange(hd, newheadinit);
+
+ if (setCopy.containsAll(range.getProtectedRange())) {
+ newheadinit.removeSuccessorException(hd);
+ range.getProtectedRange().remove(newheadinit);
+ }
+ }
+
+ return;
+ }
+
+
+ private void insertBlockBefore(ControlFlowGraph graph, BasicBlock oldblock, BasicBlock newblock) {
+
+ List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
+ lstTemp.addAll(oldblock.getPreds());
+ lstTemp.addAll(oldblock.getPredExceptions());
+
+ // replace predecessors
+ for (BasicBlock pred : lstTemp) {
+ pred.replaceSuccessor(oldblock, newblock);
+ }
+
+ // copy exception edges and extend protected ranges
+ for (BasicBlock hd : oldblock.getSuccExceptions()) {
+ newblock.addSuccessorException(hd);
+
+ ExceptionRangeCFG range = graph.getExceptionRange(hd, oldblock);
+ range.getProtectedRange().add(newblock);
+ }
+
+ // replace handler
+ for (ExceptionRangeCFG range : graph.getExceptions()) {
+ if (range.getHandler() == oldblock) {
+ range.setHandler(newblock);
+ }
+ }
+
+ newblock.addSuccessor(oldblock);
+ graph.getBlocks().addWithKey(newblock, newblock.id);
+ if (graph.getFirst() == oldblock) {
+ graph.setFirst(newblock);
+ }
+ }
+
+ private HashSet<BasicBlock> getAllBasicBlocks(Statement stat) {
+
+ List<Statement> lst = new LinkedList<Statement>();
+ lst.add(stat);
+
+ int index = 0;
+ do {
+ Statement st = lst.get(index);
+
+ if (st.type == Statement.TYPE_BASICBLOCK) {
+ index++;
+ }
+ else {
+ lst.addAll(st.getStats());
+ lst.remove(index);
+ }
+ }
+ while (index < lst.size());
+
+ HashSet<BasicBlock> res = new HashSet<BasicBlock>();
+
+ for (Statement st : lst) {
+ res.add(((BasicBlockStatement)st).getBlock());
+ }
+
+ return res;
+ }
+
+
+ private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, Object[] information) {
+
+ HashSet<BasicBlock> tryBlocks = getAllBasicBlocks(fstat.getFirst());
+ HashSet<BasicBlock> catchBlocks = getAllBasicBlocks(fstat.getHandler());
+
+ int finallytype = (Integer)information[0];
+ HashMap<BasicBlock, Boolean> mapLast = (HashMap<BasicBlock, Boolean>)information[1];
+
+ BasicBlock first = fstat.getHandler().getBasichead().getBlock();
+ boolean skippedFirst = false;
+
+ if (finallytype == 3) {
+ // empty finally
+ removeExceptionInstructionsEx(first, 3, finallytype);
+
+ if (mapLast.containsKey(first)) {
+ graph.getFinallyExits().add(first);
+ }
+
+ return true;
+ }
+ else {
+ if (first.getSeq().length() == 1 && finallytype > 0) {
+ BasicBlock firstsuc = first.getSuccs().get(0);
+ if (catchBlocks.contains(firstsuc)) {
+ first = firstsuc;
+ skippedFirst = true;
+ }
+ }
+ }
+
+ // identify start blocks
+ HashSet<BasicBlock> startBlocks = new HashSet<BasicBlock>();
+ for (BasicBlock block : tryBlocks) {
+ startBlocks.addAll(block.getSuccs());
+ }
+ // throw in the try body will point directly to the dummy exit
+ // so remove dummy exit
+ startBlocks.remove(graph.getLast());
+ startBlocks.removeAll(tryBlocks);
+
+ List<Object[]> lstAreas = new ArrayList<Object[]>();
+
+ for (BasicBlock start : startBlocks) {
+
+ Object[] arr = compareSubgraphsEx(graph, start, catchBlocks, first, finallytype, mapLast, skippedFirst);
+ if (arr == null) {
+ return false;
+ }
+
+ lstAreas.add(new Object[]{start, arr[0], arr[1]});
+ }
+
+ // try {
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
+ // } catch(Exception ex){ex.printStackTrace();}
+
+ // delete areas
+ for (Object[] area : lstAreas) {
+ deleteArea(graph, area);
+ }
+
+ // try {
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
+ // } catch(Exception ex){ex.printStackTrace();}
+
+ // INFO: empty basic blocks may remain in the graph!
+ for (Entry<BasicBlock, Boolean> entry : mapLast.entrySet()) {
+ BasicBlock last = entry.getKey();
+
+ if (entry.getValue()) {
+ removeExceptionInstructionsEx(last, 2, finallytype);
+ graph.getFinallyExits().add(last);
+ }
+ }
+
+ removeExceptionInstructionsEx(fstat.getHandler().getBasichead().getBlock(), 1, finallytype);
+
+ return true;
+ }
+
+ private Object[] compareSubgraphsEx(ControlFlowGraph graph,
+ BasicBlock startSample,
+ HashSet<BasicBlock> catchBlocks,
+ BasicBlock startCatch,
+ int finallytype,
+ HashMap<BasicBlock, Boolean> mapLast,
+ boolean skippedFirst) {
+
+ class BlockStackEntry {
+ public BasicBlock blockCatch;
+ public BasicBlock blockSample;
+
+ // TODO: correct handling (merging) of multiple paths
+ public List<int[]> lstStoreVars;
+
+ public BlockStackEntry(BasicBlock blockCatch, BasicBlock blockSample, List<int[]> lstStoreVars) {
+ this.blockCatch = blockCatch;
+ this.blockSample = blockSample;
+ this.lstStoreVars = new ArrayList<int[]>(lstStoreVars);
+ }
+ }
+
+ List<BlockStackEntry> stack = new LinkedList<BlockStackEntry>();
+
+ HashSet<BasicBlock> setSample = new HashSet<BasicBlock>();
+
+ HashMap<String, BasicBlock[]> mapNext = new HashMap<String, BasicBlock[]>();
+
+ stack.add(new BlockStackEntry(startCatch, startSample, new ArrayList<int[]>()));
+
+ while (!stack.isEmpty()) {
+
+ BlockStackEntry entry = stack.remove(0);
+ BasicBlock blockCatch = entry.blockCatch;
+ BasicBlock blockSample = entry.blockSample;
+
+ boolean isFirstBlock = !skippedFirst && blockCatch == startCatch;
+ boolean isLastBlock = mapLast.containsKey(blockCatch);
+ boolean isTrueLastBlock = isLastBlock && mapLast.get(blockCatch);
+
+ if (!compareBasicBlocksEx(graph, blockCatch, blockSample, (isFirstBlock ? 1 : 0) | (isTrueLastBlock ? 2 : 0), finallytype,
+ entry.lstStoreVars)) {
+ return null;
+ }
+
+ if (blockSample.getSuccs().size() != blockCatch.getSuccs().size()) {
+ return null;
+ }
+
+ setSample.add(blockSample);
+
+ // direct successors
+ for (int i = 0; i < blockCatch.getSuccs().size(); i++) {
+ BasicBlock sucCatch = blockCatch.getSuccs().get(i);
+ BasicBlock sucSample = blockSample.getSuccs().get(i);
+
+ if (catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) {
+ stack.add(new BlockStackEntry(sucCatch, sucSample, entry.lstStoreVars));
+ }
+ }
+
+
+ // exception successors
+ if (isLastBlock && blockSample.getSeq().isEmpty()) {
+ ; // do nothing, blockSample will be removed anyway
+ }
+ else {
+ if (blockCatch.getSuccExceptions().size() == blockSample.getSuccExceptions().size()) {
+ for (int i = 0; i < blockCatch.getSuccExceptions().size(); i++) {
+ BasicBlock sucCatch = blockCatch.getSuccExceptions().get(i);
+ BasicBlock sucSample = blockSample.getSuccExceptions().get(i);
+
+ String excCatch = graph.getExceptionRange(sucCatch, blockCatch).getUniqueExceptionsString();
+ String excSample = graph.getExceptionRange(sucSample, blockSample).getUniqueExceptionsString();
+
+ // FIXME: compare handlers if possible
+ boolean equalexc = excCatch == null ? excSample == null : excCatch.equals(excSample);
+
+ if (equalexc) {
+ if (catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) {
+
+ List<int[]> lst = entry.lstStoreVars;
+
+ if (sucCatch.getSeq().length() > 0 && sucSample.getSeq().length() > 0) {
+ Instruction instrCatch = sucCatch.getSeq().getInstr(0);
+ Instruction instrSample = sucSample.getSeq().getInstr(0);
+
+ if (instrCatch.opcode == CodeConstants.opc_astore &&
+ instrSample.opcode == CodeConstants.opc_astore) {
+ lst = new ArrayList<int[]>(lst);
+ lst.add(new int[]{instrCatch.getOperand(0), instrSample.getOperand(0)});
+ }
+ }
+
+ stack.add(new BlockStackEntry(sucCatch, sucSample, lst));
+ }
+ }
+ else {
+ return null;
+ }
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ if (isLastBlock) {
+ HashSet<BasicBlock> setSuccs = new HashSet<BasicBlock>(blockSample.getSuccs());
+ setSuccs.removeAll(setSample);
+
+ for (BlockStackEntry stackent : stack) {
+ setSuccs.remove(stackent.blockSample);
+ }
+
+ for (BasicBlock succ : setSuccs) {
+ if (graph.getLast() != succ) { // FIXME: why?
+ mapNext.put(blockSample.id + "#" + succ.id, new BasicBlock[]{blockSample, succ, isTrueLastBlock ? succ : null});
+ }
+ }
+ }
+ }
+
+ return new Object[]{setSample, getUniqueNext(graph, new HashSet<BasicBlock[]>(mapNext.values()))};
+ }
+
+ private BasicBlock getUniqueNext(ControlFlowGraph graph, HashSet<BasicBlock[]> setNext) {
+
+ // precondition: there is at most one true exit path in a finally statement
+
+ BasicBlock next = null;
+ boolean multiple = false;
+
+ for (BasicBlock[] arr : setNext) {
+
+ if (arr[2] != null) {
+ next = arr[1];
+ multiple = false;
+ break;
+ }
+ else {
+ if (next == null) {
+ next = arr[1];
+ }
+ else if (next != arr[1]) {
+ multiple = true;
+ }
+
+ if (arr[1].getPreds().size() == 1) {
+ next = arr[1];
+ }
+ }
+ }
+
+ if (multiple) { // TODO: generic solution
+ for (BasicBlock[] arr : setNext) {
+ BasicBlock block = arr[1];
+
+ if (block != next) {
+ if (InterpreterUtil.equalSets(next.getSuccs(), block.getSuccs())) {
+ InstructionSequence seqNext = next.getSeq();
+ InstructionSequence seqBlock = block.getSeq();
+
+ if (seqNext.length() == seqBlock.length()) {
+ for (int i = 0; i < seqNext.length(); i++) {
+ Instruction instrNext = seqNext.getInstr(i);
+ Instruction instrBlock = seqBlock.getInstr(i);
+
+ if (instrNext.opcode != instrBlock.opcode || instrNext.wide != instrBlock.wide
+ || instrNext.operandsCount() != instrBlock.operandsCount()) {
+ return null;
+ }
+
+ for (int j = 0; i < instrNext.getOperands().length; j++) {
+ if (instrNext.getOperand(j) != instrBlock.getOperand(j)) {
+ return null;
+ }
+ }
+ }
+ }
+ else {
+ return null;
+ }
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ // try {
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
+ // } catch(IOException ex) {
+ // ex.printStackTrace();
+ // }
+
+ for (BasicBlock[] arr : setNext) {
+ if (arr[1] != next) {
+ // FIXME: exception edge possible?
+ arr[0].removeSuccessor(arr[1]);
+ arr[0].addSuccessor(next);
+ }
+ }
+
+ DeadCodeHelper.removeDeadBlocks(graph);
+ }
+
+ return next;
+ }
+
+ private boolean compareBasicBlocksEx(ControlFlowGraph graph,
+ BasicBlock pattern,
+ BasicBlock sample,
+ int type,
+ int finallytype,
+ List<int[]> lstStoreVars) {
+
+ InstructionSequence seqPattern = pattern.getSeq();
+ InstructionSequence seqSample = sample.getSeq();
+
+ if (type != 0) {
+ seqPattern = seqPattern.clone();
+
+ if ((type & 1) > 0) { // first
+ if (finallytype > 0) {
+ seqPattern.removeInstruction(0);
+ }
+ }
+
+ if ((type & 2) > 0) { // last
+ if (finallytype == 0 || finallytype == 2) {
+ seqPattern.removeInstruction(seqPattern.length() - 1);
+ }
+
+ if (finallytype == 2) {
+ seqPattern.removeInstruction(seqPattern.length() - 1);
+ }
+ }
+ }
+
+ if (seqPattern.length() > seqSample.length()) {
+ return false;
+ }
+
+ for (int i = 0; i < seqPattern.length(); i++) {
+ Instruction instrPattern = seqPattern.getInstr(i);
+ Instruction instrSample = seqSample.getInstr(i);
+
+ // compare instructions with respect to jumps
+ if (!equalInstructions(instrPattern, instrSample, lstStoreVars)) {
+ return false;
+ }
+ }
+
+ if (seqPattern.length() < seqSample.length()) { // split in two blocks
+
+ SimpleInstructionSequence seq = new SimpleInstructionSequence();
+ for (int i = seqSample.length() - 1; i >= seqPattern.length(); i--) {
+ seq.addInstruction(0, seqSample.getInstr(i), -1);
+ seqSample.removeInstruction(i);
+ }
+
+ BasicBlock newblock = new BasicBlock(++graph.last_id);
+ newblock.setSeq(seq);
+
+ List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
+ lstTemp.addAll(sample.getSuccs());
+
+ // move successors
+ for (BasicBlock suc : lstTemp) {
+ sample.removeSuccessor(suc);
+ newblock.addSuccessor(suc);
+ }
+
+ sample.addSuccessor(newblock);
+
+ graph.getBlocks().addWithKey(newblock, newblock.id);
+
+ HashSet<BasicBlock> setFinallyExits = graph.getFinallyExits();
+ if (setFinallyExits.contains(sample)) {
+ setFinallyExits.remove(sample);
+ setFinallyExits.add(newblock);
+ }
+
+ // copy exception edges and extend protected ranges
+ for (int j = 0; j < sample.getSuccExceptions().size(); j++) {
+ BasicBlock hd = sample.getSuccExceptions().get(j);
+ newblock.addSuccessorException(hd);
+
+ ExceptionRangeCFG range = graph.getExceptionRange(hd, sample);
+ range.getProtectedRange().add(newblock);
+ }
+ }
+
+ return true;
+ }
+
+ public boolean equalInstructions(Instruction first, Instruction second, List<int[]> lstStoreVars) {
+ if (first.opcode != second.opcode || first.wide != second.wide
+ || first.operandsCount() != second.operandsCount()) {
+ return false;
+ }
+
+ if (first.group != CodeConstants.GROUP_JUMP && first.getOperands() != null) { // FIXME: switch comparison
+ for (int i = 0; i < first.getOperands().length; i++) {
+
+ int firstOp = first.getOperand(i);
+ int secondOp = second.getOperand(i);
+
+ if (firstOp != secondOp) {
+
+ // a-load/store instructions
+ if (first.opcode == CodeConstants.opc_aload || first.opcode == CodeConstants.opc_astore) {
+ for (int[] arr : lstStoreVars) {
+ if (arr[0] == firstOp && arr[1] == secondOp) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private void deleteArea(ControlFlowGraph graph, Object[] area) {
+
+ BasicBlock start = (BasicBlock)area[0];
+ BasicBlock next = (BasicBlock)area[2];
+
+ if (start == next) {
+ return;
+ }
+
+ if (next == null) {
+ // dummy exit block
+ next = graph.getLast();
+ }
+
+ // collect common exception ranges of predecessors and successors
+ HashSet<BasicBlock> setCommonExceptionHandlers = new HashSet<BasicBlock>(next.getSuccExceptions());
+ for (BasicBlock pred : start.getPreds()) {
+ setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
+ }
+
+ boolean is_outside_range = false;
+
+ HashSet<BasicBlock> setPredecessors = new HashSet<BasicBlock>(start.getPreds());
+
+ // replace start with next
+ for (BasicBlock pred : setPredecessors) {
+ pred.replaceSuccessor(start, next);
+ }
+
+ HashSet<BasicBlock> setBlocks = (HashSet<BasicBlock>)area[1];
+
+ HashSet<ExceptionRangeCFG> setCommonRemovedExceptionRanges = null;
+
+ // remove all the blocks inbetween
+ for (BasicBlock block : setBlocks) {
+
+ // artificial basic blocks (those resulted from splitting)
+ // can belong to more than one area
+ if (graph.getBlocks().containsKey(block.id)) {
+
+ if (!block.getSuccExceptions().containsAll(setCommonExceptionHandlers)) {
+ is_outside_range = true;
+ }
+
+ HashSet<ExceptionRangeCFG> setRemovedExceptionRanges = new HashSet<ExceptionRangeCFG>();
+ for (BasicBlock handler : block.getSuccExceptions()) {
+ setRemovedExceptionRanges.add(graph.getExceptionRange(handler, block));
+ }
+
+ if (setCommonRemovedExceptionRanges == null) {
+ setCommonRemovedExceptionRanges = setRemovedExceptionRanges;
+ }
+ else {
+ setCommonRemovedExceptionRanges.retainAll(setRemovedExceptionRanges);
+ }
+
+ // shift extern edges on splitted blocks
+ if (block.getSeq().isEmpty() && block.getSuccs().size() == 1) {
+ BasicBlock succs = block.getSuccs().get(0);
+ for (BasicBlock pred : new ArrayList<BasicBlock>(block.getPreds())) {
+ if (!setBlocks.contains(pred)) {
+ pred.replaceSuccessor(block, succs);
+ }
+ }
+
+ if (graph.getFirst() == block) {
+ graph.setFirst(succs);
+ }
+ }
+
+ graph.removeBlock(block);
+ }
+ }
+
+ if (is_outside_range) {
+
+ // new empty block
+ BasicBlock emptyblock = new BasicBlock(++graph.last_id);
+ emptyblock.setSeq(new SimpleInstructionSequence());
+ graph.getBlocks().addWithKey(emptyblock, emptyblock.id);
+
+ // add to ranges if necessary
+ if (setCommonRemovedExceptionRanges != null) {
+ for (ExceptionRangeCFG range : setCommonRemovedExceptionRanges) {
+ emptyblock.addSuccessorException(range.getHandler());
+ range.getProtectedRange().add(emptyblock);
+ }
+ }
+
+ // insert between predecessors and next
+ emptyblock.addSuccessor(next);
+ for (BasicBlock pred : setPredecessors) {
+ pred.replaceSuccessor(next, emptyblock);
+ }
+ }
+ }
+
+ private void removeExceptionInstructionsEx(BasicBlock block, int blocktype, int finallytype) {
+
+ InstructionSequence seq = block.getSeq();
+
+ if (finallytype == 3) { // empty finally handler
+ for (int i = seq.length() - 1; i >= 0; i--) {
+ seq.removeInstruction(i);
+ }
+ }
+ else {
+ if ((blocktype & 1) > 0) { // first
+ if (finallytype == 2 || finallytype == 1) { // astore or pop
+ seq.removeInstruction(0);
+ }
+ }
+
+ if ((blocktype & 2) > 0) { // last
+ if (finallytype == 2 || finallytype == 0) {
+ seq.removeInstruction(seq.length() - 1);
+ }
+
+ if (finallytype == 2) { // astore
+ seq.removeInstruction(seq.length() - 1);
+ }
+ }
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java
index d11753e..0af6de0 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java
@@ -1,28 +1,22 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
@@ -33,288 +27,310 @@ import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.util.List;
+
public class IdeaNotNullHelper {
-
- public static boolean removeHardcodedChecks(Statement root, StructMethod mt) {
-
- boolean checks_removed = false;
-
- // parameter @NotNull annotations
- while(findAndRemoveParameterCheck(root, mt)) { // iterate until nothing found. Each invocation removes one parameter check.
- checks_removed = true;
- }
-
- // method @NotNull annotation
- while(findAndRemoveReturnCheck(root, mt)) { // iterate until nothing found. Each invocation handles one method exit check.
- checks_removed = true;
- }
-
- return checks_removed;
- }
-
- private static boolean findAndRemoveParameterCheck(Statement stat, StructMethod mt) {
-
- Statement st = stat.getFirst();
- while(st.type == Statement.TYPE_SEQUENCE) {
- st = st.getFirst();
- }
-
- if(st.type == Statement.TYPE_IF) {
-
- IfStatement ifstat = (IfStatement)st;
- Statement ifbranch = ifstat.getIfstat();
-
- Exprent if_condition = ifstat.getHeadexprent().getCondition();
-
- boolean is_notnull_check = false;
-
- // TODO: FUNCTION_NE also possible if reversed order (in theory)
- if(ifbranch != null && if_condition.type == Exprent.EXPRENT_FUNCTION && ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ &&
- ifbranch.type == Statement.TYPE_BASICBLOCK && ifbranch.getExprents().size() == 1 && ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
-
- FunctionExprent func = (FunctionExprent)if_condition;
- Exprent first_param = func.getLstOperands().get(0);
- Exprent second_param = func.getLstOperands().get(1);
-
- if(second_param.type == Exprent.EXPRENT_CONST && ((ConstExprent)second_param).getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order
- if(first_param.type == Exprent.EXPRENT_VAR) {
- VarExprent var = (VarExprent)first_param;
-
- boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
-
- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
- VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();
-
- // parameter annotations
- StructAnnotationParameterAttribute param_annotations = (StructAnnotationParameterAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
- if(param_annotations != null) {
-
- List<List<AnnotationExprent>> param_annotations_lists = param_annotations.getParamAnnotations();
- int method_param_number = md.params.length;
-
- int index = thisvar ? 1 : 0;
- for (int i = 0; i < method_param_number; i++) {
-
- if(index == var.getIndex()) {
- if(param_annotations_lists.size() >= method_param_number - i) {
- int shift = method_param_number - param_annotations_lists.size(); // NOTE: workaround for compiler bug, count annotations starting with the last parameter
-
- List<AnnotationExprent> annotations = param_annotations_lists.get(i - shift);
-
- for(AnnotationExprent ann : annotations) {
- if(ann.getClassname().equals("org/jetbrains/annotations/NotNull")) {
- is_notnull_check = true;
- }
- }
- }
-
- break;
- }
-
- index+=md.params[i].stack_size;
- }
- }
- }
- }
- }
-
- if(!is_notnull_check) {
- return false;
- }
-
- removeParameterCheck(stat, mt);
-
- return true;
- }
-
- return false;
- }
-
- private static void removeParameterCheck(Statement stat, StructMethod mt) {
-
- Statement st = stat.getFirst();
- while(st.type == Statement.TYPE_SEQUENCE) {
- st = st.getFirst();
- }
-
- IfStatement ifstat = (IfStatement)st;
-
- if(ifstat.getElsestat() == null) { // if
- // TODO:
- } else { // if - else
-
- StatEdge ifedge = ifstat.getIfEdge();
- StatEdge elseedge = ifstat.getElseEdge();
-
- Statement ifbranch = ifstat.getIfstat();
- Statement elsebranch = ifstat.getElsestat();
-
- ifstat.getFirst().removeSuccessor(ifedge);
- ifstat.getFirst().removeSuccessor(elseedge);
-
- ifstat.getStats().removeWithKey(ifbranch.id);
- ifstat.getStats().removeWithKey(elsebranch.id);
-
- if(!ifbranch.getAllSuccessorEdges().isEmpty()) {
- ifbranch.removeSuccessor(ifbranch.getAllSuccessorEdges().get(0));
- }
-
- ifstat.getParent().replaceStatement(ifstat, elsebranch);
- ifstat.getParent().setAllParent();
- }
-
- }
-
- private static boolean findAndRemoveReturnCheck(Statement stat, StructMethod mt) {
-
- VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();
-
- boolean is_notnull_check = false;
-
- // method annotation, refers to the return value
- StructAnnotationAttribute attr = (StructAnnotationAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS);
- if(attr != null) {
- List<AnnotationExprent> annotations = attr.getAnnotations();
-
- for(AnnotationExprent ann : annotations) {
- if(ann.getClassname().equals("org/jetbrains/annotations/NotNull")) {
- is_notnull_check = true;
- }
- }
- }
-
- if(is_notnull_check) {
- return removeReturnCheck(stat, mt);
- }
-
- return false;
- }
-
-
- private static boolean removeReturnCheck(Statement stat, StructMethod mt) {
-
- Statement parent = stat.getParent();
-
- if(parent != null && parent.type == Statement.TYPE_IF && stat.type == Statement.TYPE_BASICBLOCK && stat.getExprents().size() == 1) {
- Exprent exprent = stat.getExprents().get(0);
- if(exprent.type == Exprent.EXPRENT_EXIT) {
- ExitExprent exit_exprent = (ExitExprent)exprent;
- if(exit_exprent.getExittype() == ExitExprent.EXIT_RETURN) {
- Exprent exprent_value = exit_exprent.getValue();
- //if(exprent_value.type == Exprent.EXPRENT_VAR) {
- // VarExprent var_value = (VarExprent)exprent_value;
-
- IfStatement ifparent = (IfStatement)parent;
- Exprent if_condition = ifparent.getHeadexprent().getCondition();
-
- if(ifparent.getElsestat() == stat && if_condition.type == Exprent.EXPRENT_FUNCTION &&
- ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory)
-
- FunctionExprent func = (FunctionExprent)if_condition;
- Exprent first_param = func.getLstOperands().get(0);
- Exprent second_param = func.getLstOperands().get(1);
-
- StatEdge ifedge = ifparent.getIfEdge();
- StatEdge elseedge = ifparent.getElseEdge();
-
- Statement ifbranch = ifparent.getIfstat();
- Statement elsebranch = ifparent.getElsestat();
-
- if(second_param.type == Exprent.EXPRENT_CONST && ((ConstExprent)second_param).getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order
- //if(first_param.type == Exprent.EXPRENT_VAR && ((VarExprent)first_param).getIndex() == var_value.getIndex()) {
- if(first_param.equals(exprent_value)) { // TODO: check for absence of side effects like method invocations etc.
- if(ifbranch.type == Statement.TYPE_BASICBLOCK && ifbranch.getExprents().size() == 1 && // TODO: special check for IllegalStateException
- ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
-
- ifparent.getFirst().removeSuccessor(ifedge);
- ifparent.getFirst().removeSuccessor(elseedge);
-
- ifparent.getStats().removeWithKey(ifbranch.id);
- ifparent.getStats().removeWithKey(elsebranch.id);
-
- if(!ifbranch.getAllSuccessorEdges().isEmpty()) {
- ifbranch.removeSuccessor(ifbranch.getAllSuccessorEdges().get(0));
- }
-
- if(!ifparent.getFirst().getExprents().isEmpty()) {
- elsebranch.getExprents().addAll(0, ifparent.getFirst().getExprents());
- }
-
- ifparent.getParent().replaceStatement(ifparent, elsebranch);
- ifparent.getParent().setAllParent();
-
- return true;
- }
- }
- }
- }
- //}
- }
- }
- } else if (parent != null && parent.type == Statement.TYPE_SEQUENCE && stat.type == Statement.TYPE_BASICBLOCK && stat.getExprents().size() == 1) {
- Exprent exprent = stat.getExprents().get(0);
- if(exprent.type == Exprent.EXPRENT_EXIT) {
- ExitExprent exit_exprent = (ExitExprent)exprent;
- if(exit_exprent.getExittype() == ExitExprent.EXIT_RETURN) {
- Exprent exprent_value = exit_exprent.getValue();
-
- SequenceStatement sequence = (SequenceStatement)parent;
- int sequence_stats_number = sequence.getStats().size();
-
- if(sequence_stats_number > 1 && sequence.getStats().getLast() == stat && sequence.getStats().get(sequence_stats_number - 2).type == Statement.TYPE_IF) {
-
- IfStatement ifstat = (IfStatement)sequence.getStats().get(sequence_stats_number - 2);
- Exprent if_condition = ifstat.getHeadexprent().getCondition();
-
- if(ifstat.iftype == IfStatement.IFTYPE_IF && if_condition.type == Exprent.EXPRENT_FUNCTION &&
- ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory)
-
- FunctionExprent func = (FunctionExprent)if_condition;
- Exprent first_param = func.getLstOperands().get(0);
- Exprent second_param = func.getLstOperands().get(1);
-
- Statement ifbranch = ifstat.getIfstat();
-
- if(second_param.type == Exprent.EXPRENT_CONST && ((ConstExprent)second_param).getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order
- if(first_param.equals(exprent_value)) { // TODO: check for absence of side effects like method invocations etc.
- if(ifbranch.type == Statement.TYPE_BASICBLOCK && ifbranch.getExprents().size() == 1 && // TODO: special check for IllegalStateException
- ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
-
- ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0)); // remove 'else' edge
-
- if(!ifstat.getFirst().getExprents().isEmpty()) {
- stat.getExprents().addAll(0, ifstat.getFirst().getExprents());
- }
-
- for(StatEdge edge : ifstat.getAllPredecessorEdges()) {
-
- ifstat.removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, stat);
- stat.addPredecessor(edge);
- }
-
- sequence.getStats().removeWithKey(ifstat.id);
- sequence.setFirst(sequence.getStats().get(0));
-
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
-
-
- for(Statement st: stat.getStats()) {
- if(removeReturnCheck(st, mt)) {
- return true;
- }
- }
-
- return false;
- }
-
+
+ public static boolean removeHardcodedChecks(Statement root, StructMethod mt) {
+
+ boolean checks_removed = false;
+
+ // parameter @NotNull annotations
+ while (findAndRemoveParameterCheck(root, mt)) { // iterate until nothing found. Each invocation removes one parameter check.
+ checks_removed = true;
+ }
+
+ // method @NotNull annotation
+ while (findAndRemoveReturnCheck(root, mt)) { // iterate until nothing found. Each invocation handles one method exit check.
+ checks_removed = true;
+ }
+
+ return checks_removed;
+ }
+
+ private static boolean findAndRemoveParameterCheck(Statement stat, StructMethod mt) {
+
+ Statement st = stat.getFirst();
+ while (st.type == Statement.TYPE_SEQUENCE) {
+ st = st.getFirst();
+ }
+
+ if (st.type == Statement.TYPE_IF) {
+
+ IfStatement ifstat = (IfStatement)st;
+ Statement ifbranch = ifstat.getIfstat();
+
+ Exprent if_condition = ifstat.getHeadexprent().getCondition();
+
+ boolean is_notnull_check = false;
+
+ // TODO: FUNCTION_NE also possible if reversed order (in theory)
+ if (ifbranch != null &&
+ if_condition.type == Exprent.EXPRENT_FUNCTION &&
+ ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ &&
+ ifbranch.type == Statement.TYPE_BASICBLOCK &&
+ ifbranch.getExprents().size() == 1 &&
+ ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
+
+ FunctionExprent func = (FunctionExprent)if_condition;
+ Exprent first_param = func.getLstOperands().get(0);
+ Exprent second_param = func.getLstOperands().get(1);
+
+ if (second_param.type == Exprent.EXPRENT_CONST &&
+ ((ConstExprent)second_param).getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order
+ if (first_param.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)first_param;
+
+ boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+ VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();
+
+ // parameter annotations
+ StructAnnotationParameterAttribute param_annotations = (StructAnnotationParameterAttribute)attributes
+ .getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
+ if (param_annotations != null) {
+
+ List<List<AnnotationExprent>> param_annotations_lists = param_annotations.getParamAnnotations();
+ int method_param_number = md.params.length;
+
+ int index = thisvar ? 1 : 0;
+ for (int i = 0; i < method_param_number; i++) {
+
+ if (index == var.getIndex()) {
+ if (param_annotations_lists.size() >= method_param_number - i) {
+ int shift = method_param_number -
+ param_annotations_lists
+ .size(); // NOTE: workaround for compiler bug, count annotations starting with the last parameter
+
+ List<AnnotationExprent> annotations = param_annotations_lists.get(i - shift);
+
+ for (AnnotationExprent ann : annotations) {
+ if (ann.getClassname().equals("org/jetbrains/annotations/NotNull")) {
+ is_notnull_check = true;
+ }
+ }
+ }
+
+ break;
+ }
+
+ index += md.params[i].stack_size;
+ }
+ }
+ }
+ }
+ }
+
+ if (!is_notnull_check) {
+ return false;
+ }
+
+ removeParameterCheck(stat, mt);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private static void removeParameterCheck(Statement stat, StructMethod mt) {
+
+ Statement st = stat.getFirst();
+ while (st.type == Statement.TYPE_SEQUENCE) {
+ st = st.getFirst();
+ }
+
+ IfStatement ifstat = (IfStatement)st;
+
+ if (ifstat.getElsestat() == null) { // if
+ // TODO:
+ }
+ else { // if - else
+
+ StatEdge ifedge = ifstat.getIfEdge();
+ StatEdge elseedge = ifstat.getElseEdge();
+
+ Statement ifbranch = ifstat.getIfstat();
+ Statement elsebranch = ifstat.getElsestat();
+
+ ifstat.getFirst().removeSuccessor(ifedge);
+ ifstat.getFirst().removeSuccessor(elseedge);
+
+ ifstat.getStats().removeWithKey(ifbranch.id);
+ ifstat.getStats().removeWithKey(elsebranch.id);
+
+ if (!ifbranch.getAllSuccessorEdges().isEmpty()) {
+ ifbranch.removeSuccessor(ifbranch.getAllSuccessorEdges().get(0));
+ }
+
+ ifstat.getParent().replaceStatement(ifstat, elsebranch);
+ ifstat.getParent().setAllParent();
+ }
+ }
+
+ private static boolean findAndRemoveReturnCheck(Statement stat, StructMethod mt) {
+
+ VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();
+
+ boolean is_notnull_check = false;
+
+ // method annotation, refers to the return value
+ StructAnnotationAttribute attr =
+ (StructAnnotationAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS);
+ if (attr != null) {
+ List<AnnotationExprent> annotations = attr.getAnnotations();
+
+ for (AnnotationExprent ann : annotations) {
+ if (ann.getClassname().equals("org/jetbrains/annotations/NotNull")) {
+ is_notnull_check = true;
+ }
+ }
+ }
+
+ if (is_notnull_check) {
+ return removeReturnCheck(stat, mt);
+ }
+
+ return false;
+ }
+
+
+ private static boolean removeReturnCheck(Statement stat, StructMethod mt) {
+
+ Statement parent = stat.getParent();
+
+ if (parent != null && parent.type == Statement.TYPE_IF && stat.type == Statement.TYPE_BASICBLOCK && stat.getExprents().size() == 1) {
+ Exprent exprent = stat.getExprents().get(0);
+ if (exprent.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exit_exprent = (ExitExprent)exprent;
+ if (exit_exprent.getExittype() == ExitExprent.EXIT_RETURN) {
+ Exprent exprent_value = exit_exprent.getValue();
+ //if(exprent_value.type == Exprent.EXPRENT_VAR) {
+ // VarExprent var_value = (VarExprent)exprent_value;
+
+ IfStatement ifparent = (IfStatement)parent;
+ Exprent if_condition = ifparent.getHeadexprent().getCondition();
+
+ if (ifparent.getElsestat() == stat && if_condition.type == Exprent.EXPRENT_FUNCTION &&
+ ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory)
+
+ FunctionExprent func = (FunctionExprent)if_condition;
+ Exprent first_param = func.getLstOperands().get(0);
+ Exprent second_param = func.getLstOperands().get(1);
+
+ StatEdge ifedge = ifparent.getIfEdge();
+ StatEdge elseedge = ifparent.getElseEdge();
+
+ Statement ifbranch = ifparent.getIfstat();
+ Statement elsebranch = ifparent.getElsestat();
+
+ if (second_param.type == Exprent.EXPRENT_CONST &&
+ ((ConstExprent)second_param).getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order
+ //if(first_param.type == Exprent.EXPRENT_VAR && ((VarExprent)first_param).getIndex() == var_value.getIndex()) {
+ if (first_param.equals(exprent_value)) { // TODO: check for absence of side effects like method invocations etc.
+ if (ifbranch.type == Statement.TYPE_BASICBLOCK &&
+ ifbranch.getExprents().size() == 1 &&
+ // TODO: special check for IllegalStateException
+ ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
+
+ ifparent.getFirst().removeSuccessor(ifedge);
+ ifparent.getFirst().removeSuccessor(elseedge);
+
+ ifparent.getStats().removeWithKey(ifbranch.id);
+ ifparent.getStats().removeWithKey(elsebranch.id);
+
+ if (!ifbranch.getAllSuccessorEdges().isEmpty()) {
+ ifbranch.removeSuccessor(ifbranch.getAllSuccessorEdges().get(0));
+ }
+
+ if (!ifparent.getFirst().getExprents().isEmpty()) {
+ elsebranch.getExprents().addAll(0, ifparent.getFirst().getExprents());
+ }
+
+ ifparent.getParent().replaceStatement(ifparent, elsebranch);
+ ifparent.getParent().setAllParent();
+
+ return true;
+ }
+ }
+ }
+ }
+ //}
+ }
+ }
+ }
+ else if (parent != null &&
+ parent.type == Statement.TYPE_SEQUENCE &&
+ stat.type == Statement.TYPE_BASICBLOCK &&
+ stat.getExprents().size() == 1) {
+ Exprent exprent = stat.getExprents().get(0);
+ if (exprent.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exit_exprent = (ExitExprent)exprent;
+ if (exit_exprent.getExittype() == ExitExprent.EXIT_RETURN) {
+ Exprent exprent_value = exit_exprent.getValue();
+
+ SequenceStatement sequence = (SequenceStatement)parent;
+ int sequence_stats_number = sequence.getStats().size();
+
+ if (sequence_stats_number > 1 &&
+ sequence.getStats().getLast() == stat &&
+ sequence.getStats().get(sequence_stats_number - 2).type == Statement.TYPE_IF) {
+
+ IfStatement ifstat = (IfStatement)sequence.getStats().get(sequence_stats_number - 2);
+ Exprent if_condition = ifstat.getHeadexprent().getCondition();
+
+ if (ifstat.iftype == IfStatement.IFTYPE_IF && if_condition.type == Exprent.EXPRENT_FUNCTION &&
+ ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory)
+
+ FunctionExprent func = (FunctionExprent)if_condition;
+ Exprent first_param = func.getLstOperands().get(0);
+ Exprent second_param = func.getLstOperands().get(1);
+
+ Statement ifbranch = ifstat.getIfstat();
+
+ if (second_param.type == Exprent.EXPRENT_CONST &&
+ ((ConstExprent)second_param).getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order
+ if (first_param.equals(exprent_value)) { // TODO: check for absence of side effects like method invocations etc.
+ if (ifbranch.type == Statement.TYPE_BASICBLOCK &&
+ ifbranch.getExprents().size() == 1 &&
+ // TODO: special check for IllegalStateException
+ ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
+
+ ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0)); // remove 'else' edge
+
+ if (!ifstat.getFirst().getExprents().isEmpty()) {
+ stat.getExprents().addAll(0, ifstat.getFirst().getExprents());
+ }
+
+ for (StatEdge edge : ifstat.getAllPredecessorEdges()) {
+
+ ifstat.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, stat);
+ stat.addPredecessor(edge);
+ }
+
+ sequence.getStats().removeWithKey(ifstat.id);
+ sequence.setFirst(sequence.getStats().get(0));
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ for (Statement st : stat.getStats()) {
+ if (removeReturnCheck(st, mt)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java
index 6894f71..d5f4c9c 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java
@@ -1,24 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
@@ -27,705 +23,729 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
public class IfHelper {
-
- public static boolean mergeAllIfs(RootStatement root) {
-
- boolean res = mergeAllIfsRec(root, new HashSet<Integer>());
-
- if(res) {
- SequenceHelper.condenseSequences(root);
- }
-
- return res;
- }
-
-
- private static boolean mergeAllIfsRec(Statement stat, HashSet<Integer> setReorderedIfs) {
-
- boolean res = false;
-
- if(stat.getExprents() == null) {
-
- for(;;) {
-
- boolean changed = false;
-
- for(Statement st: stat.getStats()) {
-
- res |= mergeAllIfsRec(st, setReorderedIfs);
-
- // collapse composed if's
- if(changed = IfHelper.mergeIfs(st, setReorderedIfs)) {
- break;
- }
- }
-
- res |= changed;
-
- if(!changed) {
- break;
- }
- }
- }
-
- return res;
- }
-
-
- public static boolean mergeIfs(Statement statement, HashSet<Integer> setReorderedIfs) {
-
- if(statement.type != Statement.TYPE_IF && statement.type != Statement.TYPE_SEQUENCE) {
- return false;
- }
-
- boolean res = false;
-
- for(;;) {
-
- boolean updated = false;
-
- List<Statement> lst = new ArrayList<Statement>();
- if(statement.type == Statement.TYPE_IF) {
- lst.add(statement);
- } else {
- lst.addAll(statement.getStats());
- }
-
- boolean stsingle = (lst.size() == 1);
-
- for(Statement stat: lst) {
-
- if(stat.type == Statement.TYPE_IF) {
- IfNode rtnode = buildGraph((IfStatement)stat, stsingle);
-
- if(rtnode == null) {
- continue;
- }
-
- if(updated = collapseIfIf(rtnode)) {
- break;
- }
-
- if(!setReorderedIfs.contains(stat.id)) {
-
- if(updated = collapseIfElse(rtnode)) {
- break;
- }
-
- if(updated = collapseElse(rtnode)) {
- break;
- }
- }
-
- if(updated = reorderIf((IfStatement)stat)) {
- setReorderedIfs.add(stat.id);
- break;
- }
-
- }
- }
-
- if(!updated) {
- break;
- }
-
- res |= updated;
- }
-
- return res;
- }
-
- private static boolean collapseIfIf(IfNode rtnode) {
-
- if(rtnode.edgetypes.get(0) == 0) {
- IfNode ifbranch = rtnode.succs.get(0);
- if(ifbranch.succs.size() == 2) {
-
- // if-if branch
- if(ifbranch.succs.get(1).value == rtnode.succs.get(1).value) {
-
- IfStatement ifparent = (IfStatement)rtnode.value;
- IfStatement ifchild = (IfStatement)ifbranch.value;
- Statement ifinner = ifbranch.succs.get(0).value;
-
- if(ifchild.getFirst().getExprents().isEmpty()) {
-
- ifparent.getFirst().removeSuccessor(ifparent.getIfEdge());
- ifchild.removeSuccessor(ifchild.getAllSuccessorEdges().get(0));
- ifparent.getStats().removeWithKey(ifchild.id);
-
- if(ifbranch.edgetypes.get(0).intValue() == 1) { // target null
-
- ifparent.setIfstat(null);
-
- StatEdge ifedge = ifchild.getIfEdge();
-
- ifchild.getFirst().removeSuccessor(ifedge);
- ifedge.setSource(ifparent.getFirst());
-
- if(ifedge.closure == ifchild) {
- ifedge.closure = null;
- }
- ifparent.getFirst().addSuccessor(ifedge);
-
- ifparent.setIfEdge(ifedge);
- } else {
- ifchild.getFirst().removeSuccessor(ifchild.getIfEdge());
-
- StatEdge ifedge = new StatEdge(StatEdge.TYPE_REGULAR, ifparent.getFirst(), ifinner);
- ifparent.getFirst().addSuccessor(ifedge);
- ifparent.setIfEdge(ifedge);
- ifparent.setIfstat(ifinner);
-
- ifparent.getStats().addWithKey(ifinner, ifinner.id);
- ifinner.setParent(ifparent);
-
- if(!ifinner.getAllSuccessorEdges().isEmpty()) {
- StatEdge edge = ifinner.getAllSuccessorEdges().get(0);
- if(edge.closure == ifchild) {
- edge.closure = null;
- }
- }
- }
-
- // merge if conditions
- IfExprent statexpr = ifparent.getHeadexprent();
-
- List<Exprent> lstOperands = new ArrayList<Exprent>();
- lstOperands.add(statexpr.getCondition());
- lstOperands.add(ifchild.getHeadexprent().getCondition());
-
- statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands));
-
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
- private static boolean collapseIfElse(IfNode rtnode) {
-
- if(rtnode.edgetypes.get(0).intValue() == 0) {
- IfNode ifbranch = rtnode.succs.get(0);
- if(ifbranch.succs.size() == 2) {
-
- // if-else branch
- if(ifbranch.succs.get(0).value == rtnode.succs.get(1).value) {
-
- IfStatement ifparent = (IfStatement)rtnode.value;
- IfStatement ifchild = (IfStatement)ifbranch.value;
-
- if(ifchild.getFirst().getExprents().isEmpty()) {
-
- ifparent.getFirst().removeSuccessor(ifparent.getIfEdge());
- ifchild.getFirst().removeSuccessor(ifchild.getIfEdge());
- ifparent.getStats().removeWithKey(ifchild.id);
-
- if(ifbranch.edgetypes.get(1).intValue() == 1 &&
- ifbranch.edgetypes.get(0).intValue() == 1) { // target null
-
- ifparent.setIfstat(null);
-
- StatEdge ifedge = ifchild.getAllSuccessorEdges().get(0);
-
- ifchild.removeSuccessor(ifedge);
- ifedge.setSource(ifparent.getFirst());
- ifparent.getFirst().addSuccessor(ifedge);
-
- ifparent.setIfEdge(ifedge);
- } else {
- throw new RuntimeException("inconsistent if structure!");
- }
-
- // merge if conditions
- IfExprent statexpr = ifparent.getHeadexprent();
-
- List<Exprent> lstOperands = new ArrayList<Exprent>();
- lstOperands.add(statexpr.getCondition());
- lstOperands.add(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
- Arrays.asList(new Exprent[]{ifchild.getHeadexprent().getCondition()})));
- statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands));
-
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
-
- private static boolean collapseElse(IfNode rtnode) {
-
- if(rtnode.edgetypes.get(1).intValue() == 0) {
- IfNode elsebranch = rtnode.succs.get(1);
- if(elsebranch.succs.size() == 2) {
-
- // else-if or else-else branch
- int path = elsebranch.succs.get(1).value == rtnode.succs.get(0).value?2:
- (elsebranch.succs.get(0).value == rtnode.succs.get(0).value?1:0);
-
- if(path > 0) {
-
- IfStatement firstif = (IfStatement)rtnode.value;
- IfStatement secondif = (IfStatement)elsebranch.value;
- Statement parent = firstif.getParent();
-
- if(secondif.getFirst().getExprents().isEmpty()) {
-
- firstif.getFirst().removeSuccessor(firstif.getIfEdge());
-
- // remove first if
- firstif.removeAllSuccessors(secondif);
-
- for(StatEdge edge: firstif.getAllPredecessorEdges()) {
- if(!firstif.containsStatementStrict(edge.getSource())) {
- firstif.removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, secondif);
- secondif.addPredecessor(edge);
- }
- }
-
- parent.getStats().removeWithKey(firstif.id);
- if(parent.getFirst() == firstif) {
- parent.setFirst(secondif);
- }
-
- // merge if conditions
- IfExprent statexpr = secondif.getHeadexprent();
-
- List<Exprent> lstOperands = new ArrayList<Exprent>();
- lstOperands.add(firstif.getHeadexprent().getCondition());
-
- if(path == 2) {
- lstOperands.set(0, new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
- Arrays.asList(new Exprent[]{lstOperands.get(0)})));
- }
-
- lstOperands.add(statexpr.getCondition());
-
- statexpr.setCondition(new FunctionExprent(path==1?FunctionExprent.FUNCTION_COR:FunctionExprent.FUNCTION_CADD, lstOperands));
-
- if(secondif.getFirst().getExprents().isEmpty() &&
- !firstif.getFirst().getExprents().isEmpty()) {
-
- secondif.replaceStatement(secondif.getFirst(), firstif.getFirst());
- }
-
- return true;
- }
- }
- } else if(elsebranch.succs.size() == 1) {
-
- if(elsebranch.succs.get(0).value == rtnode.succs.get(0).value) {
-
- IfStatement firstif = (IfStatement)rtnode.value;
- Statement second = elsebranch.value;
-
- firstif.removeAllSuccessors(second);
-
- for(StatEdge edge : second.getAllSuccessorEdges()) {
- second.removeSuccessor(edge);
- edge.setSource(firstif);
- firstif.addSuccessor(edge);
- }
-
- StatEdge ifedge = firstif.getIfEdge();
- firstif.getFirst().removeSuccessor(ifedge);
-
- second.addSuccessor(new StatEdge(ifedge.getType(), second, ifedge.getDestination(), ifedge.closure));
-
- StatEdge newifedge = new StatEdge(StatEdge.TYPE_REGULAR, firstif.getFirst(), second);
- firstif.getFirst().addSuccessor(newifedge);
- firstif.setIfstat(second);
-
- firstif.getStats().addWithKey(second, second.id);
- second.setParent(firstif);
-
- firstif.getParent().getStats().removeWithKey(second.id);
-
- // negate the if condition
- IfExprent statexpr = firstif.getHeadexprent();
- statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[]{statexpr.getCondition()})));
-
- return true;
- }
-
- }
- }
-
- return false;
- }
-
-
- private static IfNode buildGraph(IfStatement stat, boolean stsingle) {
-
- if(stat.iftype == IfStatement.IFTYPE_IFELSE) {
- return null;
- }
-
- IfNode res = new IfNode(stat);
-
- // if branch
- Statement ifchild = stat.getIfstat();
- if(ifchild == null) {
- StatEdge edge = stat.getIfEdge();
- res.addChild(new IfNode(edge.getDestination()), 1);
- } else {
- IfNode ifnode = new IfNode(ifchild);
- res.addChild(ifnode, 0);
- if(ifchild.type == Statement.TYPE_IF && ((IfStatement)ifchild).iftype == IfStatement.IFTYPE_IF) {
- IfStatement stat2 = (IfStatement)ifchild;
- Statement ifchild2 = stat2.getIfstat();
- if(ifchild2 == null) {
- StatEdge edge = stat2.getIfEdge();
- ifnode.addChild(new IfNode(edge.getDestination()), 1);
- } else {
- ifnode.addChild(new IfNode(ifchild2), 0);
- }
- }
-
- if(!ifchild.getAllSuccessorEdges().isEmpty()) {
- ifnode.addChild(new IfNode(ifchild.getAllSuccessorEdges().get(0).getDestination()), 1);
- }
- }
-
- // else branch
- StatEdge edge = stat.getAllSuccessorEdges().get(0);
- Statement elsechild = edge.getDestination();
- IfNode elsenode = new IfNode(elsechild);
-
- if(stsingle || edge.getType() != StatEdge.TYPE_REGULAR) {
- res.addChild(elsenode, 1);
- } else {
- res.addChild(elsenode, 0);
- if(elsechild.type == Statement.TYPE_IF && ((IfStatement)elsechild).iftype == IfStatement.IFTYPE_IF) {
- IfStatement stat2 = (IfStatement)elsechild;
- Statement ifchild2 = stat2.getIfstat();
- if(ifchild2 == null) {
- elsenode.addChild(new IfNode(stat2.getIfEdge().getDestination()), 1);
- } else {
- elsenode.addChild(new IfNode(ifchild2), 0);
- }
- }
-
- if(!elsechild.getAllSuccessorEdges().isEmpty()) {
- elsenode.addChild(new IfNode(elsechild.getAllSuccessorEdges().get(0).getDestination()), 1);
- }
- }
-
- return res;
- }
-
-
- // FIXME: rewrite the entire method!!! keep in mind finally exits!!
- private static boolean reorderIf(IfStatement ifstat) {
-
- if(ifstat.iftype == IfStatement.IFTYPE_IFELSE) {
- return false;
- }
-
- boolean ifdirect = false, elsedirect = false;;
- boolean noifstat = false, noelsestat = false;
- boolean ifdirectpath = false, elsedirectpath = false;
-
- Statement parent = ifstat.getParent();
- Statement from = parent.type == Statement.TYPE_SEQUENCE?parent:ifstat;
-
- Statement next = getNextStatement(from);
-
- if(ifstat.getIfstat() == null) {
- noifstat = true;
-
- if(ifstat.getIfEdge().getType() == StatEdge.TYPE_FINALLYEXIT) {
- ifdirect = true;
- } else {
- ifdirect = MergeHelper.isDirectPath(from, ifstat.getIfEdge().getDestination());
- }
- } else {
- List<StatEdge> lstSuccs = ifstat.getIfstat().getAllSuccessorEdges();
- if(!lstSuccs.isEmpty() && lstSuccs.get(0).getType() == StatEdge.TYPE_FINALLYEXIT) {
- ifdirect = true;
- } else {
- ifdirect = hasDirectEndEdge(ifstat.getIfstat(), from);
- }
- }
-
- Statement last = parent.type == Statement.TYPE_SEQUENCE?((SequenceStatement)parent).getStats().getLast():ifstat;
- noelsestat = (last == ifstat);
-
- if(!last.getAllSuccessorEdges().isEmpty() && last.getAllSuccessorEdges().get(0).getType() == StatEdge.TYPE_FINALLYEXIT) {
- elsedirect = true;
- } else {
- elsedirect = hasDirectEndEdge(last, from);
- }
-
- if(!noelsestat && existsPath(ifstat, ifstat.getAllSuccessorEdges().get(0).getDestination())) {
- return false;
- }
-
- if(!ifdirect && !noifstat) {
- ifdirectpath = existsPath(ifstat, next);
- }
-
- if(!elsedirect && !noelsestat) {
- SequenceStatement sequence = (SequenceStatement)parent;
-
- for(int i=sequence.getStats().size()-1;i>=0;i--) {
- Statement sttemp = sequence.getStats().get(i);
- if(sttemp == ifstat) {
- break;
- } else {
- if(elsedirectpath = existsPath(sttemp, next)) {
- break;
- }
- }
- }
- }
-
- if((ifdirect || ifdirectpath) && (elsedirect || elsedirectpath) && !noifstat && !noelsestat) { // if - then - else
-
- SequenceStatement sequence = (SequenceStatement)parent;
-
- // build and cut the new else statement
- List<Statement> lst = new ArrayList<Statement>();
- for(int i=sequence.getStats().size()-1;i>=0;i--) {
- Statement sttemp = sequence.getStats().get(i);
- if(sttemp == ifstat) {
- break;
- } else {
- lst.add(0, sttemp);
- }
- }
-
- Statement stelse;
- if(lst.size() == 1) {
- stelse = lst.get(0);
- } else {
- stelse = new SequenceStatement(lst);
- stelse.setAllParent();
- }
-
- ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0));
- for(Statement st: lst) {
- sequence.getStats().removeWithKey(st.id);
- }
-
- StatEdge elseedge = new StatEdge(StatEdge.TYPE_REGULAR, ifstat.getFirst(), stelse);
- ifstat.getFirst().addSuccessor(elseedge);
- ifstat.setElsestat(stelse);
- ifstat.setElseEdge(elseedge);
-
- ifstat.getStats().addWithKey(stelse, stelse.id);
- stelse.setParent(ifstat);
-
-// if(next.type != Statement.TYPE_DUMMYEXIT && (ifdirect || elsedirect)) {
-// StatEdge breakedge = new StatEdge(StatEdge.TYPE_BREAK, ifstat, next);
-// sequence.addLabeledEdge(breakedge);
-// ifstat.addSuccessor(breakedge);
-// }
-
- ifstat.iftype = IfStatement.IFTYPE_IFELSE;
-
- } else if(ifdirect && (!elsedirect || (noifstat && !noelsestat))) { // if - then
-
- // negate the if condition
- IfExprent statexpr = ifstat.getHeadexprent();
- statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[]{statexpr.getCondition()})));
-
- if(noelsestat) {
- StatEdge ifedge = ifstat.getIfEdge();
- StatEdge elseedge = ifstat.getAllSuccessorEdges().get(0);
-
- if(noifstat) {
- ifstat.getFirst().removeSuccessor(ifedge);
- ifstat.removeSuccessor(elseedge);
-
- ifedge.setSource(ifstat);
- elseedge.setSource(ifstat.getFirst());
-
- ifstat.addSuccessor(ifedge);
- ifstat.getFirst().addSuccessor(elseedge);
-
- ifstat.setIfEdge(elseedge);
- } else {
- Statement ifbranch = ifstat.getIfstat();
- SequenceStatement newseq = new SequenceStatement(Arrays.asList(new Statement[] {ifstat, ifbranch}));
-
- ifstat.getFirst().removeSuccessor(ifedge);
- ifstat.getStats().removeWithKey(ifbranch.id);
- ifstat.setIfstat(null);
-
- ifstat.removeSuccessor(elseedge);
- elseedge.setSource(ifstat.getFirst());
- ifstat.getFirst().addSuccessor(elseedge);
-
- ifstat.setIfEdge(elseedge);
-
- ifstat.getParent().replaceStatement(ifstat, newseq);
- newseq.setAllParent();
-
- ifstat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, ifstat, ifbranch));
- }
- } else {
-
- SequenceStatement sequence = (SequenceStatement)parent;
-
- // build and cut the new else statement
- List<Statement> lst = new ArrayList<Statement>();
- for(int i=sequence.getStats().size()-1;i>=0;i--) {
- Statement sttemp = sequence.getStats().get(i);
- if(sttemp == ifstat) {
- break;
- } else {
- lst.add(0, sttemp);
- }
- }
-
- Statement stelse;
- if(lst.size() == 1) {
- stelse = lst.get(0);
- } else {
- stelse = new SequenceStatement(lst);
- stelse.setAllParent();
- }
-
- ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0));
- for(Statement st: lst) {
- sequence.getStats().removeWithKey(st.id);
- }
-
- if(noifstat) {
- StatEdge ifedge = ifstat.getIfEdge();
-
- ifstat.getFirst().removeSuccessor(ifedge);
- ifedge.setSource(ifstat);
- ifstat.addSuccessor(ifedge);
- } else {
- Statement ifbranch = ifstat.getIfstat();
-
- ifstat.getFirst().removeSuccessor(ifstat.getIfEdge());
- ifstat.getStats().removeWithKey(ifbranch.id);
-
- ifstat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, ifstat, ifbranch));
-
- sequence.getStats().addWithKey(ifbranch, ifbranch.id);
- ifbranch.setParent(sequence);
- }
-
- StatEdge newifedge = new StatEdge(StatEdge.TYPE_REGULAR, ifstat.getFirst(), stelse);
- ifstat.getFirst().addSuccessor(newifedge);
- ifstat.setIfstat(stelse);
- ifstat.setIfEdge(newifedge);
-
- ifstat.getStats().addWithKey(stelse, stelse.id);
- stelse.setParent(ifstat);
-
- }
- } else {
- return false;
- }
-
- return true;
- }
-
- private static boolean hasDirectEndEdge(Statement stat, Statement from) {
-
- for(StatEdge edge: stat.getAllSuccessorEdges()) {
- if(MergeHelper.isDirectPath(from, edge.getDestination())) {
- return true;
- }
- }
-
- if(stat.getExprents() == null) {
- switch(stat.type) {
- case Statement.TYPE_SEQUENCE:
- return hasDirectEndEdge(stat.getStats().getLast(), from);
- case Statement.TYPE_CATCHALL:
- case Statement.TYPE_TRYCATCH:
- for(Statement st: stat.getStats()) {
- if(hasDirectEndEdge(st, from)) {
- return true;
- }
- }
- break;
- case Statement.TYPE_IF:
- IfStatement ifstat = (IfStatement)stat;
- if(ifstat.iftype == IfStatement.IFTYPE_IFELSE) {
- return hasDirectEndEdge(ifstat.getIfstat(), from) ||
- hasDirectEndEdge(ifstat.getElsestat(), from);
- }
- break;
- case Statement.TYPE_SYNCRONIZED:
- return hasDirectEndEdge(stat.getStats().get(1), from);
- case Statement.TYPE_SWITCH:
- for(Statement st: stat.getStats()) {
- if(hasDirectEndEdge(st, from)) {
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
-
- private static Statement getNextStatement(Statement stat) {
-
- Statement parent = stat.getParent();
- switch(parent.type) {
- case Statement.TYPE_ROOT:
- return ((RootStatement)parent).getDummyExit();
- case Statement.TYPE_DO:
- return parent;
- case Statement.TYPE_SEQUENCE:
- SequenceStatement sequence = (SequenceStatement)parent;
- if(sequence.getStats().getLast() != stat) {
- for(int i=sequence.getStats().size()-1;i>=0;i--) {
- if(sequence.getStats().get(i) == stat) {
- return sequence.getStats().get(i+1);
- }
- }
- }
- }
-
- return getNextStatement(parent);
- }
-
- private static boolean existsPath(Statement from, Statement to) {
-
- for(StatEdge edge: to.getAllPredecessorEdges()) {
- if(from.containsStatementStrict(edge.getSource())) {
- return true;
- }
- }
-
- return false;
- }
-
- private static class IfNode {
- public Statement value;
-
- public List<IfNode> succs = new ArrayList<IfNode>();
- public List<Integer> edgetypes = new ArrayList<Integer>();
-
- public IfNode(Statement value) {
- this.value = value;
- }
-
- public void addChild(IfNode child, int type) {
- succs.add(child);
- edgetypes.add(new Integer(type));
- }
- }
-
-
+
+ public static boolean mergeAllIfs(RootStatement root) {
+
+ boolean res = mergeAllIfsRec(root, new HashSet<Integer>());
+
+ if (res) {
+ SequenceHelper.condenseSequences(root);
+ }
+
+ return res;
+ }
+
+
+ private static boolean mergeAllIfsRec(Statement stat, HashSet<Integer> setReorderedIfs) {
+
+ boolean res = false;
+
+ if (stat.getExprents() == null) {
+
+ for (; ; ) {
+
+ boolean changed = false;
+
+ for (Statement st : stat.getStats()) {
+
+ res |= mergeAllIfsRec(st, setReorderedIfs);
+
+ // collapse composed if's
+ if (changed = IfHelper.mergeIfs(st, setReorderedIfs)) {
+ break;
+ }
+ }
+
+ res |= changed;
+
+ if (!changed) {
+ break;
+ }
+ }
+ }
+
+ return res;
+ }
+
+
+ public static boolean mergeIfs(Statement statement, HashSet<Integer> setReorderedIfs) {
+
+ if (statement.type != Statement.TYPE_IF && statement.type != Statement.TYPE_SEQUENCE) {
+ return false;
+ }
+
+ boolean res = false;
+
+ for (; ; ) {
+
+ boolean updated = false;
+
+ List<Statement> lst = new ArrayList<Statement>();
+ if (statement.type == Statement.TYPE_IF) {
+ lst.add(statement);
+ }
+ else {
+ lst.addAll(statement.getStats());
+ }
+
+ boolean stsingle = (lst.size() == 1);
+
+ for (Statement stat : lst) {
+
+ if (stat.type == Statement.TYPE_IF) {
+ IfNode rtnode = buildGraph((IfStatement)stat, stsingle);
+
+ if (rtnode == null) {
+ continue;
+ }
+
+ if (updated = collapseIfIf(rtnode)) {
+ break;
+ }
+
+ if (!setReorderedIfs.contains(stat.id)) {
+
+ if (updated = collapseIfElse(rtnode)) {
+ break;
+ }
+
+ if (updated = collapseElse(rtnode)) {
+ break;
+ }
+ }
+
+ if (updated = reorderIf((IfStatement)stat)) {
+ setReorderedIfs.add(stat.id);
+ break;
+ }
+ }
+ }
+
+ if (!updated) {
+ break;
+ }
+
+ res |= updated;
+ }
+
+ return res;
+ }
+
+ private static boolean collapseIfIf(IfNode rtnode) {
+
+ if (rtnode.edgetypes.get(0) == 0) {
+ IfNode ifbranch = rtnode.succs.get(0);
+ if (ifbranch.succs.size() == 2) {
+
+ // if-if branch
+ if (ifbranch.succs.get(1).value == rtnode.succs.get(1).value) {
+
+ IfStatement ifparent = (IfStatement)rtnode.value;
+ IfStatement ifchild = (IfStatement)ifbranch.value;
+ Statement ifinner = ifbranch.succs.get(0).value;
+
+ if (ifchild.getFirst().getExprents().isEmpty()) {
+
+ ifparent.getFirst().removeSuccessor(ifparent.getIfEdge());
+ ifchild.removeSuccessor(ifchild.getAllSuccessorEdges().get(0));
+ ifparent.getStats().removeWithKey(ifchild.id);
+
+ if (ifbranch.edgetypes.get(0).intValue() == 1) { // target null
+
+ ifparent.setIfstat(null);
+
+ StatEdge ifedge = ifchild.getIfEdge();
+
+ ifchild.getFirst().removeSuccessor(ifedge);
+ ifedge.setSource(ifparent.getFirst());
+
+ if (ifedge.closure == ifchild) {
+ ifedge.closure = null;
+ }
+ ifparent.getFirst().addSuccessor(ifedge);
+
+ ifparent.setIfEdge(ifedge);
+ }
+ else {
+ ifchild.getFirst().removeSuccessor(ifchild.getIfEdge());
+
+ StatEdge ifedge = new StatEdge(StatEdge.TYPE_REGULAR, ifparent.getFirst(), ifinner);
+ ifparent.getFirst().addSuccessor(ifedge);
+ ifparent.setIfEdge(ifedge);
+ ifparent.setIfstat(ifinner);
+
+ ifparent.getStats().addWithKey(ifinner, ifinner.id);
+ ifinner.setParent(ifparent);
+
+ if (!ifinner.getAllSuccessorEdges().isEmpty()) {
+ StatEdge edge = ifinner.getAllSuccessorEdges().get(0);
+ if (edge.closure == ifchild) {
+ edge.closure = null;
+ }
+ }
+ }
+
+ // merge if conditions
+ IfExprent statexpr = ifparent.getHeadexprent();
+
+ List<Exprent> lstOperands = new ArrayList<Exprent>();
+ lstOperands.add(statexpr.getCondition());
+ lstOperands.add(ifchild.getHeadexprent().getCondition());
+
+ statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands));
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean collapseIfElse(IfNode rtnode) {
+
+ if (rtnode.edgetypes.get(0).intValue() == 0) {
+ IfNode ifbranch = rtnode.succs.get(0);
+ if (ifbranch.succs.size() == 2) {
+
+ // if-else branch
+ if (ifbranch.succs.get(0).value == rtnode.succs.get(1).value) {
+
+ IfStatement ifparent = (IfStatement)rtnode.value;
+ IfStatement ifchild = (IfStatement)ifbranch.value;
+
+ if (ifchild.getFirst().getExprents().isEmpty()) {
+
+ ifparent.getFirst().removeSuccessor(ifparent.getIfEdge());
+ ifchild.getFirst().removeSuccessor(ifchild.getIfEdge());
+ ifparent.getStats().removeWithKey(ifchild.id);
+
+ if (ifbranch.edgetypes.get(1).intValue() == 1 &&
+ ifbranch.edgetypes.get(0).intValue() == 1) { // target null
+
+ ifparent.setIfstat(null);
+
+ StatEdge ifedge = ifchild.getAllSuccessorEdges().get(0);
+
+ ifchild.removeSuccessor(ifedge);
+ ifedge.setSource(ifparent.getFirst());
+ ifparent.getFirst().addSuccessor(ifedge);
+
+ ifparent.setIfEdge(ifedge);
+ }
+ else {
+ throw new RuntimeException("inconsistent if structure!");
+ }
+
+ // merge if conditions
+ IfExprent statexpr = ifparent.getHeadexprent();
+
+ List<Exprent> lstOperands = new ArrayList<Exprent>();
+ lstOperands.add(statexpr.getCondition());
+ lstOperands.add(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
+ Arrays.asList(new Exprent[]{ifchild.getHeadexprent().getCondition()})));
+ statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands));
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static boolean collapseElse(IfNode rtnode) {
+
+ if (rtnode.edgetypes.get(1).intValue() == 0) {
+ IfNode elsebranch = rtnode.succs.get(1);
+ if (elsebranch.succs.size() == 2) {
+
+ // else-if or else-else branch
+ int path = elsebranch.succs.get(1).value == rtnode.succs.get(0).value ? 2 :
+ (elsebranch.succs.get(0).value == rtnode.succs.get(0).value ? 1 : 0);
+
+ if (path > 0) {
+
+ IfStatement firstif = (IfStatement)rtnode.value;
+ IfStatement secondif = (IfStatement)elsebranch.value;
+ Statement parent = firstif.getParent();
+
+ if (secondif.getFirst().getExprents().isEmpty()) {
+
+ firstif.getFirst().removeSuccessor(firstif.getIfEdge());
+
+ // remove first if
+ firstif.removeAllSuccessors(secondif);
+
+ for (StatEdge edge : firstif.getAllPredecessorEdges()) {
+ if (!firstif.containsStatementStrict(edge.getSource())) {
+ firstif.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, secondif);
+ secondif.addPredecessor(edge);
+ }
+ }
+
+ parent.getStats().removeWithKey(firstif.id);
+ if (parent.getFirst() == firstif) {
+ parent.setFirst(secondif);
+ }
+
+ // merge if conditions
+ IfExprent statexpr = secondif.getHeadexprent();
+
+ List<Exprent> lstOperands = new ArrayList<Exprent>();
+ lstOperands.add(firstif.getHeadexprent().getCondition());
+
+ if (path == 2) {
+ lstOperands.set(0, new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
+ Arrays.asList(new Exprent[]{lstOperands.get(0)})));
+ }
+
+ lstOperands.add(statexpr.getCondition());
+
+ statexpr
+ .setCondition(new FunctionExprent(path == 1 ? FunctionExprent.FUNCTION_COR : FunctionExprent.FUNCTION_CADD, lstOperands));
+
+ if (secondif.getFirst().getExprents().isEmpty() &&
+ !firstif.getFirst().getExprents().isEmpty()) {
+
+ secondif.replaceStatement(secondif.getFirst(), firstif.getFirst());
+ }
+
+ return true;
+ }
+ }
+ }
+ else if (elsebranch.succs.size() == 1) {
+
+ if (elsebranch.succs.get(0).value == rtnode.succs.get(0).value) {
+
+ IfStatement firstif = (IfStatement)rtnode.value;
+ Statement second = elsebranch.value;
+
+ firstif.removeAllSuccessors(second);
+
+ for (StatEdge edge : second.getAllSuccessorEdges()) {
+ second.removeSuccessor(edge);
+ edge.setSource(firstif);
+ firstif.addSuccessor(edge);
+ }
+
+ StatEdge ifedge = firstif.getIfEdge();
+ firstif.getFirst().removeSuccessor(ifedge);
+
+ second.addSuccessor(new StatEdge(ifedge.getType(), second, ifedge.getDestination(), ifedge.closure));
+
+ StatEdge newifedge = new StatEdge(StatEdge.TYPE_REGULAR, firstif.getFirst(), second);
+ firstif.getFirst().addSuccessor(newifedge);
+ firstif.setIfstat(second);
+
+ firstif.getStats().addWithKey(second, second.id);
+ second.setParent(firstif);
+
+ firstif.getParent().getStats().removeWithKey(second.id);
+
+ // negate the if condition
+ IfExprent statexpr = firstif.getHeadexprent();
+ statexpr
+ .setCondition(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[]{statexpr.getCondition()})));
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static IfNode buildGraph(IfStatement stat, boolean stsingle) {
+
+ if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
+ return null;
+ }
+
+ IfNode res = new IfNode(stat);
+
+ // if branch
+ Statement ifchild = stat.getIfstat();
+ if (ifchild == null) {
+ StatEdge edge = stat.getIfEdge();
+ res.addChild(new IfNode(edge.getDestination()), 1);
+ }
+ else {
+ IfNode ifnode = new IfNode(ifchild);
+ res.addChild(ifnode, 0);
+ if (ifchild.type == Statement.TYPE_IF && ((IfStatement)ifchild).iftype == IfStatement.IFTYPE_IF) {
+ IfStatement stat2 = (IfStatement)ifchild;
+ Statement ifchild2 = stat2.getIfstat();
+ if (ifchild2 == null) {
+ StatEdge edge = stat2.getIfEdge();
+ ifnode.addChild(new IfNode(edge.getDestination()), 1);
+ }
+ else {
+ ifnode.addChild(new IfNode(ifchild2), 0);
+ }
+ }
+
+ if (!ifchild.getAllSuccessorEdges().isEmpty()) {
+ ifnode.addChild(new IfNode(ifchild.getAllSuccessorEdges().get(0).getDestination()), 1);
+ }
+ }
+
+ // else branch
+ StatEdge edge = stat.getAllSuccessorEdges().get(0);
+ Statement elsechild = edge.getDestination();
+ IfNode elsenode = new IfNode(elsechild);
+
+ if (stsingle || edge.getType() != StatEdge.TYPE_REGULAR) {
+ res.addChild(elsenode, 1);
+ }
+ else {
+ res.addChild(elsenode, 0);
+ if (elsechild.type == Statement.TYPE_IF && ((IfStatement)elsechild).iftype == IfStatement.IFTYPE_IF) {
+ IfStatement stat2 = (IfStatement)elsechild;
+ Statement ifchild2 = stat2.getIfstat();
+ if (ifchild2 == null) {
+ elsenode.addChild(new IfNode(stat2.getIfEdge().getDestination()), 1);
+ }
+ else {
+ elsenode.addChild(new IfNode(ifchild2), 0);
+ }
+ }
+
+ if (!elsechild.getAllSuccessorEdges().isEmpty()) {
+ elsenode.addChild(new IfNode(elsechild.getAllSuccessorEdges().get(0).getDestination()), 1);
+ }
+ }
+
+ return res;
+ }
+
+
+ // FIXME: rewrite the entire method!!! keep in mind finally exits!!
+ private static boolean reorderIf(IfStatement ifstat) {
+
+ if (ifstat.iftype == IfStatement.IFTYPE_IFELSE) {
+ return false;
+ }
+
+ boolean ifdirect = false, elsedirect = false;
+ ;
+ boolean noifstat = false, noelsestat = false;
+ boolean ifdirectpath = false, elsedirectpath = false;
+
+ Statement parent = ifstat.getParent();
+ Statement from = parent.type == Statement.TYPE_SEQUENCE ? parent : ifstat;
+
+ Statement next = getNextStatement(from);
+
+ if (ifstat.getIfstat() == null) {
+ noifstat = true;
+
+ if (ifstat.getIfEdge().getType() == StatEdge.TYPE_FINALLYEXIT) {
+ ifdirect = true;
+ }
+ else {
+ ifdirect = MergeHelper.isDirectPath(from, ifstat.getIfEdge().getDestination());
+ }
+ }
+ else {
+ List<StatEdge> lstSuccs = ifstat.getIfstat().getAllSuccessorEdges();
+ if (!lstSuccs.isEmpty() && lstSuccs.get(0).getType() == StatEdge.TYPE_FINALLYEXIT) {
+ ifdirect = true;
+ }
+ else {
+ ifdirect = hasDirectEndEdge(ifstat.getIfstat(), from);
+ }
+ }
+
+ Statement last = parent.type == Statement.TYPE_SEQUENCE ? ((SequenceStatement)parent).getStats().getLast() : ifstat;
+ noelsestat = (last == ifstat);
+
+ if (!last.getAllSuccessorEdges().isEmpty() && last.getAllSuccessorEdges().get(0).getType() == StatEdge.TYPE_FINALLYEXIT) {
+ elsedirect = true;
+ }
+ else {
+ elsedirect = hasDirectEndEdge(last, from);
+ }
+
+ if (!noelsestat && existsPath(ifstat, ifstat.getAllSuccessorEdges().get(0).getDestination())) {
+ return false;
+ }
+
+ if (!ifdirect && !noifstat) {
+ ifdirectpath = existsPath(ifstat, next);
+ }
+
+ if (!elsedirect && !noelsestat) {
+ SequenceStatement sequence = (SequenceStatement)parent;
+
+ for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
+ Statement sttemp = sequence.getStats().get(i);
+ if (sttemp == ifstat) {
+ break;
+ }
+ else {
+ if (elsedirectpath = existsPath(sttemp, next)) {
+ break;
+ }
+ }
+ }
+ }
+
+ if ((ifdirect || ifdirectpath) && (elsedirect || elsedirectpath) && !noifstat && !noelsestat) { // if - then - else
+
+ SequenceStatement sequence = (SequenceStatement)parent;
+
+ // build and cut the new else statement
+ List<Statement> lst = new ArrayList<Statement>();
+ for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
+ Statement sttemp = sequence.getStats().get(i);
+ if (sttemp == ifstat) {
+ break;
+ }
+ else {
+ lst.add(0, sttemp);
+ }
+ }
+
+ Statement stelse;
+ if (lst.size() == 1) {
+ stelse = lst.get(0);
+ }
+ else {
+ stelse = new SequenceStatement(lst);
+ stelse.setAllParent();
+ }
+
+ ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0));
+ for (Statement st : lst) {
+ sequence.getStats().removeWithKey(st.id);
+ }
+
+ StatEdge elseedge = new StatEdge(StatEdge.TYPE_REGULAR, ifstat.getFirst(), stelse);
+ ifstat.getFirst().addSuccessor(elseedge);
+ ifstat.setElsestat(stelse);
+ ifstat.setElseEdge(elseedge);
+
+ ifstat.getStats().addWithKey(stelse, stelse.id);
+ stelse.setParent(ifstat);
+
+ // if(next.type != Statement.TYPE_DUMMYEXIT && (ifdirect || elsedirect)) {
+ // StatEdge breakedge = new StatEdge(StatEdge.TYPE_BREAK, ifstat, next);
+ // sequence.addLabeledEdge(breakedge);
+ // ifstat.addSuccessor(breakedge);
+ // }
+
+ ifstat.iftype = IfStatement.IFTYPE_IFELSE;
+ }
+ else if (ifdirect && (!elsedirect || (noifstat && !noelsestat))) { // if - then
+
+ // negate the if condition
+ IfExprent statexpr = ifstat.getHeadexprent();
+ statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[]{statexpr.getCondition()})));
+
+ if (noelsestat) {
+ StatEdge ifedge = ifstat.getIfEdge();
+ StatEdge elseedge = ifstat.getAllSuccessorEdges().get(0);
+
+ if (noifstat) {
+ ifstat.getFirst().removeSuccessor(ifedge);
+ ifstat.removeSuccessor(elseedge);
+
+ ifedge.setSource(ifstat);
+ elseedge.setSource(ifstat.getFirst());
+
+ ifstat.addSuccessor(ifedge);
+ ifstat.getFirst().addSuccessor(elseedge);
+
+ ifstat.setIfEdge(elseedge);
+ }
+ else {
+ Statement ifbranch = ifstat.getIfstat();
+ SequenceStatement newseq = new SequenceStatement(Arrays.asList(new Statement[]{ifstat, ifbranch}));
+
+ ifstat.getFirst().removeSuccessor(ifedge);
+ ifstat.getStats().removeWithKey(ifbranch.id);
+ ifstat.setIfstat(null);
+
+ ifstat.removeSuccessor(elseedge);
+ elseedge.setSource(ifstat.getFirst());
+ ifstat.getFirst().addSuccessor(elseedge);
+
+ ifstat.setIfEdge(elseedge);
+
+ ifstat.getParent().replaceStatement(ifstat, newseq);
+ newseq.setAllParent();
+
+ ifstat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, ifstat, ifbranch));
+ }
+ }
+ else {
+
+ SequenceStatement sequence = (SequenceStatement)parent;
+
+ // build and cut the new else statement
+ List<Statement> lst = new ArrayList<Statement>();
+ for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
+ Statement sttemp = sequence.getStats().get(i);
+ if (sttemp == ifstat) {
+ break;
+ }
+ else {
+ lst.add(0, sttemp);
+ }
+ }
+
+ Statement stelse;
+ if (lst.size() == 1) {
+ stelse = lst.get(0);
+ }
+ else {
+ stelse = new SequenceStatement(lst);
+ stelse.setAllParent();
+ }
+
+ ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0));
+ for (Statement st : lst) {
+ sequence.getStats().removeWithKey(st.id);
+ }
+
+ if (noifstat) {
+ StatEdge ifedge = ifstat.getIfEdge();
+
+ ifstat.getFirst().removeSuccessor(ifedge);
+ ifedge.setSource(ifstat);
+ ifstat.addSuccessor(ifedge);
+ }
+ else {
+ Statement ifbranch = ifstat.getIfstat();
+
+ ifstat.getFirst().removeSuccessor(ifstat.getIfEdge());
+ ifstat.getStats().removeWithKey(ifbranch.id);
+
+ ifstat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, ifstat, ifbranch));
+
+ sequence.getStats().addWithKey(ifbranch, ifbranch.id);
+ ifbranch.setParent(sequence);
+ }
+
+ StatEdge newifedge = new StatEdge(StatEdge.TYPE_REGULAR, ifstat.getFirst(), stelse);
+ ifstat.getFirst().addSuccessor(newifedge);
+ ifstat.setIfstat(stelse);
+ ifstat.setIfEdge(newifedge);
+
+ ifstat.getStats().addWithKey(stelse, stelse.id);
+ stelse.setParent(ifstat);
+ }
+ }
+ else {
+ return false;
+ }
+
+ return true;
+ }
+
+ private static boolean hasDirectEndEdge(Statement stat, Statement from) {
+
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ if (MergeHelper.isDirectPath(from, edge.getDestination())) {
+ return true;
+ }
+ }
+
+ if (stat.getExprents() == null) {
+ switch (stat.type) {
+ case Statement.TYPE_SEQUENCE:
+ return hasDirectEndEdge(stat.getStats().getLast(), from);
+ case Statement.TYPE_CATCHALL:
+ case Statement.TYPE_TRYCATCH:
+ for (Statement st : stat.getStats()) {
+ if (hasDirectEndEdge(st, from)) {
+ return true;
+ }
+ }
+ break;
+ case Statement.TYPE_IF:
+ IfStatement ifstat = (IfStatement)stat;
+ if (ifstat.iftype == IfStatement.IFTYPE_IFELSE) {
+ return hasDirectEndEdge(ifstat.getIfstat(), from) ||
+ hasDirectEndEdge(ifstat.getElsestat(), from);
+ }
+ break;
+ case Statement.TYPE_SYNCRONIZED:
+ return hasDirectEndEdge(stat.getStats().get(1), from);
+ case Statement.TYPE_SWITCH:
+ for (Statement st : stat.getStats()) {
+ if (hasDirectEndEdge(st, from)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static Statement getNextStatement(Statement stat) {
+
+ Statement parent = stat.getParent();
+ switch (parent.type) {
+ case Statement.TYPE_ROOT:
+ return ((RootStatement)parent).getDummyExit();
+ case Statement.TYPE_DO:
+ return parent;
+ case Statement.TYPE_SEQUENCE:
+ SequenceStatement sequence = (SequenceStatement)parent;
+ if (sequence.getStats().getLast() != stat) {
+ for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
+ if (sequence.getStats().get(i) == stat) {
+ return sequence.getStats().get(i + 1);
+ }
+ }
+ }
+ }
+
+ return getNextStatement(parent);
+ }
+
+ private static boolean existsPath(Statement from, Statement to) {
+
+ for (StatEdge edge : to.getAllPredecessorEdges()) {
+ if (from.containsStatementStrict(edge.getSource())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static class IfNode {
+ public Statement value;
+
+ public List<IfNode> succs = new ArrayList<IfNode>();
+ public List<Integer> edgetypes = new ArrayList<Integer>();
+
+ public IfNode(Statement value) {
+ this.value = value;
+ }
+
+ public void addChild(IfNode child, int type) {
+ succs.add(child);
+ edgetypes.add(new Integer(type));
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java
index 3fe181a..b9ffb8f 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java
@@ -1,223 +1,220 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SwitchStatement;
-
public class InlineSingleBlockHelper {
-
-
- public static boolean inlineSingleBlocks(RootStatement root) {
-
- boolean res = inlineSingleBlocksRec(root);
-
- if(res) {
- SequenceHelper.condenseSequences(root);
- }
-
- return res;
- }
-
- private static boolean inlineSingleBlocksRec(Statement stat) {
-
- boolean res = false;
-
- for(Statement st : stat.getStats()) {
- res |= inlineSingleBlocksRec(st);
- }
-
- if(stat.type == Statement.TYPE_SEQUENCE) {
-
- SequenceStatement seq = (SequenceStatement)stat;
- for(int i=1;i<seq.getStats().size();i++) {
- if(isInlineable(seq, i)) {
- inlineBlock(seq, i);
- return true;
- }
- }
- }
-
- return res;
- }
-
- private static void inlineBlock(SequenceStatement seq, int index) {
-
- Statement first = seq.getStats().get(index);
- Statement pre = seq.getStats().get(index-1);
- pre.removeSuccessor(pre.getAllSuccessorEdges().get(0)); // single regular edge
-
- StatEdge edge = first.getPredecessorEdges(StatEdge.TYPE_BREAK).get(0);
- Statement source = edge.getSource();
- Statement parent = source.getParent();
- source.removeSuccessor(edge);
-
- List<Statement> lst = new ArrayList<Statement>();
- for(int i=seq.getStats().size()-1;i>=index;i--) {
- lst.add(0, seq.getStats().remove(i));
- }
-
- if(parent.type == Statement.TYPE_IF && ((IfStatement)parent).iftype == IfStatement.IFTYPE_IF &&
- source == parent.getFirst()) {
- IfStatement ifparent = (IfStatement)parent;
- SequenceStatement block = new SequenceStatement(lst);
- block.setAllParent();
-
- StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, source, block);
- source.addSuccessor(newedge);
- ifparent.setIfEdge(newedge);
- ifparent.setIfstat(block);
-
- ifparent.getStats().addWithKey(block, block.id);
- block.setParent(ifparent);
-
- } else {
- lst.add(0, source);
-
- SequenceStatement block = new SequenceStatement(lst);
- block.setAllParent();
-
- parent.replaceStatement(source, block);
-
- // LabelHelper.lowContinueLabels not applicable because of forward continue edges
- // LabelHelper.lowContinueLabels(block, new HashSet<StatEdge>());
- // do it by hand
- for(StatEdge prededge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
-
- block.removePredecessor(prededge);
- prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, source);
- source.addPredecessor(prededge);
-
- source.addLabeledEdge(prededge);
- }
-
-
- if(parent.type == Statement.TYPE_SWITCH) {
- ((SwitchStatement)parent).sortEdgesAndNodes();
- }
-
- source.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, source, first));
- }
-
- }
-
- private static boolean isInlineable(SequenceStatement seq, int index) {
-
- Statement first = seq.getStats().get(index);
- Statement pre = seq.getStats().get(index-1);
-
- if(pre.hasBasicSuccEdge()) {
- return false;
- }
-
-
- List<StatEdge> lst = first.getPredecessorEdges(StatEdge.TYPE_BREAK);
-
- if(lst.size() == 1) {
- StatEdge edge = lst.get(0);
-
- if(sameCatchRanges(edge)) {
- if(edge.explicit) {
- return true;
- } else {
- for(int i=index;i<seq.getStats().size();i++) {
- if(!noExitLabels(seq.getStats().get(i), seq)) {
- return false;
- }
- }
- return true;
- }
- }
- // FIXME: count labels properly
- }
-
- return false;
- }
-
- private static boolean sameCatchRanges(StatEdge edge) {
-
- Statement from = edge.getSource();
- Statement to = edge.getDestination();
-
- for(;;) {
-
- Statement parent = from.getParent();
- if(parent.containsStatementStrict(to)) {
- break;
- }
-
- if(parent.type == Statement.TYPE_TRYCATCH ||
- parent.type == Statement.TYPE_CATCHALL) {
- if(parent.getFirst() == from) {
- return false;
- }
- } else if(parent.type == Statement.TYPE_SYNCRONIZED) {
- if(parent.getStats().get(1) == from) {
- return false;
- }
- }
-
- from = parent;
- }
-
- return true;
- }
-
- private static boolean noExitLabels(Statement block, Statement sequence) {
-
- for(StatEdge edge : block.getAllSuccessorEdges()) {
- if(edge.getType() != StatEdge.TYPE_REGULAR && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
- if(!sequence.containsStatementStrict(edge.getDestination())) {
- return false;
- }
- }
- }
-
- for(Statement st : block.getStats()) {
- if(!noExitLabels(st, sequence)) {
- return false;
- }
- }
-
- return true;
- }
-
- public static boolean isBreakEdgeLabeled(Statement source, Statement closure) {
-
- if(closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) {
-
- Statement parent = source.getParent();
-
- if(parent == closure) {
- return false;
- } else {
- return parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH ||
- isBreakEdgeLabeled(parent, closure);
- }
- } else {
- return true;
- }
- }
-
-
+
+ public static boolean inlineSingleBlocks(RootStatement root) {
+
+ boolean res = inlineSingleBlocksRec(root);
+
+ if (res) {
+ SequenceHelper.condenseSequences(root);
+ }
+
+ return res;
+ }
+
+ private static boolean inlineSingleBlocksRec(Statement stat) {
+
+ boolean res = false;
+
+ for (Statement st : stat.getStats()) {
+ res |= inlineSingleBlocksRec(st);
+ }
+
+ if (stat.type == Statement.TYPE_SEQUENCE) {
+
+ SequenceStatement seq = (SequenceStatement)stat;
+ for (int i = 1; i < seq.getStats().size(); i++) {
+ if (isInlineable(seq, i)) {
+ inlineBlock(seq, i);
+ return true;
+ }
+ }
+ }
+
+ return res;
+ }
+
+ private static void inlineBlock(SequenceStatement seq, int index) {
+
+ Statement first = seq.getStats().get(index);
+ Statement pre = seq.getStats().get(index - 1);
+ pre.removeSuccessor(pre.getAllSuccessorEdges().get(0)); // single regular edge
+
+ StatEdge edge = first.getPredecessorEdges(StatEdge.TYPE_BREAK).get(0);
+ Statement source = edge.getSource();
+ Statement parent = source.getParent();
+ source.removeSuccessor(edge);
+
+ List<Statement> lst = new ArrayList<Statement>();
+ for (int i = seq.getStats().size() - 1; i >= index; i--) {
+ lst.add(0, seq.getStats().remove(i));
+ }
+
+ if (parent.type == Statement.TYPE_IF && ((IfStatement)parent).iftype == IfStatement.IFTYPE_IF &&
+ source == parent.getFirst()) {
+ IfStatement ifparent = (IfStatement)parent;
+ SequenceStatement block = new SequenceStatement(lst);
+ block.setAllParent();
+
+ StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, source, block);
+ source.addSuccessor(newedge);
+ ifparent.setIfEdge(newedge);
+ ifparent.setIfstat(block);
+
+ ifparent.getStats().addWithKey(block, block.id);
+ block.setParent(ifparent);
+ }
+ else {
+ lst.add(0, source);
+
+ SequenceStatement block = new SequenceStatement(lst);
+ block.setAllParent();
+
+ parent.replaceStatement(source, block);
+
+ // LabelHelper.lowContinueLabels not applicable because of forward continue edges
+ // LabelHelper.lowContinueLabels(block, new HashSet<StatEdge>());
+ // do it by hand
+ for (StatEdge prededge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
+
+ block.removePredecessor(prededge);
+ prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, source);
+ source.addPredecessor(prededge);
+
+ source.addLabeledEdge(prededge);
+ }
+
+
+ if (parent.type == Statement.TYPE_SWITCH) {
+ ((SwitchStatement)parent).sortEdgesAndNodes();
+ }
+
+ source.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, source, first));
+ }
+ }
+
+ private static boolean isInlineable(SequenceStatement seq, int index) {
+
+ Statement first = seq.getStats().get(index);
+ Statement pre = seq.getStats().get(index - 1);
+
+ if (pre.hasBasicSuccEdge()) {
+ return false;
+ }
+
+
+ List<StatEdge> lst = first.getPredecessorEdges(StatEdge.TYPE_BREAK);
+
+ if (lst.size() == 1) {
+ StatEdge edge = lst.get(0);
+
+ if (sameCatchRanges(edge)) {
+ if (edge.explicit) {
+ return true;
+ }
+ else {
+ for (int i = index; i < seq.getStats().size(); i++) {
+ if (!noExitLabels(seq.getStats().get(i), seq)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ // FIXME: count labels properly
+ }
+
+ return false;
+ }
+
+ private static boolean sameCatchRanges(StatEdge edge) {
+
+ Statement from = edge.getSource();
+ Statement to = edge.getDestination();
+
+ for (; ; ) {
+
+ Statement parent = from.getParent();
+ if (parent.containsStatementStrict(to)) {
+ break;
+ }
+
+ if (parent.type == Statement.TYPE_TRYCATCH ||
+ parent.type == Statement.TYPE_CATCHALL) {
+ if (parent.getFirst() == from) {
+ return false;
+ }
+ }
+ else if (parent.type == Statement.TYPE_SYNCRONIZED) {
+ if (parent.getStats().get(1) == from) {
+ return false;
+ }
+ }
+
+ from = parent;
+ }
+
+ return true;
+ }
+
+ private static boolean noExitLabels(Statement block, Statement sequence) {
+
+ for (StatEdge edge : block.getAllSuccessorEdges()) {
+ if (edge.getType() != StatEdge.TYPE_REGULAR && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
+ if (!sequence.containsStatementStrict(edge.getDestination())) {
+ return false;
+ }
+ }
+ }
+
+ for (Statement st : block.getStats()) {
+ if (!noExitLabels(st, sequence)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean isBreakEdgeLabeled(Statement source, Statement closure) {
+
+ if (closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) {
+
+ Statement parent = source.getParent();
+
+ if (parent == closure) {
+ return false;
+ }
+ else {
+ return parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH ||
+ isBreakEdgeLabeled(parent, closure);
+ }
+ }
+ else {
+ return true;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java
index 6d7a897..2e00d5b 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java
@@ -1,521 +1,513 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SwitchStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+
+import java.util.*;
+import java.util.Map.Entry;
public class LabelHelper {
-
- public static void cleanUpEdges(RootStatement root) {
-
- resetAllEdges(root);
-
- removeNonImmediateEdges(root);
-
- liftClosures(root);
-
- lowContinueLabels(root, new HashSet<StatEdge>());
-
- lowClosures(root);
-
- }
-
- public static void identifyLabels(RootStatement root) {
-
- setExplicitEdges(root);
-
- hideDefaultSwitchEdges(root);
-
- processStatementLabel(root);
-
- setRetEdgesUnlabeled(root);
- }
-
- private static void liftClosures(Statement stat) {
-
- for(StatEdge edge : stat.getAllSuccessorEdges()) {
- switch(edge.getType()) {
- case StatEdge.TYPE_CONTINUE:
- if(edge.getDestination() != edge.closure) {
- edge.getDestination().addLabeledEdge(edge);
- }
- break;
- case StatEdge.TYPE_BREAK:
- Statement dest = edge.getDestination();
- if(dest.type != Statement.TYPE_DUMMYEXIT) {
- Statement parent = dest.getParent();
-
- List<Statement> lst = new ArrayList<Statement>();
- if(parent.type == Statement.TYPE_SEQUENCE) {
- lst.addAll(((SequenceStatement)parent).getStats());
- } else if(parent.type == Statement.TYPE_SWITCH) {
- lst.addAll(((SwitchStatement)parent).getCaseStatements());
- }
-
- for(int i=0;i<lst.size();i++) {
- if(lst.get(i) == dest) {
- lst.get(i-1).addLabeledEdge(edge);
- break;
- }
- }
- }
- }
- }
-
- for(Statement st : stat.getStats()) {
- liftClosures(st);
- }
-
- }
-
- private static void removeNonImmediateEdges(Statement stat) {
-
- for(Statement st : stat.getStats()) {
- removeNonImmediateEdges(st);
- }
-
- if(!stat.hasBasicSuccEdge()) {
- for(StatEdge edge : stat.getSuccessorEdges(StatEdge.TYPE_CONTINUE | StatEdge.TYPE_BREAK)) {
- stat.removeSuccessor(edge);
- }
- }
- }
-
- public static void lowContinueLabels(Statement stat, HashSet<StatEdge> edges) {
-
- boolean ok = (stat.type != Statement.TYPE_DO);
- if(!ok) {
- DoStatement dostat = (DoStatement)stat;
- ok = dostat.getLooptype() == DoStatement.LOOP_DO ||
- dostat.getLooptype() == DoStatement.LOOP_WHILE ||
- (dostat.getLooptype() == DoStatement.LOOP_FOR && dostat.getIncExprent() == null);
- }
-
- if(ok) {
- edges.addAll(stat.getPredecessorEdges(StatEdge.TYPE_CONTINUE));
- }
-
- if(ok && stat.type == Statement.TYPE_DO) {
- for(StatEdge edge: edges) {
- if(stat.containsStatementStrict(edge.getSource())) {
-
- edge.getDestination().removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, stat);
- stat.addPredecessor(edge);
-
- stat.addLabeledEdge(edge);
- }
- }
- }
-
- for(Statement st: stat.getStats()) {
- if(st == stat.getFirst()) {
- lowContinueLabels(st, edges);
- } else {
- lowContinueLabels(st, new HashSet<StatEdge>());
- }
- }
- }
-
- public static void lowClosures(Statement stat) {
-
- for(StatEdge edge : new ArrayList<StatEdge>(stat.getLabelEdges())) {
-
- if(edge.getType() == StatEdge.TYPE_BREAK) { // FIXME: ?
- for(Statement st : stat.getStats()) {
- if(st.containsStatementStrict(edge.getSource())) {
- if(MergeHelper.isDirectPath(st, edge.getDestination())) {
- st.addLabeledEdge(edge);
- }
- }
- }
- }
- }
-
- for(Statement st: stat.getStats()) {
- lowClosures(st);
- }
-
- }
-
- private static void resetAllEdges(Statement stat) {
-
- for(Statement st: stat.getStats()) {
- resetAllEdges(st);
- }
-
- for(StatEdge edge: stat.getAllSuccessorEdges()) {
- edge.explicit = true;
- edge.labeled = true;
- }
- }
-
- private static void setRetEdgesUnlabeled(RootStatement root) {
- Statement exit = root.getDummyExit();
- for(StatEdge edge: exit.getAllPredecessorEdges()) {
- List<Exprent> lst = edge.getSource().getExprents();
- if(edge.getType() == StatEdge.TYPE_FINALLYEXIT || (lst != null && !lst.isEmpty() &&
- lst.get(lst.size()-1).type == Exprent.EXPRENT_EXIT)) {
- edge.labeled = false;
- }
- }
- }
-
- private static HashMap<Statement, List<StatEdge>> setExplicitEdges(Statement stat) {
-
- HashMap<Statement, List<StatEdge>> mapEdges = new HashMap<Statement, List<StatEdge>>();
-
- if(stat.getExprents() != null) {
- return mapEdges;
- }
-
-
- switch(stat.type) {
- case Statement.TYPE_TRYCATCH:
- case Statement.TYPE_CATCHALL:
-
- for(Statement st : stat.getStats()) {
- HashMap<Statement, List<StatEdge>> mapEdges1 = setExplicitEdges(st);
- processEdgesWithNext(st, mapEdges1, null);
-
- if(stat.type == Statement.TYPE_TRYCATCH || st == stat.getFirst()) { // edges leaving a finally catch block are always explicit
- // merge the maps
- if(mapEdges1 != null) {
- for(Entry<Statement, List<StatEdge>> entr : mapEdges1.entrySet()) {
- if(mapEdges.containsKey(entr.getKey())) {
- mapEdges.get(entr.getKey()).addAll(entr.getValue());
- } else {
- mapEdges.put(entr.getKey(), entr.getValue());
- }
- }
- }
- }
- }
-
- break;
- case Statement.TYPE_DO:
- mapEdges = setExplicitEdges(stat.getFirst());
- processEdgesWithNext(stat.getFirst(), mapEdges, stat);
- break;
- case Statement.TYPE_IF:
- IfStatement ifstat = (IfStatement)stat;
- // head statement is a basic block
- if(ifstat.getIfstat() == null) { // empty if
- processEdgesWithNext(ifstat.getFirst(), mapEdges, null);
- } else {
- if(ifstat.getIfstat() != null) {
- mapEdges = setExplicitEdges(ifstat.getIfstat());
- processEdgesWithNext(ifstat.getIfstat(), mapEdges, null);
- }
-
- HashMap<Statement, List<StatEdge>> mapEdges1 = null;
- if(ifstat.getElsestat() != null) {
- mapEdges1 = setExplicitEdges(ifstat.getElsestat());
- processEdgesWithNext(ifstat.getElsestat(), mapEdges1, null);
- }
-
- // merge the maps
- if(mapEdges1 != null) {
- for(Entry<Statement, List<StatEdge>> entr : mapEdges1.entrySet()) {
- if(mapEdges.containsKey(entr.getKey())) {
- mapEdges.get(entr.getKey()).addAll(entr.getValue());
- } else {
- mapEdges.put(entr.getKey(), entr.getValue());
- }
- }
- }
- }
- break;
- case Statement.TYPE_ROOT:
- mapEdges = setExplicitEdges(stat.getFirst());
- processEdgesWithNext(stat.getFirst(), mapEdges, ((RootStatement)stat).getDummyExit());
- break;
- case Statement.TYPE_SEQUENCE:
- int index = 0;
- while(index < stat.getStats().size()-1) {
- Statement st = stat.getStats().get(index);
- processEdgesWithNext(st, setExplicitEdges(st), stat.getStats().get(index+1));
- index++;
- }
-
- Statement st = stat.getStats().get(index);
- mapEdges = setExplicitEdges(st);
- processEdgesWithNext(st, mapEdges, null);
- break;
- case Statement.TYPE_SWITCH:
- SwitchStatement swst = (SwitchStatement)stat;
-
- for(int i=0;i<swst.getCaseStatements().size()-1;i++) {
- Statement stt = swst.getCaseStatements().get(i);
- Statement stnext = swst.getCaseStatements().get(i+1);
-
- if(stnext.getExprents() != null && stnext.getExprents().isEmpty()) {
- stnext = stnext.getAllSuccessorEdges().get(0).getDestination();
- }
- processEdgesWithNext(stt, setExplicitEdges(stt), stnext);
- }
-
- int last = swst.getCaseStatements().size()-1;
- if(last >= 0) { // empty switch possible
- Statement stlast = swst.getCaseStatements().get(last);
- if(stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
- StatEdge edge = stlast.getAllSuccessorEdges().get(0);
- mapEdges.put(edge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[] {edge})));
- } else {
- mapEdges = setExplicitEdges(stlast);
- processEdgesWithNext(stlast, mapEdges, null);
- }
- }
-
- break;
- case Statement.TYPE_SYNCRONIZED:
- SynchronizedStatement synstat = (SynchronizedStatement)stat;
-
- processEdgesWithNext(synstat.getFirst(), setExplicitEdges(stat.getFirst()), synstat.getBody()); // FIXME: basic block?
- mapEdges = setExplicitEdges(synstat.getBody());
- processEdgesWithNext(synstat.getBody(), mapEdges, null);
- }
-
-
- return mapEdges;
- }
-
- private static void processEdgesWithNext(Statement stat, HashMap<Statement, List<StatEdge>> mapEdges, Statement next) {
-
- StatEdge statedge = null;
-
- List<StatEdge> lstSuccs = stat.getAllSuccessorEdges();
- if(!lstSuccs.isEmpty()) {
- statedge = lstSuccs.get(0);
-
- if(statedge.getDestination() == next) {
- statedge.explicit = false;
- statedge = null;
- } else {
- next = statedge.getDestination();
- }
- }
-
- // no next for a do statement
- if(stat.type == Statement.TYPE_DO && ((DoStatement)stat).getLooptype() == DoStatement.LOOP_DO) {
- next = null;
- }
-
- if(next == null) {
- if(mapEdges.size() == 1) {
- List<StatEdge> lstEdges = mapEdges.values().iterator().next();
- if(lstEdges.size() > 1 && mapEdges.keySet().iterator().next().type != Statement.TYPE_DUMMYEXIT) {
- StatEdge edge_example = lstEdges.get(0);
-
- Statement closure = stat.getParent();
- if(!closure.containsStatementStrict(edge_example.closure)) {
- closure = edge_example.closure;
- }
-
- StatEdge newedge = new StatEdge(edge_example.getType(), stat, edge_example.getDestination(), closure);
- stat.addSuccessor(newedge);
-
- for(StatEdge edge : lstEdges) {
- edge.explicit = false;
- }
-
- mapEdges.put(newedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[] {newedge})));
- }
- }
- } else {
-
- boolean implfound = false;
-
- for(Entry<Statement, List<StatEdge>> entr : mapEdges.entrySet()) {
- if(entr.getKey() == next) {
- for(StatEdge edge : entr.getValue()) {
- edge.explicit = false;
- }
- implfound = true;
- break;
- }
- }
-
- if(stat.getAllSuccessorEdges().isEmpty() && !implfound) {
- List<StatEdge> lstEdges = null;
- for(Entry<Statement, List<StatEdge>> entr : mapEdges.entrySet()) {
- if(entr.getKey().type != Statement.TYPE_DUMMYEXIT &&
- (lstEdges == null || entr.getValue().size() > lstEdges.size())) {
- lstEdges = entr.getValue();
- }
- }
-
- if(lstEdges != null && lstEdges.size() > 1) {
- StatEdge edge_example = lstEdges.get(0);
-
- Statement closure = stat.getParent();
- if(!closure.containsStatementStrict(edge_example.closure)) {
- closure = edge_example.closure;
- }
-
- StatEdge newedge = new StatEdge(edge_example.getType(), stat, edge_example.getDestination(), closure);
- stat.addSuccessor(newedge);
-
- for(StatEdge edge : lstEdges) {
- edge.explicit = false;
- }
- }
- }
-
- mapEdges.clear();
- }
-
- if(statedge != null) {
- mapEdges.put(statedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[] {statedge})));
- }
-
- }
-
- private static void hideDefaultSwitchEdges(Statement stat) {
-
- if(stat.type == Statement.TYPE_SWITCH) {
- SwitchStatement swst = (SwitchStatement)stat;
-
- int last = swst.getCaseStatements().size()-1;
- if(last >= 0) { // empty switch possible
- Statement stlast = swst.getCaseStatements().get(last);
-
- if(stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
- if(!stlast.getAllSuccessorEdges().get(0).explicit) {
- List<StatEdge> lstEdges = swst.getCaseEdges().get(last);
- lstEdges.remove(swst.getDefault_edge());
-
- if(lstEdges.isEmpty()) {
- swst.getCaseStatements().remove(last);
- swst.getCaseEdges().remove(last);
- }
- }
- }
- }
- }
-
- for(Statement st : stat.getStats()) {
- hideDefaultSwitchEdges(st);
- }
-
- }
-
- private static HashSet<Statement>[] processStatementLabel(Statement stat) {
-
- HashSet<Statement> setBreak = new HashSet<Statement>();
- HashSet<Statement> setContinue = new HashSet<Statement>();
-
- if(stat.getExprents() == null) {
- for(Statement st: stat.getStats()) {
- HashSet<Statement>[] arr = processStatementLabel(st);
-
- setBreak.addAll(arr[0]);
- setContinue.addAll(arr[1]);
- }
-
- boolean shieldtype = (stat.type == Statement.TYPE_DO || stat.type == Statement.TYPE_SWITCH);
-
- for(StatEdge edge: stat.getLabelEdges()) {
- if(edge.explicit) {
- if(shieldtype && ((edge.getType() == StatEdge.TYPE_BREAK && setBreak.contains(edge.getSource())) ||
- (edge.getType() == StatEdge.TYPE_CONTINUE && setContinue.contains(edge.getSource())))) {
- edge.labeled = false;
- }
- }
- }
-
- switch(stat.type) {
- case Statement.TYPE_DO:
- setContinue.clear();
- case Statement.TYPE_SWITCH:
- setBreak.clear();
- }
- }
-
- setBreak.add(stat);
- setContinue.add(stat);
-
- return new HashSet[] {setBreak, setContinue};
- }
-
- public static void replaceContinueWithBreak(Statement stat) {
-
- if(stat.type == Statement.TYPE_DO) {
-
- List<StatEdge> lst = stat.getPredecessorEdges(StatEdge.TYPE_CONTINUE);
-
- for(StatEdge edge : lst) {
-
- if(edge.explicit) {
- Statement minclosure = getMinContinueClosure(edge);
-
- if(minclosure != edge.closure &&
- !InlineSingleBlockHelper.isBreakEdgeLabeled(edge.getSource(), minclosure)) {
- edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK);
- edge.labeled = false;
- minclosure.addLabeledEdge(edge);
- }
- }
- }
- }
-
- for(Statement st : stat.getStats()) {
- replaceContinueWithBreak(st);
- }
-
- }
-
- private static Statement getMinContinueClosure(StatEdge edge) {
-
- Statement closure = edge.closure;
- for(;;) {
-
- boolean found = false;
-
- for(Statement st : closure.getStats()) {
- if(st.containsStatementStrict(edge.getSource())) {
- if(MergeHelper.isDirectPath(st, edge.getDestination())) {
- closure = st;
- found = true;
- break;
- }
- }
- }
-
- if(!found) {
- break;
- }
- }
-
- return closure;
- }
-
+
+ public static void cleanUpEdges(RootStatement root) {
+
+ resetAllEdges(root);
+
+ removeNonImmediateEdges(root);
+
+ liftClosures(root);
+
+ lowContinueLabels(root, new HashSet<StatEdge>());
+
+ lowClosures(root);
+ }
+
+ public static void identifyLabels(RootStatement root) {
+
+ setExplicitEdges(root);
+
+ hideDefaultSwitchEdges(root);
+
+ processStatementLabel(root);
+
+ setRetEdgesUnlabeled(root);
+ }
+
+ private static void liftClosures(Statement stat) {
+
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ switch (edge.getType()) {
+ case StatEdge.TYPE_CONTINUE:
+ if (edge.getDestination() != edge.closure) {
+ edge.getDestination().addLabeledEdge(edge);
+ }
+ break;
+ case StatEdge.TYPE_BREAK:
+ Statement dest = edge.getDestination();
+ if (dest.type != Statement.TYPE_DUMMYEXIT) {
+ Statement parent = dest.getParent();
+
+ List<Statement> lst = new ArrayList<Statement>();
+ if (parent.type == Statement.TYPE_SEQUENCE) {
+ lst.addAll(((SequenceStatement)parent).getStats());
+ }
+ else if (parent.type == Statement.TYPE_SWITCH) {
+ lst.addAll(((SwitchStatement)parent).getCaseStatements());
+ }
+
+ for (int i = 0; i < lst.size(); i++) {
+ if (lst.get(i) == dest) {
+ lst.get(i - 1).addLabeledEdge(edge);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ liftClosures(st);
+ }
+ }
+
+ private static void removeNonImmediateEdges(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ removeNonImmediateEdges(st);
+ }
+
+ if (!stat.hasBasicSuccEdge()) {
+ for (StatEdge edge : stat.getSuccessorEdges(StatEdge.TYPE_CONTINUE | StatEdge.TYPE_BREAK)) {
+ stat.removeSuccessor(edge);
+ }
+ }
+ }
+
+ public static void lowContinueLabels(Statement stat, HashSet<StatEdge> edges) {
+
+ boolean ok = (stat.type != Statement.TYPE_DO);
+ if (!ok) {
+ DoStatement dostat = (DoStatement)stat;
+ ok = dostat.getLooptype() == DoStatement.LOOP_DO ||
+ dostat.getLooptype() == DoStatement.LOOP_WHILE ||
+ (dostat.getLooptype() == DoStatement.LOOP_FOR && dostat.getIncExprent() == null);
+ }
+
+ if (ok) {
+ edges.addAll(stat.getPredecessorEdges(StatEdge.TYPE_CONTINUE));
+ }
+
+ if (ok && stat.type == Statement.TYPE_DO) {
+ for (StatEdge edge : edges) {
+ if (stat.containsStatementStrict(edge.getSource())) {
+
+ edge.getDestination().removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, stat);
+ stat.addPredecessor(edge);
+
+ stat.addLabeledEdge(edge);
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ if (st == stat.getFirst()) {
+ lowContinueLabels(st, edges);
+ }
+ else {
+ lowContinueLabels(st, new HashSet<StatEdge>());
+ }
+ }
+ }
+
+ public static void lowClosures(Statement stat) {
+
+ for (StatEdge edge : new ArrayList<StatEdge>(stat.getLabelEdges())) {
+
+ if (edge.getType() == StatEdge.TYPE_BREAK) { // FIXME: ?
+ for (Statement st : stat.getStats()) {
+ if (st.containsStatementStrict(edge.getSource())) {
+ if (MergeHelper.isDirectPath(st, edge.getDestination())) {
+ st.addLabeledEdge(edge);
+ }
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ lowClosures(st);
+ }
+ }
+
+ private static void resetAllEdges(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ resetAllEdges(st);
+ }
+
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ edge.explicit = true;
+ edge.labeled = true;
+ }
+ }
+
+ private static void setRetEdgesUnlabeled(RootStatement root) {
+ Statement exit = root.getDummyExit();
+ for (StatEdge edge : exit.getAllPredecessorEdges()) {
+ List<Exprent> lst = edge.getSource().getExprents();
+ if (edge.getType() == StatEdge.TYPE_FINALLYEXIT || (lst != null && !lst.isEmpty() &&
+ lst.get(lst.size() - 1).type == Exprent.EXPRENT_EXIT)) {
+ edge.labeled = false;
+ }
+ }
+ }
+
+ private static HashMap<Statement, List<StatEdge>> setExplicitEdges(Statement stat) {
+
+ HashMap<Statement, List<StatEdge>> mapEdges = new HashMap<Statement, List<StatEdge>>();
+
+ if (stat.getExprents() != null) {
+ return mapEdges;
+ }
+
+
+ switch (stat.type) {
+ case Statement.TYPE_TRYCATCH:
+ case Statement.TYPE_CATCHALL:
+
+ for (Statement st : stat.getStats()) {
+ HashMap<Statement, List<StatEdge>> mapEdges1 = setExplicitEdges(st);
+ processEdgesWithNext(st, mapEdges1, null);
+
+ if (stat.type == Statement.TYPE_TRYCATCH || st == stat.getFirst()) { // edges leaving a finally catch block are always explicit
+ // merge the maps
+ if (mapEdges1 != null) {
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges1.entrySet()) {
+ if (mapEdges.containsKey(entr.getKey())) {
+ mapEdges.get(entr.getKey()).addAll(entr.getValue());
+ }
+ else {
+ mapEdges.put(entr.getKey(), entr.getValue());
+ }
+ }
+ }
+ }
+ }
+
+ break;
+ case Statement.TYPE_DO:
+ mapEdges = setExplicitEdges(stat.getFirst());
+ processEdgesWithNext(stat.getFirst(), mapEdges, stat);
+ break;
+ case Statement.TYPE_IF:
+ IfStatement ifstat = (IfStatement)stat;
+ // head statement is a basic block
+ if (ifstat.getIfstat() == null) { // empty if
+ processEdgesWithNext(ifstat.getFirst(), mapEdges, null);
+ }
+ else {
+ if (ifstat.getIfstat() != null) {
+ mapEdges = setExplicitEdges(ifstat.getIfstat());
+ processEdgesWithNext(ifstat.getIfstat(), mapEdges, null);
+ }
+
+ HashMap<Statement, List<StatEdge>> mapEdges1 = null;
+ if (ifstat.getElsestat() != null) {
+ mapEdges1 = setExplicitEdges(ifstat.getElsestat());
+ processEdgesWithNext(ifstat.getElsestat(), mapEdges1, null);
+ }
+
+ // merge the maps
+ if (mapEdges1 != null) {
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges1.entrySet()) {
+ if (mapEdges.containsKey(entr.getKey())) {
+ mapEdges.get(entr.getKey()).addAll(entr.getValue());
+ }
+ else {
+ mapEdges.put(entr.getKey(), entr.getValue());
+ }
+ }
+ }
+ }
+ break;
+ case Statement.TYPE_ROOT:
+ mapEdges = setExplicitEdges(stat.getFirst());
+ processEdgesWithNext(stat.getFirst(), mapEdges, ((RootStatement)stat).getDummyExit());
+ break;
+ case Statement.TYPE_SEQUENCE:
+ int index = 0;
+ while (index < stat.getStats().size() - 1) {
+ Statement st = stat.getStats().get(index);
+ processEdgesWithNext(st, setExplicitEdges(st), stat.getStats().get(index + 1));
+ index++;
+ }
+
+ Statement st = stat.getStats().get(index);
+ mapEdges = setExplicitEdges(st);
+ processEdgesWithNext(st, mapEdges, null);
+ break;
+ case Statement.TYPE_SWITCH:
+ SwitchStatement swst = (SwitchStatement)stat;
+
+ for (int i = 0; i < swst.getCaseStatements().size() - 1; i++) {
+ Statement stt = swst.getCaseStatements().get(i);
+ Statement stnext = swst.getCaseStatements().get(i + 1);
+
+ if (stnext.getExprents() != null && stnext.getExprents().isEmpty()) {
+ stnext = stnext.getAllSuccessorEdges().get(0).getDestination();
+ }
+ processEdgesWithNext(stt, setExplicitEdges(stt), stnext);
+ }
+
+ int last = swst.getCaseStatements().size() - 1;
+ if (last >= 0) { // empty switch possible
+ Statement stlast = swst.getCaseStatements().get(last);
+ if (stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
+ StatEdge edge = stlast.getAllSuccessorEdges().get(0);
+ mapEdges.put(edge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{edge})));
+ }
+ else {
+ mapEdges = setExplicitEdges(stlast);
+ processEdgesWithNext(stlast, mapEdges, null);
+ }
+ }
+
+ break;
+ case Statement.TYPE_SYNCRONIZED:
+ SynchronizedStatement synstat = (SynchronizedStatement)stat;
+
+ processEdgesWithNext(synstat.getFirst(), setExplicitEdges(stat.getFirst()), synstat.getBody()); // FIXME: basic block?
+ mapEdges = setExplicitEdges(synstat.getBody());
+ processEdgesWithNext(synstat.getBody(), mapEdges, null);
+ }
+
+
+ return mapEdges;
+ }
+
+ private static void processEdgesWithNext(Statement stat, HashMap<Statement, List<StatEdge>> mapEdges, Statement next) {
+
+ StatEdge statedge = null;
+
+ List<StatEdge> lstSuccs = stat.getAllSuccessorEdges();
+ if (!lstSuccs.isEmpty()) {
+ statedge = lstSuccs.get(0);
+
+ if (statedge.getDestination() == next) {
+ statedge.explicit = false;
+ statedge = null;
+ }
+ else {
+ next = statedge.getDestination();
+ }
+ }
+
+ // no next for a do statement
+ if (stat.type == Statement.TYPE_DO && ((DoStatement)stat).getLooptype() == DoStatement.LOOP_DO) {
+ next = null;
+ }
+
+ if (next == null) {
+ if (mapEdges.size() == 1) {
+ List<StatEdge> lstEdges = mapEdges.values().iterator().next();
+ if (lstEdges.size() > 1 && mapEdges.keySet().iterator().next().type != Statement.TYPE_DUMMYEXIT) {
+ StatEdge edge_example = lstEdges.get(0);
+
+ Statement closure = stat.getParent();
+ if (!closure.containsStatementStrict(edge_example.closure)) {
+ closure = edge_example.closure;
+ }
+
+ StatEdge newedge = new StatEdge(edge_example.getType(), stat, edge_example.getDestination(), closure);
+ stat.addSuccessor(newedge);
+
+ for (StatEdge edge : lstEdges) {
+ edge.explicit = false;
+ }
+
+ mapEdges.put(newedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{newedge})));
+ }
+ }
+ }
+ else {
+
+ boolean implfound = false;
+
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges.entrySet()) {
+ if (entr.getKey() == next) {
+ for (StatEdge edge : entr.getValue()) {
+ edge.explicit = false;
+ }
+ implfound = true;
+ break;
+ }
+ }
+
+ if (stat.getAllSuccessorEdges().isEmpty() && !implfound) {
+ List<StatEdge> lstEdges = null;
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges.entrySet()) {
+ if (entr.getKey().type != Statement.TYPE_DUMMYEXIT &&
+ (lstEdges == null || entr.getValue().size() > lstEdges.size())) {
+ lstEdges = entr.getValue();
+ }
+ }
+
+ if (lstEdges != null && lstEdges.size() > 1) {
+ StatEdge edge_example = lstEdges.get(0);
+
+ Statement closure = stat.getParent();
+ if (!closure.containsStatementStrict(edge_example.closure)) {
+ closure = edge_example.closure;
+ }
+
+ StatEdge newedge = new StatEdge(edge_example.getType(), stat, edge_example.getDestination(), closure);
+ stat.addSuccessor(newedge);
+
+ for (StatEdge edge : lstEdges) {
+ edge.explicit = false;
+ }
+ }
+ }
+
+ mapEdges.clear();
+ }
+
+ if (statedge != null) {
+ mapEdges.put(statedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{statedge})));
+ }
+ }
+
+ private static void hideDefaultSwitchEdges(Statement stat) {
+
+ if (stat.type == Statement.TYPE_SWITCH) {
+ SwitchStatement swst = (SwitchStatement)stat;
+
+ int last = swst.getCaseStatements().size() - 1;
+ if (last >= 0) { // empty switch possible
+ Statement stlast = swst.getCaseStatements().get(last);
+
+ if (stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
+ if (!stlast.getAllSuccessorEdges().get(0).explicit) {
+ List<StatEdge> lstEdges = swst.getCaseEdges().get(last);
+ lstEdges.remove(swst.getDefault_edge());
+
+ if (lstEdges.isEmpty()) {
+ swst.getCaseStatements().remove(last);
+ swst.getCaseEdges().remove(last);
+ }
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ hideDefaultSwitchEdges(st);
+ }
+ }
+
+ private static HashSet<Statement>[] processStatementLabel(Statement stat) {
+
+ HashSet<Statement> setBreak = new HashSet<Statement>();
+ HashSet<Statement> setContinue = new HashSet<Statement>();
+
+ if (stat.getExprents() == null) {
+ for (Statement st : stat.getStats()) {
+ HashSet<Statement>[] arr = processStatementLabel(st);
+
+ setBreak.addAll(arr[0]);
+ setContinue.addAll(arr[1]);
+ }
+
+ boolean shieldtype = (stat.type == Statement.TYPE_DO || stat.type == Statement.TYPE_SWITCH);
+
+ for (StatEdge edge : stat.getLabelEdges()) {
+ if (edge.explicit) {
+ if (shieldtype && ((edge.getType() == StatEdge.TYPE_BREAK && setBreak.contains(edge.getSource())) ||
+ (edge.getType() == StatEdge.TYPE_CONTINUE && setContinue.contains(edge.getSource())))) {
+ edge.labeled = false;
+ }
+ }
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_DO:
+ setContinue.clear();
+ case Statement.TYPE_SWITCH:
+ setBreak.clear();
+ }
+ }
+
+ setBreak.add(stat);
+ setContinue.add(stat);
+
+ return new HashSet[]{setBreak, setContinue};
+ }
+
+ public static void replaceContinueWithBreak(Statement stat) {
+
+ if (stat.type == Statement.TYPE_DO) {
+
+ List<StatEdge> lst = stat.getPredecessorEdges(StatEdge.TYPE_CONTINUE);
+
+ for (StatEdge edge : lst) {
+
+ if (edge.explicit) {
+ Statement minclosure = getMinContinueClosure(edge);
+
+ if (minclosure != edge.closure &&
+ !InlineSingleBlockHelper.isBreakEdgeLabeled(edge.getSource(), minclosure)) {
+ edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK);
+ edge.labeled = false;
+ minclosure.addLabeledEdge(edge);
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ replaceContinueWithBreak(st);
+ }
+ }
+
+ private static Statement getMinContinueClosure(StatEdge edge) {
+
+ Statement closure = edge.closure;
+ for (; ; ) {
+
+ boolean found = false;
+
+ for (Statement st : closure.getStats()) {
+ if (st.containsStatementStrict(edge.getSource())) {
+ if (MergeHelper.isDirectPath(st, edge.getDestination())) {
+ closure = st;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ return closure;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java
index 5e0130b..180f162 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java
@@ -1,209 +1,206 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Set;
public class LoopExtractHelper {
-
-
- public static boolean extractLoops(Statement root) {
-
- boolean res = (extractLoopsRec(root) != 0);
-
- if(res) {
- SequenceHelper.condenseSequences(root);
- }
-
- return res;
- }
-
-
- private static int extractLoopsRec(Statement stat) {
-
- boolean res = false;
-
- for(;;) {
-
- boolean updated = false;
-
- for(Statement st: stat.getStats()) {
- int extr = extractLoopsRec(st);
- res |= (extr != 0);
-
- if(extr == 2) {
- updated = true;
- break;
- }
- }
-
- if(!updated) {
- break;
- }
- }
-
- if(stat.type == Statement.TYPE_DO) {
- if(extractLoop((DoStatement)stat)) {
- return 2;
- }
- }
-
- return res?1:0;
- }
-
-
-
- private static boolean extractLoop(DoStatement stat) {
-
- if(stat.getLooptype() != DoStatement.LOOP_DO) {
- return false;
- }
-
- for(StatEdge edge: stat.getLabelEdges()) {
- if(edge.getType() != StatEdge.TYPE_CONTINUE && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
- return false;
- }
- }
-
- if(!extractLastIf(stat)) {
- return extractFirstIf(stat);
- } else {
- return true;
- }
- }
-
- private static boolean extractLastIf(DoStatement stat) {
-
- // search for an if condition at the end of the loop
- Statement last = stat.getFirst();
- while(last.type == Statement.TYPE_SEQUENCE) {
- last = last.getStats().getLast();
- }
-
- if(last.type == Statement.TYPE_IF) {
- IfStatement lastif = (IfStatement)last;
- if(lastif.iftype == IfStatement.IFTYPE_IF && lastif.getIfstat() != null) {
- Statement ifstat = lastif.getIfstat();
- StatEdge elseedge = lastif.getAllSuccessorEdges().get(0);
-
- if(elseedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.closure == stat) {
-
- Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD);
- set.remove(last);
-
- if(set.isEmpty()) { // no direct continues in a do{}while loop
- if(isExternStatement(stat, ifstat, ifstat)) {
- extractIfBlock(stat, lastif);
- return true;
- }
- }
- }
- }
- }
- return false;
- }
-
- private static boolean extractFirstIf(DoStatement stat) {
-
- // search for an if condition at the entrance of the loop
- Statement first = stat.getFirst();
- while(first.type == Statement.TYPE_SEQUENCE) {
- first = first.getFirst();
- }
-
- // found an if statement
- if(first.type == Statement.TYPE_IF) {
- IfStatement firstif = (IfStatement)first;
-
- if(firstif.getFirst().getExprents().isEmpty()) {
-
- if(firstif.iftype == IfStatement.IFTYPE_IF && firstif.getIfstat()!=null) {
- Statement ifstat = firstif.getIfstat();
-
- if(isExternStatement(stat, ifstat, ifstat)) {
- extractIfBlock(stat, firstif);
- return true;
- }
- }
- }
- }
- return false;
- }
-
-
-
- private static boolean isExternStatement(DoStatement loop, Statement block, Statement stat) {
-
- for(StatEdge edge: stat.getAllSuccessorEdges()) {
- if(loop.containsStatement(edge.getDestination()) &&
- !block.containsStatement(edge.getDestination())) {
- return false;
- }
- }
-
- for(Statement st: stat.getStats()) {
- if(!isExternStatement(loop, block, st)) {
- return false;
- }
- }
-
- return true;
- }
-
-
- private static void extractIfBlock(DoStatement loop, IfStatement ifstat) {
-
- Statement target = ifstat.getIfstat();
- StatEdge ifedge = ifstat.getIfEdge();
-
- ifstat.setIfstat(null);
- ifedge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, ifedge, StatEdge.TYPE_BREAK);
- ifedge.closure = loop;
- ifstat.getStats().removeWithKey(target.id);
-
- loop.addLabeledEdge(ifedge);
-
- SequenceStatement block = new SequenceStatement(Arrays.asList(new Statement[] {loop, target}));
- loop.getParent().replaceStatement(loop, block);
- block.setAllParent();
-
- loop.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, loop, target));
-
- for(StatEdge edge: new ArrayList<StatEdge>(block.getLabelEdges())) {
- if(edge.getType() == StatEdge.TYPE_CONTINUE || edge == ifedge) {
- loop.addLabeledEdge(edge);
- }
- }
-
- for(StatEdge edge: block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
- if(loop.containsStatementStrict(edge.getSource())) {
- block.removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, loop);
- loop.addPredecessor(edge);
- }
- }
- }
-
+
+ public static boolean extractLoops(Statement root) {
+
+ boolean res = (extractLoopsRec(root) != 0);
+
+ if (res) {
+ SequenceHelper.condenseSequences(root);
+ }
+
+ return res;
+ }
+
+
+ private static int extractLoopsRec(Statement stat) {
+
+ boolean res = false;
+
+ for (; ; ) {
+
+ boolean updated = false;
+
+ for (Statement st : stat.getStats()) {
+ int extr = extractLoopsRec(st);
+ res |= (extr != 0);
+
+ if (extr == 2) {
+ updated = true;
+ break;
+ }
+ }
+
+ if (!updated) {
+ break;
+ }
+ }
+
+ if (stat.type == Statement.TYPE_DO) {
+ if (extractLoop((DoStatement)stat)) {
+ return 2;
+ }
+ }
+
+ return res ? 1 : 0;
+ }
+
+
+ private static boolean extractLoop(DoStatement stat) {
+
+ if (stat.getLooptype() != DoStatement.LOOP_DO) {
+ return false;
+ }
+
+ for (StatEdge edge : stat.getLabelEdges()) {
+ if (edge.getType() != StatEdge.TYPE_CONTINUE && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
+ return false;
+ }
+ }
+
+ if (!extractLastIf(stat)) {
+ return extractFirstIf(stat);
+ }
+ else {
+ return true;
+ }
+ }
+
+ private static boolean extractLastIf(DoStatement stat) {
+
+ // search for an if condition at the end of the loop
+ Statement last = stat.getFirst();
+ while (last.type == Statement.TYPE_SEQUENCE) {
+ last = last.getStats().getLast();
+ }
+
+ if (last.type == Statement.TYPE_IF) {
+ IfStatement lastif = (IfStatement)last;
+ if (lastif.iftype == IfStatement.IFTYPE_IF && lastif.getIfstat() != null) {
+ Statement ifstat = lastif.getIfstat();
+ StatEdge elseedge = lastif.getAllSuccessorEdges().get(0);
+
+ if (elseedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.closure == stat) {
+
+ Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD);
+ set.remove(last);
+
+ if (set.isEmpty()) { // no direct continues in a do{}while loop
+ if (isExternStatement(stat, ifstat, ifstat)) {
+ extractIfBlock(stat, lastif);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private static boolean extractFirstIf(DoStatement stat) {
+
+ // search for an if condition at the entrance of the loop
+ Statement first = stat.getFirst();
+ while (first.type == Statement.TYPE_SEQUENCE) {
+ first = first.getFirst();
+ }
+
+ // found an if statement
+ if (first.type == Statement.TYPE_IF) {
+ IfStatement firstif = (IfStatement)first;
+
+ if (firstif.getFirst().getExprents().isEmpty()) {
+
+ if (firstif.iftype == IfStatement.IFTYPE_IF && firstif.getIfstat() != null) {
+ Statement ifstat = firstif.getIfstat();
+
+ if (isExternStatement(stat, ifstat, ifstat)) {
+ extractIfBlock(stat, firstif);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+
+ private static boolean isExternStatement(DoStatement loop, Statement block, Statement stat) {
+
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ if (loop.containsStatement(edge.getDestination()) &&
+ !block.containsStatement(edge.getDestination())) {
+ return false;
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ if (!isExternStatement(loop, block, st)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ private static void extractIfBlock(DoStatement loop, IfStatement ifstat) {
+
+ Statement target = ifstat.getIfstat();
+ StatEdge ifedge = ifstat.getIfEdge();
+
+ ifstat.setIfstat(null);
+ ifedge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, ifedge, StatEdge.TYPE_BREAK);
+ ifedge.closure = loop;
+ ifstat.getStats().removeWithKey(target.id);
+
+ loop.addLabeledEdge(ifedge);
+
+ SequenceStatement block = new SequenceStatement(Arrays.asList(new Statement[]{loop, target}));
+ loop.getParent().replaceStatement(loop, block);
+ block.setAllParent();
+
+ loop.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, loop, target));
+
+ for (StatEdge edge : new ArrayList<StatEdge>(block.getLabelEdges())) {
+ if (edge.getType() == StatEdge.TYPE_CONTINUE || edge == ifedge) {
+ loop.addLabeledEdge(edge);
+ }
+ }
+
+ for (StatEdge edge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
+ if (loop.containsStatementStrict(edge.getSource())) {
+ block.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, loop);
+ loop.addPredecessor(edge);
+ }
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java
index 5811ef8..dcd501a 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java
@@ -1,207 +1,208 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.List;
-
import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement;
+import java.util.List;
+
public class LowBreakHelper {
-
- public static void lowBreakLabels(Statement root) {
-
- lowBreakLabelsRec(root);
-
- liftBreakLabels(root);
- }
-
- private static void lowBreakLabelsRec(Statement stat) {
-
- for(;;) {
-
- boolean found = false;
-
- for(StatEdge edge: stat.getLabelEdges()) {
- if(edge.getType() == StatEdge.TYPE_BREAK) {
- Statement minclosure = getMinClosure(stat, edge.getSource());
- if(minclosure != stat) {
- minclosure.addLabeledEdge(edge);
- edge.labeled = isBreakEdgeLabeled(edge.getSource(), minclosure);
- found = true;
- break;
- }
- }
- }
-
- if(!found) {
- break;
- }
- }
-
- for(Statement st: stat.getStats()) {
- lowBreakLabelsRec(st);
- }
-
- }
-
- public static boolean isBreakEdgeLabeled(Statement source, Statement closure) {
-
- if(closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) {
-
- Statement parent = source.getParent();
-
- if(parent == closure) {
- return false;
- } else {
- return isBreakEdgeLabeled(parent, closure) ||
- (parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH);
- }
- } else {
- return true;
- }
- }
-
- public static Statement getMinClosure(Statement closure, Statement source) {
-
- for(;;) {
-
- Statement newclosure = null;
-
- switch(closure.type) {
- case Statement.TYPE_SEQUENCE:
- Statement last = closure.getStats().getLast();
-
- if(isOkClosure(closure, source, last)) {
- newclosure = last;
- }
- break;
- case Statement.TYPE_IF:
- IfStatement ifclosure = (IfStatement)closure;
- if(isOkClosure(closure, source, ifclosure.getIfstat())) {
- newclosure = ifclosure.getIfstat();
- } else if(isOkClosure(closure, source, ifclosure.getElsestat())) {
- newclosure = ifclosure.getElsestat();
- }
- break;
- case Statement.TYPE_TRYCATCH:
- for(Statement st: closure.getStats()) {
- if(isOkClosure(closure, source, st)) {
- newclosure = st;
- break;
- }
- }
- break;
- case Statement.TYPE_SYNCRONIZED:
- Statement body = ((SynchronizedStatement)closure).getBody();
-
- if(isOkClosure(closure, source, body)) {
- newclosure = body;
- }
- }
-
- if(newclosure == null) {
- break;
- }
-
- closure = newclosure;
- }
-
- return closure;
- }
-
- private static boolean isOkClosure(Statement closure, Statement source, Statement stat) {
-
- boolean ok = false;
-
- if(stat != null && stat.containsStatementStrict(source)) {
-
- List<StatEdge> lst = stat.getAllSuccessorEdges();
-
- ok = lst.isEmpty();
- if(!ok) {
- StatEdge edge = lst.get(0);
- ok = (edge.closure == closure && edge.getType() == StatEdge.TYPE_BREAK);
- }
- }
-
- return ok;
- }
-
-
- private static void liftBreakLabels(Statement stat) {
-
- for(Statement st: stat.getStats()) {
- liftBreakLabels(st);
- }
-
-
- for(;;) {
-
- boolean found = false;
-
- for(StatEdge edge: stat.getLabelEdges()) {
- if(edge.explicit && edge.labeled && edge.getType() == StatEdge.TYPE_BREAK) {
-
- Statement newclosure = getMaxBreakLift(stat, edge);
-
- if(newclosure != null) {
- newclosure.addLabeledEdge(edge);
- edge.labeled = isBreakEdgeLabeled(edge.getSource(), newclosure);
-
- found = true;
- break;
- }
- }
- }
-
- if(!found) {
- break;
- }
- }
-
- }
-
- private static Statement getMaxBreakLift(Statement stat, StatEdge edge) {
-
- Statement closure = null;
- Statement newclosure = stat;
-
- while((newclosure = getNextBreakLift(newclosure, edge)) != null) {
- closure = newclosure;
- }
-
- return closure;
- }
-
- private static Statement getNextBreakLift(Statement stat, StatEdge edge) {
-
- Statement closure = stat.getParent();
-
- while(closure!=null && !closure.containsStatementStrict(edge.getDestination())) {
-
- boolean labeled = isBreakEdgeLabeled(edge.getSource(), closure);
- if(closure.isLabeled() || !labeled) {
- return closure;
- }
-
- closure = closure.getParent();
- }
-
- return null;
- }
-
+
+ public static void lowBreakLabels(Statement root) {
+
+ lowBreakLabelsRec(root);
+
+ liftBreakLabels(root);
+ }
+
+ private static void lowBreakLabelsRec(Statement stat) {
+
+ for (; ; ) {
+
+ boolean found = false;
+
+ for (StatEdge edge : stat.getLabelEdges()) {
+ if (edge.getType() == StatEdge.TYPE_BREAK) {
+ Statement minclosure = getMinClosure(stat, edge.getSource());
+ if (minclosure != stat) {
+ minclosure.addLabeledEdge(edge);
+ edge.labeled = isBreakEdgeLabeled(edge.getSource(), minclosure);
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ lowBreakLabelsRec(st);
+ }
+ }
+
+ public static boolean isBreakEdgeLabeled(Statement source, Statement closure) {
+
+ if (closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) {
+
+ Statement parent = source.getParent();
+
+ if (parent == closure) {
+ return false;
+ }
+ else {
+ return isBreakEdgeLabeled(parent, closure) ||
+ (parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH);
+ }
+ }
+ else {
+ return true;
+ }
+ }
+
+ public static Statement getMinClosure(Statement closure, Statement source) {
+
+ for (; ; ) {
+
+ Statement newclosure = null;
+
+ switch (closure.type) {
+ case Statement.TYPE_SEQUENCE:
+ Statement last = closure.getStats().getLast();
+
+ if (isOkClosure(closure, source, last)) {
+ newclosure = last;
+ }
+ break;
+ case Statement.TYPE_IF:
+ IfStatement ifclosure = (IfStatement)closure;
+ if (isOkClosure(closure, source, ifclosure.getIfstat())) {
+ newclosure = ifclosure.getIfstat();
+ }
+ else if (isOkClosure(closure, source, ifclosure.getElsestat())) {
+ newclosure = ifclosure.getElsestat();
+ }
+ break;
+ case Statement.TYPE_TRYCATCH:
+ for (Statement st : closure.getStats()) {
+ if (isOkClosure(closure, source, st)) {
+ newclosure = st;
+ break;
+ }
+ }
+ break;
+ case Statement.TYPE_SYNCRONIZED:
+ Statement body = ((SynchronizedStatement)closure).getBody();
+
+ if (isOkClosure(closure, source, body)) {
+ newclosure = body;
+ }
+ }
+
+ if (newclosure == null) {
+ break;
+ }
+
+ closure = newclosure;
+ }
+
+ return closure;
+ }
+
+ private static boolean isOkClosure(Statement closure, Statement source, Statement stat) {
+
+ boolean ok = false;
+
+ if (stat != null && stat.containsStatementStrict(source)) {
+
+ List<StatEdge> lst = stat.getAllSuccessorEdges();
+
+ ok = lst.isEmpty();
+ if (!ok) {
+ StatEdge edge = lst.get(0);
+ ok = (edge.closure == closure && edge.getType() == StatEdge.TYPE_BREAK);
+ }
+ }
+
+ return ok;
+ }
+
+
+ private static void liftBreakLabels(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ liftBreakLabels(st);
+ }
+
+
+ for (; ; ) {
+
+ boolean found = false;
+
+ for (StatEdge edge : stat.getLabelEdges()) {
+ if (edge.explicit && edge.labeled && edge.getType() == StatEdge.TYPE_BREAK) {
+
+ Statement newclosure = getMaxBreakLift(stat, edge);
+
+ if (newclosure != null) {
+ newclosure.addLabeledEdge(edge);
+ edge.labeled = isBreakEdgeLabeled(edge.getSource(), newclosure);
+
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+ }
+
+ private static Statement getMaxBreakLift(Statement stat, StatEdge edge) {
+
+ Statement closure = null;
+ Statement newclosure = stat;
+
+ while ((newclosure = getNextBreakLift(newclosure, edge)) != null) {
+ closure = newclosure;
+ }
+
+ return closure;
+ }
+
+ private static Statement getNextBreakLift(Statement stat, StatEdge edge) {
+
+ Statement closure = stat.getParent();
+
+ while (closure != null && !closure.containsStatementStrict(edge.getDestination())) {
+
+ boolean labeled = isBreakEdgeLabeled(edge.getSource(), closure);
+ if (closure.isLabeled() || !labeled) {
+ return closure;
+ }
+
+ closure = closure.getParent();
+ }
+
+ return null;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java
index b9149e6..4ce408b 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java
@@ -1,416 +1,421 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SwitchStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
public class MergeHelper {
- public static void enhanceLoops(Statement root) {
-
- while(enhanceLoopsRec(root));
-
- SequenceHelper.condenseSequences(root);
- }
-
- private static boolean enhanceLoopsRec(Statement stat) {
-
- boolean res = false;
-
- for(Statement st: stat.getStats()) {
- if(st.getExprents() == null) {
- res |= enhanceLoopsRec(st);
- }
- }
-
- if(stat.type == Statement.TYPE_DO) {
- res |= enhanceLoop((DoStatement)stat);
- }
-
- return res;
- }
-
- private static boolean enhanceLoop(DoStatement stat) {
-
- int oldloop = stat.getLooptype();
-
- switch(oldloop) {
- case DoStatement.LOOP_DO:
-
- // identify a while loop
- if(matchWhile(stat)) {
- // identify a for loop - subtype of while
- matchFor(stat);
- } else {
- // identify a do{}while loop
- matchDoWhile(stat);
- }
-
- break;
- case DoStatement.LOOP_WHILE:
- matchFor(stat);
- }
-
- return (stat.getLooptype() != oldloop);
- }
-
- private static boolean matchDoWhile(DoStatement stat) {
-
- // search for an if condition at the end of the loop
- Statement last = stat.getFirst();
- while(last.type == Statement.TYPE_SEQUENCE) {
- last = last.getStats().getLast();
- }
-
- if(last.type == Statement.TYPE_IF) {
- IfStatement lastif = (IfStatement)last;
- if(lastif.iftype == IfStatement.IFTYPE_IF && lastif.getIfstat() == null) {
- StatEdge ifedge = lastif.getIfEdge();
- StatEdge elseedge = lastif.getAllSuccessorEdges().get(0);
-
- if((ifedge.getType() == StatEdge.TYPE_BREAK && elseedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.closure == stat
- && isDirectPath(stat, ifedge.getDestination())) ||
- (ifedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.getType() == StatEdge.TYPE_BREAK && ifedge.closure == stat
- && isDirectPath(stat, elseedge.getDestination()))) {
-
- Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD);
- set.remove(last);
-
- if(!set.isEmpty()) {
- return false;
- }
-
-
- stat.setLooptype(DoStatement.LOOP_DOWHILE);
-
- IfExprent ifexpr = (IfExprent)lastif.getHeadexprent().copy();
- if(ifedge.getType() == StatEdge.TYPE_BREAK) {
- ifexpr.negateIf();
- }
- stat.setConditionExprent(ifexpr.getCondition());
- lastif.getFirst().removeSuccessor(ifedge);
- lastif.removeSuccessor(elseedge);
-
- // remove empty if
- if(lastif.getFirst().getExprents().isEmpty()) {
- removeLastEmptyStatement(stat, lastif);
- } else {
- lastif.setExprents(lastif.getFirst().getExprents());
-
- StatEdge newedge = new StatEdge(StatEdge.TYPE_CONTINUE, lastif, stat);
- lastif.addSuccessor(newedge);
- stat.addLabeledEdge(newedge);
- }
-
- if(stat.getAllSuccessorEdges().isEmpty()) {
- StatEdge edge = elseedge.getType() == StatEdge.TYPE_CONTINUE?ifedge:elseedge;
-
- edge.setSource(stat);
- if(edge.closure == stat) {
- edge.closure = stat.getParent();
- }
- stat.addSuccessor(edge);
- }
-
- return true;
- }
- }
- }
- return false;
- }
-
- private static boolean matchWhile(DoStatement stat) {
-
- // search for an if condition at the entrance of the loop
- Statement first = stat.getFirst();
- while(first.type == Statement.TYPE_SEQUENCE) {
- first = first.getFirst();
- }
-
- // found an if statement
- if(first.type == Statement.TYPE_IF) {
- IfStatement firstif = (IfStatement)first;
-
- if(firstif.getFirst().getExprents().isEmpty()) {
-
- if(firstif.iftype == IfStatement.IFTYPE_IF) {
- if(firstif.getIfstat()==null) {
- StatEdge ifedge = firstif.getIfEdge();
- if(isDirectPath(stat, ifedge.getDestination())) {
- // exit condition identified
- stat.setLooptype(DoStatement.LOOP_WHILE);
-
- // negate condition (while header)
- IfExprent ifexpr = (IfExprent)firstif.getHeadexprent().copy();
- ifexpr.negateIf();
- stat.setConditionExprent(ifexpr.getCondition());
-
- // remove edges
- firstif.getFirst().removeSuccessor(ifedge);
- firstif.removeSuccessor(firstif.getAllSuccessorEdges().get(0));
-
- if(stat.getAllSuccessorEdges().isEmpty()) {
- ifedge.setSource(stat);
- if(ifedge.closure == stat) {
- ifedge.closure = stat.getParent();
- }
- stat.addSuccessor(ifedge);
- }
-
- // remove empty if statement as it is now part of the loop
- if(firstif == stat.getFirst()) {
- BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
- DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
- bstat.setExprents(new ArrayList<Exprent>());
- stat.replaceStatement(firstif, bstat);
- } else {
- // precondition: sequence must contain more than one statement!
- Statement sequence = firstif.getParent();
- sequence.getStats().removeWithKey(firstif.id);
- sequence.setFirst(sequence.getStats().get(0));
- }
-
- return true;
- }
- } else {
- StatEdge elseedge = firstif.getAllSuccessorEdges().get(0);
- if(isDirectPath(stat, elseedge.getDestination())) {
- // exit condition identified
- stat.setLooptype(DoStatement.LOOP_WHILE);
-
- // no need to negate the while condition
- stat.setConditionExprent(((IfExprent)firstif.getHeadexprent().copy()).getCondition());
-
- // remove edges
- StatEdge ifedge = firstif.getIfEdge();
- firstif.getFirst().removeSuccessor(ifedge);
- firstif.removeSuccessor(elseedge);
-
- if(stat.getAllSuccessorEdges().isEmpty()) {
-
- elseedge.setSource(stat);
- if(elseedge.closure == stat) {
- elseedge.closure = stat.getParent();
- }
- stat.addSuccessor(elseedge);
- }
-
- if(firstif.getIfstat() == null) {
- BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
- DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
- bstat.setExprents(new ArrayList<Exprent>());
-
- ifedge.setSource(bstat);
- bstat.addSuccessor(ifedge);
-
- stat.replaceStatement(firstif, bstat);
- } else {
- // replace the if statement with its content
- first.getParent().replaceStatement(first, firstif.getIfstat());
-
- // lift closures
- for(StatEdge prededge : elseedge.getDestination().getPredecessorEdges(StatEdge.TYPE_BREAK)) {
- if(stat.containsStatementStrict(prededge.closure)) {
- stat.addLabeledEdge(prededge);
- }
- }
-
- LabelHelper.lowClosures(stat);
- }
-
- return true;
- }
- }
- }
- }
- }
- return false;
- }
-
- public static boolean isDirectPath(Statement stat, Statement endstat) {
-
- Set<Statement> setStat = stat.getNeighboursSet(Statement.STATEDGE_DIRECT_ALL, Statement.DIRECTION_FORWARD);
- if(setStat.isEmpty()) {
- Statement parent = stat.getParent();
- if(parent == null) {
- return false;
- } else {
- switch(parent.type) {
- case Statement.TYPE_ROOT:
- return endstat.type == Statement.TYPE_DUMMYEXIT;
- case Statement.TYPE_DO:
- return (endstat == parent);
- case Statement.TYPE_SWITCH:
- SwitchStatement swst = (SwitchStatement)parent;
- for(int i=0;i<swst.getCaseStatements().size()-1;i++){
- Statement stt = swst.getCaseStatements().get(i);
- if(stt == stat) {
- Statement stnext = swst.getCaseStatements().get(i+1);
-
- if(stnext.getExprents() != null && stnext.getExprents().isEmpty()) {
- stnext = stnext.getAllSuccessorEdges().get(0).getDestination();
- }
- return (endstat == stnext);
- }
- }
- default:
- return isDirectPath(parent, endstat);
- }
- }
-
- } else {
- return setStat.contains(endstat);
- }
- }
-
- private static boolean matchFor(DoStatement stat) {
-
- Exprent lastDoExprent = null, initDoExprent = null;
- Statement lastData = null, preData = null;
-
- // get last exprent
- lastData = getLastDirectData(stat.getFirst());
- if(lastData == null || lastData.getExprents().isEmpty()) {
- return false;
- }
-
- List<Exprent> lstExpr = lastData.getExprents();
- lastDoExprent = lstExpr.get(lstExpr.size()-1);
-
- boolean issingle = false;
- if(lstExpr.size() == 1) { // single exprent
- if(lastData.getAllPredecessorEdges().size() > 1) { // break edges
- issingle = true;
- }
- }
-
- boolean haslast = issingle || (lastDoExprent.type == Exprent.EXPRENT_ASSIGNMENT ||
- lastDoExprent.type == Exprent.EXPRENT_FUNCTION);
-
- if(!haslast) {
- return false;
- }
-
- boolean hasinit = false;
-
- // search for an initializing exprent
- Statement current = stat;
- for(;;){
- Statement parent = current.getParent();
- if(parent == null) {
- break;
- }
-
- if(parent.type == Statement.TYPE_SEQUENCE) {
- if(current == parent.getFirst()) {
- current = parent;
- } else {
- preData = current.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD).get(0);
- preData = getLastDirectData(preData);
- if(preData != null && !preData.getExprents().isEmpty()) {
- initDoExprent = preData.getExprents().get(preData.getExprents().size()-1);
- if(initDoExprent.type == Exprent.EXPRENT_ASSIGNMENT) {
- hasinit = true;
- }
- }
- break;
- }
- } else {
- break;
- }
- }
-
- if((hasinit && haslast) || issingle) { // FIXME: issingle sufficient?
-
- Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD);
- set.remove(lastData);
-
- if(!set.isEmpty()) {
- return false;
- }
-
- stat.setLooptype(DoStatement.LOOP_FOR);
- if(hasinit) {
- stat.setInitExprent(preData.getExprents().remove(preData.getExprents().size()-1));
- }
- stat.setIncExprent(lastData.getExprents().remove(lastData.getExprents().size()-1));
- }
-
- if(lastData.getExprents().isEmpty()) {
- List<StatEdge> lst = lastData.getAllSuccessorEdges();
- if(!lst.isEmpty()) {
- lastData.removeSuccessor(lst.get(0));
- }
- removeLastEmptyStatement(stat, lastData);
- }
-
- return true;
- }
-
- private static void removeLastEmptyStatement(DoStatement dostat, Statement stat) {
-
- if(stat == dostat.getFirst()) {
- BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
- DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
- bstat.setExprents(new ArrayList<Exprent>());
- dostat.replaceStatement(stat, bstat);
- } else {
- for(StatEdge edge: stat.getAllPredecessorEdges()) {
- edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_CONTINUE);
-
- stat.removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, dostat);
- dostat.addPredecessor(edge);
-
- dostat.addLabeledEdge(edge);
- }
-
- // parent is a sequence statement
- stat.getParent().getStats().removeWithKey(stat.id);
- }
-
- }
-
- private static Statement getLastDirectData(Statement stat) {
-
- if(stat.getExprents() != null) {
- return stat;
- }
-
- switch(stat.type) {
- case Statement.TYPE_SEQUENCE:
- for(int i=stat.getStats().size()-1;i>=0;i--) {
- Statement tmp = getLastDirectData(stat.getStats().get(i));
- if(tmp == null || !tmp.getExprents().isEmpty()) {
- return tmp;
- }
- }
- }
- return null;
- }
+ public static void enhanceLoops(Statement root) {
+
+ while (enhanceLoopsRec(root)) ;
+
+ SequenceHelper.condenseSequences(root);
+ }
+
+ private static boolean enhanceLoopsRec(Statement stat) {
+
+ boolean res = false;
+
+ for (Statement st : stat.getStats()) {
+ if (st.getExprents() == null) {
+ res |= enhanceLoopsRec(st);
+ }
+ }
+
+ if (stat.type == Statement.TYPE_DO) {
+ res |= enhanceLoop((DoStatement)stat);
+ }
+
+ return res;
+ }
+
+ private static boolean enhanceLoop(DoStatement stat) {
+
+ int oldloop = stat.getLooptype();
+
+ switch (oldloop) {
+ case DoStatement.LOOP_DO:
+
+ // identify a while loop
+ if (matchWhile(stat)) {
+ // identify a for loop - subtype of while
+ matchFor(stat);
+ }
+ else {
+ // identify a do{}while loop
+ matchDoWhile(stat);
+ }
+
+ break;
+ case DoStatement.LOOP_WHILE:
+ matchFor(stat);
+ }
+
+ return (stat.getLooptype() != oldloop);
+ }
+
+ private static boolean matchDoWhile(DoStatement stat) {
+
+ // search for an if condition at the end of the loop
+ Statement last = stat.getFirst();
+ while (last.type == Statement.TYPE_SEQUENCE) {
+ last = last.getStats().getLast();
+ }
+
+ if (last.type == Statement.TYPE_IF) {
+ IfStatement lastif = (IfStatement)last;
+ if (lastif.iftype == IfStatement.IFTYPE_IF && lastif.getIfstat() == null) {
+ StatEdge ifedge = lastif.getIfEdge();
+ StatEdge elseedge = lastif.getAllSuccessorEdges().get(0);
+
+ if ((ifedge.getType() == StatEdge.TYPE_BREAK && elseedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.closure == stat
+ && isDirectPath(stat, ifedge.getDestination())) ||
+ (ifedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.getType() == StatEdge.TYPE_BREAK && ifedge.closure == stat
+ && isDirectPath(stat, elseedge.getDestination()))) {
+
+ Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD);
+ set.remove(last);
+
+ if (!set.isEmpty()) {
+ return false;
+ }
+
+
+ stat.setLooptype(DoStatement.LOOP_DOWHILE);
+
+ IfExprent ifexpr = (IfExprent)lastif.getHeadexprent().copy();
+ if (ifedge.getType() == StatEdge.TYPE_BREAK) {
+ ifexpr.negateIf();
+ }
+ stat.setConditionExprent(ifexpr.getCondition());
+ lastif.getFirst().removeSuccessor(ifedge);
+ lastif.removeSuccessor(elseedge);
+
+ // remove empty if
+ if (lastif.getFirst().getExprents().isEmpty()) {
+ removeLastEmptyStatement(stat, lastif);
+ }
+ else {
+ lastif.setExprents(lastif.getFirst().getExprents());
+
+ StatEdge newedge = new StatEdge(StatEdge.TYPE_CONTINUE, lastif, stat);
+ lastif.addSuccessor(newedge);
+ stat.addLabeledEdge(newedge);
+ }
+
+ if (stat.getAllSuccessorEdges().isEmpty()) {
+ StatEdge edge = elseedge.getType() == StatEdge.TYPE_CONTINUE ? ifedge : elseedge;
+
+ edge.setSource(stat);
+ if (edge.closure == stat) {
+ edge.closure = stat.getParent();
+ }
+ stat.addSuccessor(edge);
+ }
+
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static boolean matchWhile(DoStatement stat) {
+
+ // search for an if condition at the entrance of the loop
+ Statement first = stat.getFirst();
+ while (first.type == Statement.TYPE_SEQUENCE) {
+ first = first.getFirst();
+ }
+
+ // found an if statement
+ if (first.type == Statement.TYPE_IF) {
+ IfStatement firstif = (IfStatement)first;
+
+ if (firstif.getFirst().getExprents().isEmpty()) {
+
+ if (firstif.iftype == IfStatement.IFTYPE_IF) {
+ if (firstif.getIfstat() == null) {
+ StatEdge ifedge = firstif.getIfEdge();
+ if (isDirectPath(stat, ifedge.getDestination())) {
+ // exit condition identified
+ stat.setLooptype(DoStatement.LOOP_WHILE);
+
+ // negate condition (while header)
+ IfExprent ifexpr = (IfExprent)firstif.getHeadexprent().copy();
+ ifexpr.negateIf();
+ stat.setConditionExprent(ifexpr.getCondition());
+
+ // remove edges
+ firstif.getFirst().removeSuccessor(ifedge);
+ firstif.removeSuccessor(firstif.getAllSuccessorEdges().get(0));
+
+ if (stat.getAllSuccessorEdges().isEmpty()) {
+ ifedge.setSource(stat);
+ if (ifedge.closure == stat) {
+ ifedge.closure = stat.getParent();
+ }
+ stat.addSuccessor(ifedge);
+ }
+
+ // remove empty if statement as it is now part of the loop
+ if (firstif == stat.getFirst()) {
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ bstat.setExprents(new ArrayList<Exprent>());
+ stat.replaceStatement(firstif, bstat);
+ }
+ else {
+ // precondition: sequence must contain more than one statement!
+ Statement sequence = firstif.getParent();
+ sequence.getStats().removeWithKey(firstif.id);
+ sequence.setFirst(sequence.getStats().get(0));
+ }
+
+ return true;
+ }
+ }
+ else {
+ StatEdge elseedge = firstif.getAllSuccessorEdges().get(0);
+ if (isDirectPath(stat, elseedge.getDestination())) {
+ // exit condition identified
+ stat.setLooptype(DoStatement.LOOP_WHILE);
+
+ // no need to negate the while condition
+ stat.setConditionExprent(((IfExprent)firstif.getHeadexprent().copy()).getCondition());
+
+ // remove edges
+ StatEdge ifedge = firstif.getIfEdge();
+ firstif.getFirst().removeSuccessor(ifedge);
+ firstif.removeSuccessor(elseedge);
+
+ if (stat.getAllSuccessorEdges().isEmpty()) {
+
+ elseedge.setSource(stat);
+ if (elseedge.closure == stat) {
+ elseedge.closure = stat.getParent();
+ }
+ stat.addSuccessor(elseedge);
+ }
+
+ if (firstif.getIfstat() == null) {
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ bstat.setExprents(new ArrayList<Exprent>());
+
+ ifedge.setSource(bstat);
+ bstat.addSuccessor(ifedge);
+
+ stat.replaceStatement(firstif, bstat);
+ }
+ else {
+ // replace the if statement with its content
+ first.getParent().replaceStatement(first, firstif.getIfstat());
+
+ // lift closures
+ for (StatEdge prededge : elseedge.getDestination().getPredecessorEdges(StatEdge.TYPE_BREAK)) {
+ if (stat.containsStatementStrict(prededge.closure)) {
+ stat.addLabeledEdge(prededge);
+ }
+ }
+
+ LabelHelper.lowClosures(stat);
+ }
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public static boolean isDirectPath(Statement stat, Statement endstat) {
+
+ Set<Statement> setStat = stat.getNeighboursSet(Statement.STATEDGE_DIRECT_ALL, Statement.DIRECTION_FORWARD);
+ if (setStat.isEmpty()) {
+ Statement parent = stat.getParent();
+ if (parent == null) {
+ return false;
+ }
+ else {
+ switch (parent.type) {
+ case Statement.TYPE_ROOT:
+ return endstat.type == Statement.TYPE_DUMMYEXIT;
+ case Statement.TYPE_DO:
+ return (endstat == parent);
+ case Statement.TYPE_SWITCH:
+ SwitchStatement swst = (SwitchStatement)parent;
+ for (int i = 0; i < swst.getCaseStatements().size() - 1; i++) {
+ Statement stt = swst.getCaseStatements().get(i);
+ if (stt == stat) {
+ Statement stnext = swst.getCaseStatements().get(i + 1);
+
+ if (stnext.getExprents() != null && stnext.getExprents().isEmpty()) {
+ stnext = stnext.getAllSuccessorEdges().get(0).getDestination();
+ }
+ return (endstat == stnext);
+ }
+ }
+ default:
+ return isDirectPath(parent, endstat);
+ }
+ }
+ }
+ else {
+ return setStat.contains(endstat);
+ }
+ }
+
+ private static boolean matchFor(DoStatement stat) {
+
+ Exprent lastDoExprent = null, initDoExprent = null;
+ Statement lastData = null, preData = null;
+
+ // get last exprent
+ lastData = getLastDirectData(stat.getFirst());
+ if (lastData == null || lastData.getExprents().isEmpty()) {
+ return false;
+ }
+
+ List<Exprent> lstExpr = lastData.getExprents();
+ lastDoExprent = lstExpr.get(lstExpr.size() - 1);
+
+ boolean issingle = false;
+ if (lstExpr.size() == 1) { // single exprent
+ if (lastData.getAllPredecessorEdges().size() > 1) { // break edges
+ issingle = true;
+ }
+ }
+
+ boolean haslast = issingle || (lastDoExprent.type == Exprent.EXPRENT_ASSIGNMENT ||
+ lastDoExprent.type == Exprent.EXPRENT_FUNCTION);
+
+ if (!haslast) {
+ return false;
+ }
+
+ boolean hasinit = false;
+
+ // search for an initializing exprent
+ Statement current = stat;
+ for (; ; ) {
+ Statement parent = current.getParent();
+ if (parent == null) {
+ break;
+ }
+
+ if (parent.type == Statement.TYPE_SEQUENCE) {
+ if (current == parent.getFirst()) {
+ current = parent;
+ }
+ else {
+ preData = current.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD).get(0);
+ preData = getLastDirectData(preData);
+ if (preData != null && !preData.getExprents().isEmpty()) {
+ initDoExprent = preData.getExprents().get(preData.getExprents().size() - 1);
+ if (initDoExprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ hasinit = true;
+ }
+ }
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ if ((hasinit && haslast) || issingle) { // FIXME: issingle sufficient?
+
+ Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD);
+ set.remove(lastData);
+
+ if (!set.isEmpty()) {
+ return false;
+ }
+
+ stat.setLooptype(DoStatement.LOOP_FOR);
+ if (hasinit) {
+ stat.setInitExprent(preData.getExprents().remove(preData.getExprents().size() - 1));
+ }
+ stat.setIncExprent(lastData.getExprents().remove(lastData.getExprents().size() - 1));
+ }
+
+ if (lastData.getExprents().isEmpty()) {
+ List<StatEdge> lst = lastData.getAllSuccessorEdges();
+ if (!lst.isEmpty()) {
+ lastData.removeSuccessor(lst.get(0));
+ }
+ removeLastEmptyStatement(stat, lastData);
+ }
+
+ return true;
+ }
+
+ private static void removeLastEmptyStatement(DoStatement dostat, Statement stat) {
+
+ if (stat == dostat.getFirst()) {
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ bstat.setExprents(new ArrayList<Exprent>());
+ dostat.replaceStatement(stat, bstat);
+ }
+ else {
+ for (StatEdge edge : stat.getAllPredecessorEdges()) {
+ edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_CONTINUE);
+
+ stat.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, dostat);
+ dostat.addPredecessor(edge);
+
+ dostat.addLabeledEdge(edge);
+ }
+
+ // parent is a sequence statement
+ stat.getParent().getStats().removeWithKey(stat.id);
+ }
+ }
+
+ private static Statement getLastDirectData(Statement stat) {
+
+ if (stat.getExprents() != null) {
+ return stat;
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_SEQUENCE:
+ for (int i = stat.getStats().size() - 1; i >= 0; i--) {
+ Statement tmp = getLastDirectData(stat.getStats().get(i));
+ if (tmp == null || !tmp.getExprents().isEmpty()) {
+ return tmp;
+ }
+ }
+ }
+ return null;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java
index be90625..aacb61f 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java
@@ -1,24 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
@@ -29,125 +25,130 @@ import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatements
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
import org.jetbrains.java.decompiler.struct.gen.VarType;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+
public class PPandMMHelper {
- private boolean exprentReplaced;
-
- public boolean findPPandMM(RootStatement root) {
-
- FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
- DirectGraph dgraph = flatthelper.buildDirectGraph(root);
-
- LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
- stack.add(dgraph.first);
-
- HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
-
- boolean res = false;
-
- while(!stack.isEmpty()) {
-
- DirectNode node = stack.removeFirst();
-
- if(setVisited.contains(node)) {
- continue;
- }
- setVisited.add(node);
-
- res |= processExprentList(node.exprents);
-
- stack.addAll(node.succs);
- }
-
- return res;
- }
-
- private boolean processExprentList(List<Exprent> lst) {
-
- boolean result = false;
-
- for(int i=0;i<lst.size();i++) {
- Exprent exprent = lst.get(i);
- exprentReplaced = false;
-
- Exprent retexpr = processExprentRecursive(exprent);
- if(retexpr != null) {
- lst.set(i, retexpr);
-
- result = true;
- i--; // process the same exprent again
- }
-
- result |= exprentReplaced;
- }
-
- return result;
- }
-
- private Exprent processExprentRecursive(Exprent exprent) {
-
- boolean replaced = true;
- while(replaced) {
- replaced = false;
-
- for(Exprent expr: exprent.getAllExprents()) {
- Exprent retexpr = processExprentRecursive(expr);
- if(retexpr != null) {
- exprent.replaceExprent(expr, retexpr);
- replaced = true;
- exprentReplaced = true;
- break;
- }
- }
- }
-
- if(exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent as = (AssignmentExprent)exprent;
-
- if(as.getRight().type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent func = (FunctionExprent)as.getRight();
-
- VarType midlayer = null;
- if(func.getFunctype() >= FunctionExprent.FUNCTION_I2L &&
- func.getFunctype() <= FunctionExprent.FUNCTION_I2S) {
- midlayer = func.getSimpleCastType();
- if(func.getLstOperands().get(0).type == Exprent.EXPRENT_FUNCTION) {
- func = (FunctionExprent)func.getLstOperands().get(0);
- } else {
- return null;
- }
- }
-
- if(func.getFunctype() == FunctionExprent.FUNCTION_ADD ||
- func.getFunctype() == FunctionExprent.FUNCTION_SUB) {
- Exprent econd = func.getLstOperands().get(0);
- Exprent econst = func.getLstOperands().get(1);
-
- if(econst.type != Exprent.EXPRENT_CONST && econd.type == Exprent.EXPRENT_CONST &&
- func.getFunctype() == FunctionExprent.FUNCTION_ADD) {
- econd = econst;
- econst = func.getLstOperands().get(0);
- }
-
- if(econst.type == Exprent.EXPRENT_CONST && ((ConstExprent)econst).hasValueOne()) {
- Exprent left = as.getLeft();
-
- VarType condtype = econd.getExprType();
- if(left.equals(econd) && (midlayer == null || midlayer.equals(condtype))) {
- FunctionExprent ret = new FunctionExprent(
- func.getFunctype() == FunctionExprent.FUNCTION_ADD?FunctionExprent.FUNCTION_PPI:FunctionExprent.FUNCTION_MMI,
- Arrays.asList(new Exprent[]{econd}));
- ret.setImplicitType(condtype);
-
- exprentReplaced = true;
- return ret;
- }
- }
- }
- }
- }
-
- return null;
- }
-
+ private boolean exprentReplaced;
+
+ public boolean findPPandMM(RootStatement root) {
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ stack.add(dgraph.first);
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+
+ boolean res = false;
+
+ while (!stack.isEmpty()) {
+
+ DirectNode node = stack.removeFirst();
+
+ if (setVisited.contains(node)) {
+ continue;
+ }
+ setVisited.add(node);
+
+ res |= processExprentList(node.exprents);
+
+ stack.addAll(node.succs);
+ }
+
+ return res;
+ }
+
+ private boolean processExprentList(List<Exprent> lst) {
+
+ boolean result = false;
+
+ for (int i = 0; i < lst.size(); i++) {
+ Exprent exprent = lst.get(i);
+ exprentReplaced = false;
+
+ Exprent retexpr = processExprentRecursive(exprent);
+ if (retexpr != null) {
+ lst.set(i, retexpr);
+
+ result = true;
+ i--; // process the same exprent again
+ }
+
+ result |= exprentReplaced;
+ }
+
+ return result;
+ }
+
+ private Exprent processExprentRecursive(Exprent exprent) {
+
+ boolean replaced = true;
+ while (replaced) {
+ replaced = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ Exprent retexpr = processExprentRecursive(expr);
+ if (retexpr != null) {
+ exprent.replaceExprent(expr, retexpr);
+ replaced = true;
+ exprentReplaced = true;
+ break;
+ }
+ }
+ }
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)exprent;
+
+ if (as.getRight().type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent func = (FunctionExprent)as.getRight();
+
+ VarType midlayer = null;
+ if (func.getFunctype() >= FunctionExprent.FUNCTION_I2L &&
+ func.getFunctype() <= FunctionExprent.FUNCTION_I2S) {
+ midlayer = func.getSimpleCastType();
+ if (func.getLstOperands().get(0).type == Exprent.EXPRENT_FUNCTION) {
+ func = (FunctionExprent)func.getLstOperands().get(0);
+ }
+ else {
+ return null;
+ }
+ }
+
+ if (func.getFunctype() == FunctionExprent.FUNCTION_ADD ||
+ func.getFunctype() == FunctionExprent.FUNCTION_SUB) {
+ Exprent econd = func.getLstOperands().get(0);
+ Exprent econst = func.getLstOperands().get(1);
+
+ if (econst.type != Exprent.EXPRENT_CONST && econd.type == Exprent.EXPRENT_CONST &&
+ func.getFunctype() == FunctionExprent.FUNCTION_ADD) {
+ econd = econst;
+ econst = func.getLstOperands().get(0);
+ }
+
+ if (econst.type == Exprent.EXPRENT_CONST && ((ConstExprent)econst).hasValueOne()) {
+ Exprent left = as.getLeft();
+
+ VarType condtype = econd.getExprType();
+ if (left.equals(econd) && (midlayer == null || midlayer.equals(condtype))) {
+ FunctionExprent ret = new FunctionExprent(
+ func.getFunctype() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI,
+ Arrays.asList(new Exprent[]{econd}));
+ ret.setImplicitType(condtype);
+
+ exprentReplaced = true;
+ return ret;
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/PrimitiveExprsList.java b/src/org/jetbrains/java/decompiler/modules/decompiler/PrimitiveExprsList.java
index 0a0ef45..6dbc887 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/PrimitiveExprsList.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/PrimitiveExprsList.java
@@ -1,47 +1,49 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-
public class PrimitiveExprsList {
- private List<Exprent> lstExprents = new ArrayList<Exprent>();
-
- private ExprentStack stack = new ExprentStack();
-
- public PrimitiveExprsList() {}
-
- public PrimitiveExprsList copyStack() {
- PrimitiveExprsList prlst = new PrimitiveExprsList();
- prlst.setStack(stack.clone());
- return prlst;
- }
-
- public List<Exprent> getLstExprents() {
- return lstExprents;
- }
-
- public ExprentStack getStack() {
- return stack;
- }
-
- public void setStack(ExprentStack stack) {
- this.stack = stack;
- }
+ private List<Exprent> lstExprents = new ArrayList<Exprent>();
+
+ private ExprentStack stack = new ExprentStack();
+
+ public PrimitiveExprsList() {
+ }
+
+ public PrimitiveExprsList copyStack() {
+ PrimitiveExprsList prlst = new PrimitiveExprsList();
+ prlst.setStack(stack.clone());
+ return prlst;
+ }
+
+ public List<Exprent> getLstExprents() {
+ return lstExprents;
+ }
+
+ public ExprentStack getStack() {
+ return stack;
+ }
+
+ public void setStack(ExprentStack stack) {
+ this.stack = stack;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java
index e8f1e0a..8dcf9d5 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java
@@ -1,428 +1,432 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
import org.jetbrains.java.decompiler.struct.gen.VarType;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
public class SecondaryFunctionsHelper {
- private static final int[] funcsnot = new int[] {
- FunctionExprent.FUNCTION_NE,
- FunctionExprent.FUNCTION_EQ,
- FunctionExprent.FUNCTION_GE,
- FunctionExprent.FUNCTION_LT,
- FunctionExprent.FUNCTION_LE,
- FunctionExprent.FUNCTION_GT,
- FunctionExprent.FUNCTION_COR,
- FunctionExprent.FUNCTION_CADD
- };
-
- private static final HashMap<Integer, Integer[]> mapNumComparisons = new HashMap<Integer, Integer[]>();
-
- static {
- mapNumComparisons.put(FunctionExprent.FUNCTION_EQ, new Integer[] {FunctionExprent.FUNCTION_LT, FunctionExprent.FUNCTION_EQ, FunctionExprent.FUNCTION_GT});
- mapNumComparisons.put(FunctionExprent.FUNCTION_NE, new Integer[] {FunctionExprent.FUNCTION_GE, FunctionExprent.FUNCTION_NE, FunctionExprent.FUNCTION_LE});
- mapNumComparisons.put(FunctionExprent.FUNCTION_GT, new Integer[] {FunctionExprent.FUNCTION_GE, FunctionExprent.FUNCTION_GT, null});
- mapNumComparisons.put(FunctionExprent.FUNCTION_GE, new Integer[] {null, FunctionExprent.FUNCTION_GE, FunctionExprent.FUNCTION_GT});
- mapNumComparisons.put(FunctionExprent.FUNCTION_LT, new Integer[] {null, FunctionExprent.FUNCTION_LT, FunctionExprent.FUNCTION_LE});
- mapNumComparisons.put(FunctionExprent.FUNCTION_LE, new Integer[] {FunctionExprent.FUNCTION_LT, FunctionExprent.FUNCTION_LE, null});
- }
-
-
- public static boolean identifySecondaryFunctions(Statement stat) {
-
- if(stat.getExprents() == null) {
- // if(){;}else{...} -> if(!){...}
- if(stat.type == Statement.TYPE_IF) {
- IfStatement ifelsestat = (IfStatement)stat;
- Statement ifstat = ifelsestat.getIfstat();
-
- if(ifelsestat.iftype == IfStatement.IFTYPE_IFELSE && ifstat.getExprents() != null &&
- ifstat.getExprents().isEmpty() && (ifstat.getAllSuccessorEdges().isEmpty() || !ifstat.getAllSuccessorEdges().get(0).explicit)) {
-
- // move else to the if position
- ifelsestat.getStats().removeWithKey(ifstat.id);
-
- ifelsestat.iftype = IfStatement.IFTYPE_IF;
- ifelsestat.setIfstat(ifelsestat.getElsestat());
- ifelsestat.setElsestat(null);
-
- if(ifelsestat.getAllSuccessorEdges().isEmpty() && !ifstat.getAllSuccessorEdges().isEmpty()) {
- StatEdge endedge = ifstat.getAllSuccessorEdges().get(0);
-
- ifstat.removeSuccessor(endedge);
- endedge.setSource(ifelsestat);
- if(endedge.closure != null) {
- ifelsestat.getParent().addLabeledEdge(endedge);
- }
- ifelsestat.addSuccessor(endedge);
- }
-
- ifelsestat.getFirst().removeSuccessor(ifelsestat.getIfEdge());
-
- ifelsestat.setIfEdge(ifelsestat.getElseEdge());
- ifelsestat.setElseEdge(null);
-
- // negate head expression
- ifelsestat.setNegated(!ifelsestat.isNegated());
- ifelsestat.getHeadexprentList().set(0, ((IfExprent)ifelsestat.getHeadexprent().copy()).negateIf());
-
- return true;
- }
- }
- }
-
-
- boolean replaced = true;
- while(replaced) {
- replaced = false;
-
- List<Object> lstObjects = new ArrayList<Object>(stat.getExprents()==null?stat.getSequentialObjects():stat.getExprents());
-
- for(int i=0;i<lstObjects.size();i++) {
- Object obj = lstObjects.get(i);
-
- if(obj instanceof Statement) {
- if(identifySecondaryFunctions((Statement)obj)) {
- replaced = true;
- break;
- }
- } else if(obj instanceof Exprent) {
- Exprent retexpr = identifySecondaryFunctions((Exprent)obj, true);
- if(retexpr != null) {
- if(stat.getExprents()==null) {
- // only head expressions can be replaced!
- stat.replaceExprent((Exprent)obj, retexpr);
- } else {
- stat.getExprents().set(i, retexpr);
- }
- replaced = true;
- break;
- }
- }
- }
- }
-
- return false;
- }
-
-
- private static Exprent identifySecondaryFunctions(Exprent exprent, boolean statement_level) {
-
- if(exprent.type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent fexpr = (FunctionExprent)exprent;
-
- switch(fexpr.getFunctype()) {
- case FunctionExprent.FUNCTION_BOOLNOT:
-
- Exprent retparam = propagateBoolNot(fexpr);
-
- if(retparam != null) {
- return retparam;
- }
-
- break;
- case FunctionExprent.FUNCTION_EQ:
- case FunctionExprent.FUNCTION_NE:
- case FunctionExprent.FUNCTION_GT:
- case FunctionExprent.FUNCTION_GE:
- case FunctionExprent.FUNCTION_LT:
- case FunctionExprent.FUNCTION_LE:
- Exprent expr1 = fexpr.getLstOperands().get(0);
- Exprent expr2 = fexpr.getLstOperands().get(1);
-
- if(expr1.type == Exprent.EXPRENT_CONST) {
- expr2 = expr1;
- expr1 = fexpr.getLstOperands().get(1);
- }
-
- if(expr1.type == Exprent.EXPRENT_FUNCTION && expr2.type == Exprent.EXPRENT_CONST) {
- FunctionExprent funcexpr = (FunctionExprent)expr1;
- ConstExprent cexpr = (ConstExprent)expr2;
-
- int functype = funcexpr.getFunctype();
- if(functype == FunctionExprent.FUNCTION_LCMP || functype == FunctionExprent.FUNCTION_FCMPG ||
- functype == FunctionExprent.FUNCTION_FCMPL || functype == FunctionExprent.FUNCTION_DCMPG ||
- functype == FunctionExprent.FUNCTION_DCMPL) {
-
- int desttype = -1;
-
- Integer[] destcons = mapNumComparisons.get(fexpr.getFunctype());
- if(destcons != null) {
- int index = cexpr.getIntValue()+1;
- if(index >= 0 && index <= 2) {
- Integer destcon = destcons[index];
- if(destcon != null) {
- desttype = destcon.intValue();
- }
- }
- }
-
- if(desttype >= 0) {
- return new FunctionExprent(desttype, funcexpr.getLstOperands());
- }
- }
- }
- }
- }
-
-
- boolean replaced = true;
- while(replaced) {
- replaced = false;
-
- for(Exprent expr: exprent.getAllExprents()) {
- Exprent retexpr = identifySecondaryFunctions(expr, false);
- if(retexpr != null) {
- exprent.replaceExprent(expr, retexpr);
- replaced = true;
- break;
- }
- }
- }
-
- switch(exprent.type) {
- case Exprent.EXPRENT_FUNCTION:
- FunctionExprent fexpr = (FunctionExprent)exprent;
- List<Exprent> lstOperands = fexpr.getLstOperands();
-
- switch(fexpr.getFunctype()) {
- case FunctionExprent.FUNCTION_XOR:
- for(int i=0;i<2;i++) {
- Exprent operand = lstOperands.get(i);
- VarType operandtype = operand.getExprType();
-
- if(operand.type == Exprent.EXPRENT_CONST &&
- operandtype.type != CodeConstants.TYPE_BOOLEAN) {
- ConstExprent cexpr = (ConstExprent)operand;
- long val;
- if(operandtype.type == CodeConstants.TYPE_LONG) {
- val = ((Long)cexpr.getValue()).longValue();
- } else {
- val = ((Integer)cexpr.getValue()).intValue();
- }
-
- if(val == -1) {
- List<Exprent> lstBitNotOperand = new ArrayList<Exprent>();
- lstBitNotOperand.add(lstOperands.get(1-i));
- return new FunctionExprent(FunctionExprent.FUNCTION_BITNOT, lstBitNotOperand);
- }
- }
- }
- break;
- case FunctionExprent.FUNCTION_EQ:
- case FunctionExprent.FUNCTION_NE:
- if(lstOperands.get(0).getExprType().type == CodeConstants.TYPE_BOOLEAN &&
- lstOperands.get(1).getExprType().type == CodeConstants.TYPE_BOOLEAN) {
- for(int i=0;i<2;i++) {
- if(lstOperands.get(i).type == Exprent.EXPRENT_CONST) {
- ConstExprent cexpr = (ConstExprent)lstOperands.get(i);
- int val = ((Integer)cexpr.getValue()).intValue();
-
- if((fexpr.getFunctype() == FunctionExprent.FUNCTION_EQ && val == 1) ||
- (fexpr.getFunctype() == FunctionExprent.FUNCTION_NE && val == 0)) {
- return lstOperands.get(1-i);
- } else {
- List<Exprent> lstNotOperand = new ArrayList<Exprent>();
- lstNotOperand.add(lstOperands.get(1-i));
- return new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, lstNotOperand);
- }
- }
- }
- }
- break;
- case FunctionExprent.FUNCTION_BOOLNOT:
- if(lstOperands.get(0).type == Exprent.EXPRENT_CONST) {
- int val = ((ConstExprent)lstOperands.get(0)).getIntValue();
- if(val == 0) {
- return new ConstExprent(VarType.VARTYPE_BOOLEAN, new Integer(1));
- } else {
- return new ConstExprent(VarType.VARTYPE_BOOLEAN, new Integer(0));
- }
- }
- break;
- case FunctionExprent.FUNCTION_IIF:
- Exprent expr1 = lstOperands.get(1);
- Exprent expr2 = lstOperands.get(2);
-
- if(expr1.type == Exprent.EXPRENT_CONST && expr2.type == Exprent.EXPRENT_CONST) {
- ConstExprent cexpr1 = (ConstExprent)expr1;
- ConstExprent cexpr2 = (ConstExprent)expr2;
-
- if(cexpr1.getExprType().type == CodeConstants.TYPE_BOOLEAN &&
- cexpr2.getExprType().type == CodeConstants.TYPE_BOOLEAN) {
-
- if(cexpr1.getIntValue() == 0 && cexpr2.getIntValue() != 0) {
- return new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[] {lstOperands.get(0)}));
- } else if(cexpr1.getIntValue() != 0 && cexpr2.getIntValue() == 0) {
- return lstOperands.get(0);
- }
- }
- }
- break;
- case FunctionExprent.FUNCTION_LCMP:
- case FunctionExprent.FUNCTION_FCMPL:
- case FunctionExprent.FUNCTION_FCMPG:
- case FunctionExprent.FUNCTION_DCMPL:
- case FunctionExprent.FUNCTION_DCMPG:
- int var = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
- VarType type = lstOperands.get(0).getExprType();
- VarProcessor processor = (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR);
-
- FunctionExprent iff = new FunctionExprent(FunctionExprent.FUNCTION_IIF, Arrays.asList(new Exprent[] {
- new FunctionExprent(FunctionExprent.FUNCTION_LT, Arrays.asList(new Exprent[] {new VarExprent(var, type, processor),
- ConstExprent.getZeroConstant(type.type)})),
- new ConstExprent(VarType.VARTYPE_INT, new Integer(-1)),
- new ConstExprent(VarType.VARTYPE_INT, new Integer(1))}));
-
- FunctionExprent head = new FunctionExprent(FunctionExprent.FUNCTION_EQ, Arrays.asList(new Exprent[] {
- new AssignmentExprent(new VarExprent(var, type, processor), new FunctionExprent(FunctionExprent.FUNCTION_SUB,
- Arrays.asList(new Exprent[] {lstOperands.get(0), lstOperands.get(1)}))),
- ConstExprent.getZeroConstant(type.type)}));
-
- processor.setVarType(new VarVersionPaar(var, 0), type);
-
- return new FunctionExprent(FunctionExprent.FUNCTION_IIF, Arrays.asList(new Exprent[] {
- head, new ConstExprent(VarType.VARTYPE_INT, new Integer(0)), iff}));
- }
- break;
- case Exprent.EXPRENT_ASSIGNMENT: // check for conditional assignment
- AssignmentExprent asexpr = (AssignmentExprent)exprent;
- Exprent right = asexpr.getRight();
- Exprent left = asexpr.getLeft();
-
- if(right.type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent func = (FunctionExprent)right;
-
- VarType midlayer = null;
- if(func.getFunctype() >= FunctionExprent.FUNCTION_I2L &&
- func.getFunctype() <= FunctionExprent.FUNCTION_I2S) {
- right = func.getLstOperands().get(0);
- midlayer = func.getSimpleCastType();
- if(right.type == Exprent.EXPRENT_FUNCTION) {
- func = (FunctionExprent)right;
- } else {
- return null;
- }
- }
-
- List<Exprent> lstFuncOperands = func.getLstOperands();
-
- Exprent cond = null;
-
- switch(func.getFunctype()) {
- case FunctionExprent.FUNCTION_ADD:
- case FunctionExprent.FUNCTION_AND:
- case FunctionExprent.FUNCTION_OR:
- case FunctionExprent.FUNCTION_XOR:
- if(left.equals(lstFuncOperands.get(1))) {
- cond = lstFuncOperands.get(0);
- break;
- }
- case FunctionExprent.FUNCTION_SUB:
- case FunctionExprent.FUNCTION_MUL:
- case FunctionExprent.FUNCTION_DIV:
- case FunctionExprent.FUNCTION_REM:
- case FunctionExprent.FUNCTION_SHL:
- case FunctionExprent.FUNCTION_SHR:
- case FunctionExprent.FUNCTION_USHR:
- if(left.equals(lstFuncOperands.get(0))) {
- cond = lstFuncOperands.get(1);
- }
- }
-
- if(cond!=null && (midlayer == null || midlayer.equals(cond.getExprType()))) {
- asexpr.setRight(cond);
- asexpr.setCondtype(func.getFunctype());
- }
- }
- break;
- case Exprent.EXPRENT_INVOCATION:
- if(!statement_level) { // simplify if exprent is a real expression. The opposite case is pretty absurd, can still happen however (and happened at least once).
- Exprent retexpr = ConcatenationHelper.contractStringConcat(exprent);
- if(!exprent.equals(retexpr)) {
- return retexpr;
- }
- }
- }
-
- return null;
-
- }
-
- public static Exprent propagateBoolNot(Exprent exprent) {
-
- if(exprent.type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent fexpr = (FunctionExprent)exprent;
-
- if(fexpr.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT) {
-
- Exprent param = fexpr.getLstOperands().get(0);
-
- if(param.type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent fparam = (FunctionExprent)param;
-
- int ftype = fparam.getFunctype();
- switch(ftype) {
- case FunctionExprent.FUNCTION_BOOLNOT:
- Exprent newexpr = fparam.getLstOperands().get(0);
- Exprent retexpr = propagateBoolNot(newexpr);
- return retexpr == null?newexpr:retexpr;
- case FunctionExprent.FUNCTION_CADD:
- case FunctionExprent.FUNCTION_COR:
- List<Exprent> operands = fparam.getLstOperands();
- for(int i=0;i<operands.size();i++) {
- Exprent newparam = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
- Arrays.asList(new Exprent[]{operands.get(i)}));
-
- Exprent retparam = propagateBoolNot(newparam);
- operands.set(i, retparam == null?newparam:retparam);
- }
- case FunctionExprent.FUNCTION_EQ:
- case FunctionExprent.FUNCTION_NE:
- case FunctionExprent.FUNCTION_LT:
- case FunctionExprent.FUNCTION_GE:
- case FunctionExprent.FUNCTION_GT:
- case FunctionExprent.FUNCTION_LE:
- fparam.setFunctype(funcsnot[ftype-FunctionExprent.FUNCTION_EQ]);
- return fparam;
- }
- }
- }
- }
-
- return null;
- }
-
+ private static final int[] funcsnot = new int[]{
+ FunctionExprent.FUNCTION_NE,
+ FunctionExprent.FUNCTION_EQ,
+ FunctionExprent.FUNCTION_GE,
+ FunctionExprent.FUNCTION_LT,
+ FunctionExprent.FUNCTION_LE,
+ FunctionExprent.FUNCTION_GT,
+ FunctionExprent.FUNCTION_COR,
+ FunctionExprent.FUNCTION_CADD
+ };
+
+ private static final HashMap<Integer, Integer[]> mapNumComparisons = new HashMap<Integer, Integer[]>();
+
+ static {
+ mapNumComparisons.put(FunctionExprent.FUNCTION_EQ,
+ new Integer[]{FunctionExprent.FUNCTION_LT, FunctionExprent.FUNCTION_EQ, FunctionExprent.FUNCTION_GT});
+ mapNumComparisons.put(FunctionExprent.FUNCTION_NE,
+ new Integer[]{FunctionExprent.FUNCTION_GE, FunctionExprent.FUNCTION_NE, FunctionExprent.FUNCTION_LE});
+ mapNumComparisons.put(FunctionExprent.FUNCTION_GT, new Integer[]{FunctionExprent.FUNCTION_GE, FunctionExprent.FUNCTION_GT, null});
+ mapNumComparisons.put(FunctionExprent.FUNCTION_GE, new Integer[]{null, FunctionExprent.FUNCTION_GE, FunctionExprent.FUNCTION_GT});
+ mapNumComparisons.put(FunctionExprent.FUNCTION_LT, new Integer[]{null, FunctionExprent.FUNCTION_LT, FunctionExprent.FUNCTION_LE});
+ mapNumComparisons.put(FunctionExprent.FUNCTION_LE, new Integer[]{FunctionExprent.FUNCTION_LT, FunctionExprent.FUNCTION_LE, null});
+ }
+
+
+ public static boolean identifySecondaryFunctions(Statement stat) {
+
+ if (stat.getExprents() == null) {
+ // if(){;}else{...} -> if(!){...}
+ if (stat.type == Statement.TYPE_IF) {
+ IfStatement ifelsestat = (IfStatement)stat;
+ Statement ifstat = ifelsestat.getIfstat();
+
+ if (ifelsestat.iftype == IfStatement.IFTYPE_IFELSE && ifstat.getExprents() != null &&
+ ifstat.getExprents().isEmpty() && (ifstat.getAllSuccessorEdges().isEmpty() || !ifstat.getAllSuccessorEdges().get(0).explicit)) {
+
+ // move else to the if position
+ ifelsestat.getStats().removeWithKey(ifstat.id);
+
+ ifelsestat.iftype = IfStatement.IFTYPE_IF;
+ ifelsestat.setIfstat(ifelsestat.getElsestat());
+ ifelsestat.setElsestat(null);
+
+ if (ifelsestat.getAllSuccessorEdges().isEmpty() && !ifstat.getAllSuccessorEdges().isEmpty()) {
+ StatEdge endedge = ifstat.getAllSuccessorEdges().get(0);
+
+ ifstat.removeSuccessor(endedge);
+ endedge.setSource(ifelsestat);
+ if (endedge.closure != null) {
+ ifelsestat.getParent().addLabeledEdge(endedge);
+ }
+ ifelsestat.addSuccessor(endedge);
+ }
+
+ ifelsestat.getFirst().removeSuccessor(ifelsestat.getIfEdge());
+
+ ifelsestat.setIfEdge(ifelsestat.getElseEdge());
+ ifelsestat.setElseEdge(null);
+
+ // negate head expression
+ ifelsestat.setNegated(!ifelsestat.isNegated());
+ ifelsestat.getHeadexprentList().set(0, ((IfExprent)ifelsestat.getHeadexprent().copy()).negateIf());
+
+ return true;
+ }
+ }
+ }
+
+
+ boolean replaced = true;
+ while (replaced) {
+ replaced = false;
+
+ List<Object> lstObjects = new ArrayList<Object>(stat.getExprents() == null ? stat.getSequentialObjects() : stat.getExprents());
+
+ for (int i = 0; i < lstObjects.size(); i++) {
+ Object obj = lstObjects.get(i);
+
+ if (obj instanceof Statement) {
+ if (identifySecondaryFunctions((Statement)obj)) {
+ replaced = true;
+ break;
+ }
+ }
+ else if (obj instanceof Exprent) {
+ Exprent retexpr = identifySecondaryFunctions((Exprent)obj, true);
+ if (retexpr != null) {
+ if (stat.getExprents() == null) {
+ // only head expressions can be replaced!
+ stat.replaceExprent((Exprent)obj, retexpr);
+ }
+ else {
+ stat.getExprents().set(i, retexpr);
+ }
+ replaced = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static Exprent identifySecondaryFunctions(Exprent exprent, boolean statement_level) {
+
+ if (exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+
+ switch (fexpr.getFunctype()) {
+ case FunctionExprent.FUNCTION_BOOLNOT:
+
+ Exprent retparam = propagateBoolNot(fexpr);
+
+ if (retparam != null) {
+ return retparam;
+ }
+
+ break;
+ case FunctionExprent.FUNCTION_EQ:
+ case FunctionExprent.FUNCTION_NE:
+ case FunctionExprent.FUNCTION_GT:
+ case FunctionExprent.FUNCTION_GE:
+ case FunctionExprent.FUNCTION_LT:
+ case FunctionExprent.FUNCTION_LE:
+ Exprent expr1 = fexpr.getLstOperands().get(0);
+ Exprent expr2 = fexpr.getLstOperands().get(1);
+
+ if (expr1.type == Exprent.EXPRENT_CONST) {
+ expr2 = expr1;
+ expr1 = fexpr.getLstOperands().get(1);
+ }
+
+ if (expr1.type == Exprent.EXPRENT_FUNCTION && expr2.type == Exprent.EXPRENT_CONST) {
+ FunctionExprent funcexpr = (FunctionExprent)expr1;
+ ConstExprent cexpr = (ConstExprent)expr2;
+
+ int functype = funcexpr.getFunctype();
+ if (functype == FunctionExprent.FUNCTION_LCMP || functype == FunctionExprent.FUNCTION_FCMPG ||
+ functype == FunctionExprent.FUNCTION_FCMPL || functype == FunctionExprent.FUNCTION_DCMPG ||
+ functype == FunctionExprent.FUNCTION_DCMPL) {
+
+ int desttype = -1;
+
+ Integer[] destcons = mapNumComparisons.get(fexpr.getFunctype());
+ if (destcons != null) {
+ int index = cexpr.getIntValue() + 1;
+ if (index >= 0 && index <= 2) {
+ Integer destcon = destcons[index];
+ if (destcon != null) {
+ desttype = destcon.intValue();
+ }
+ }
+ }
+
+ if (desttype >= 0) {
+ return new FunctionExprent(desttype, funcexpr.getLstOperands());
+ }
+ }
+ }
+ }
+ }
+
+
+ boolean replaced = true;
+ while (replaced) {
+ replaced = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ Exprent retexpr = identifySecondaryFunctions(expr, false);
+ if (retexpr != null) {
+ exprent.replaceExprent(expr, retexpr);
+ replaced = true;
+ break;
+ }
+ }
+ }
+
+ switch (exprent.type) {
+ case Exprent.EXPRENT_FUNCTION:
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+ List<Exprent> lstOperands = fexpr.getLstOperands();
+
+ switch (fexpr.getFunctype()) {
+ case FunctionExprent.FUNCTION_XOR:
+ for (int i = 0; i < 2; i++) {
+ Exprent operand = lstOperands.get(i);
+ VarType operandtype = operand.getExprType();
+
+ if (operand.type == Exprent.EXPRENT_CONST &&
+ operandtype.type != CodeConstants.TYPE_BOOLEAN) {
+ ConstExprent cexpr = (ConstExprent)operand;
+ long val;
+ if (operandtype.type == CodeConstants.TYPE_LONG) {
+ val = ((Long)cexpr.getValue()).longValue();
+ }
+ else {
+ val = ((Integer)cexpr.getValue()).intValue();
+ }
+
+ if (val == -1) {
+ List<Exprent> lstBitNotOperand = new ArrayList<Exprent>();
+ lstBitNotOperand.add(lstOperands.get(1 - i));
+ return new FunctionExprent(FunctionExprent.FUNCTION_BITNOT, lstBitNotOperand);
+ }
+ }
+ }
+ break;
+ case FunctionExprent.FUNCTION_EQ:
+ case FunctionExprent.FUNCTION_NE:
+ if (lstOperands.get(0).getExprType().type == CodeConstants.TYPE_BOOLEAN &&
+ lstOperands.get(1).getExprType().type == CodeConstants.TYPE_BOOLEAN) {
+ for (int i = 0; i < 2; i++) {
+ if (lstOperands.get(i).type == Exprent.EXPRENT_CONST) {
+ ConstExprent cexpr = (ConstExprent)lstOperands.get(i);
+ int val = ((Integer)cexpr.getValue()).intValue();
+
+ if ((fexpr.getFunctype() == FunctionExprent.FUNCTION_EQ && val == 1) ||
+ (fexpr.getFunctype() == FunctionExprent.FUNCTION_NE && val == 0)) {
+ return lstOperands.get(1 - i);
+ }
+ else {
+ List<Exprent> lstNotOperand = new ArrayList<Exprent>();
+ lstNotOperand.add(lstOperands.get(1 - i));
+ return new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, lstNotOperand);
+ }
+ }
+ }
+ }
+ break;
+ case FunctionExprent.FUNCTION_BOOLNOT:
+ if (lstOperands.get(0).type == Exprent.EXPRENT_CONST) {
+ int val = ((ConstExprent)lstOperands.get(0)).getIntValue();
+ if (val == 0) {
+ return new ConstExprent(VarType.VARTYPE_BOOLEAN, new Integer(1));
+ }
+ else {
+ return new ConstExprent(VarType.VARTYPE_BOOLEAN, new Integer(0));
+ }
+ }
+ break;
+ case FunctionExprent.FUNCTION_IIF:
+ Exprent expr1 = lstOperands.get(1);
+ Exprent expr2 = lstOperands.get(2);
+
+ if (expr1.type == Exprent.EXPRENT_CONST && expr2.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cexpr1 = (ConstExprent)expr1;
+ ConstExprent cexpr2 = (ConstExprent)expr2;
+
+ if (cexpr1.getExprType().type == CodeConstants.TYPE_BOOLEAN &&
+ cexpr2.getExprType().type == CodeConstants.TYPE_BOOLEAN) {
+
+ if (cexpr1.getIntValue() == 0 && cexpr2.getIntValue() != 0) {
+ return new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[]{lstOperands.get(0)}));
+ }
+ else if (cexpr1.getIntValue() != 0 && cexpr2.getIntValue() == 0) {
+ return lstOperands.get(0);
+ }
+ }
+ }
+ break;
+ case FunctionExprent.FUNCTION_LCMP:
+ case FunctionExprent.FUNCTION_FCMPL:
+ case FunctionExprent.FUNCTION_FCMPG:
+ case FunctionExprent.FUNCTION_DCMPL:
+ case FunctionExprent.FUNCTION_DCMPG:
+ int var = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
+ VarType type = lstOperands.get(0).getExprType();
+ VarProcessor processor = (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR);
+
+ FunctionExprent iff = new FunctionExprent(FunctionExprent.FUNCTION_IIF, Arrays.asList(new Exprent[]{
+ new FunctionExprent(FunctionExprent.FUNCTION_LT, Arrays.asList(new Exprent[]{new VarExprent(var, type, processor),
+ ConstExprent.getZeroConstant(type.type)})),
+ new ConstExprent(VarType.VARTYPE_INT, new Integer(-1)),
+ new ConstExprent(VarType.VARTYPE_INT, new Integer(1))}));
+
+ FunctionExprent head = new FunctionExprent(FunctionExprent.FUNCTION_EQ, Arrays.asList(new Exprent[]{
+ new AssignmentExprent(new VarExprent(var, type, processor), new FunctionExprent(FunctionExprent.FUNCTION_SUB,
+ Arrays.asList(
+ new Exprent[]{lstOperands.get(0),
+ lstOperands.get(1)}))),
+ ConstExprent.getZeroConstant(type.type)}));
+
+ processor.setVarType(new VarVersionPaar(var, 0), type);
+
+ return new FunctionExprent(FunctionExprent.FUNCTION_IIF, Arrays.asList(new Exprent[]{
+ head, new ConstExprent(VarType.VARTYPE_INT, new Integer(0)), iff}));
+ }
+ break;
+ case Exprent.EXPRENT_ASSIGNMENT: // check for conditional assignment
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ Exprent right = asexpr.getRight();
+ Exprent left = asexpr.getLeft();
+
+ if (right.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent func = (FunctionExprent)right;
+
+ VarType midlayer = null;
+ if (func.getFunctype() >= FunctionExprent.FUNCTION_I2L &&
+ func.getFunctype() <= FunctionExprent.FUNCTION_I2S) {
+ right = func.getLstOperands().get(0);
+ midlayer = func.getSimpleCastType();
+ if (right.type == Exprent.EXPRENT_FUNCTION) {
+ func = (FunctionExprent)right;
+ }
+ else {
+ return null;
+ }
+ }
+
+ List<Exprent> lstFuncOperands = func.getLstOperands();
+
+ Exprent cond = null;
+
+ switch (func.getFunctype()) {
+ case FunctionExprent.FUNCTION_ADD:
+ case FunctionExprent.FUNCTION_AND:
+ case FunctionExprent.FUNCTION_OR:
+ case FunctionExprent.FUNCTION_XOR:
+ if (left.equals(lstFuncOperands.get(1))) {
+ cond = lstFuncOperands.get(0);
+ break;
+ }
+ case FunctionExprent.FUNCTION_SUB:
+ case FunctionExprent.FUNCTION_MUL:
+ case FunctionExprent.FUNCTION_DIV:
+ case FunctionExprent.FUNCTION_REM:
+ case FunctionExprent.FUNCTION_SHL:
+ case FunctionExprent.FUNCTION_SHR:
+ case FunctionExprent.FUNCTION_USHR:
+ if (left.equals(lstFuncOperands.get(0))) {
+ cond = lstFuncOperands.get(1);
+ }
+ }
+
+ if (cond != null && (midlayer == null || midlayer.equals(cond.getExprType()))) {
+ asexpr.setRight(cond);
+ asexpr.setCondtype(func.getFunctype());
+ }
+ }
+ break;
+ case Exprent.EXPRENT_INVOCATION:
+ if (!statement_level) { // simplify if exprent is a real expression. The opposite case is pretty absurd, can still happen however (and happened at least once).
+ Exprent retexpr = ConcatenationHelper.contractStringConcat(exprent);
+ if (!exprent.equals(retexpr)) {
+ return retexpr;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public static Exprent propagateBoolNot(Exprent exprent) {
+
+ if (exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+
+ if (fexpr.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT) {
+
+ Exprent param = fexpr.getLstOperands().get(0);
+
+ if (param.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fparam = (FunctionExprent)param;
+
+ int ftype = fparam.getFunctype();
+ switch (ftype) {
+ case FunctionExprent.FUNCTION_BOOLNOT:
+ Exprent newexpr = fparam.getLstOperands().get(0);
+ Exprent retexpr = propagateBoolNot(newexpr);
+ return retexpr == null ? newexpr : retexpr;
+ case FunctionExprent.FUNCTION_CADD:
+ case FunctionExprent.FUNCTION_COR:
+ List<Exprent> operands = fparam.getLstOperands();
+ for (int i = 0; i < operands.size(); i++) {
+ Exprent newparam = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
+ Arrays.asList(new Exprent[]{operands.get(i)}));
+
+ Exprent retparam = propagateBoolNot(newparam);
+ operands.set(i, retparam == null ? newparam : retparam);
+ }
+ case FunctionExprent.FUNCTION_EQ:
+ case FunctionExprent.FUNCTION_NE:
+ case FunctionExprent.FUNCTION_LT:
+ case FunctionExprent.FUNCTION_GE:
+ case FunctionExprent.FUNCTION_GT:
+ case FunctionExprent.FUNCTION_LE:
+ fparam.setFunctype(funcsnot[ftype - FunctionExprent.FUNCTION_EQ]);
+ return fparam;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java
index 69721e8..aa69931 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java
@@ -1,23 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
@@ -26,301 +23,305 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatemen
import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
public class SequenceHelper {
- public static void condenseSequences(Statement root) {
- condenseSequencesRec(root);
- }
-
- private static void condenseSequencesRec(Statement stat) {
-
- if(stat.type == Statement.TYPE_SEQUENCE) {
-
- List<Statement> lst = new ArrayList<Statement>();
- lst.addAll(stat.getStats());
-
- boolean unfolded = false;
-
- // unfold blocks
- for(int i=0;i<lst.size();i++) {
- Statement st = lst.get(i);
- if(st.type == Statement.TYPE_SEQUENCE) {
-
- removeEmptyStatements((SequenceStatement)st);
-
- if(i == lst.size()-1 || isSequenceDisbandable(st, lst.get(i+1))) {
- // move predecessors
- Statement first = st.getFirst();
- for(StatEdge edge: st.getAllPredecessorEdges()) {
- st.removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, first);
- first.addPredecessor(edge);
- }
-
- // move successors
- Statement last = st.getStats().getLast();
- if(last.getAllSuccessorEdges().isEmpty() && i<lst.size()-1) {
- last.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, last, lst.get(i+1)));
- } else {
- for(StatEdge edge: last.getAllSuccessorEdges()) {
- if(i == lst.size()-1) {
- if(edge.closure == st) {
- stat.addLabeledEdge(edge);
- }
- } else {
- edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_REGULAR);
- edge.closure.getLabelEdges().remove(edge);
- edge.closure = null;
- }
- }
- }
-
- for(StatEdge edge : st.getAllSuccessorEdges()) {
- st.removeSuccessor(edge);
- }
-
- for(StatEdge edge: new HashSet<StatEdge>(st.getLabelEdges())) {
- if(edge.getSource() != last) {
- last.addLabeledEdge(edge);
- }
- }
-
- lst.remove(i);
- lst.addAll(i, st.getStats());
- i--;
-
- unfolded = true;
- }
- }
- }
-
- if(unfolded) {
- SequenceStatement sequence = new SequenceStatement(lst);
- sequence.setAllParent();
-
- stat.getParent().replaceStatement(stat, sequence);
-
- stat = sequence;
- }
- }
-
- // sequence consisting of one statement -> disband
- if(stat.type == Statement.TYPE_SEQUENCE) {
-
- removeEmptyStatements((SequenceStatement)stat);
-
- if(stat.getStats().size() == 1) {
-
- Statement st = stat.getFirst();
-
- boolean ok = st.getAllSuccessorEdges().isEmpty();
- if(!ok) {
- StatEdge edge = st.getAllSuccessorEdges().get(0);
-
- ok = stat.getAllSuccessorEdges().isEmpty();
- if(!ok) {
- StatEdge statedge = stat.getAllSuccessorEdges().get(0);
- ok = (edge.getDestination() == statedge.getDestination());
-
- if(ok) {
- st.removeSuccessor(edge);
- }
- }
- }
-
- if(ok) {
- stat.getParent().replaceStatement(stat, st);
- stat = st;
- }
- }
- }
-
- // replace flat statements with synthetic basic blocks
- outer:
- for(;;) {
- for(Statement st: stat.getStats()) {
- if((st.getStats().isEmpty() || st.getExprents() != null) && st.type != Statement.TYPE_BASICBLOCK) {
- destroyAndFlattenStatement(st);
- continue outer;
- }
- }
- break;
- }
-
- // recursion
- for(int i=0;i<stat.getStats().size();i++) {
- condenseSequencesRec(stat.getStats().get(i));
- }
-
- }
-
- private static boolean isSequenceDisbandable(Statement block, Statement next) {
-
- Statement last = block.getStats().getLast();
- List<StatEdge> lstSuccs = last.getAllSuccessorEdges();
- if(!lstSuccs.isEmpty()) {
- if(lstSuccs.get(0).getDestination() != next) {
- return false;
- }
- }
-
- for(StatEdge edge : next.getPredecessorEdges(StatEdge.TYPE_BREAK)) {
- if(last != edge.getSource() && !last.containsStatementStrict(edge.getSource())) {
- return false;
- }
- }
-
- return true;
- }
-
- private static void removeEmptyStatements(SequenceStatement sequence) {
-
- if(sequence.getStats().size() <= 1) {
- return;
- }
-
- mergeFlatStatements(sequence);
-
- for(;;) {
-
- boolean found = false;
-
- for(Statement st: sequence.getStats()) {
-
- if(st.getExprents() != null && st.getExprents().isEmpty()) {
-
- if(st.getAllSuccessorEdges().isEmpty()) {
- List<StatEdge> lstBreaks = st.getPredecessorEdges(StatEdge.TYPE_BREAK);
-
- if(lstBreaks.isEmpty()) {
- for(StatEdge edge: st.getAllPredecessorEdges()) {
- edge.getSource().removeSuccessor(edge);
- }
- found = true;
- }
- } else {
- StatEdge sucedge = st.getAllSuccessorEdges().get(0);
- if(sucedge.getType() != StatEdge.TYPE_FINALLYEXIT) {
- st.removeSuccessor(sucedge);
-
- for(StatEdge edge: st.getAllPredecessorEdges()) {
- if(sucedge.getType()!=StatEdge.TYPE_REGULAR) {
- edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, sucedge.getType());
- }
-
- st.removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, sucedge.getDestination());
- sucedge.getDestination().addPredecessor(edge);
-
- if(sucedge.closure != null) {
- sucedge.closure.addLabeledEdge(edge);
- }
- }
- found = true;
- }
- }
-
- if(found) {
- sequence.getStats().removeWithKey(st.id);
- break;
- }
- }
- }
-
- if(!found) {
- break;
- }
- }
-
- sequence.setFirst(sequence.getStats().get(0));
-
- }
-
- private static void mergeFlatStatements(SequenceStatement sequence) {
-
- for(;;) {
-
- Statement next = null;
- Statement current = null;
-
- boolean found = false;
-
- for(int i=sequence.getStats().size()-1;i>=0;i--) {
-
- next = current;
- current = sequence.getStats().get(i);
-
- if(next != null && current.getExprents()!=null && !current.getExprents().isEmpty()) {
- if(next.getExprents()!=null) {
- next.getExprents().addAll(0, current.getExprents());
- current.getExprents().clear();
- found = true;
- } else {
- Statement first = getFirstExprentlist(next);
- if(first != null) {
- first.getExprents().addAll(0, current.getExprents());
- current.getExprents().clear();
- found = true;
- }
- }
- }
- }
-
- if(!found) {
- break;
- }
- }
-
- }
-
- private static Statement getFirstExprentlist(Statement stat) {
-
- if(stat.getExprents() != null) {
- return stat;
- }
-
- switch(stat.type) {
- case Statement.TYPE_IF:
- case Statement.TYPE_SEQUENCE:
- case Statement.TYPE_SWITCH:
- case Statement.TYPE_SYNCRONIZED:
- return getFirstExprentlist(stat.getFirst());
- }
-
- return null;
- }
-
-
- public static void destroyAndFlattenStatement(Statement stat) {
-
- destroyStatementContent(stat, false);
-
- BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
- DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
- if(stat.getExprents() == null) {
- bstat.setExprents(new ArrayList<Exprent>());
- } else {
- bstat.setExprents(DecHelper.copyExprentList(stat.getExprents()));
- }
-
- stat.getParent().replaceStatement(stat, bstat);
- }
-
- public static void destroyStatementContent(Statement stat, boolean self) {
-
- for(Statement st: stat.getStats()) {
- destroyStatementContent(st, true);
- }
- stat.getStats().clear();
-
- if(self) {
- for(StatEdge edge : stat.getAllSuccessorEdges()) {
- stat.removeSuccessor(edge);
- }
- }
-
- }
-
+ public static void condenseSequences(Statement root) {
+ condenseSequencesRec(root);
+ }
+
+ private static void condenseSequencesRec(Statement stat) {
+
+ if (stat.type == Statement.TYPE_SEQUENCE) {
+
+ List<Statement> lst = new ArrayList<Statement>();
+ lst.addAll(stat.getStats());
+
+ boolean unfolded = false;
+
+ // unfold blocks
+ for (int i = 0; i < lst.size(); i++) {
+ Statement st = lst.get(i);
+ if (st.type == Statement.TYPE_SEQUENCE) {
+
+ removeEmptyStatements((SequenceStatement)st);
+
+ if (i == lst.size() - 1 || isSequenceDisbandable(st, lst.get(i + 1))) {
+ // move predecessors
+ Statement first = st.getFirst();
+ for (StatEdge edge : st.getAllPredecessorEdges()) {
+ st.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, first);
+ first.addPredecessor(edge);
+ }
+
+ // move successors
+ Statement last = st.getStats().getLast();
+ if (last.getAllSuccessorEdges().isEmpty() && i < lst.size() - 1) {
+ last.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, last, lst.get(i + 1)));
+ }
+ else {
+ for (StatEdge edge : last.getAllSuccessorEdges()) {
+ if (i == lst.size() - 1) {
+ if (edge.closure == st) {
+ stat.addLabeledEdge(edge);
+ }
+ }
+ else {
+ edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_REGULAR);
+ edge.closure.getLabelEdges().remove(edge);
+ edge.closure = null;
+ }
+ }
+ }
+
+ for (StatEdge edge : st.getAllSuccessorEdges()) {
+ st.removeSuccessor(edge);
+ }
+
+ for (StatEdge edge : new HashSet<StatEdge>(st.getLabelEdges())) {
+ if (edge.getSource() != last) {
+ last.addLabeledEdge(edge);
+ }
+ }
+
+ lst.remove(i);
+ lst.addAll(i, st.getStats());
+ i--;
+
+ unfolded = true;
+ }
+ }
+ }
+
+ if (unfolded) {
+ SequenceStatement sequence = new SequenceStatement(lst);
+ sequence.setAllParent();
+
+ stat.getParent().replaceStatement(stat, sequence);
+
+ stat = sequence;
+ }
+ }
+
+ // sequence consisting of one statement -> disband
+ if (stat.type == Statement.TYPE_SEQUENCE) {
+
+ removeEmptyStatements((SequenceStatement)stat);
+
+ if (stat.getStats().size() == 1) {
+
+ Statement st = stat.getFirst();
+
+ boolean ok = st.getAllSuccessorEdges().isEmpty();
+ if (!ok) {
+ StatEdge edge = st.getAllSuccessorEdges().get(0);
+
+ ok = stat.getAllSuccessorEdges().isEmpty();
+ if (!ok) {
+ StatEdge statedge = stat.getAllSuccessorEdges().get(0);
+ ok = (edge.getDestination() == statedge.getDestination());
+
+ if (ok) {
+ st.removeSuccessor(edge);
+ }
+ }
+ }
+
+ if (ok) {
+ stat.getParent().replaceStatement(stat, st);
+ stat = st;
+ }
+ }
+ }
+
+ // replace flat statements with synthetic basic blocks
+ outer:
+ for (; ; ) {
+ for (Statement st : stat.getStats()) {
+ if ((st.getStats().isEmpty() || st.getExprents() != null) && st.type != Statement.TYPE_BASICBLOCK) {
+ destroyAndFlattenStatement(st);
+ continue outer;
+ }
+ }
+ break;
+ }
+
+ // recursion
+ for (int i = 0; i < stat.getStats().size(); i++) {
+ condenseSequencesRec(stat.getStats().get(i));
+ }
+ }
+
+ private static boolean isSequenceDisbandable(Statement block, Statement next) {
+
+ Statement last = block.getStats().getLast();
+ List<StatEdge> lstSuccs = last.getAllSuccessorEdges();
+ if (!lstSuccs.isEmpty()) {
+ if (lstSuccs.get(0).getDestination() != next) {
+ return false;
+ }
+ }
+
+ for (StatEdge edge : next.getPredecessorEdges(StatEdge.TYPE_BREAK)) {
+ if (last != edge.getSource() && !last.containsStatementStrict(edge.getSource())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static void removeEmptyStatements(SequenceStatement sequence) {
+
+ if (sequence.getStats().size() <= 1) {
+ return;
+ }
+
+ mergeFlatStatements(sequence);
+
+ for (; ; ) {
+
+ boolean found = false;
+
+ for (Statement st : sequence.getStats()) {
+
+ if (st.getExprents() != null && st.getExprents().isEmpty()) {
+
+ if (st.getAllSuccessorEdges().isEmpty()) {
+ List<StatEdge> lstBreaks = st.getPredecessorEdges(StatEdge.TYPE_BREAK);
+
+ if (lstBreaks.isEmpty()) {
+ for (StatEdge edge : st.getAllPredecessorEdges()) {
+ edge.getSource().removeSuccessor(edge);
+ }
+ found = true;
+ }
+ }
+ else {
+ StatEdge sucedge = st.getAllSuccessorEdges().get(0);
+ if (sucedge.getType() != StatEdge.TYPE_FINALLYEXIT) {
+ st.removeSuccessor(sucedge);
+
+ for (StatEdge edge : st.getAllPredecessorEdges()) {
+ if (sucedge.getType() != StatEdge.TYPE_REGULAR) {
+ edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, sucedge.getType());
+ }
+
+ st.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, sucedge.getDestination());
+ sucedge.getDestination().addPredecessor(edge);
+
+ if (sucedge.closure != null) {
+ sucedge.closure.addLabeledEdge(edge);
+ }
+ }
+ found = true;
+ }
+ }
+
+ if (found) {
+ sequence.getStats().removeWithKey(st.id);
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ sequence.setFirst(sequence.getStats().get(0));
+ }
+
+ private static void mergeFlatStatements(SequenceStatement sequence) {
+
+ for (; ; ) {
+
+ Statement next = null;
+ Statement current = null;
+
+ boolean found = false;
+
+ for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
+
+ next = current;
+ current = sequence.getStats().get(i);
+
+ if (next != null && current.getExprents() != null && !current.getExprents().isEmpty()) {
+ if (next.getExprents() != null) {
+ next.getExprents().addAll(0, current.getExprents());
+ current.getExprents().clear();
+ found = true;
+ }
+ else {
+ Statement first = getFirstExprentlist(next);
+ if (first != null) {
+ first.getExprents().addAll(0, current.getExprents());
+ current.getExprents().clear();
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+ }
+
+ private static Statement getFirstExprentlist(Statement stat) {
+
+ if (stat.getExprents() != null) {
+ return stat;
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_IF:
+ case Statement.TYPE_SEQUENCE:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ return getFirstExprentlist(stat.getFirst());
+ }
+
+ return null;
+ }
+
+
+ public static void destroyAndFlattenStatement(Statement stat) {
+
+ destroyStatementContent(stat, false);
+
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ if (stat.getExprents() == null) {
+ bstat.setExprents(new ArrayList<Exprent>());
+ }
+ else {
+ bstat.setExprents(DecHelper.copyExprentList(stat.getExprents()));
+ }
+
+ stat.getParent().replaceStatement(stat, bstat);
+ }
+
+ public static void destroyStatementContent(Statement stat, boolean self) {
+
+ for (Statement st : stat.getStats()) {
+ destroyStatementContent(st, true);
+ }
+ stat.getStats().clear();
+
+ if (self) {
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ stat.removeSuccessor(edge);
+ }
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java
index 8f55013..a7d5702 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java
@@ -1,42 +1,25 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ArrayExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.MonitorExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.SSAConstructorSparseEx;
import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
@@ -45,819 +28,826 @@ import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+import java.util.*;
+import java.util.Map.Entry;
+
public class SimplifyExprentsHelper {
- private boolean firstInvocation;
-
- public SimplifyExprentsHelper(boolean firstInvocation) {
- this.firstInvocation = firstInvocation;
- }
-
- public boolean simplifyStackVarsStatement(Statement stat, HashSet<Integer> setReorderedIfs, SSAConstructorSparseEx ssa, StructClass cl) {
-
- boolean res = false;
-
- if(stat.getExprents() == null) {
-
- for(;;) {
-
- boolean changed = false;
-
- for(Statement st: stat.getStats()) {
- res |= simplifyStackVarsStatement(st, setReorderedIfs, ssa, cl);
-
- // collapse composed if's
- if(changed = IfHelper.mergeIfs(st, setReorderedIfs)) {
- break;
- }
-
- // collapse iff ?: statement
- if(changed = buildIff(st, ssa)) {
- break;
- }
- }
-
- res |= changed;
-
- if(!changed) {
- break;
- }
- }
-
- } else {
- res |= simplifyStackVarsExprents(stat.getExprents(), cl);
- }
-
- return res;
- }
-
- private boolean simplifyStackVarsExprents(List<Exprent> list, StructClass cl) {
-
- boolean res = false;
-
- int index = 0;
-
- while(index < list.size()) {
-
- Exprent current = list.get(index);
-
- Exprent ret = isSimpleConstructorInvocation(current);
- if(ret != null) {
- list.set(index, ret);
- res = true;
-
- continue;
- }
-
- // lambda expression (Java 8)
- ret = isLambda(current, cl);
- if(ret != null) {
- list.set(index, ret);
- res = true;
-
- continue;
- }
-
- // remove monitor exit
- if(isMonitorExit(current)) {
- list.remove(index);
- res = true;
-
- continue;
- }
-
- // trivial assignment of a stack variable
- if(isTrivialStackAssignment(current)) {
- list.remove(index);
- res = true;
-
- continue;
- }
-
- if(index == list.size()-1) {
- break;
- }
-
-
- Exprent next = list.get(index+1);
-
-
- // constructor invocation
- if(isConstructorInvocationRemote(list, index)) {
- list.remove(index);
- res = true;
-
- continue;
- }
-
- // remove getClass() invocation, which is part of a qualified new
- if(DecompilerContext.getOption(IFernflowerPreferences.REMOVE_GETCLASS_NEW)) {
- if(isQualifiedNewGetClass(current, next)) {
- list.remove(index);
- res = true;
-
- continue;
- }
- }
-
- // direct initialization of an array
- int arrcount = isArrayInitializer(list, index);
- if(arrcount > 0) {
- for(int i=0;i<arrcount;i++) {
- list.remove(index+1);
- }
- res = true;
-
- continue;
- }
-
- // add array initializer expression
- if(addArrayInitializer(current, next)) {
- list.remove(index+1);
- res = true;
-
- continue;
- }
-
- // integer ++expr and --expr (except for vars!)
- Exprent func = isPPIorMMI(current);
- if(func != null) {
- list.set(index, func);
- res = true;
-
- continue;
- }
-
- // expr++ and expr--
- if(isIPPorIMM(current, next)) {
- list.remove(index+1);
- res = true;
-
- continue;
- }
-
- // assignment on stack
- if(isStackAssignement(current, next)) {
- list.remove(index+1);
- res = true;
-
- continue;
- }
-
- if(!firstInvocation && isStackAssignement2(current, next)) {
- list.remove(index+1);
- res = true;
-
- continue;
- }
-
- index++;
- }
-
- return res;
- }
-
- private static boolean addArrayInitializer(Exprent first, Exprent second) {
-
- if(first.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent as = (AssignmentExprent)first;
-
- if(as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) {
- NewExprent newex = (NewExprent)as.getRight();
-
- if(!newex.getLstArrayElements().isEmpty()) {
-
- VarExprent arrvar = (VarExprent)as.getLeft();
-
- if(second.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent aas = (AssignmentExprent)second;
- if(aas.getLeft().type == Exprent.EXPRENT_ARRAY) {
- ArrayExprent arrex = (ArrayExprent)aas.getLeft();
- if(arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray())
- && arrex.getIndex().type == Exprent.EXPRENT_CONST) {
-
- int constvalue = ((ConstExprent)arrex.getIndex()).getIntValue();
-
- if(constvalue < newex.getLstArrayElements().size()) {
- Exprent init = newex.getLstArrayElements().get(constvalue);
- if(init.type == Exprent.EXPRENT_CONST) {
- ConstExprent cinit = (ConstExprent)init;
-
- VarType arrtype = newex.getNewtype().copy();
- arrtype.decArrayDim();
-
- ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype);
-
- if(cinit.equals(defaultval)) {
-
- Exprent tempexpr = aas.getRight();
-
- if(!tempexpr.containsExprent(arrvar)) {
- newex.getLstArrayElements().set(constvalue, tempexpr);
-
- if(tempexpr.type == Exprent.EXPRENT_NEW) {
- NewExprent tempnewex = (NewExprent)tempexpr;
- int dims = newex.getNewtype().arraydim;
- if(dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) {
- tempnewex.setDirectArrayInit(true);
- }
- }
-
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- return false;
- }
-
-
-
- private static int isArrayInitializer(List<Exprent> list, int index) {
-
- Exprent current = list.get(index);
- if(current.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent as = (AssignmentExprent)current;
-
- if(as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) {
- NewExprent newex = (NewExprent)as.getRight();
-
- if(newex.getExprType().arraydim > 0 && newex.getLstDims().size() == 1 && newex.getLstArrayElements().isEmpty() &&
- newex.getLstDims().get(0).type == Exprent.EXPRENT_CONST) {
-
- int size = ((Integer)((ConstExprent)newex.getLstDims().get(0)).getValue()).intValue();
- if(size == 0) {
- return 0;
- }
-
- VarExprent arrvar = (VarExprent)as.getLeft();
-
- HashMap<Integer, Exprent> mapInit = new HashMap<Integer, Exprent>();
-
- int i=1;
- while(index+i < list.size() && i <= size) {
- boolean found = false;
-
- Exprent expr = list.get(index+i);
- if(expr.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent aas = (AssignmentExprent)expr;
- if(aas.getLeft().type == Exprent.EXPRENT_ARRAY) {
- ArrayExprent arrex = (ArrayExprent)aas.getLeft();
- if(arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray())
- && arrex.getIndex().type == Exprent.EXPRENT_CONST) {
-
- int constvalue = ((ConstExprent)arrex.getIndex()).getIntValue(); // TODO: check for a number type. Failure extremely improbable, but nevertheless...
-
- if(constvalue < size && !mapInit.containsKey(constvalue)) {
-
- if(!aas.getRight().containsExprent(arrvar)) {
- mapInit.put(constvalue, aas.getRight());
- found = true;
- }
- }
- }
- }
- }
-
- if(!found) {
- break;
- }
-
- i++;
- }
-
- double fraction = ((double)mapInit.size()) / size;
-
- if((arrvar.isStack() && fraction > 0) || (size <= 7 && fraction >= 0.3) ||
- (size > 7 && fraction >= 0.7)) {
-
- List<Exprent> lstRet = new ArrayList<Exprent>();
-
- VarType arrtype = newex.getNewtype().copy();
- arrtype.decArrayDim();
-
- ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype);
-
- for(int j=0;j<size;j++) {
- lstRet.add(defaultval.copy());
- }
-
- int dims = newex.getNewtype().arraydim;
- for(Entry<Integer, Exprent> ent: mapInit.entrySet()) {
- Exprent tempexpr = ent.getValue();
- lstRet.set(ent.getKey(), tempexpr);
-
- if(tempexpr.type == Exprent.EXPRENT_NEW) {
- NewExprent tempnewex = (NewExprent)tempexpr;
- if(dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) {
- tempnewex.setDirectArrayInit(true);
- }
- }
- }
-
- newex.setLstArrayElements(lstRet);
-
- return mapInit.size();
- }
- }
- }
- }
-
- return 0;
- }
-
- private static boolean isTrivialStackAssignment(Exprent first) {
-
- if(first.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent asf = (AssignmentExprent)first;
-
- if(asf.getLeft().type == Exprent.EXPRENT_VAR && asf.getRight().type == Exprent.EXPRENT_VAR) {
- VarExprent varleft = (VarExprent)asf.getLeft();
- VarExprent varright = (VarExprent)asf.getRight();
-
- if(varleft.getIndex() == varright.getIndex() && varleft.isStack() &&
- varright.isStack()) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- private static boolean isStackAssignement2(Exprent first, Exprent second) { // e.g. 1.4-style class invocation
-
- if(first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent asf = (AssignmentExprent)first;
- AssignmentExprent ass = (AssignmentExprent)second;
-
- if(asf.getLeft().type == Exprent.EXPRENT_VAR && ass.getRight().type == Exprent.EXPRENT_VAR &&
- asf.getLeft().equals(ass.getRight()) && ((VarExprent)asf.getLeft()).isStack()) {
- if(ass.getLeft().type != Exprent.EXPRENT_VAR || !((VarExprent)ass.getLeft()).isStack()) {
- asf.setRight(new AssignmentExprent(ass.getLeft(), asf.getRight()));
- return true;
- }
- }
- }
-
- return false;
- }
-
- private static boolean isStackAssignement(Exprent first, Exprent second) {
-
- if(first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent asf = (AssignmentExprent)first;
- AssignmentExprent ass = (AssignmentExprent)second;
-
- for(;;) {
- if(asf.getRight().equals(ass.getRight())) {
- if((asf.getLeft().type == Exprent.EXPRENT_VAR && ((VarExprent)asf.getLeft()).isStack()) &&
- (ass.getLeft().type != Exprent.EXPRENT_VAR || !((VarExprent)ass.getLeft()).isStack())) {
-
- if(!ass.getLeft().containsExprent(asf.getLeft())) {
- asf.setRight(ass);
- return true;
- }
- }
- }
- if(asf.getRight().type == Exprent.EXPRENT_ASSIGNMENT) {
- asf = (AssignmentExprent)asf.getRight();
- } else {
- break;
- }
- }
-
- }
-
- return false;
- }
-
- private static Exprent isPPIorMMI(Exprent first) {
-
- if(first.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent as = (AssignmentExprent)first;
-
- if(as.getRight().type == Exprent.EXPRENT_FUNCTION) {
- FunctionExprent func = (FunctionExprent)as.getRight();
-
- if(func.getFunctype() == FunctionExprent.FUNCTION_ADD ||
- func.getFunctype() == FunctionExprent.FUNCTION_SUB) {
- Exprent econd = func.getLstOperands().get(0);
- Exprent econst = func.getLstOperands().get(1);
-
- if(econst.type != Exprent.EXPRENT_CONST && econd.type == Exprent.EXPRENT_CONST &&
- func.getFunctype() == FunctionExprent.FUNCTION_ADD) {
- econd = econst;
- econst = func.getLstOperands().get(0);
- }
-
- if(econst.type == Exprent.EXPRENT_CONST && ((ConstExprent)econst).hasValueOne()) {
- Exprent left = as.getLeft();
-
- if(left.type != Exprent.EXPRENT_VAR && left.equals(econd)) {
- FunctionExprent ret = new FunctionExprent(
- func.getFunctype() == FunctionExprent.FUNCTION_ADD?FunctionExprent.FUNCTION_PPI:FunctionExprent.FUNCTION_MMI,
- Arrays.asList(new Exprent[]{econd}));
- ret.setImplicitType(VarType.VARTYPE_INT);
- return ret;
- }
- }
- }
- }
- }
-
- return null;
- }
-
- private static boolean isIPPorIMM(Exprent first, Exprent second) {
-
- if(first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_FUNCTION) {
- AssignmentExprent as = (AssignmentExprent)first;
- FunctionExprent in = (FunctionExprent)second;
-
- if((in.getFunctype() == FunctionExprent.FUNCTION_MMI || in.getFunctype() == FunctionExprent.FUNCTION_PPI) &&
- in.getLstOperands().get(0).equals(as.getRight())) {
-
- if(in.getFunctype() == FunctionExprent.FUNCTION_MMI) {
- in.setFunctype(FunctionExprent.FUNCTION_IMM);
- } else {
- in.setFunctype(FunctionExprent.FUNCTION_IPP);
- }
- as.setRight(in);
-
- return true;
- }
- }
-
- return false;
- }
-
- private static boolean isMonitorExit(Exprent first) {
- if(first.type == Exprent.EXPRENT_MONITOR) {
- MonitorExprent monexpr = (MonitorExprent)first;
- if(monexpr.getMontype() == MonitorExprent.MONITOR_EXIT && monexpr.getValue().type == Exprent.EXPRENT_VAR
- && !((VarExprent)monexpr.getValue()).isStack()) {
- return true;
- }
- }
-
- return false;
- }
-
- private static boolean isQualifiedNewGetClass(Exprent first, Exprent second) {
-
- if(first.type == Exprent.EXPRENT_INVOCATION) {
- InvocationExprent invexpr = (InvocationExprent)first;
-
- if(!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR && invexpr.getName().equals("getClass") &&
- invexpr.getStringDescriptor().equals("()Ljava/lang/Class;")) {
-
- List<Exprent> lstExprents = second.getAllExprents();
- lstExprents.add(second);
-
- for(Exprent expr : lstExprents) {
- if(expr.type == Exprent.EXPRENT_NEW) {
- NewExprent nexpr = (NewExprent)expr;
- if(nexpr.getConstructor() != null && !nexpr.getConstructor().getLstParameters().isEmpty() &&
- nexpr.getConstructor().getLstParameters().get(0).equals(invexpr.getInstance())) {
-
- String classname = nexpr.getNewtype().value;
- ClassNode node = DecompilerContext.getClassprocessor().getMapRootClasses().get(classname);
- if(node != null && node.type != ClassNode.CLASS_ROOT) {
- return true;
- }
- }
- }
- }
-
- }
- }
-
- return false;
- }
-
-// private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) {
-//
-// Exprent current = list.get(index);
-//
-// if(current.type == Exprent.EXPRENT_ASSIGNMENT) {
-// AssignmentExprent as = (AssignmentExprent)current;
-//
-// if(as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) {
-//
-// NewExprent newexpr = (NewExprent)as.getRight();
-// VarType newtype = newexpr.getNewtype();
-// VarVersionPaar leftPaar = new VarVersionPaar((VarExprent)as.getLeft());
-//
-// if(newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0 &&
-// newexpr.getConstructor() == null) {
-//
-// Set<VarVersionPaar> setChangedVars = new HashSet<VarVersionPaar>();
-//
-// for(int i = index + 1; i < list.size(); i++) {
-// Exprent remote = list.get(i);
-//
-// if(remote.type == Exprent.EXPRENT_INVOCATION) {
-// InvocationExprent in = (InvocationExprent)remote;
-//
-// if(in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_VAR
-// && as.getLeft().equals(in.getInstance())) {
-//
-// Set<VarVersionPaar> setVars = remote.getAllVariables();
-// setVars.remove(leftPaar);
-// setVars.retainAll(setChangedVars);
-//
-// if(setVars.isEmpty()) {
-//
-// newexpr.setConstructor(in);
-// in.setInstance(null);
-//
-// if(!setChangedVars.isEmpty()) { // some exprents inbetween
-// list.add(index+1, as.copy());
-// list.remove(i+1);
-// } else {
-// list.set(i, as.copy());
-// }
-//
-// return true;
-// }
-// }
-// }
-//
-// boolean isTempAssignment = false;
-//
-// if(remote.type == Exprent.EXPRENT_ASSIGNMENT) { // ugly solution
-// AssignmentExprent asremote = (AssignmentExprent)remote;
-// if(asremote.getLeft().type == Exprent.EXPRENT_VAR &&
-// asremote.getRight().type == Exprent.EXPRENT_VAR) {
-// setChangedVars.add(new VarVersionPaar((VarExprent)asremote.getLeft()));
-// isTempAssignment = true;
-// }
-//
-// // FIXME: needs to be rewritten
-// // propagate (var = new X) forward to the <init> invokation and then reduce
-//
-//// if(asremote.getLeft().type == Exprent.EXPRENT_VAR) {
-//// List<Exprent> lstRightExprents = asremote.getRight().getAllExprents(true);
-//// lstRightExprents.add(asremote.getRight());
-////
-//// Set<VarVersionPaar> setTempChangedVars = new HashSet<VarVersionPaar>();
-//// boolean isTemp = true;
-////
-//// for(Exprent expr : lstRightExprents) {
-//// if(expr.type != Exprent.EXPRENT_VAR && expr.type != Exprent.EXPRENT_FIELD) {
-//// isTemp = false;
-//// break;
-//// } else if(expr.type == Exprent.EXPRENT_VAR) {
-//// setTempChangedVars.add(new VarVersionPaar((VarExprent)expr));
-//// }
-//// }
-////
-//// if(isTemp) {
-//// setChangedVars.addAll(setTempChangedVars);
-//// isTempAssignment = true;
-//// }
-//// }
-//// } else if(remote.type == Exprent.EXPRENT_FUNCTION) {
-//// FunctionExprent fexpr = (FunctionExprent)remote;
-//// if(fexpr.getFunctype() == FunctionExprent.FUNCTION_IPP || fexpr.getFunctype() == FunctionExprent.FUNCTION_IMM
-//// || fexpr.getFunctype() == FunctionExprent.FUNCTION_PPI || fexpr.getFunctype() == FunctionExprent.FUNCTION_MMI) {
-//// if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_VAR) {
-//// setChangedVars.add(new VarVersionPaar((VarExprent)fexpr.getLstOperands().get(0)));
-//// isTempAssignment = true;
-//// }
-//// }
-// }
-//
-// if(!isTempAssignment) {
-// Set<VarVersionPaar> setVars = remote.getAllVariables();
-// if(setVars.contains(leftPaar)) {
-// return false;
-// } else {
-// setChangedVars.addAll(setVars);
-// }
-// }
-// }
-// }
-// }
-// }
-//
-// return false;
-// }
-
- // propagate (var = new X) forward to the <init> invokation
- private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) {
-
- Exprent current = list.get(index);
-
- if(current.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent as = (AssignmentExprent)current;
-
- if(as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) {
-
- NewExprent newexpr = (NewExprent)as.getRight();
- VarType newtype = newexpr.getNewtype();
- VarVersionPaar leftPaar = new VarVersionPaar((VarExprent)as.getLeft());
-
- if(newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0 && newexpr.getConstructor() == null) {
-
- for(int i = index + 1; i < list.size(); i++) {
- Exprent remote = list.get(i);
-
- // <init> invocation
- if(remote.type == Exprent.EXPRENT_INVOCATION) {
- InvocationExprent in = (InvocationExprent)remote;
-
- if(in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_VAR && as.getLeft().equals(in.getInstance())) {
-
- newexpr.setConstructor(in);
- in.setInstance(null);
-
- list.set(i, as.copy());
-
- return true;
- }
- }
-
- // check for variable in use
- Set<VarVersionPaar> setVars = remote.getAllVariables();
- if(setVars.contains(leftPaar)) { // variable used somewhere in between -> exit, need a better reduced code
- return false;
- }
- }
- }
- }
- }
-
- return false;
- }
-
- private static Exprent isLambda(Exprent exprent, StructClass cl) {
-
- List<Exprent> lst = exprent.getAllExprents();
- for(Exprent expr: lst) {
- Exprent ret = isLambda(expr, cl);
- if(ret != null) {
- exprent.replaceExprent(expr, ret);
- }
- }
-
- if(exprent.type == Exprent.EXPRENT_INVOCATION) {
- InvocationExprent in = (InvocationExprent)exprent;
-
- if(in.getInvocationTyp() == InvocationExprent.INVOKE_DYNAMIC) {
-
- String lambda_class_name = cl.qualifiedName + in.getInvokeDynamicClassSuffix();
- ClassNode lambda_class = DecompilerContext.getClassprocessor().getMapRootClasses().get(lambda_class_name);
-
- if(lambda_class != null) { // real lambda class found, replace invocation with an anonymous class
-
- NewExprent newexp = new NewExprent(new VarType(lambda_class_name, true), null, 0);
- newexp.setConstructor(in);
- // note: we don't set the instance to null with in.setInstance(null) like it is done for a common constructor invokation
- // lambda can also be a reference to a virtual method (e.g. String x; ...(x::toString);)
- // in this case instance will hold the corresponding object
-
- return newexp;
- }
- }
- }
-
- return null;
- }
-
-
- private static Exprent isSimpleConstructorInvocation(Exprent exprent) {
-
- List<Exprent> lst = exprent.getAllExprents();
- for(Exprent expr: lst) {
- Exprent ret = isSimpleConstructorInvocation(expr);
- if(ret != null) {
- exprent.replaceExprent(expr, ret);
- }
- }
-
- if(exprent.type == Exprent.EXPRENT_INVOCATION) {
- InvocationExprent in = (InvocationExprent)exprent;
- if(in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_NEW) {
- NewExprent newexp = (NewExprent)in.getInstance();
- newexp.setConstructor(in);
- in.setInstance(null);
- return newexp;
- }
- }
-
- return null;
- }
-
-
- private static boolean buildIff(Statement stat, SSAConstructorSparseEx ssa) {
-
- if(stat.type == Statement.TYPE_IF && stat.getExprents() == null) {
- IfStatement stif = (IfStatement)stat;
- if(stif.iftype == IfStatement.IFTYPE_IFELSE) {
- Statement ifstat = stif.getIfstat();
- Statement elsestat = stif.getElsestat();
-
- if(ifstat.getExprents() != null && ifstat.getExprents().size() == 1
- && elsestat.getExprents()!= null && elsestat.getExprents().size() == 1
- && ifstat.getAllSuccessorEdges().size() == 1 && elsestat.getAllSuccessorEdges().size() == 1
- && ifstat.getAllSuccessorEdges().get(0).getDestination() == elsestat.getAllSuccessorEdges().get(0).getDestination()) {
-
- Exprent ifexpr = ifstat.getExprents().get(0);
- Exprent elseexpr = elsestat.getExprents().get(0);
-
- if(ifexpr.type == Exprent.EXPRENT_ASSIGNMENT && elseexpr.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent ifas = (AssignmentExprent)ifexpr;
- AssignmentExprent elseas = (AssignmentExprent)elseexpr;
-
- if(ifas.getLeft().type == Exprent.EXPRENT_VAR && elseas.getLeft().type == Exprent.EXPRENT_VAR) {
- VarExprent ifvar = (VarExprent)ifas.getLeft();
- VarExprent elsevar = (VarExprent)elseas.getLeft();
-
- if(ifvar.getIndex() == elsevar.getIndex() && ifvar.isStack()) { // ifvar.getIndex() >= VarExprent.STACK_BASE) {
-
- boolean found = false;
-
- for(Entry<VarVersionPaar, FastSparseSet<Integer>> ent : ssa.getPhi().entrySet()) {
- if(ent.getKey().var == ifvar.getIndex()) {
- if(ent.getValue().contains(ifvar.getVersion()) && ent.getValue().contains(elsevar.getVersion())) {
- found = true;
- break;
- }
- }
- }
-
- if(found) {
- List<Exprent> data = new ArrayList<Exprent>();
- data.addAll(stif.getFirst().getExprents());
-
- data.add(new AssignmentExprent(ifvar, new FunctionExprent(FunctionExprent.FUNCTION_IIF,
- Arrays.asList(new Exprent[] {((IfExprent)stif.getHeadexprent()).getCondition(),
- ifas.getRight(),
- elseas.getRight()}))));
- stif.setExprents(data);
-
- if(stif.getAllSuccessorEdges().isEmpty()) {
- StatEdge ifedge = ifstat.getAllSuccessorEdges().get(0);
- StatEdge edge = new StatEdge(ifedge.getType(), stif, ifedge.getDestination());
-
- stif.addSuccessor(edge);
- if(ifedge.closure != null) {
- ifedge.closure.addLabeledEdge(edge);
- }
- }
-
- SequenceHelper.destroyAndFlattenStatement(stif);
-
- return true;
- }
- }
- }
- } else if(ifexpr.type == Exprent.EXPRENT_EXIT && elseexpr.type == Exprent.EXPRENT_EXIT) {
- ExitExprent ifex = (ExitExprent)ifexpr;
- ExitExprent elseex = (ExitExprent)elseexpr;
-
- if(ifex.getExittype() == elseex.getExittype() && ifex.getValue() != null && elseex.getValue() != null &&
- ifex.getExittype() == ExitExprent.EXIT_RETURN) {
-
- // throw is dangerous, because of implicit casting to a common superclass
- // e.g. throws IOException and throw true?new RuntimeException():new IOException(); won't work
- if(ifex.getExittype() == ExitExprent.EXIT_THROW &&
- !ifex.getValue().getExprType().equals(elseex.getValue().getExprType())) { // note: getExprType unreliable at this point!
- return false;
- }
-
- List<Exprent> data = new ArrayList<Exprent>();
- data.addAll(stif.getFirst().getExprents());
-
- data.add(new ExitExprent(ifex.getExittype(), new FunctionExprent(FunctionExprent.FUNCTION_IIF,
- Arrays.asList(new Exprent[] {((IfExprent)stif.getHeadexprent()).getCondition(),
- ifex.getValue(),
- elseex.getValue()})), ifex.getRettype()));
- stif.setExprents(data);
-
- StatEdge retedge = ifstat.getAllSuccessorEdges().get(0);
- stif.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, stif, retedge.getDestination(), retedge.closure==stif?stif.getParent():retedge.closure));
-
- SequenceHelper.destroyAndFlattenStatement(stif);
-
- return true;
- }
- }
- }
- }
- }
-
- return false;
- }
-
-
+ private boolean firstInvocation;
+
+ public SimplifyExprentsHelper(boolean firstInvocation) {
+ this.firstInvocation = firstInvocation;
+ }
+
+ public boolean simplifyStackVarsStatement(Statement stat, HashSet<Integer> setReorderedIfs, SSAConstructorSparseEx ssa, StructClass cl) {
+
+ boolean res = false;
+
+ if (stat.getExprents() == null) {
+
+ for (; ; ) {
+
+ boolean changed = false;
+
+ for (Statement st : stat.getStats()) {
+ res |= simplifyStackVarsStatement(st, setReorderedIfs, ssa, cl);
+
+ // collapse composed if's
+ if (changed = IfHelper.mergeIfs(st, setReorderedIfs)) {
+ break;
+ }
+
+ // collapse iff ?: statement
+ if (changed = buildIff(st, ssa)) {
+ break;
+ }
+ }
+
+ res |= changed;
+
+ if (!changed) {
+ break;
+ }
+ }
+ }
+ else {
+ res |= simplifyStackVarsExprents(stat.getExprents(), cl);
+ }
+
+ return res;
+ }
+
+ private boolean simplifyStackVarsExprents(List<Exprent> list, StructClass cl) {
+
+ boolean res = false;
+
+ int index = 0;
+
+ while (index < list.size()) {
+
+ Exprent current = list.get(index);
+
+ Exprent ret = isSimpleConstructorInvocation(current);
+ if (ret != null) {
+ list.set(index, ret);
+ res = true;
+
+ continue;
+ }
+
+ // lambda expression (Java 8)
+ ret = isLambda(current, cl);
+ if (ret != null) {
+ list.set(index, ret);
+ res = true;
+
+ continue;
+ }
+
+ // remove monitor exit
+ if (isMonitorExit(current)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+
+ // trivial assignment of a stack variable
+ if (isTrivialStackAssignment(current)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+
+ if (index == list.size() - 1) {
+ break;
+ }
+
+
+ Exprent next = list.get(index + 1);
+
+
+ // constructor invocation
+ if (isConstructorInvocationRemote(list, index)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+
+ // remove getClass() invocation, which is part of a qualified new
+ if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_GETCLASS_NEW)) {
+ if (isQualifiedNewGetClass(current, next)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+ }
+
+ // direct initialization of an array
+ int arrcount = isArrayInitializer(list, index);
+ if (arrcount > 0) {
+ for (int i = 0; i < arrcount; i++) {
+ list.remove(index + 1);
+ }
+ res = true;
+
+ continue;
+ }
+
+ // add array initializer expression
+ if (addArrayInitializer(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ // integer ++expr and --expr (except for vars!)
+ Exprent func = isPPIorMMI(current);
+ if (func != null) {
+ list.set(index, func);
+ res = true;
+
+ continue;
+ }
+
+ // expr++ and expr--
+ if (isIPPorIMM(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ // assignment on stack
+ if (isStackAssignement(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ if (!firstInvocation && isStackAssignement2(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ index++;
+ }
+
+ return res;
+ }
+
+ private static boolean addArrayInitializer(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)first;
+
+ if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) {
+ NewExprent newex = (NewExprent)as.getRight();
+
+ if (!newex.getLstArrayElements().isEmpty()) {
+
+ VarExprent arrvar = (VarExprent)as.getLeft();
+
+ if (second.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent aas = (AssignmentExprent)second;
+ if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) {
+ ArrayExprent arrex = (ArrayExprent)aas.getLeft();
+ if (arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray())
+ && arrex.getIndex().type == Exprent.EXPRENT_CONST) {
+
+ int constvalue = ((ConstExprent)arrex.getIndex()).getIntValue();
+
+ if (constvalue < newex.getLstArrayElements().size()) {
+ Exprent init = newex.getLstArrayElements().get(constvalue);
+ if (init.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cinit = (ConstExprent)init;
+
+ VarType arrtype = newex.getNewtype().copy();
+ arrtype.decArrayDim();
+
+ ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype);
+
+ if (cinit.equals(defaultval)) {
+
+ Exprent tempexpr = aas.getRight();
+
+ if (!tempexpr.containsExprent(arrvar)) {
+ newex.getLstArrayElements().set(constvalue, tempexpr);
+
+ if (tempexpr.type == Exprent.EXPRENT_NEW) {
+ NewExprent tempnewex = (NewExprent)tempexpr;
+ int dims = newex.getNewtype().arraydim;
+ if (dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) {
+ tempnewex.setDirectArrayInit(true);
+ }
+ }
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static int isArrayInitializer(List<Exprent> list, int index) {
+
+ Exprent current = list.get(index);
+ if (current.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)current;
+
+ if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) {
+ NewExprent newex = (NewExprent)as.getRight();
+
+ if (newex.getExprType().arraydim > 0 && newex.getLstDims().size() == 1 && newex.getLstArrayElements().isEmpty() &&
+ newex.getLstDims().get(0).type == Exprent.EXPRENT_CONST) {
+
+ int size = ((Integer)((ConstExprent)newex.getLstDims().get(0)).getValue()).intValue();
+ if (size == 0) {
+ return 0;
+ }
+
+ VarExprent arrvar = (VarExprent)as.getLeft();
+
+ HashMap<Integer, Exprent> mapInit = new HashMap<Integer, Exprent>();
+
+ int i = 1;
+ while (index + i < list.size() && i <= size) {
+ boolean found = false;
+
+ Exprent expr = list.get(index + i);
+ if (expr.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent aas = (AssignmentExprent)expr;
+ if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) {
+ ArrayExprent arrex = (ArrayExprent)aas.getLeft();
+ if (arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray())
+ && arrex.getIndex().type == Exprent.EXPRENT_CONST) {
+
+ int constvalue = ((ConstExprent)arrex.getIndex())
+ .getIntValue(); // TODO: check for a number type. Failure extremely improbable, but nevertheless...
+
+ if (constvalue < size && !mapInit.containsKey(constvalue)) {
+
+ if (!aas.getRight().containsExprent(arrvar)) {
+ mapInit.put(constvalue, aas.getRight());
+ found = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+
+ i++;
+ }
+
+ double fraction = ((double)mapInit.size()) / size;
+
+ if ((arrvar.isStack() && fraction > 0) || (size <= 7 && fraction >= 0.3) ||
+ (size > 7 && fraction >= 0.7)) {
+
+ List<Exprent> lstRet = new ArrayList<Exprent>();
+
+ VarType arrtype = newex.getNewtype().copy();
+ arrtype.decArrayDim();
+
+ ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype);
+
+ for (int j = 0; j < size; j++) {
+ lstRet.add(defaultval.copy());
+ }
+
+ int dims = newex.getNewtype().arraydim;
+ for (Entry<Integer, Exprent> ent : mapInit.entrySet()) {
+ Exprent tempexpr = ent.getValue();
+ lstRet.set(ent.getKey(), tempexpr);
+
+ if (tempexpr.type == Exprent.EXPRENT_NEW) {
+ NewExprent tempnewex = (NewExprent)tempexpr;
+ if (dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) {
+ tempnewex.setDirectArrayInit(true);
+ }
+ }
+ }
+
+ newex.setLstArrayElements(lstRet);
+
+ return mapInit.size();
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ private static boolean isTrivialStackAssignment(Exprent first) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asf = (AssignmentExprent)first;
+
+ if (asf.getLeft().type == Exprent.EXPRENT_VAR && asf.getRight().type == Exprent.EXPRENT_VAR) {
+ VarExprent varleft = (VarExprent)asf.getLeft();
+ VarExprent varright = (VarExprent)asf.getRight();
+
+ if (varleft.getIndex() == varright.getIndex() && varleft.isStack() &&
+ varright.isStack()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isStackAssignement2(Exprent first, Exprent second) { // e.g. 1.4-style class invocation
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asf = (AssignmentExprent)first;
+ AssignmentExprent ass = (AssignmentExprent)second;
+
+ if (asf.getLeft().type == Exprent.EXPRENT_VAR && ass.getRight().type == Exprent.EXPRENT_VAR &&
+ asf.getLeft().equals(ass.getRight()) && ((VarExprent)asf.getLeft()).isStack()) {
+ if (ass.getLeft().type != Exprent.EXPRENT_VAR || !((VarExprent)ass.getLeft()).isStack()) {
+ asf.setRight(new AssignmentExprent(ass.getLeft(), asf.getRight()));
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isStackAssignement(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asf = (AssignmentExprent)first;
+ AssignmentExprent ass = (AssignmentExprent)second;
+
+ for (; ; ) {
+ if (asf.getRight().equals(ass.getRight())) {
+ if ((asf.getLeft().type == Exprent.EXPRENT_VAR && ((VarExprent)asf.getLeft()).isStack()) &&
+ (ass.getLeft().type != Exprent.EXPRENT_VAR || !((VarExprent)ass.getLeft()).isStack())) {
+
+ if (!ass.getLeft().containsExprent(asf.getLeft())) {
+ asf.setRight(ass);
+ return true;
+ }
+ }
+ }
+ if (asf.getRight().type == Exprent.EXPRENT_ASSIGNMENT) {
+ asf = (AssignmentExprent)asf.getRight();
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static Exprent isPPIorMMI(Exprent first) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)first;
+
+ if (as.getRight().type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent func = (FunctionExprent)as.getRight();
+
+ if (func.getFunctype() == FunctionExprent.FUNCTION_ADD ||
+ func.getFunctype() == FunctionExprent.FUNCTION_SUB) {
+ Exprent econd = func.getLstOperands().get(0);
+ Exprent econst = func.getLstOperands().get(1);
+
+ if (econst.type != Exprent.EXPRENT_CONST && econd.type == Exprent.EXPRENT_CONST &&
+ func.getFunctype() == FunctionExprent.FUNCTION_ADD) {
+ econd = econst;
+ econst = func.getLstOperands().get(0);
+ }
+
+ if (econst.type == Exprent.EXPRENT_CONST && ((ConstExprent)econst).hasValueOne()) {
+ Exprent left = as.getLeft();
+
+ if (left.type != Exprent.EXPRENT_VAR && left.equals(econd)) {
+ FunctionExprent ret = new FunctionExprent(
+ func.getFunctype() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI,
+ Arrays.asList(new Exprent[]{econd}));
+ ret.setImplicitType(VarType.VARTYPE_INT);
+ return ret;
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isIPPorIMM(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_FUNCTION) {
+ AssignmentExprent as = (AssignmentExprent)first;
+ FunctionExprent in = (FunctionExprent)second;
+
+ if ((in.getFunctype() == FunctionExprent.FUNCTION_MMI || in.getFunctype() == FunctionExprent.FUNCTION_PPI) &&
+ in.getLstOperands().get(0).equals(as.getRight())) {
+
+ if (in.getFunctype() == FunctionExprent.FUNCTION_MMI) {
+ in.setFunctype(FunctionExprent.FUNCTION_IMM);
+ }
+ else {
+ in.setFunctype(FunctionExprent.FUNCTION_IPP);
+ }
+ as.setRight(in);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isMonitorExit(Exprent first) {
+ if (first.type == Exprent.EXPRENT_MONITOR) {
+ MonitorExprent monexpr = (MonitorExprent)first;
+ if (monexpr.getMontype() == MonitorExprent.MONITOR_EXIT && monexpr.getValue().type == Exprent.EXPRENT_VAR
+ && !((VarExprent)monexpr.getValue()).isStack()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isQualifiedNewGetClass(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)first;
+
+ if (!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR && invexpr.getName().equals("getClass") &&
+ invexpr.getStringDescriptor().equals("()Ljava/lang/Class;")) {
+
+ List<Exprent> lstExprents = second.getAllExprents();
+ lstExprents.add(second);
+
+ for (Exprent expr : lstExprents) {
+ if (expr.type == Exprent.EXPRENT_NEW) {
+ NewExprent nexpr = (NewExprent)expr;
+ if (nexpr.getConstructor() != null && !nexpr.getConstructor().getLstParameters().isEmpty() &&
+ nexpr.getConstructor().getLstParameters().get(0).equals(invexpr.getInstance())) {
+
+ String classname = nexpr.getNewtype().value;
+ ClassNode node = DecompilerContext.getClassprocessor().getMapRootClasses().get(classname);
+ if (node != null && node.type != ClassNode.CLASS_ROOT) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) {
+ //
+ // Exprent current = list.get(index);
+ //
+ // if(current.type == Exprent.EXPRENT_ASSIGNMENT) {
+ // AssignmentExprent as = (AssignmentExprent)current;
+ //
+ // if(as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) {
+ //
+ // NewExprent newexpr = (NewExprent)as.getRight();
+ // VarType newtype = newexpr.getNewtype();
+ // VarVersionPaar leftPaar = new VarVersionPaar((VarExprent)as.getLeft());
+ //
+ // if(newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0 &&
+ // newexpr.getConstructor() == null) {
+ //
+ // Set<VarVersionPaar> setChangedVars = new HashSet<VarVersionPaar>();
+ //
+ // for(int i = index + 1; i < list.size(); i++) {
+ // Exprent remote = list.get(i);
+ //
+ // if(remote.type == Exprent.EXPRENT_INVOCATION) {
+ // InvocationExprent in = (InvocationExprent)remote;
+ //
+ // if(in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_VAR
+ // && as.getLeft().equals(in.getInstance())) {
+ //
+ // Set<VarVersionPaar> setVars = remote.getAllVariables();
+ // setVars.remove(leftPaar);
+ // setVars.retainAll(setChangedVars);
+ //
+ // if(setVars.isEmpty()) {
+ //
+ // newexpr.setConstructor(in);
+ // in.setInstance(null);
+ //
+ // if(!setChangedVars.isEmpty()) { // some exprents inbetween
+ // list.add(index+1, as.copy());
+ // list.remove(i+1);
+ // } else {
+ // list.set(i, as.copy());
+ // }
+ //
+ // return true;
+ // }
+ // }
+ // }
+ //
+ // boolean isTempAssignment = false;
+ //
+ // if(remote.type == Exprent.EXPRENT_ASSIGNMENT) { // ugly solution
+ // AssignmentExprent asremote = (AssignmentExprent)remote;
+ // if(asremote.getLeft().type == Exprent.EXPRENT_VAR &&
+ // asremote.getRight().type == Exprent.EXPRENT_VAR) {
+ // setChangedVars.add(new VarVersionPaar((VarExprent)asremote.getLeft()));
+ // isTempAssignment = true;
+ // }
+ //
+ // // FIXME: needs to be rewritten
+ // // propagate (var = new X) forward to the <init> invokation and then reduce
+ //
+ //// if(asremote.getLeft().type == Exprent.EXPRENT_VAR) {
+ //// List<Exprent> lstRightExprents = asremote.getRight().getAllExprents(true);
+ //// lstRightExprents.add(asremote.getRight());
+ ////
+ //// Set<VarVersionPaar> setTempChangedVars = new HashSet<VarVersionPaar>();
+ //// boolean isTemp = true;
+ ////
+ //// for(Exprent expr : lstRightExprents) {
+ //// if(expr.type != Exprent.EXPRENT_VAR && expr.type != Exprent.EXPRENT_FIELD) {
+ //// isTemp = false;
+ //// break;
+ //// } else if(expr.type == Exprent.EXPRENT_VAR) {
+ //// setTempChangedVars.add(new VarVersionPaar((VarExprent)expr));
+ //// }
+ //// }
+ ////
+ //// if(isTemp) {
+ //// setChangedVars.addAll(setTempChangedVars);
+ //// isTempAssignment = true;
+ //// }
+ //// }
+ //// } else if(remote.type == Exprent.EXPRENT_FUNCTION) {
+ //// FunctionExprent fexpr = (FunctionExprent)remote;
+ //// if(fexpr.getFunctype() == FunctionExprent.FUNCTION_IPP || fexpr.getFunctype() == FunctionExprent.FUNCTION_IMM
+ //// || fexpr.getFunctype() == FunctionExprent.FUNCTION_PPI || fexpr.getFunctype() == FunctionExprent.FUNCTION_MMI) {
+ //// if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_VAR) {
+ //// setChangedVars.add(new VarVersionPaar((VarExprent)fexpr.getLstOperands().get(0)));
+ //// isTempAssignment = true;
+ //// }
+ //// }
+ // }
+ //
+ // if(!isTempAssignment) {
+ // Set<VarVersionPaar> setVars = remote.getAllVariables();
+ // if(setVars.contains(leftPaar)) {
+ // return false;
+ // } else {
+ // setChangedVars.addAll(setVars);
+ // }
+ // }
+ // }
+ // }
+ // }
+ // }
+ //
+ // return false;
+ // }
+
+ // propagate (var = new X) forward to the <init> invokation
+ private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) {
+
+ Exprent current = list.get(index);
+
+ if (current.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)current;
+
+ if (as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) {
+
+ NewExprent newexpr = (NewExprent)as.getRight();
+ VarType newtype = newexpr.getNewtype();
+ VarVersionPaar leftPaar = new VarVersionPaar((VarExprent)as.getLeft());
+
+ if (newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0 && newexpr.getConstructor() == null) {
+
+ for (int i = index + 1; i < list.size(); i++) {
+ Exprent remote = list.get(i);
+
+ // <init> invocation
+ if (remote.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent in = (InvocationExprent)remote;
+
+ if (in.getFunctype() == InvocationExprent.TYP_INIT &&
+ in.getInstance().type == Exprent.EXPRENT_VAR &&
+ as.getLeft().equals(in.getInstance())) {
+
+ newexpr.setConstructor(in);
+ in.setInstance(null);
+
+ list.set(i, as.copy());
+
+ return true;
+ }
+ }
+
+ // check for variable in use
+ Set<VarVersionPaar> setVars = remote.getAllVariables();
+ if (setVars.contains(leftPaar)) { // variable used somewhere in between -> exit, need a better reduced code
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static Exprent isLambda(Exprent exprent, StructClass cl) {
+
+ List<Exprent> lst = exprent.getAllExprents();
+ for (Exprent expr : lst) {
+ Exprent ret = isLambda(expr, cl);
+ if (ret != null) {
+ exprent.replaceExprent(expr, ret);
+ }
+ }
+
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent in = (InvocationExprent)exprent;
+
+ if (in.getInvocationTyp() == InvocationExprent.INVOKE_DYNAMIC) {
+
+ String lambda_class_name = cl.qualifiedName + in.getInvokeDynamicClassSuffix();
+ ClassNode lambda_class = DecompilerContext.getClassprocessor().getMapRootClasses().get(lambda_class_name);
+
+ if (lambda_class != null) { // real lambda class found, replace invocation with an anonymous class
+
+ NewExprent newexp = new NewExprent(new VarType(lambda_class_name, true), null, 0);
+ newexp.setConstructor(in);
+ // note: we don't set the instance to null with in.setInstance(null) like it is done for a common constructor invokation
+ // lambda can also be a reference to a virtual method (e.g. String x; ...(x::toString);)
+ // in this case instance will hold the corresponding object
+
+ return newexp;
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ private static Exprent isSimpleConstructorInvocation(Exprent exprent) {
+
+ List<Exprent> lst = exprent.getAllExprents();
+ for (Exprent expr : lst) {
+ Exprent ret = isSimpleConstructorInvocation(expr);
+ if (ret != null) {
+ exprent.replaceExprent(expr, ret);
+ }
+ }
+
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent in = (InvocationExprent)exprent;
+ if (in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_NEW) {
+ NewExprent newexp = (NewExprent)in.getInstance();
+ newexp.setConstructor(in);
+ in.setInstance(null);
+ return newexp;
+ }
+ }
+
+ return null;
+ }
+
+
+ private static boolean buildIff(Statement stat, SSAConstructorSparseEx ssa) {
+
+ if (stat.type == Statement.TYPE_IF && stat.getExprents() == null) {
+ IfStatement stif = (IfStatement)stat;
+ if (stif.iftype == IfStatement.IFTYPE_IFELSE) {
+ Statement ifstat = stif.getIfstat();
+ Statement elsestat = stif.getElsestat();
+
+ if (ifstat.getExprents() != null && ifstat.getExprents().size() == 1
+ && elsestat.getExprents() != null && elsestat.getExprents().size() == 1
+ && ifstat.getAllSuccessorEdges().size() == 1 && elsestat.getAllSuccessorEdges().size() == 1
+ && ifstat.getAllSuccessorEdges().get(0).getDestination() == elsestat.getAllSuccessorEdges().get(0).getDestination()) {
+
+ Exprent ifexpr = ifstat.getExprents().get(0);
+ Exprent elseexpr = elsestat.getExprents().get(0);
+
+ if (ifexpr.type == Exprent.EXPRENT_ASSIGNMENT && elseexpr.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent ifas = (AssignmentExprent)ifexpr;
+ AssignmentExprent elseas = (AssignmentExprent)elseexpr;
+
+ if (ifas.getLeft().type == Exprent.EXPRENT_VAR && elseas.getLeft().type == Exprent.EXPRENT_VAR) {
+ VarExprent ifvar = (VarExprent)ifas.getLeft();
+ VarExprent elsevar = (VarExprent)elseas.getLeft();
+
+ if (ifvar.getIndex() == elsevar.getIndex() && ifvar.isStack()) { // ifvar.getIndex() >= VarExprent.STACK_BASE) {
+
+ boolean found = false;
+
+ for (Entry<VarVersionPaar, FastSparseSet<Integer>> ent : ssa.getPhi().entrySet()) {
+ if (ent.getKey().var == ifvar.getIndex()) {
+ if (ent.getValue().contains(ifvar.getVersion()) && ent.getValue().contains(elsevar.getVersion())) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ List<Exprent> data = new ArrayList<Exprent>();
+ data.addAll(stif.getFirst().getExprents());
+
+ data.add(new AssignmentExprent(ifvar, new FunctionExprent(FunctionExprent.FUNCTION_IIF,
+ Arrays.asList(new Exprent[]{
+ ((IfExprent)stif.getHeadexprent()).getCondition(),
+ ifas.getRight(),
+ elseas.getRight()}))));
+ stif.setExprents(data);
+
+ if (stif.getAllSuccessorEdges().isEmpty()) {
+ StatEdge ifedge = ifstat.getAllSuccessorEdges().get(0);
+ StatEdge edge = new StatEdge(ifedge.getType(), stif, ifedge.getDestination());
+
+ stif.addSuccessor(edge);
+ if (ifedge.closure != null) {
+ ifedge.closure.addLabeledEdge(edge);
+ }
+ }
+
+ SequenceHelper.destroyAndFlattenStatement(stif);
+
+ return true;
+ }
+ }
+ }
+ }
+ else if (ifexpr.type == Exprent.EXPRENT_EXIT && elseexpr.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent ifex = (ExitExprent)ifexpr;
+ ExitExprent elseex = (ExitExprent)elseexpr;
+
+ if (ifex.getExittype() == elseex.getExittype() && ifex.getValue() != null && elseex.getValue() != null &&
+ ifex.getExittype() == ExitExprent.EXIT_RETURN) {
+
+ // throw is dangerous, because of implicit casting to a common superclass
+ // e.g. throws IOException and throw true?new RuntimeException():new IOException(); won't work
+ if (ifex.getExittype() == ExitExprent.EXIT_THROW &&
+ !ifex.getValue().getExprType().equals(elseex.getValue().getExprType())) { // note: getExprType unreliable at this point!
+ return false;
+ }
+
+ List<Exprent> data = new ArrayList<Exprent>();
+ data.addAll(stif.getFirst().getExprents());
+
+ data.add(new ExitExprent(ifex.getExittype(), new FunctionExprent(FunctionExprent.FUNCTION_IIF,
+ Arrays.asList(new Exprent[]{
+ ((IfExprent)stif.getHeadexprent()).getCondition(),
+ ifex.getValue(),
+ elseex.getValue()})), ifex.getRettype()));
+ stif.setExprents(data);
+
+ StatEdge retedge = ifstat.getAllSuccessorEdges().get(0);
+ stif.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, stif, retedge.getDestination(),
+ retedge.closure == stif ? stif.getParent() : retedge.closure));
+
+ SequenceHelper.destroyAndFlattenStatement(stif);
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java
index 5dae30c..d0f3f03 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java
@@ -1,38 +1,23 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.MonitorExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
-import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
-import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper;
-import org.jetbrains.java.decompiler.modules.decompiler.sforms.SSAConstructorSparseEx;
-import org.jetbrains.java.decompiler.modules.decompiler.sforms.SSAUConstructorSparseEx;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.*;
import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
@@ -46,671 +31,705 @@ import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
+import java.util.*;
+import java.util.Map.Entry;
+
public class StackVarsProcessor {
- public void simplifyStackVars(RootStatement root, StructMethod mt, StructClass cl) {
-
- HashSet<Integer> setReorderedIfs = new HashSet<Integer>();
-
- SSAUConstructorSparseEx ssau = null;
-
- for(;;) {
-
- boolean found = false;
-
-// System.out.println("--------------- \r\n"+root.toJava());
-
- SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
- ssa.splitVariables(root, mt);
-
-// System.out.println("--------------- \r\n"+root.toJava());
-
-
- SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(ssau == null);
- while(sehelper.simplifyStackVarsStatement(root, setReorderedIfs, ssa, cl)) {
-// System.out.println("--------------- \r\n"+root.toJava());
- found = true;
- }
-
-
-// System.out.println("=============== \r\n"+root.toJava());
-
- setVersionsToNull(root);
-
- SequenceHelper.condenseSequences(root);
-
- ssau = new SSAUConstructorSparseEx();
- ssau.splitVariables(root, mt);
-
-// try {
-// DotExporter.toDotFile(ssau.getSsuversions(), new File("c:\\Temp\\gr12_my.dot"));
-// } catch(Exception ex) {
-// ex.printStackTrace();
-// }
-
-// System.out.println("++++++++++++++++ \r\n"+root.toJava());
-
-
- if(iterateStatements(root, ssau)) {
- found = true;
- }
-
-// System.out.println("***************** \r\n"+root.toJava());
-
- setVersionsToNull(root);
-
- if(!found) {
- break;
- }
- }
-
- // remove unused assignments
- ssau = new SSAUConstructorSparseEx();
- ssau.splitVariables(root, mt);
-
-// try {
-// DotExporter.toDotFile(ssau.getSsuversions(), new File("c:\\Temp\\gr12_my.dot"));
-// } catch(Exception ex) {
-// ex.printStackTrace();
-// }
-
- iterateStatements(root, ssau);
-
-// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
-
- setVersionsToNull(root);
- }
-
- private void setVersionsToNull(Statement stat) {
-
- if(stat.getExprents() == null) {
- for(Object obj: stat.getSequentialObjects()) {
- if(obj instanceof Statement) {
- setVersionsToNull((Statement)obj);
- } else if(obj instanceof Exprent) {
- setExprentVersionsToNull((Exprent)obj);
- }
- }
- } else {
- for(Exprent exprent: stat.getExprents()) {
- setExprentVersionsToNull(exprent);
- }
- }
- }
-
- private void setExprentVersionsToNull(Exprent exprent) {
-
- List<Exprent> lst = exprent.getAllExprents(true);
- lst.add(exprent);
-
- for(Exprent expr: lst) {
- if(expr.type == Exprent.EXPRENT_VAR) {
- ((VarExprent)expr).setVersion(0);
- }
- }
- }
-
-
- private boolean iterateStatements(RootStatement root, SSAUConstructorSparseEx ssa) {
-
- FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
- DirectGraph dgraph = flatthelper.buildDirectGraph(root);
-
- boolean res = false;
-
- HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
- LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
- LinkedList<HashMap<VarVersionPaar, Exprent>> stackMaps = new LinkedList<HashMap<VarVersionPaar, Exprent>>();
-
- stack.add(dgraph.first);
- stackMaps.add(new HashMap<VarVersionPaar, Exprent>());
-
- while(!stack.isEmpty()) {
-
- DirectNode nd = stack.removeFirst();
- HashMap<VarVersionPaar, Exprent> mapVarValues = stackMaps.removeFirst();
-
- if(setVisited.contains(nd)) {
- continue;
- }
- setVisited.add(nd);
-
- List<List<Exprent>> lstLists = new ArrayList<List<Exprent>>();
-
- if(!nd.exprents.isEmpty()) {
- lstLists.add(nd.exprents);
- }
-
- if(nd.succs.size() == 1){
- DirectNode ndsucc = nd.succs.get(0);
- if(ndsucc.type == DirectNode.NODE_TAIL && !ndsucc.exprents.isEmpty()) {
- lstLists.add(nd.succs.get(0).exprents);
- nd = ndsucc;
- }
- }
-
- for(int i=0;i<lstLists.size();i++) {
- List<Exprent> lst = lstLists.get(i);
-
- int index = 0;
- while(index < lst.size()) {
- Exprent next = null;
- if(index == lst.size()-1) {
- if(i<lstLists.size()-1) {
- next = lstLists.get(i+1).get(0);
- }
- } else {
- next = lst.get(index+1);
- }
-
- int[] ret = iterateExprent(lst, index, next, mapVarValues, ssa);
-
- //System.out.println("***************** \r\n"+root.toJava());
-
- if(ret[0] >= 0) {
- index = ret[0];
- } else {
- index++;
- }
- res |= (ret[1] == 1);
- }
- }
-
- for(DirectNode ndx: nd.succs) {
- stack.add(ndx);
- stackMaps.add(new HashMap<VarVersionPaar, Exprent>(mapVarValues));
- }
-
- // make sure the 3 special exprent lists in a loop (init, condition, increment) are not empty
- // change loop type if necessary
- if(nd.exprents.isEmpty() &&
- (nd.type == DirectNode.NODE_INIT || nd.type == DirectNode.NODE_CONDITION || nd.type == DirectNode.NODE_INCREMENT)) {
- nd.exprents.add(null);
-
- if(nd.statement.type == Statement.TYPE_DO) {
- DoStatement loop = (DoStatement)nd.statement;
-
- if(loop.getLooptype() == DoStatement.LOOP_FOR && loop.getInitExprent() == null && loop.getIncExprent() == null) { // "downgrade" loop to 'while'
- loop.setLooptype(DoStatement.LOOP_WHILE);
- }
- }
- }
- }
-
- return res;
- }
-
-
- private Exprent isReplaceableVar(Exprent exprent, HashMap<VarVersionPaar, Exprent> mapVarValues, SSAUConstructorSparseEx ssau) {
-
- Exprent dest = null;
-
- if(exprent.type == Exprent.EXPRENT_VAR) {
- VarExprent var = (VarExprent)exprent;
- dest = mapVarValues.get(new VarVersionPaar(var));
- }
-
- return dest;
- }
-
- private void replaceSingleVar(Exprent parent, VarExprent var, Exprent dest, SSAUConstructorSparseEx ssau) {
-
- parent.replaceExprent(var, dest);
-
- // live sets
- SFormsFastMapDirect livemap = ssau.getLiveVarVersionsMap(new VarVersionPaar(var));
- HashSet<VarVersionPaar> setVars = getAllVersions(dest);
-
- for(VarVersionPaar varpaar : setVars) {
- VarVersionNode node = ssau.getSsuversions().nodes.getWithKey(varpaar);
-
- for(Iterator<Entry<Integer, FastSparseSet<Integer>>> itent = node.live.entryList().iterator();itent.hasNext();) {
- Entry<Integer, FastSparseSet<Integer>> ent = itent.next();
-
- Integer key = ent.getKey();
-
- if(!livemap.containsKey(key)) {
- itent.remove();
- } else {
- FastSparseSet<Integer> set = ent.getValue();
-
- set.complement(livemap.get(key));
- if(set.isEmpty()) {
- itent.remove();
- }
- }
- }
- }
- }
-
- private int[] iterateExprent(List<Exprent> lstExprents, int index, Exprent next, HashMap<VarVersionPaar,
- Exprent> mapVarValues, SSAUConstructorSparseEx ssau) {
-
- Exprent exprent = lstExprents.get(index);
-
- int changed = 0;
-
- for(Exprent expr: exprent.getAllExprents()) {
- for(;;) {
- Object[] arr = iterateChildExprent(expr, exprent, next, mapVarValues, ssau);
- Exprent retexpr = (Exprent)arr[0];
- changed |= (Boolean)arr[1]?1:0;
-
- boolean isReplaceable = (Boolean)arr[2];
- if(retexpr != null) {
- if(isReplaceable) {
- replaceSingleVar(exprent, (VarExprent)expr, retexpr, ssau);
- expr = retexpr;
- } else {
- exprent.replaceExprent(expr, retexpr);
- }
- changed = 1;
- }
-
- if(!isReplaceable) {
- break;
- }
- }
- }
-
- // no var on the highest level, so no replacing
-
- VarExprent left = null;
- Exprent right = null;
-
- if(exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent as = (AssignmentExprent)exprent;
- if(as.getLeft().type == Exprent.EXPRENT_VAR) {
- left = (VarExprent)as.getLeft();
- right = as.getRight();
- }
- }
-
- if(left == null) {
- return new int[]{-1, changed};
- }
-
- VarVersionPaar leftpaar = new VarVersionPaar(left);
-
- List<VarVersionNode> usedVers = new ArrayList<VarVersionNode>();
- boolean notdom = getUsedVersions(ssau, leftpaar, usedVers);
-
- if(!notdom && usedVers.isEmpty()) {
- if(left.isStack() && (right.type == Exprent.EXPRENT_INVOCATION ||
- right.type == Exprent.EXPRENT_ASSIGNMENT || right.type == Exprent.EXPRENT_NEW)) {
- if(right.type == Exprent.EXPRENT_NEW) {
- // new Object(); permitted
- NewExprent nexpr = (NewExprent)right;
- if(nexpr.isAnonymous() || nexpr.getNewtype().arraydim > 0
- || nexpr.getNewtype().type != CodeConstants.TYPE_OBJECT) {
- return new int[]{-1, changed};
- }
- }
-
- lstExprents.set(index, right);
- return new int[]{index+1, 1};
- } else if(right.type == Exprent.EXPRENT_VAR) {
- lstExprents.remove(index);
- return new int[]{index, 1};
- } else {
- return new int[]{-1, changed};
- }
- }
-
- int useflags = right.getExprentUse();
-
- // stack variables only
- if(!left.isStack() &&
- (right.type != Exprent.EXPRENT_VAR || ((VarExprent)right).isStack())) { // special case catch(... ex)
- return new int[]{-1, changed};
- }
-
- if((useflags & Exprent.MULTIPLE_USES) == 0 && (notdom || usedVers.size()>1)) {
- return new int[]{-1, changed};
- }
-
- HashMap<Integer, HashSet<VarVersionPaar>> mapVars = getAllVarVersions(leftpaar, right, ssau);
-
- boolean isSelfReference = mapVars.containsKey(leftpaar.var);
- if(isSelfReference && notdom) {
- return new int[]{-1, changed};
- }
-
- HashSet<VarVersionPaar> setNextVars = next==null?null:getAllVersions(next);
-
- // FIXME: fix the entire method!
- if(right.type != Exprent.EXPRENT_CONST && right.type != Exprent.EXPRENT_VAR && setNextVars!=null && mapVars.containsKey(leftpaar.var)) {
- for(VarVersionNode usedvar: usedVers) {
- if(!setNextVars.contains(new VarVersionPaar(usedvar.var, usedvar.version))) {
- return new int[]{-1, changed};
- }
- }
- }
-
- mapVars.remove(leftpaar.var);
-
- boolean vernotreplaced = false;
- boolean verreplaced = false;
-
-
- HashSet<VarVersionPaar> setTempUsedVers = new HashSet<VarVersionPaar>();
-
- for(VarVersionNode usedvar: usedVers) {
- VarVersionPaar usedver = new VarVersionPaar(usedvar.var, usedvar.version);
- if(isVersionToBeReplaced(usedver, mapVars, ssau, leftpaar) &&
- (right.type == Exprent.EXPRENT_CONST || right.type == Exprent.EXPRENT_VAR || right.type == Exprent.EXPRENT_FIELD
- || setNextVars==null || setNextVars.contains(usedver))) {
-
- setTempUsedVers.add(usedver);
- verreplaced = true;
- } else {
- vernotreplaced = true;
- }
- }
-
- if(isSelfReference && vernotreplaced) {
- return new int[]{-1, changed};
- } else {
- for(VarVersionPaar usedver: setTempUsedVers) {
- Exprent copy = right.copy();
- if(right.type == Exprent.EXPRENT_FIELD && ssau.getMapFieldVars().containsKey(right.id)) {
- ssau.getMapFieldVars().put(copy.id, ssau.getMapFieldVars().get(right.id));
- }
-
- mapVarValues.put(usedver, copy);
- }
- }
-
- if(!notdom && !vernotreplaced) {
- // remove assignment
- lstExprents.remove(index);
- return new int[]{index, 1};
- } else if(verreplaced){
- return new int[]{index+1, changed};
- } else {
- return new int[]{-1, changed};
- }
- }
-
- private HashSet<VarVersionPaar> getAllVersions(Exprent exprent) {
-
- HashSet<VarVersionPaar> res = new HashSet<VarVersionPaar>();
-
- List<Exprent> listTemp = new ArrayList<Exprent>(exprent.getAllExprents(true));
- listTemp.add(exprent);
-
- for(Exprent expr: listTemp) {
- if(expr.type == Exprent.EXPRENT_VAR) {
- VarExprent var = (VarExprent)expr;
- res.add(new VarVersionPaar(var));
- }
- }
-
- return res;
- }
-
- private Object[] iterateChildExprent(Exprent exprent, Exprent parent, Exprent next, HashMap<VarVersionPaar, Exprent> mapVarValues, SSAUConstructorSparseEx ssau) {
-
- boolean changed = false;
-
- for(Exprent expr: exprent.getAllExprents()) {
- for(;;) {
- Object[] arr = iterateChildExprent(expr, parent, next, mapVarValues, ssau);
- Exprent retexpr = (Exprent)arr[0];
- changed |= (Boolean)arr[1];
-
- boolean isReplaceable = (Boolean)arr[2];
- if(retexpr != null) {
- if(isReplaceable) {
- replaceSingleVar(exprent, (VarExprent)expr, retexpr, ssau);
- expr = retexpr;
- } else {
- exprent.replaceExprent(expr, retexpr);
- }
- changed = true;
- }
-
- if(!isReplaceable) {
- break;
- }
- }
- }
-
- Exprent dest = isReplaceableVar(exprent, mapVarValues, ssau);
- if(dest != null) {
- return new Object[]{dest, true, true};
- }
-
-
- VarExprent left = null;
- Exprent right = null;
-
- if(exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
- AssignmentExprent as = (AssignmentExprent)exprent;
- if(as.getLeft().type == Exprent.EXPRENT_VAR) {
- left = (VarExprent)as.getLeft();
- right = as.getRight();
- }
- }
-
- if(left == null) {
- return new Object[]{null, changed, false};
- }
-
- boolean isHeadSynchronized = false;
- if(next == null && parent.type == Exprent.EXPRENT_MONITOR) {
- MonitorExprent monexpr = (MonitorExprent)parent;
- if(monexpr.getMontype() == MonitorExprent.MONITOR_ENTER && exprent.equals(monexpr.getValue())) {
- isHeadSynchronized = true;
- }
- }
-
- // stack variable or synchronized head exprent
- if(!left.isStack() && !isHeadSynchronized) {
- return new Object[]{null, changed, false};
- }
-
- VarVersionPaar leftpaar = new VarVersionPaar(left);
-
- List<VarVersionNode> usedVers = new ArrayList<VarVersionNode>();
- boolean notdom = getUsedVersions(ssau, leftpaar, usedVers);
-
- if(!notdom && usedVers.isEmpty()) {
- return new Object[]{right, changed, false};
- }
-
- // stack variables only
- if(!left.isStack()) {
- return new Object[]{null, changed, false};
- }
-
- int useflags = right.getExprentUse();
-
- if((useflags & Exprent.BOTH_FLAGS) != Exprent.BOTH_FLAGS) {
- return new Object[]{null, changed, false};
- }
-
- HashMap<Integer, HashSet<VarVersionPaar>> mapVars = getAllVarVersions(leftpaar, right, ssau);
-
- if(mapVars.containsKey(leftpaar.var) && notdom) {
- return new Object[]{null, changed, false};
- }
-
-
- mapVars.remove(leftpaar.var);
-
- HashSet<VarVersionPaar> setAllowedVars = getAllVersions(parent);
- if(next != null) {
- setAllowedVars.addAll(getAllVersions(next));
- }
-
- boolean vernotreplaced = false;
-
- HashSet<VarVersionPaar> setTempUsedVers = new HashSet<VarVersionPaar>();
-
- for(VarVersionNode usedvar: usedVers) {
- VarVersionPaar usedver = new VarVersionPaar(usedvar.var, usedvar.version);
- if(isVersionToBeReplaced(usedver, mapVars, ssau, leftpaar) &&
- (right.type == Exprent.EXPRENT_VAR || setAllowedVars.contains(usedver))) {
-
- setTempUsedVers.add(usedver);
- } else {
- vernotreplaced = true;
- }
- }
-
- if(!notdom && !vernotreplaced) {
-
- for(VarVersionPaar usedver: setTempUsedVers) {
- Exprent copy = right.copy();
- if(right.type == Exprent.EXPRENT_FIELD && ssau.getMapFieldVars().containsKey(right.id)) {
- ssau.getMapFieldVars().put(copy.id, ssau.getMapFieldVars().get(right.id));
- }
-
- mapVarValues.put(usedver, copy);
- }
-
- // remove assignment
- return new Object[]{right, changed, false};
- }
-
- return new Object[]{null, changed, false};
- }
-
- private boolean getUsedVersions(SSAUConstructorSparseEx ssa, VarVersionPaar var, List<VarVersionNode> res) {
-
- VarVersionsGraph ssuversions = ssa.getSsuversions();
- VarVersionNode varnode = ssuversions.nodes.getWithKey(var);
-
- HashSet<VarVersionNode> setVisited = new HashSet<VarVersionNode>();
-
- HashSet<VarVersionNode> setNotDoms = new HashSet<VarVersionNode>();
-
- LinkedList<VarVersionNode> stack = new LinkedList<VarVersionNode>();
- stack.add(varnode);
-
- while(!stack.isEmpty()) {
-
- VarVersionNode nd = stack.remove(0);
- setVisited.add(nd);
-
- if(nd != varnode && (nd.flags & VarVersionNode.FLAG_PHANTOM_FINEXIT)==0) {
- res.add(nd);
- }
-
- for(VarVersionEdge edge: nd.succs) {
- VarVersionNode succ = edge.dest;
-
- if(!setVisited.contains(edge.dest)) {
-
- boolean isDominated = true;
- for(VarVersionEdge prededge : succ.preds) {
- if(!setVisited.contains(prededge.source)) {
- isDominated = false;
- break;
- }
- }
-
- if(isDominated) {
- stack.add(succ);
- } else {
- setNotDoms.add(succ);
- }
- }
- }
- }
-
- setNotDoms.removeAll(setVisited);
-
- return !setNotDoms.isEmpty();
- }
-
- private boolean isVersionToBeReplaced(VarVersionPaar usedvar, HashMap<Integer, HashSet<VarVersionPaar>> mapVars, SSAUConstructorSparseEx ssau, VarVersionPaar leftpaar) {
-
- VarVersionsGraph ssuversions = ssau.getSsuversions();
-
- SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(usedvar);
- if(mapLiveVars == null) {
- // dummy version, predecessor of a phi node
- return false;
- }
-
- // compare protected ranges
- if(!InterpreterUtil.equalObjects(ssau.getMapVersionFirstRange().get(leftpaar),
- ssau.getMapVersionFirstRange().get(usedvar))) {
- return false;
- }
-
- for(Entry<Integer, HashSet<VarVersionPaar>> ent: mapVars.entrySet()) {
- FastSparseSet<Integer> liveverset = mapLiveVars.get(ent.getKey());
- if(liveverset == null) {
- return false;
- }
-
- HashSet<VarVersionNode> domset = new HashSet<VarVersionNode>();
- for(VarVersionPaar verpaar: ent.getValue()) {
- domset.add(ssuversions.nodes.getWithKey(verpaar));
- }
-
- boolean isdom = false;
-
- for(Integer livever: liveverset) {
- VarVersionNode node = ssuversions.nodes.getWithKey(new VarVersionPaar(ent.getKey().intValue(), livever.intValue()));
-
- if(ssuversions.isDominatorSet(node, domset)) {
- isdom = true;
- break;
- }
- }
-
- if(!isdom) {
- return false;
- }
- }
-
- return true;
- }
-
- private HashMap<Integer, HashSet<VarVersionPaar>> getAllVarVersions(VarVersionPaar leftvar, Exprent exprent, SSAUConstructorSparseEx ssau) {
-
- HashMap<Integer, HashSet<VarVersionPaar>> map = new HashMap<Integer, HashSet<VarVersionPaar>>();
- SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(leftvar);
-
- List<Exprent> lst = exprent.getAllExprents(true);
- lst.add(exprent);
-
- for(Exprent expr: lst) {
- if(expr.type == Exprent.EXPRENT_VAR) {
- int varindex = ((VarExprent)expr).getIndex();
- if(leftvar.var != varindex) {
- if(mapLiveVars.containsKey(varindex)) {
- HashSet<VarVersionPaar> verset = new HashSet<VarVersionPaar>();
- for(Integer vers: mapLiveVars.get(varindex)) {
- verset.add(new VarVersionPaar(varindex, vers.intValue()));
- }
- map.put(varindex, verset);
- } else {
- throw new RuntimeException("inkonsistent live map!");
- }
- } else {
- map.put(varindex, null);
- }
- } else if(expr.type == Exprent.EXPRENT_FIELD) {
- if(ssau.getMapFieldVars().containsKey(expr.id)) {
- int varindex = ssau.getMapFieldVars().get(expr.id);
- if(mapLiveVars.containsKey(varindex)) {
- HashSet<VarVersionPaar> verset = new HashSet<VarVersionPaar>();
- for(Integer vers: mapLiveVars.get(varindex)) {
- verset.add(new VarVersionPaar(varindex, vers.intValue()));
- }
- map.put(varindex, verset);
- }
- }
- }
- }
-
- return map;
- }
-
+ public void simplifyStackVars(RootStatement root, StructMethod mt, StructClass cl) {
+
+ HashSet<Integer> setReorderedIfs = new HashSet<Integer>();
+
+ SSAUConstructorSparseEx ssau = null;
+
+ for (; ; ) {
+
+ boolean found = false;
+
+ // System.out.println("--------------- \r\n"+root.toJava());
+
+ SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
+ ssa.splitVariables(root, mt);
+
+ // System.out.println("--------------- \r\n"+root.toJava());
+
+
+ SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(ssau == null);
+ while (sehelper.simplifyStackVarsStatement(root, setReorderedIfs, ssa, cl)) {
+ // System.out.println("--------------- \r\n"+root.toJava());
+ found = true;
+ }
+
+
+ // System.out.println("=============== \r\n"+root.toJava());
+
+ setVersionsToNull(root);
+
+ SequenceHelper.condenseSequences(root);
+
+ ssau = new SSAUConstructorSparseEx();
+ ssau.splitVariables(root, mt);
+
+ // try {
+ // DotExporter.toDotFile(ssau.getSsuversions(), new File("c:\\Temp\\gr12_my.dot"));
+ // } catch(Exception ex) {
+ // ex.printStackTrace();
+ // }
+
+ // System.out.println("++++++++++++++++ \r\n"+root.toJava());
+
+
+ if (iterateStatements(root, ssau)) {
+ found = true;
+ }
+
+ // System.out.println("***************** \r\n"+root.toJava());
+
+ setVersionsToNull(root);
+
+ if (!found) {
+ break;
+ }
+ }
+
+ // remove unused assignments
+ ssau = new SSAUConstructorSparseEx();
+ ssau.splitVariables(root, mt);
+
+ // try {
+ // DotExporter.toDotFile(ssau.getSsuversions(), new File("c:\\Temp\\gr12_my.dot"));
+ // } catch(Exception ex) {
+ // ex.printStackTrace();
+ // }
+
+ iterateStatements(root, ssau);
+
+ // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ setVersionsToNull(root);
+ }
+
+ private void setVersionsToNull(Statement stat) {
+
+ if (stat.getExprents() == null) {
+ for (Object obj : stat.getSequentialObjects()) {
+ if (obj instanceof Statement) {
+ setVersionsToNull((Statement)obj);
+ }
+ else if (obj instanceof Exprent) {
+ setExprentVersionsToNull((Exprent)obj);
+ }
+ }
+ }
+ else {
+ for (Exprent exprent : stat.getExprents()) {
+ setExprentVersionsToNull(exprent);
+ }
+ }
+ }
+
+ private void setExprentVersionsToNull(Exprent exprent) {
+
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ ((VarExprent)expr).setVersion(0);
+ }
+ }
+ }
+
+
+ private boolean iterateStatements(RootStatement root, SSAUConstructorSparseEx ssa) {
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ boolean res = false;
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ LinkedList<HashMap<VarVersionPaar, Exprent>> stackMaps = new LinkedList<HashMap<VarVersionPaar, Exprent>>();
+
+ stack.add(dgraph.first);
+ stackMaps.add(new HashMap<VarVersionPaar, Exprent>());
+
+ while (!stack.isEmpty()) {
+
+ DirectNode nd = stack.removeFirst();
+ HashMap<VarVersionPaar, Exprent> mapVarValues = stackMaps.removeFirst();
+
+ if (setVisited.contains(nd)) {
+ continue;
+ }
+ setVisited.add(nd);
+
+ List<List<Exprent>> lstLists = new ArrayList<List<Exprent>>();
+
+ if (!nd.exprents.isEmpty()) {
+ lstLists.add(nd.exprents);
+ }
+
+ if (nd.succs.size() == 1) {
+ DirectNode ndsucc = nd.succs.get(0);
+ if (ndsucc.type == DirectNode.NODE_TAIL && !ndsucc.exprents.isEmpty()) {
+ lstLists.add(nd.succs.get(0).exprents);
+ nd = ndsucc;
+ }
+ }
+
+ for (int i = 0; i < lstLists.size(); i++) {
+ List<Exprent> lst = lstLists.get(i);
+
+ int index = 0;
+ while (index < lst.size()) {
+ Exprent next = null;
+ if (index == lst.size() - 1) {
+ if (i < lstLists.size() - 1) {
+ next = lstLists.get(i + 1).get(0);
+ }
+ }
+ else {
+ next = lst.get(index + 1);
+ }
+
+ int[] ret = iterateExprent(lst, index, next, mapVarValues, ssa);
+
+ //System.out.println("***************** \r\n"+root.toJava());
+
+ if (ret[0] >= 0) {
+ index = ret[0];
+ }
+ else {
+ index++;
+ }
+ res |= (ret[1] == 1);
+ }
+ }
+
+ for (DirectNode ndx : nd.succs) {
+ stack.add(ndx);
+ stackMaps.add(new HashMap<VarVersionPaar, Exprent>(mapVarValues));
+ }
+
+ // make sure the 3 special exprent lists in a loop (init, condition, increment) are not empty
+ // change loop type if necessary
+ if (nd.exprents.isEmpty() &&
+ (nd.type == DirectNode.NODE_INIT || nd.type == DirectNode.NODE_CONDITION || nd.type == DirectNode.NODE_INCREMENT)) {
+ nd.exprents.add(null);
+
+ if (nd.statement.type == Statement.TYPE_DO) {
+ DoStatement loop = (DoStatement)nd.statement;
+
+ if (loop.getLooptype() == DoStatement.LOOP_FOR &&
+ loop.getInitExprent() == null &&
+ loop.getIncExprent() == null) { // "downgrade" loop to 'while'
+ loop.setLooptype(DoStatement.LOOP_WHILE);
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+
+ private Exprent isReplaceableVar(Exprent exprent, HashMap<VarVersionPaar, Exprent> mapVarValues, SSAUConstructorSparseEx ssau) {
+
+ Exprent dest = null;
+
+ if (exprent.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)exprent;
+ dest = mapVarValues.get(new VarVersionPaar(var));
+ }
+
+ return dest;
+ }
+
+ private void replaceSingleVar(Exprent parent, VarExprent var, Exprent dest, SSAUConstructorSparseEx ssau) {
+
+ parent.replaceExprent(var, dest);
+
+ // live sets
+ SFormsFastMapDirect livemap = ssau.getLiveVarVersionsMap(new VarVersionPaar(var));
+ HashSet<VarVersionPaar> setVars = getAllVersions(dest);
+
+ for (VarVersionPaar varpaar : setVars) {
+ VarVersionNode node = ssau.getSsuversions().nodes.getWithKey(varpaar);
+
+ for (Iterator<Entry<Integer, FastSparseSet<Integer>>> itent = node.live.entryList().iterator(); itent.hasNext(); ) {
+ Entry<Integer, FastSparseSet<Integer>> ent = itent.next();
+
+ Integer key = ent.getKey();
+
+ if (!livemap.containsKey(key)) {
+ itent.remove();
+ }
+ else {
+ FastSparseSet<Integer> set = ent.getValue();
+
+ set.complement(livemap.get(key));
+ if (set.isEmpty()) {
+ itent.remove();
+ }
+ }
+ }
+ }
+ }
+
+ private int[] iterateExprent(List<Exprent> lstExprents, int index, Exprent next, HashMap<VarVersionPaar,
+ Exprent> mapVarValues, SSAUConstructorSparseEx ssau) {
+
+ Exprent exprent = lstExprents.get(index);
+
+ int changed = 0;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ for (; ; ) {
+ Object[] arr = iterateChildExprent(expr, exprent, next, mapVarValues, ssau);
+ Exprent retexpr = (Exprent)arr[0];
+ changed |= (Boolean)arr[1] ? 1 : 0;
+
+ boolean isReplaceable = (Boolean)arr[2];
+ if (retexpr != null) {
+ if (isReplaceable) {
+ replaceSingleVar(exprent, (VarExprent)expr, retexpr, ssau);
+ expr = retexpr;
+ }
+ else {
+ exprent.replaceExprent(expr, retexpr);
+ }
+ changed = 1;
+ }
+
+ if (!isReplaceable) {
+ break;
+ }
+ }
+ }
+
+ // no var on the highest level, so no replacing
+
+ VarExprent left = null;
+ Exprent right = null;
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)exprent;
+ if (as.getLeft().type == Exprent.EXPRENT_VAR) {
+ left = (VarExprent)as.getLeft();
+ right = as.getRight();
+ }
+ }
+
+ if (left == null) {
+ return new int[]{-1, changed};
+ }
+
+ VarVersionPaar leftpaar = new VarVersionPaar(left);
+
+ List<VarVersionNode> usedVers = new ArrayList<VarVersionNode>();
+ boolean notdom = getUsedVersions(ssau, leftpaar, usedVers);
+
+ if (!notdom && usedVers.isEmpty()) {
+ if (left.isStack() && (right.type == Exprent.EXPRENT_INVOCATION ||
+ right.type == Exprent.EXPRENT_ASSIGNMENT || right.type == Exprent.EXPRENT_NEW)) {
+ if (right.type == Exprent.EXPRENT_NEW) {
+ // new Object(); permitted
+ NewExprent nexpr = (NewExprent)right;
+ if (nexpr.isAnonymous() || nexpr.getNewtype().arraydim > 0
+ || nexpr.getNewtype().type != CodeConstants.TYPE_OBJECT) {
+ return new int[]{-1, changed};
+ }
+ }
+
+ lstExprents.set(index, right);
+ return new int[]{index + 1, 1};
+ }
+ else if (right.type == Exprent.EXPRENT_VAR) {
+ lstExprents.remove(index);
+ return new int[]{index, 1};
+ }
+ else {
+ return new int[]{-1, changed};
+ }
+ }
+
+ int useflags = right.getExprentUse();
+
+ // stack variables only
+ if (!left.isStack() &&
+ (right.type != Exprent.EXPRENT_VAR || ((VarExprent)right).isStack())) { // special case catch(... ex)
+ return new int[]{-1, changed};
+ }
+
+ if ((useflags & Exprent.MULTIPLE_USES) == 0 && (notdom || usedVers.size() > 1)) {
+ return new int[]{-1, changed};
+ }
+
+ HashMap<Integer, HashSet<VarVersionPaar>> mapVars = getAllVarVersions(leftpaar, right, ssau);
+
+ boolean isSelfReference = mapVars.containsKey(leftpaar.var);
+ if (isSelfReference && notdom) {
+ return new int[]{-1, changed};
+ }
+
+ HashSet<VarVersionPaar> setNextVars = next == null ? null : getAllVersions(next);
+
+ // FIXME: fix the entire method!
+ if (right.type != Exprent.EXPRENT_CONST &&
+ right.type != Exprent.EXPRENT_VAR &&
+ setNextVars != null &&
+ mapVars.containsKey(leftpaar.var)) {
+ for (VarVersionNode usedvar : usedVers) {
+ if (!setNextVars.contains(new VarVersionPaar(usedvar.var, usedvar.version))) {
+ return new int[]{-1, changed};
+ }
+ }
+ }
+
+ mapVars.remove(leftpaar.var);
+
+ boolean vernotreplaced = false;
+ boolean verreplaced = false;
+
+
+ HashSet<VarVersionPaar> setTempUsedVers = new HashSet<VarVersionPaar>();
+
+ for (VarVersionNode usedvar : usedVers) {
+ VarVersionPaar usedver = new VarVersionPaar(usedvar.var, usedvar.version);
+ if (isVersionToBeReplaced(usedver, mapVars, ssau, leftpaar) &&
+ (right.type == Exprent.EXPRENT_CONST || right.type == Exprent.EXPRENT_VAR || right.type == Exprent.EXPRENT_FIELD
+ || setNextVars == null || setNextVars.contains(usedver))) {
+
+ setTempUsedVers.add(usedver);
+ verreplaced = true;
+ }
+ else {
+ vernotreplaced = true;
+ }
+ }
+
+ if (isSelfReference && vernotreplaced) {
+ return new int[]{-1, changed};
+ }
+ else {
+ for (VarVersionPaar usedver : setTempUsedVers) {
+ Exprent copy = right.copy();
+ if (right.type == Exprent.EXPRENT_FIELD && ssau.getMapFieldVars().containsKey(right.id)) {
+ ssau.getMapFieldVars().put(copy.id, ssau.getMapFieldVars().get(right.id));
+ }
+
+ mapVarValues.put(usedver, copy);
+ }
+ }
+
+ if (!notdom && !vernotreplaced) {
+ // remove assignment
+ lstExprents.remove(index);
+ return new int[]{index, 1};
+ }
+ else if (verreplaced) {
+ return new int[]{index + 1, changed};
+ }
+ else {
+ return new int[]{-1, changed};
+ }
+ }
+
+ private HashSet<VarVersionPaar> getAllVersions(Exprent exprent) {
+
+ HashSet<VarVersionPaar> res = new HashSet<VarVersionPaar>();
+
+ List<Exprent> listTemp = new ArrayList<Exprent>(exprent.getAllExprents(true));
+ listTemp.add(exprent);
+
+ for (Exprent expr : listTemp) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)expr;
+ res.add(new VarVersionPaar(var));
+ }
+ }
+
+ return res;
+ }
+
+ private Object[] iterateChildExprent(Exprent exprent,
+ Exprent parent,
+ Exprent next,
+ HashMap<VarVersionPaar, Exprent> mapVarValues,
+ SSAUConstructorSparseEx ssau) {
+
+ boolean changed = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ for (; ; ) {
+ Object[] arr = iterateChildExprent(expr, parent, next, mapVarValues, ssau);
+ Exprent retexpr = (Exprent)arr[0];
+ changed |= (Boolean)arr[1];
+
+ boolean isReplaceable = (Boolean)arr[2];
+ if (retexpr != null) {
+ if (isReplaceable) {
+ replaceSingleVar(exprent, (VarExprent)expr, retexpr, ssau);
+ expr = retexpr;
+ }
+ else {
+ exprent.replaceExprent(expr, retexpr);
+ }
+ changed = true;
+ }
+
+ if (!isReplaceable) {
+ break;
+ }
+ }
+ }
+
+ Exprent dest = isReplaceableVar(exprent, mapVarValues, ssau);
+ if (dest != null) {
+ return new Object[]{dest, true, true};
+ }
+
+
+ VarExprent left = null;
+ Exprent right = null;
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)exprent;
+ if (as.getLeft().type == Exprent.EXPRENT_VAR) {
+ left = (VarExprent)as.getLeft();
+ right = as.getRight();
+ }
+ }
+
+ if (left == null) {
+ return new Object[]{null, changed, false};
+ }
+
+ boolean isHeadSynchronized = false;
+ if (next == null && parent.type == Exprent.EXPRENT_MONITOR) {
+ MonitorExprent monexpr = (MonitorExprent)parent;
+ if (monexpr.getMontype() == MonitorExprent.MONITOR_ENTER && exprent.equals(monexpr.getValue())) {
+ isHeadSynchronized = true;
+ }
+ }
+
+ // stack variable or synchronized head exprent
+ if (!left.isStack() && !isHeadSynchronized) {
+ return new Object[]{null, changed, false};
+ }
+
+ VarVersionPaar leftpaar = new VarVersionPaar(left);
+
+ List<VarVersionNode> usedVers = new ArrayList<VarVersionNode>();
+ boolean notdom = getUsedVersions(ssau, leftpaar, usedVers);
+
+ if (!notdom && usedVers.isEmpty()) {
+ return new Object[]{right, changed, false};
+ }
+
+ // stack variables only
+ if (!left.isStack()) {
+ return new Object[]{null, changed, false};
+ }
+
+ int useflags = right.getExprentUse();
+
+ if ((useflags & Exprent.BOTH_FLAGS) != Exprent.BOTH_FLAGS) {
+ return new Object[]{null, changed, false};
+ }
+
+ HashMap<Integer, HashSet<VarVersionPaar>> mapVars = getAllVarVersions(leftpaar, right, ssau);
+
+ if (mapVars.containsKey(leftpaar.var) && notdom) {
+ return new Object[]{null, changed, false};
+ }
+
+
+ mapVars.remove(leftpaar.var);
+
+ HashSet<VarVersionPaar> setAllowedVars = getAllVersions(parent);
+ if (next != null) {
+ setAllowedVars.addAll(getAllVersions(next));
+ }
+
+ boolean vernotreplaced = false;
+
+ HashSet<VarVersionPaar> setTempUsedVers = new HashSet<VarVersionPaar>();
+
+ for (VarVersionNode usedvar : usedVers) {
+ VarVersionPaar usedver = new VarVersionPaar(usedvar.var, usedvar.version);
+ if (isVersionToBeReplaced(usedver, mapVars, ssau, leftpaar) &&
+ (right.type == Exprent.EXPRENT_VAR || setAllowedVars.contains(usedver))) {
+
+ setTempUsedVers.add(usedver);
+ }
+ else {
+ vernotreplaced = true;
+ }
+ }
+
+ if (!notdom && !vernotreplaced) {
+
+ for (VarVersionPaar usedver : setTempUsedVers) {
+ Exprent copy = right.copy();
+ if (right.type == Exprent.EXPRENT_FIELD && ssau.getMapFieldVars().containsKey(right.id)) {
+ ssau.getMapFieldVars().put(copy.id, ssau.getMapFieldVars().get(right.id));
+ }
+
+ mapVarValues.put(usedver, copy);
+ }
+
+ // remove assignment
+ return new Object[]{right, changed, false};
+ }
+
+ return new Object[]{null, changed, false};
+ }
+
+ private boolean getUsedVersions(SSAUConstructorSparseEx ssa, VarVersionPaar var, List<VarVersionNode> res) {
+
+ VarVersionsGraph ssuversions = ssa.getSsuversions();
+ VarVersionNode varnode = ssuversions.nodes.getWithKey(var);
+
+ HashSet<VarVersionNode> setVisited = new HashSet<VarVersionNode>();
+
+ HashSet<VarVersionNode> setNotDoms = new HashSet<VarVersionNode>();
+
+ LinkedList<VarVersionNode> stack = new LinkedList<VarVersionNode>();
+ stack.add(varnode);
+
+ while (!stack.isEmpty()) {
+
+ VarVersionNode nd = stack.remove(0);
+ setVisited.add(nd);
+
+ if (nd != varnode && (nd.flags & VarVersionNode.FLAG_PHANTOM_FINEXIT) == 0) {
+ res.add(nd);
+ }
+
+ for (VarVersionEdge edge : nd.succs) {
+ VarVersionNode succ = edge.dest;
+
+ if (!setVisited.contains(edge.dest)) {
+
+ boolean isDominated = true;
+ for (VarVersionEdge prededge : succ.preds) {
+ if (!setVisited.contains(prededge.source)) {
+ isDominated = false;
+ break;
+ }
+ }
+
+ if (isDominated) {
+ stack.add(succ);
+ }
+ else {
+ setNotDoms.add(succ);
+ }
+ }
+ }
+ }
+
+ setNotDoms.removeAll(setVisited);
+
+ return !setNotDoms.isEmpty();
+ }
+
+ private boolean isVersionToBeReplaced(VarVersionPaar usedvar,
+ HashMap<Integer, HashSet<VarVersionPaar>> mapVars,
+ SSAUConstructorSparseEx ssau,
+ VarVersionPaar leftpaar) {
+
+ VarVersionsGraph ssuversions = ssau.getSsuversions();
+
+ SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(usedvar);
+ if (mapLiveVars == null) {
+ // dummy version, predecessor of a phi node
+ return false;
+ }
+
+ // compare protected ranges
+ if (!InterpreterUtil.equalObjects(ssau.getMapVersionFirstRange().get(leftpaar),
+ ssau.getMapVersionFirstRange().get(usedvar))) {
+ return false;
+ }
+
+ for (Entry<Integer, HashSet<VarVersionPaar>> ent : mapVars.entrySet()) {
+ FastSparseSet<Integer> liveverset = mapLiveVars.get(ent.getKey());
+ if (liveverset == null) {
+ return false;
+ }
+
+ HashSet<VarVersionNode> domset = new HashSet<VarVersionNode>();
+ for (VarVersionPaar verpaar : ent.getValue()) {
+ domset.add(ssuversions.nodes.getWithKey(verpaar));
+ }
+
+ boolean isdom = false;
+
+ for (Integer livever : liveverset) {
+ VarVersionNode node = ssuversions.nodes.getWithKey(new VarVersionPaar(ent.getKey().intValue(), livever.intValue()));
+
+ if (ssuversions.isDominatorSet(node, domset)) {
+ isdom = true;
+ break;
+ }
+ }
+
+ if (!isdom) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private HashMap<Integer, HashSet<VarVersionPaar>> getAllVarVersions(VarVersionPaar leftvar,
+ Exprent exprent,
+ SSAUConstructorSparseEx ssau) {
+
+ HashMap<Integer, HashSet<VarVersionPaar>> map = new HashMap<Integer, HashSet<VarVersionPaar>>();
+ SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(leftvar);
+
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ int varindex = ((VarExprent)expr).getIndex();
+ if (leftvar.var != varindex) {
+ if (mapLiveVars.containsKey(varindex)) {
+ HashSet<VarVersionPaar> verset = new HashSet<VarVersionPaar>();
+ for (Integer vers : mapLiveVars.get(varindex)) {
+ verset.add(new VarVersionPaar(varindex, vers.intValue()));
+ }
+ map.put(varindex, verset);
+ }
+ else {
+ throw new RuntimeException("inkonsistent live map!");
+ }
+ }
+ else {
+ map.put(varindex, null);
+ }
+ }
+ else if (expr.type == Exprent.EXPRENT_FIELD) {
+ if (ssau.getMapFieldVars().containsKey(expr.id)) {
+ int varindex = ssau.getMapFieldVars().get(expr.id);
+ if (mapLiveVars.containsKey(varindex)) {
+ HashSet<VarVersionPaar> verset = new HashSet<VarVersionPaar>();
+ for (Integer vers : mapLiveVars.get(varindex)) {
+ verset.add(new VarVersionPaar(varindex, vers.intValue()));
+ }
+ map.put(varindex, verset);
+ }
+ }
+ }
+ }
+
+ return map;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java b/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java
index b20c2c7..26d427b 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java
@@ -1,103 +1,104 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
-
public class StatEdge {
-
- public static final int TYPE_ALL = 0xFF;
-
- public static final int TYPE_REGULAR = 1;
- public static final int TYPE_EXCEPTION = 2;
- public static final int TYPE_BREAK = 4;
- public static final int TYPE_CONTINUE = 8;
- public static final int TYPE_FINALLYEXIT = 32;
-
- public static final int[] TYPES = new int[] {
- TYPE_REGULAR,
- TYPE_EXCEPTION,
- TYPE_BREAK,
- TYPE_CONTINUE,
- TYPE_FINALLYEXIT
- };
-
- private int type;
-
- private Statement source;
-
- private Statement destination;
-
- private List<String> exceptions;
-
- public Statement closure;
-
- public boolean labeled = true;
-
- public boolean explicit = true;
-
- public StatEdge(int type, Statement source, Statement destination, Statement closure) {
- this(type, source, destination);
- this.closure = closure;
- }
-
- public StatEdge(int type, Statement source, Statement destination) {
- this.type = type;
- this.source = source;
- this.destination = destination;
- }
-
- public StatEdge(Statement source, Statement destination, List<String> exceptions) {
- this(TYPE_EXCEPTION, source, destination);
- if(exceptions != null) {
- this.exceptions = new ArrayList<String>(exceptions);
- }
- }
-
- public int getType() {
- return type;
- }
-
- public void setType(int type) {
- this.type = type;
- }
-
- public Statement getSource() {
- return source;
- }
-
- public void setSource(Statement source) {
- this.source = source;
- }
-
- public Statement getDestination() {
- return destination;
- }
-
- public void setDestination(Statement destination) {
- this.destination = destination;
- }
-
- public List<String> getExceptions() {
- return this.exceptions;
- }
-
-// public void setException(String exception) {
-// this.exception = exception;
-// }
+
+ public static final int TYPE_ALL = 0xFF;
+
+ public static final int TYPE_REGULAR = 1;
+ public static final int TYPE_EXCEPTION = 2;
+ public static final int TYPE_BREAK = 4;
+ public static final int TYPE_CONTINUE = 8;
+ public static final int TYPE_FINALLYEXIT = 32;
+
+ public static final int[] TYPES = new int[]{
+ TYPE_REGULAR,
+ TYPE_EXCEPTION,
+ TYPE_BREAK,
+ TYPE_CONTINUE,
+ TYPE_FINALLYEXIT
+ };
+
+ private int type;
+
+ private Statement source;
+
+ private Statement destination;
+
+ private List<String> exceptions;
+
+ public Statement closure;
+
+ public boolean labeled = true;
+
+ public boolean explicit = true;
+
+ public StatEdge(int type, Statement source, Statement destination, Statement closure) {
+ this(type, source, destination);
+ this.closure = closure;
+ }
+
+ public StatEdge(int type, Statement source, Statement destination) {
+ this.type = type;
+ this.source = source;
+ this.destination = destination;
+ }
+
+ public StatEdge(Statement source, Statement destination, List<String> exceptions) {
+ this(TYPE_EXCEPTION, source, destination);
+ if (exceptions != null) {
+ this.exceptions = new ArrayList<String>(exceptions);
+ }
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public Statement getSource() {
+ return source;
+ }
+
+ public void setSource(Statement source) {
+ this.source = source;
+ }
+
+ public Statement getDestination() {
+ return destination;
+ }
+
+ public void setDestination(Statement destination) {
+ this.destination = destination;
+ }
+
+ public List<String> getExceptions() {
+ return this.exceptions;
+ }
+
+ // public void setException(String exception) {
+ // this.exception = exception;
+ // }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/StrongConnectivityHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/StrongConnectivityHelper.java
index a686f77..23f778d 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/StrongConnectivityHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/StrongConnectivityHelper.java
@@ -1,27 +1,28 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.util.ListStack;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
-import org.jetbrains.java.decompiler.util.ListStack;
-
// --------------------------------------------------------------------
// Algorithm
// --------------------------------------------------------------------
@@ -62,143 +63,145 @@ import org.jetbrains.java.decompiler.util.ListStack;
public class StrongConnectivityHelper {
- private ListStack<Statement> lstack;
-
- private int ncounter;
-
- private HashSet<Statement> tset;
- private HashMap<Statement, Integer> dfsnummap;
- private HashMap<Statement, Integer> lowmap;
-
- private List<List<Statement>> components;
-
- private HashSet<Statement> setProcessed;
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public StrongConnectivityHelper() {}
-
- public StrongConnectivityHelper(Statement stat) {
- findComponents(stat);
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public List<List<Statement>> findComponents(Statement stat) {
-
- components = new ArrayList<List<Statement>>();
- setProcessed = new HashSet<Statement>();
-
- visitTree(stat.getFirst());
-
- for(Statement st: stat.getStats()) {
- if(!setProcessed.contains(st) && st.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL).isEmpty()) {
- visitTree(st);
- }
- }
-
- // should not find any more nodes! FIXME: ??
- for(Statement st: stat.getStats()) {
- if(!setProcessed.contains(st)) {
- visitTree(st);
- }
- }
-
- return components;
- }
-
- public static boolean isExitComponent(List<Statement> lst) {
-
- HashSet<Statement> set = new HashSet<Statement>();
- for(Statement stat : lst) {
- set.addAll(stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD));
- }
- set.removeAll(lst);
-
- return (set.size() == 0);
- }
-
- public static List<Statement> getExitReps(List<List<Statement>> lst) {
-
- List<Statement> res = new ArrayList<Statement>();
-
- for(List<Statement> comp : lst) {
- if(isExitComponent(comp)) {
- res.add(comp.get(0));
- }
- }
-
- return res;
- }
-
- // *****************************************************************************
- // private methods
- // *****************************************************************************
-
- private void visitTree(Statement stat) {
- lstack = new ListStack<Statement>();
- ncounter = 0;
- tset = new HashSet<Statement>();
- dfsnummap = new HashMap<Statement, Integer>();
- lowmap = new HashMap<Statement, Integer>();
-
- visit(stat);
-
- setProcessed.addAll(tset);
- setProcessed.add(stat);
- }
-
- private void visit(Statement stat) {
-
- lstack.push(stat);
- dfsnummap.put(stat, ncounter);
- lowmap.put(stat, ncounter);
- ncounter++;
-
- List<Statement> lstSuccs = stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD); // TODO: set?
- lstSuccs.removeAll(setProcessed);
-
- for(int i=0;i<lstSuccs.size();i++) {
- Statement succ = lstSuccs.get(i);
- int secvalue;
-
- if(tset.contains(succ)) {
- secvalue = dfsnummap.get(succ);
- } else {
- tset.add(succ);
- visit(succ);
- secvalue = lowmap.get(succ);
- }
- lowmap.put(stat, Math.min(lowmap.get(stat), secvalue));
- }
-
-
- if(lowmap.get(stat).intValue() == dfsnummap.get(stat).intValue()) {
- List<Statement> lst = new ArrayList<Statement>();
- Statement v;
- do {
- v = lstack.pop();
- lst.add(v);
- } while(v!=stat);
- components.add(lst);
- }
- }
-
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public List<List<Statement>> getComponents() {
- return components;
- }
-
- public void setComponents(List<List<Statement>> components) {
- this.components = components;
- }
-
+ private ListStack<Statement> lstack;
+
+ private int ncounter;
+
+ private HashSet<Statement> tset;
+ private HashMap<Statement, Integer> dfsnummap;
+ private HashMap<Statement, Integer> lowmap;
+
+ private List<List<Statement>> components;
+
+ private HashSet<Statement> setProcessed;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public StrongConnectivityHelper() {
+ }
+
+ public StrongConnectivityHelper(Statement stat) {
+ findComponents(stat);
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public List<List<Statement>> findComponents(Statement stat) {
+
+ components = new ArrayList<List<Statement>>();
+ setProcessed = new HashSet<Statement>();
+
+ visitTree(stat.getFirst());
+
+ for (Statement st : stat.getStats()) {
+ if (!setProcessed.contains(st) && st.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL).isEmpty()) {
+ visitTree(st);
+ }
+ }
+
+ // should not find any more nodes! FIXME: ??
+ for (Statement st : stat.getStats()) {
+ if (!setProcessed.contains(st)) {
+ visitTree(st);
+ }
+ }
+
+ return components;
+ }
+
+ public static boolean isExitComponent(List<Statement> lst) {
+
+ HashSet<Statement> set = new HashSet<Statement>();
+ for (Statement stat : lst) {
+ set.addAll(stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD));
+ }
+ set.removeAll(lst);
+
+ return (set.size() == 0);
+ }
+
+ public static List<Statement> getExitReps(List<List<Statement>> lst) {
+
+ List<Statement> res = new ArrayList<Statement>();
+
+ for (List<Statement> comp : lst) {
+ if (isExitComponent(comp)) {
+ res.add(comp.get(0));
+ }
+ }
+
+ return res;
+ }
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private void visitTree(Statement stat) {
+ lstack = new ListStack<Statement>();
+ ncounter = 0;
+ tset = new HashSet<Statement>();
+ dfsnummap = new HashMap<Statement, Integer>();
+ lowmap = new HashMap<Statement, Integer>();
+
+ visit(stat);
+
+ setProcessed.addAll(tset);
+ setProcessed.add(stat);
+ }
+
+ private void visit(Statement stat) {
+
+ lstack.push(stat);
+ dfsnummap.put(stat, ncounter);
+ lowmap.put(stat, ncounter);
+ ncounter++;
+
+ List<Statement> lstSuccs = stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD); // TODO: set?
+ lstSuccs.removeAll(setProcessed);
+
+ for (int i = 0; i < lstSuccs.size(); i++) {
+ Statement succ = lstSuccs.get(i);
+ int secvalue;
+
+ if (tset.contains(succ)) {
+ secvalue = dfsnummap.get(succ);
+ }
+ else {
+ tset.add(succ);
+ visit(succ);
+ secvalue = lowmap.get(succ);
+ }
+ lowmap.put(stat, Math.min(lowmap.get(stat), secvalue));
+ }
+
+
+ if (lowmap.get(stat).intValue() == dfsnummap.get(stat).intValue()) {
+ List<Statement> lst = new ArrayList<Statement>();
+ Statement v;
+ do {
+ v = lstack.pop();
+ lst.add(v);
+ }
+ while (v != stat);
+ components.add(lst);
+ }
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public List<List<Statement>> getComponents() {
+ return components;
+ }
+
+ public void setComponents(List<List<Statement>> components) {
+ this.components = components;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorEngine.java b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorEngine.java
index e17a271..b79c864 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorEngine.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorEngine.java
@@ -1,127 +1,128 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.decompose;
-import java.util.List;
-
import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.util.List;
+
public class DominatorEngine {
- private Statement statement;
-
- private VBStyleCollection<Integer, Integer> colOrderedIDoms = new VBStyleCollection<Integer, Integer>();
-
-
- public DominatorEngine(Statement statement) {
- this.statement = statement;
- }
-
- public void initialize() {
- calcIDoms();
- }
-
- private void orderStatements() {
-
- for(Statement stat : statement.getReversePostOrderList()) {
- colOrderedIDoms.addWithKey(null, stat.id);
- }
-
- }
-
- private Integer getCommonIDom(Integer key1, Integer key2, VBStyleCollection<Integer, Integer> orderedIDoms) {
-
- if(key1 == null) {
- return key2;
- } else if(key2 == null) {
- return key1;
- }
-
- int index1 = orderedIDoms.getIndexByKey(key1);
- int index2 = orderedIDoms.getIndexByKey(key2);
-
- while(index1 != index2) {
- if(index1 > index2) {
- key1 = orderedIDoms.getWithKey(key1);
- index1 = orderedIDoms.getIndexByKey(key1);
- } else {
- key2 = orderedIDoms.getWithKey(key2);
- index2 = orderedIDoms.getIndexByKey(key2);
- }
- }
-
- return key1;
- }
-
- private void calcIDoms() {
-
- orderStatements();
-
- colOrderedIDoms.putWithKey(statement.getFirst().id, statement.getFirst().id);
-
- // exclude first statement
- List<Integer> lstIds = colOrderedIDoms.getLstKeys().subList(1, colOrderedIDoms.getLstKeys().size());
-
- for(;;) {
-
- boolean changed = false;
-
- for(Integer id : lstIds) {
-
- Statement stat = statement.getStats().getWithKey(id);
- Integer idom = null;
-
- for(StatEdge edge : stat.getAllPredecessorEdges()) {
- if(colOrderedIDoms.getWithKey(edge.getSource().id) != null) {
- idom = getCommonIDom(idom, edge.getSource().id, colOrderedIDoms);
- }
- }
-
- Integer oldidom = colOrderedIDoms.putWithKey(idom, id);
- if(!idom.equals(oldidom)) {
- changed = true;
- }
- }
-
- if(!changed) {
- break;
- }
- }
-
- }
-
- public VBStyleCollection<Integer, Integer> getOrderedIDoms() {
- return colOrderedIDoms;
- }
-
- public boolean isDominator(Integer node, Integer dom) {
-
- while(!node.equals(dom)) {
-
- Integer idom = colOrderedIDoms.getWithKey(node);
-
- if(idom.equals(node)) {
- return false; // root node
- } else {
- node = idom;
- }
- }
-
- return true;
- }
-
+ private Statement statement;
+
+ private VBStyleCollection<Integer, Integer> colOrderedIDoms = new VBStyleCollection<Integer, Integer>();
+
+
+ public DominatorEngine(Statement statement) {
+ this.statement = statement;
+ }
+
+ public void initialize() {
+ calcIDoms();
+ }
+
+ private void orderStatements() {
+
+ for (Statement stat : statement.getReversePostOrderList()) {
+ colOrderedIDoms.addWithKey(null, stat.id);
+ }
+ }
+
+ private Integer getCommonIDom(Integer key1, Integer key2, VBStyleCollection<Integer, Integer> orderedIDoms) {
+
+ if (key1 == null) {
+ return key2;
+ }
+ else if (key2 == null) {
+ return key1;
+ }
+
+ int index1 = orderedIDoms.getIndexByKey(key1);
+ int index2 = orderedIDoms.getIndexByKey(key2);
+
+ while (index1 != index2) {
+ if (index1 > index2) {
+ key1 = orderedIDoms.getWithKey(key1);
+ index1 = orderedIDoms.getIndexByKey(key1);
+ }
+ else {
+ key2 = orderedIDoms.getWithKey(key2);
+ index2 = orderedIDoms.getIndexByKey(key2);
+ }
+ }
+
+ return key1;
+ }
+
+ private void calcIDoms() {
+
+ orderStatements();
+
+ colOrderedIDoms.putWithKey(statement.getFirst().id, statement.getFirst().id);
+
+ // exclude first statement
+ List<Integer> lstIds = colOrderedIDoms.getLstKeys().subList(1, colOrderedIDoms.getLstKeys().size());
+
+ for (; ; ) {
+
+ boolean changed = false;
+
+ for (Integer id : lstIds) {
+
+ Statement stat = statement.getStats().getWithKey(id);
+ Integer idom = null;
+
+ for (StatEdge edge : stat.getAllPredecessorEdges()) {
+ if (colOrderedIDoms.getWithKey(edge.getSource().id) != null) {
+ idom = getCommonIDom(idom, edge.getSource().id, colOrderedIDoms);
+ }
+ }
+
+ Integer oldidom = colOrderedIDoms.putWithKey(idom, id);
+ if (!idom.equals(oldidom)) {
+ changed = true;
+ }
+ }
+
+ if (!changed) {
+ break;
+ }
+ }
+ }
+
+ public VBStyleCollection<Integer, Integer> getOrderedIDoms() {
+ return colOrderedIDoms;
+ }
+
+ public boolean isDominator(Integer node, Integer dom) {
+
+ while (!node.equals(dom)) {
+
+ Integer idom = colOrderedIDoms.getWithKey(node);
+
+ if (idom.equals(node)) {
+ return false; // root node
+ }
+ else {
+ node = idom;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java
index cf9e90c..c11d5bf 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java
@@ -1,188 +1,184 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.decompose;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.util.*;
+import java.util.Map.Entry;
+
public class DominatorTreeExceptionFilter {
- private Statement statement;
-
- // idom, nodes
- private Map<Integer, Set<Integer>> mapTreeBranches = new HashMap<Integer, Set<Integer>>();
-
- // handler, range nodes
- private Map<Integer, Set<Integer>> mapExceptionRanges = new HashMap<Integer, Set<Integer>>();
-
- // handler, head dom
- private Map<Integer, Integer> mapExceptionDoms = new HashMap<Integer, Integer>();
-
- // statement, handler, exit nodes
- private Map<Integer, Map<Integer, Integer>> mapExceptionRangeUniqueExit = new HashMap<Integer, Map<Integer, Integer>>();
-
- private DominatorEngine domEngine;
-
- public DominatorTreeExceptionFilter(Statement statement) {
- this.statement = statement;
- }
-
- public void initialize() {
-
- domEngine = new DominatorEngine(statement);
- domEngine.initialize();
-
- buildDominatorTree();
-
- buildExceptionRanges();
-
- buildFilter(statement.getFirst().id);
-
- // free resources
- mapTreeBranches.clear();
- mapExceptionRanges.clear();
-
- }
-
- public boolean acceptStatementPair(Integer head, Integer exit) {
-
- Map<Integer, Integer> filter = mapExceptionRangeUniqueExit.get(head);
- for(Entry<Integer, Integer> entry : filter.entrySet()) {
- if(!head.equals(mapExceptionDoms.get(entry.getKey()))) {
- Integer filterExit = entry.getValue();
- if(filterExit.intValue() == -1 || !filterExit.equals(exit)) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- private void buildDominatorTree() {
-
- VBStyleCollection<Integer, Integer> orderedIDoms = domEngine.getOrderedIDoms();
-
- List<Integer> lstKeys = orderedIDoms.getLstKeys();
- for(int index = lstKeys.size()-1;index>=0;index--) {
- Integer key = lstKeys.get(index);
- Integer idom = orderedIDoms.get(index);
-
- Set<Integer> set = mapTreeBranches.get(idom);
- if(set == null) {
- mapTreeBranches.put(idom, set = new HashSet<Integer>());
- }
- set.add(key);
- }
-
- Integer firstid = statement.getFirst().id;
- mapTreeBranches.get(firstid).remove(firstid);
- }
-
- private void buildExceptionRanges() {
-
- for(Statement stat : statement.getStats()) {
- List<Statement> lstPreds = stat.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD);
- if(!lstPreds.isEmpty()) {
-
- Set<Integer> set = new HashSet<Integer>();
-
- for(Statement st : lstPreds) {
- set.add(st.id);
- }
-
- mapExceptionRanges.put(stat.id, set);
- }
- }
-
- mapExceptionDoms = buildExceptionDoms(statement.getFirst().id);
- }
-
- private Map<Integer, Integer> buildExceptionDoms(Integer id) {
-
- Map<Integer, Integer> map = new HashMap<Integer, Integer>();
-
- Set<Integer> children = mapTreeBranches.get(id);
- if(children != null) {
- for(Integer childid : children) {
- Map<Integer, Integer> mapChild = buildExceptionDoms(childid);
- for(Integer handler : mapChild.keySet()) {
- map.put(handler, map.containsKey(handler)?id:mapChild.get(handler));
- }
- }
- }
-
- for(Entry<Integer, Set<Integer>> entry : mapExceptionRanges.entrySet()) {
- if(entry.getValue().contains(id)) {
- map.put(entry.getKey(), id);
- }
- }
-
- return map;
- }
-
-
- private void buildFilter(Integer id) {
-
- Map<Integer, Integer> map = new HashMap<Integer, Integer>();
-
- Set<Integer> children = mapTreeBranches.get(id);
- if(children != null) {
- for(Integer childid : children) {
-
- buildFilter(childid);
-
- Map<Integer, Integer> mapChild = mapExceptionRangeUniqueExit.get(childid);
-
- for(Entry<Integer, Set<Integer>> entry : mapExceptionRanges.entrySet()) {
-
- Integer handler = entry.getKey();
- Set<Integer> range = entry.getValue();
-
- if(range.contains(id)) {
-
- Integer exit = null;
-
- if(!range.contains(childid)) {
- exit = childid;
- } else {
- // exit = map.containsKey(handler)?-1:mapChild.get(handler); FIXME: Eclipse bug?
- exit = map.containsKey(handler)?new Integer(-1):mapChild.get(handler);
- }
-
- if(exit != null) {
- map.put(handler, exit);
- }
- }
- }
- }
- }
-
- mapExceptionRangeUniqueExit.put(id, map);
- }
-
- public DominatorEngine getDomEngine() {
- return domEngine;
- }
-
+ private Statement statement;
+
+ // idom, nodes
+ private Map<Integer, Set<Integer>> mapTreeBranches = new HashMap<Integer, Set<Integer>>();
+
+ // handler, range nodes
+ private Map<Integer, Set<Integer>> mapExceptionRanges = new HashMap<Integer, Set<Integer>>();
+
+ // handler, head dom
+ private Map<Integer, Integer> mapExceptionDoms = new HashMap<Integer, Integer>();
+
+ // statement, handler, exit nodes
+ private Map<Integer, Map<Integer, Integer>> mapExceptionRangeUniqueExit = new HashMap<Integer, Map<Integer, Integer>>();
+
+ private DominatorEngine domEngine;
+
+ public DominatorTreeExceptionFilter(Statement statement) {
+ this.statement = statement;
+ }
+
+ public void initialize() {
+
+ domEngine = new DominatorEngine(statement);
+ domEngine.initialize();
+
+ buildDominatorTree();
+
+ buildExceptionRanges();
+
+ buildFilter(statement.getFirst().id);
+
+ // free resources
+ mapTreeBranches.clear();
+ mapExceptionRanges.clear();
+ }
+
+ public boolean acceptStatementPair(Integer head, Integer exit) {
+
+ Map<Integer, Integer> filter = mapExceptionRangeUniqueExit.get(head);
+ for (Entry<Integer, Integer> entry : filter.entrySet()) {
+ if (!head.equals(mapExceptionDoms.get(entry.getKey()))) {
+ Integer filterExit = entry.getValue();
+ if (filterExit.intValue() == -1 || !filterExit.equals(exit)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private void buildDominatorTree() {
+
+ VBStyleCollection<Integer, Integer> orderedIDoms = domEngine.getOrderedIDoms();
+
+ List<Integer> lstKeys = orderedIDoms.getLstKeys();
+ for (int index = lstKeys.size() - 1; index >= 0; index--) {
+ Integer key = lstKeys.get(index);
+ Integer idom = orderedIDoms.get(index);
+
+ Set<Integer> set = mapTreeBranches.get(idom);
+ if (set == null) {
+ mapTreeBranches.put(idom, set = new HashSet<Integer>());
+ }
+ set.add(key);
+ }
+
+ Integer firstid = statement.getFirst().id;
+ mapTreeBranches.get(firstid).remove(firstid);
+ }
+
+ private void buildExceptionRanges() {
+
+ for (Statement stat : statement.getStats()) {
+ List<Statement> lstPreds = stat.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD);
+ if (!lstPreds.isEmpty()) {
+
+ Set<Integer> set = new HashSet<Integer>();
+
+ for (Statement st : lstPreds) {
+ set.add(st.id);
+ }
+
+ mapExceptionRanges.put(stat.id, set);
+ }
+ }
+
+ mapExceptionDoms = buildExceptionDoms(statement.getFirst().id);
+ }
+
+ private Map<Integer, Integer> buildExceptionDoms(Integer id) {
+
+ Map<Integer, Integer> map = new HashMap<Integer, Integer>();
+
+ Set<Integer> children = mapTreeBranches.get(id);
+ if (children != null) {
+ for (Integer childid : children) {
+ Map<Integer, Integer> mapChild = buildExceptionDoms(childid);
+ for (Integer handler : mapChild.keySet()) {
+ map.put(handler, map.containsKey(handler) ? id : mapChild.get(handler));
+ }
+ }
+ }
+
+ for (Entry<Integer, Set<Integer>> entry : mapExceptionRanges.entrySet()) {
+ if (entry.getValue().contains(id)) {
+ map.put(entry.getKey(), id);
+ }
+ }
+
+ return map;
+ }
+
+
+ private void buildFilter(Integer id) {
+
+ Map<Integer, Integer> map = new HashMap<Integer, Integer>();
+
+ Set<Integer> children = mapTreeBranches.get(id);
+ if (children != null) {
+ for (Integer childid : children) {
+
+ buildFilter(childid);
+
+ Map<Integer, Integer> mapChild = mapExceptionRangeUniqueExit.get(childid);
+
+ for (Entry<Integer, Set<Integer>> entry : mapExceptionRanges.entrySet()) {
+
+ Integer handler = entry.getKey();
+ Set<Integer> range = entry.getValue();
+
+ if (range.contains(id)) {
+
+ Integer exit = null;
+
+ if (!range.contains(childid)) {
+ exit = childid;
+ }
+ else {
+ // exit = map.containsKey(handler)?-1:mapChild.get(handler); FIXME: Eclipse bug?
+ exit = map.containsKey(handler) ? new Integer(-1) : mapChild.get(handler);
+ }
+
+ if (exit != null) {
+ map.put(handler, exit);
+ }
+ }
+ }
+ }
+ }
+
+ mapExceptionRangeUniqueExit.put(id, map);
+ }
+
+ public DominatorEngine getDomEngine() {
+ return domEngine;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java
index e3093b5..daa898a 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java
@@ -1,362 +1,355 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.decompose;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.util.FastFixedSetFactory;
-import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.FastFixedSetFactory.FastFixedSet;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.*;
+import java.util.Map.Entry;
public class FastExtendedPostdominanceHelper {
- private List<Statement> lstReversePostOrderList;
-
- private HashMap<Integer, FastFixedSet<Integer>> mapSupportPoints = new HashMap<Integer, FastFixedSet<Integer>>();
-
- private HashMap<Integer, FastFixedSet<Integer>> mapExtPostdominators = new HashMap<Integer, FastFixedSet<Integer>>();
-
- private Statement statement;
-
- private FastFixedSetFactory<Integer> factory;
-
- public HashMap<Integer, Set<Integer>> getExtendedPostdominators(Statement statement) {
-
- this.statement = statement;
-
- HashSet<Integer> set = new HashSet<Integer>();
- for(Statement st : statement.getStats()) {
- set.add(st.id);
- }
- this.factory = new FastFixedSetFactory<Integer>(set);
-
- lstReversePostOrderList = statement.getReversePostOrderList();
-
-// try {
-// DotExporter.toDotFile(statement, new File("c:\\Temp\\stat1.dot"));
-// } catch (Exception ex) {
-// ex.printStackTrace();
-// }
-
- calcDefaultReachableSets();
-
- removeErroneousNodes();
-
- DominatorTreeExceptionFilter filter = new DominatorTreeExceptionFilter(statement);
- filter.initialize();
-
- filterOnExceptionRanges(filter);
-
- filterOnDominance(filter);
-
- HashMap<Integer, Set<Integer>> res = new HashMap<Integer, Set<Integer>>();
- for(Entry<Integer, FastFixedSet<Integer>> entry : mapExtPostdominators.entrySet()) {
- res.put(entry.getKey(), entry.getValue().toPlainSet());
- }
-
- return res;
- }
-
-
- private void filterOnDominance(DominatorTreeExceptionFilter filter) {
-
- DominatorEngine engine = filter.getDomEngine();
-
- for(Integer head : new HashSet<Integer>(mapExtPostdominators.keySet())) {
-
- FastFixedSet<Integer> setPostdoms = mapExtPostdominators.get(head);
-
- LinkedList<Statement> stack = new LinkedList<Statement>();
- LinkedList<FastFixedSet<Integer>> stackPath = new LinkedList<FastFixedSet<Integer>>();
-
- stack.add(statement.getStats().getWithKey(head));
- stackPath.add(factory.spawnEmptySet());
-
- Set<Statement> setVisited = new HashSet<Statement>();
-
- while(!stack.isEmpty()) {
-
- Statement stat = stack.removeFirst();
- FastFixedSet<Integer> path = stackPath.removeFirst();
-
- if(setPostdoms.contains(stat.id)) {
- path.add(stat.id);
- }
-
- if(path.contains(setPostdoms)) {
- continue;
- }
-
- setVisited.add(stat);
-
- int domflag = 0;
-
- for(Iterator<Integer> it = setPostdoms.iterator();it.hasNext();) {
- Integer post = it.next();
-
- if(!path.contains(post)) {
- if(domflag == 0) {
- domflag = engine.isDominator(stat.id, head)?2:1;
- }
-
- if(domflag == 1) { // not a dominator
- it.remove();
- }
- }
- }
-
- for(StatEdge edge : stat.getSuccessorEdges(StatEdge.TYPE_REGULAR)) {
- if(!setVisited.contains(edge.getDestination())) {
- stack.add(edge.getDestination());
- stackPath.add(path.getCopy());
- }
- }
- }
-
- if(setPostdoms.isEmpty()) {
- mapExtPostdominators.remove(head);
- }
-
- }
- }
-
-
- private void filterOnExceptionRanges(DominatorTreeExceptionFilter filter) {
-
-
- for(Integer head : new HashSet<Integer>(mapExtPostdominators.keySet())) {
-
- FastFixedSet<Integer> set = mapExtPostdominators.get(head);
- for(Iterator<Integer> it = set.iterator();it.hasNext();) {
- if(!filter.acceptStatementPair(head, it.next())) {
- it.remove();
- }
- }
- if(set.isEmpty()) {
- mapExtPostdominators.remove(head);
- }
- }
-
- }
-
-
- private void removeErroneousNodes() {
-
- mapSupportPoints = new HashMap<Integer, FastFixedSet<Integer>>();
-
- calcReachabilitySuppPoints(StatEdge.TYPE_REGULAR);
-
- iterateReachability(new IReachabilityAction() {
- public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets) {
-
- Integer nodeid = node.id;
-
- FastFixedSet<Integer> setReachability = mapSets.get(nodeid);
- List<FastFixedSet<Integer>> lstPredSets = new ArrayList<FastFixedSet<Integer>>();
-
- for(StatEdge prededge : node.getPredecessorEdges(StatEdge.TYPE_REGULAR)) {
- FastFixedSet<Integer> setPred = mapSets.get(prededge.getSource().id);
- if(setPred == null) {
- setPred = mapSupportPoints.get(prededge.getSource().id);
- }
-
- // setPred cannot be empty as it is a reachability set
- lstPredSets.add(setPred);
- }
-
- for(Integer id : setReachability.toPlainSet()) {
-
- FastFixedSet<Integer> setReachabilityCopy = setReachability.getCopy();
-
- FastFixedSet<Integer> setIntersection = factory.spawnEmptySet();
- boolean isIntersectionInitialized = false;
-
- for(FastFixedSet<Integer> predset : lstPredSets) {
- if(predset.contains(id)) {
- if(!isIntersectionInitialized) {
- setIntersection.union(predset);
- isIntersectionInitialized = true;
- } else {
- setIntersection.intersection(predset);
- }
- }
- }
-
- if(nodeid != id.intValue()) {
- setIntersection.add(nodeid);
- } else {
- setIntersection.remove(nodeid);
- }
-
- setReachabilityCopy.complement(setIntersection);
-
- mapExtPostdominators.get(id).complement(setReachabilityCopy);
- }
-
- return false;
- }
- }, StatEdge.TYPE_REGULAR);
-
- // exception handlers cannot be postdominator nodes
- // TODO: replace with a standard set?
- FastFixedSet<Integer> setHandlers = factory.spawnEmptySet();
- boolean handlerfound = false;
-
- for(Statement stat : statement.getStats()) {
- if(stat.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL).isEmpty() &&
- !stat.getPredecessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty()) { // exception handler
- setHandlers.add(stat.id);
- handlerfound = true;
- }
- }
-
- if(handlerfound) {
- for(FastFixedSet<Integer> set : mapExtPostdominators.values()) {
- set.complement(setHandlers);
- }
- }
- }
-
-
- private void calcDefaultReachableSets() {
-
- int edgetype = StatEdge.TYPE_REGULAR | StatEdge.TYPE_EXCEPTION;
-
- calcReachabilitySuppPoints(edgetype);
-
- for(Statement stat : statement.getStats()) {
- mapExtPostdominators.put(stat.id, factory.spawnEmptySet());
- }
-
- iterateReachability(new IReachabilityAction() {
- public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets) {
-
- Integer nodeid = node.id;
- FastFixedSet<Integer> setReachability = mapSets.get(nodeid);
-
- for(Integer id : setReachability.toPlainSet()) {
- mapExtPostdominators.get(id).add(nodeid);
- }
-
- return false;
- }
- }, edgetype);
-
- }
-
-
- private void calcReachabilitySuppPoints(final int edgetype) {
-
- iterateReachability(new IReachabilityAction() {
- public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets) {
-
- // consider to be a support point
- for(StatEdge sucedge : node.getAllSuccessorEdges()) {
- if((sucedge.getType() & edgetype) != 0) {
- if(mapSets.containsKey(sucedge.getDestination().id)) {
- FastFixedSet<Integer> setReachability = mapSets.get(node.id);
-
- if(!InterpreterUtil.equalObjects(setReachability, mapSupportPoints.get(node.id))) {
- mapSupportPoints.put(node.id, setReachability);
- return true;
- }
- }
- }
- }
-
- return false;
- }
- }, edgetype);
-
- }
-
- private void iterateReachability(IReachabilityAction action, int edgetype) {
-
- for(;;) {
-
- boolean iterate = false;
-
- HashMap<Integer, FastFixedSet<Integer>> mapSets = new HashMap<Integer, FastFixedSet<Integer>>();
-
- for(Statement stat : lstReversePostOrderList) {
-
- FastFixedSet<Integer> set = factory.spawnEmptySet();
- set.add(stat.id);
-
- for(StatEdge prededge : stat.getAllPredecessorEdges()) {
- if((prededge.getType() & edgetype) != 0) {
- Statement pred = prededge.getSource();
-
- FastFixedSet<Integer> setPred = mapSets.get(pred.id);
- if(setPred == null) {
- setPred = mapSupportPoints.get(pred.id);
- }
-
- if(setPred != null) {
- set.union(setPred);
- }
- }
- }
-
- mapSets.put(stat.id, set);
-
- if(action != null) {
- iterate |= action.action(stat, mapSets);
- }
-
- // remove reachability information of fully processed nodes (saves memory)
- for(StatEdge prededge : stat.getAllPredecessorEdges()) {
- if((prededge.getType() & edgetype) != 0) {
- Statement pred = prededge.getSource();
-
- if(mapSets.containsKey(pred.id)) {
- boolean remstat = true;
- for(StatEdge sucedge : pred.getAllSuccessorEdges()) {
- if((sucedge.getType() & edgetype) != 0) {
- if(!mapSets.containsKey(sucedge.getDestination().id)) {
- remstat = false;
- break;
- }
- }
- }
-
- if(remstat) {
- mapSets.put(pred.id, null);
- }
- }
- }
- }
- }
-
- if(!iterate) {
- break;
- }
- }
- }
-
-
- private interface IReachabilityAction {
- public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets);
- }
+ private List<Statement> lstReversePostOrderList;
+
+ private HashMap<Integer, FastFixedSet<Integer>> mapSupportPoints = new HashMap<Integer, FastFixedSet<Integer>>();
+
+ private HashMap<Integer, FastFixedSet<Integer>> mapExtPostdominators = new HashMap<Integer, FastFixedSet<Integer>>();
+
+ private Statement statement;
+
+ private FastFixedSetFactory<Integer> factory;
+
+ public HashMap<Integer, Set<Integer>> getExtendedPostdominators(Statement statement) {
+
+ this.statement = statement;
+
+ HashSet<Integer> set = new HashSet<Integer>();
+ for (Statement st : statement.getStats()) {
+ set.add(st.id);
+ }
+ this.factory = new FastFixedSetFactory<Integer>(set);
+
+ lstReversePostOrderList = statement.getReversePostOrderList();
+
+ // try {
+ // DotExporter.toDotFile(statement, new File("c:\\Temp\\stat1.dot"));
+ // } catch (Exception ex) {
+ // ex.printStackTrace();
+ // }
+
+ calcDefaultReachableSets();
+
+ removeErroneousNodes();
+
+ DominatorTreeExceptionFilter filter = new DominatorTreeExceptionFilter(statement);
+ filter.initialize();
+
+ filterOnExceptionRanges(filter);
+
+ filterOnDominance(filter);
+
+ HashMap<Integer, Set<Integer>> res = new HashMap<Integer, Set<Integer>>();
+ for (Entry<Integer, FastFixedSet<Integer>> entry : mapExtPostdominators.entrySet()) {
+ res.put(entry.getKey(), entry.getValue().toPlainSet());
+ }
+
+ return res;
+ }
+
+
+ private void filterOnDominance(DominatorTreeExceptionFilter filter) {
+
+ DominatorEngine engine = filter.getDomEngine();
+
+ for (Integer head : new HashSet<Integer>(mapExtPostdominators.keySet())) {
+
+ FastFixedSet<Integer> setPostdoms = mapExtPostdominators.get(head);
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ LinkedList<FastFixedSet<Integer>> stackPath = new LinkedList<FastFixedSet<Integer>>();
+
+ stack.add(statement.getStats().getWithKey(head));
+ stackPath.add(factory.spawnEmptySet());
+
+ Set<Statement> setVisited = new HashSet<Statement>();
+
+ while (!stack.isEmpty()) {
+
+ Statement stat = stack.removeFirst();
+ FastFixedSet<Integer> path = stackPath.removeFirst();
+
+ if (setPostdoms.contains(stat.id)) {
+ path.add(stat.id);
+ }
+
+ if (path.contains(setPostdoms)) {
+ continue;
+ }
+
+ setVisited.add(stat);
+
+ int domflag = 0;
+
+ for (Iterator<Integer> it = setPostdoms.iterator(); it.hasNext(); ) {
+ Integer post = it.next();
+
+ if (!path.contains(post)) {
+ if (domflag == 0) {
+ domflag = engine.isDominator(stat.id, head) ? 2 : 1;
+ }
+
+ if (domflag == 1) { // not a dominator
+ it.remove();
+ }
+ }
+ }
+
+ for (StatEdge edge : stat.getSuccessorEdges(StatEdge.TYPE_REGULAR)) {
+ if (!setVisited.contains(edge.getDestination())) {
+ stack.add(edge.getDestination());
+ stackPath.add(path.getCopy());
+ }
+ }
+ }
+
+ if (setPostdoms.isEmpty()) {
+ mapExtPostdominators.remove(head);
+ }
+ }
+ }
+
+
+ private void filterOnExceptionRanges(DominatorTreeExceptionFilter filter) {
+
+
+ for (Integer head : new HashSet<Integer>(mapExtPostdominators.keySet())) {
+
+ FastFixedSet<Integer> set = mapExtPostdominators.get(head);
+ for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) {
+ if (!filter.acceptStatementPair(head, it.next())) {
+ it.remove();
+ }
+ }
+ if (set.isEmpty()) {
+ mapExtPostdominators.remove(head);
+ }
+ }
+ }
+
+
+ private void removeErroneousNodes() {
+
+ mapSupportPoints = new HashMap<Integer, FastFixedSet<Integer>>();
+
+ calcReachabilitySuppPoints(StatEdge.TYPE_REGULAR);
+
+ iterateReachability(new IReachabilityAction() {
+ public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets) {
+
+ Integer nodeid = node.id;
+
+ FastFixedSet<Integer> setReachability = mapSets.get(nodeid);
+ List<FastFixedSet<Integer>> lstPredSets = new ArrayList<FastFixedSet<Integer>>();
+
+ for (StatEdge prededge : node.getPredecessorEdges(StatEdge.TYPE_REGULAR)) {
+ FastFixedSet<Integer> setPred = mapSets.get(prededge.getSource().id);
+ if (setPred == null) {
+ setPred = mapSupportPoints.get(prededge.getSource().id);
+ }
+
+ // setPred cannot be empty as it is a reachability set
+ lstPredSets.add(setPred);
+ }
+
+ for (Integer id : setReachability.toPlainSet()) {
+
+ FastFixedSet<Integer> setReachabilityCopy = setReachability.getCopy();
+
+ FastFixedSet<Integer> setIntersection = factory.spawnEmptySet();
+ boolean isIntersectionInitialized = false;
+
+ for (FastFixedSet<Integer> predset : lstPredSets) {
+ if (predset.contains(id)) {
+ if (!isIntersectionInitialized) {
+ setIntersection.union(predset);
+ isIntersectionInitialized = true;
+ }
+ else {
+ setIntersection.intersection(predset);
+ }
+ }
+ }
+
+ if (nodeid != id.intValue()) {
+ setIntersection.add(nodeid);
+ }
+ else {
+ setIntersection.remove(nodeid);
+ }
+
+ setReachabilityCopy.complement(setIntersection);
+
+ mapExtPostdominators.get(id).complement(setReachabilityCopy);
+ }
+
+ return false;
+ }
+ }, StatEdge.TYPE_REGULAR);
+
+ // exception handlers cannot be postdominator nodes
+ // TODO: replace with a standard set?
+ FastFixedSet<Integer> setHandlers = factory.spawnEmptySet();
+ boolean handlerfound = false;
+
+ for (Statement stat : statement.getStats()) {
+ if (stat.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL).isEmpty() &&
+ !stat.getPredecessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty()) { // exception handler
+ setHandlers.add(stat.id);
+ handlerfound = true;
+ }
+ }
+
+ if (handlerfound) {
+ for (FastFixedSet<Integer> set : mapExtPostdominators.values()) {
+ set.complement(setHandlers);
+ }
+ }
+ }
+
+
+ private void calcDefaultReachableSets() {
+
+ int edgetype = StatEdge.TYPE_REGULAR | StatEdge.TYPE_EXCEPTION;
+
+ calcReachabilitySuppPoints(edgetype);
+
+ for (Statement stat : statement.getStats()) {
+ mapExtPostdominators.put(stat.id, factory.spawnEmptySet());
+ }
+
+ iterateReachability(new IReachabilityAction() {
+ public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets) {
+
+ Integer nodeid = node.id;
+ FastFixedSet<Integer> setReachability = mapSets.get(nodeid);
+
+ for (Integer id : setReachability.toPlainSet()) {
+ mapExtPostdominators.get(id).add(nodeid);
+ }
+
+ return false;
+ }
+ }, edgetype);
+ }
+
+
+ private void calcReachabilitySuppPoints(final int edgetype) {
+
+ iterateReachability(new IReachabilityAction() {
+ public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets) {
+
+ // consider to be a support point
+ for (StatEdge sucedge : node.getAllSuccessorEdges()) {
+ if ((sucedge.getType() & edgetype) != 0) {
+ if (mapSets.containsKey(sucedge.getDestination().id)) {
+ FastFixedSet<Integer> setReachability = mapSets.get(node.id);
+
+ if (!InterpreterUtil.equalObjects(setReachability, mapSupportPoints.get(node.id))) {
+ mapSupportPoints.put(node.id, setReachability);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+ }, edgetype);
+ }
+
+ private void iterateReachability(IReachabilityAction action, int edgetype) {
+
+ for (; ; ) {
+
+ boolean iterate = false;
+
+ HashMap<Integer, FastFixedSet<Integer>> mapSets = new HashMap<Integer, FastFixedSet<Integer>>();
+
+ for (Statement stat : lstReversePostOrderList) {
+
+ FastFixedSet<Integer> set = factory.spawnEmptySet();
+ set.add(stat.id);
+
+ for (StatEdge prededge : stat.getAllPredecessorEdges()) {
+ if ((prededge.getType() & edgetype) != 0) {
+ Statement pred = prededge.getSource();
+
+ FastFixedSet<Integer> setPred = mapSets.get(pred.id);
+ if (setPred == null) {
+ setPred = mapSupportPoints.get(pred.id);
+ }
+
+ if (setPred != null) {
+ set.union(setPred);
+ }
+ }
+ }
+
+ mapSets.put(stat.id, set);
+
+ if (action != null) {
+ iterate |= action.action(stat, mapSets);
+ }
+
+ // remove reachability information of fully processed nodes (saves memory)
+ for (StatEdge prededge : stat.getAllPredecessorEdges()) {
+ if ((prededge.getType() & edgetype) != 0) {
+ Statement pred = prededge.getSource();
+
+ if (mapSets.containsKey(pred.id)) {
+ boolean remstat = true;
+ for (StatEdge sucedge : pred.getAllSuccessorEdges()) {
+ if ((sucedge.getType() & edgetype) != 0) {
+ if (!mapSets.containsKey(sucedge.getDestination().id)) {
+ remstat = false;
+ break;
+ }
+ }
+ }
+
+ if (remstat) {
+ mapSets.put(pred.id, null);
+ }
+ }
+ }
+ }
+ }
+
+ if (!iterate) {
+ break;
+ }
+ }
+ }
+
+
+ private interface IReachabilityAction {
+ public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets);
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/GenericDominatorEngine.java b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/GenericDominatorEngine.java
index ed35202..2eca3b7 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/GenericDominatorEngine.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/GenericDominatorEngine.java
@@ -1,150 +1,152 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.decompose;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
import java.util.List;
import java.util.Set;
-import org.jetbrains.java.decompiler.util.VBStyleCollection;
-
public class GenericDominatorEngine {
- private IGraph graph;
-
- private VBStyleCollection<IGraphNode, IGraphNode> colOrderedIDoms = new VBStyleCollection<IGraphNode, IGraphNode>();
-
- private Set<? extends IGraphNode> setRoots;
-
- public GenericDominatorEngine(IGraph graph) {
- this.graph = graph;
- }
-
- public void initialize() {
- calcIDoms();
- }
-
- private void orderNodes() {
-
- setRoots = graph.getRoots();
-
- for(IGraphNode node : graph.getReversePostOrderList()) {
- colOrderedIDoms.addWithKey(null, node);
- }
-
- }
-
- private IGraphNode getCommonIDom(IGraphNode node1, IGraphNode node2, VBStyleCollection<IGraphNode, IGraphNode> orderedIDoms) {
-
- IGraphNode nodeOld;
-
- if(node1 == null) {
- return node2;
- } else if(node2 == null) {
- return node1;
- }
-
- int index1 = orderedIDoms.getIndexByKey(node1);
- int index2 = orderedIDoms.getIndexByKey(node2);
-
- while(index1 != index2) {
- if(index1 > index2) {
- nodeOld = node1;
- node1 = orderedIDoms.getWithKey(node1);
-
- if(nodeOld == node1) { // no idom - root or merging point
- return null;
- }
-
- index1 = orderedIDoms.getIndexByKey(node1);
- } else {
- nodeOld = node2;
- node2 = orderedIDoms.getWithKey(node2);
-
- if(nodeOld == node2) { // no idom - root or merging point
- return null;
- }
-
- index2 = orderedIDoms.getIndexByKey(node2);
- }
- }
-
- return node1;
- }
-
- private void calcIDoms() {
-
- orderNodes();
-
- List<IGraphNode> lstNodes = colOrderedIDoms.getLstKeys();
-
- for(;;) {
-
- boolean changed = false;
-
- for(IGraphNode node : lstNodes) {
-
- IGraphNode idom = null;
-
- if(!setRoots.contains(node)) {
- for(IGraphNode pred : node.getPredecessors()) {
- if(colOrderedIDoms.getWithKey(pred) != null) {
- idom = getCommonIDom(idom, pred, colOrderedIDoms);
- if(idom == null) {
- break; // no idom found: merging point of two trees
- }
- }
- }
- }
-
- if(idom == null) {
- idom = node;
- }
-
- IGraphNode oldidom = colOrderedIDoms.putWithKey(idom, node);
- if(!idom.equals(oldidom)) { // oldidom is null iff the node is touched for the first time
- changed = true;
- }
- }
-
- if(!changed) {
- break;
- }
- }
-
- }
-
- public VBStyleCollection<IGraphNode, IGraphNode> getOrderedIDoms() {
- return colOrderedIDoms;
- }
-
- public boolean isDominator(IGraphNode node, IGraphNode dom) {
-
- while(!node.equals(dom)) {
-
- IGraphNode idom = colOrderedIDoms.getWithKey(node);
-
- if(idom == node) {
- return false; // root node or merging point
- } else if(idom == null) {
- throw new RuntimeException("Inconsistent idom sequence discovered!");
- } else {
- node = idom;
- }
- }
-
- return true;
- }
-
+ private IGraph graph;
+
+ private VBStyleCollection<IGraphNode, IGraphNode> colOrderedIDoms = new VBStyleCollection<IGraphNode, IGraphNode>();
+
+ private Set<? extends IGraphNode> setRoots;
+
+ public GenericDominatorEngine(IGraph graph) {
+ this.graph = graph;
+ }
+
+ public void initialize() {
+ calcIDoms();
+ }
+
+ private void orderNodes() {
+
+ setRoots = graph.getRoots();
+
+ for (IGraphNode node : graph.getReversePostOrderList()) {
+ colOrderedIDoms.addWithKey(null, node);
+ }
+ }
+
+ private IGraphNode getCommonIDom(IGraphNode node1, IGraphNode node2, VBStyleCollection<IGraphNode, IGraphNode> orderedIDoms) {
+
+ IGraphNode nodeOld;
+
+ if (node1 == null) {
+ return node2;
+ }
+ else if (node2 == null) {
+ return node1;
+ }
+
+ int index1 = orderedIDoms.getIndexByKey(node1);
+ int index2 = orderedIDoms.getIndexByKey(node2);
+
+ while (index1 != index2) {
+ if (index1 > index2) {
+ nodeOld = node1;
+ node1 = orderedIDoms.getWithKey(node1);
+
+ if (nodeOld == node1) { // no idom - root or merging point
+ return null;
+ }
+
+ index1 = orderedIDoms.getIndexByKey(node1);
+ }
+ else {
+ nodeOld = node2;
+ node2 = orderedIDoms.getWithKey(node2);
+
+ if (nodeOld == node2) { // no idom - root or merging point
+ return null;
+ }
+
+ index2 = orderedIDoms.getIndexByKey(node2);
+ }
+ }
+
+ return node1;
+ }
+
+ private void calcIDoms() {
+
+ orderNodes();
+
+ List<IGraphNode> lstNodes = colOrderedIDoms.getLstKeys();
+
+ for (; ; ) {
+
+ boolean changed = false;
+
+ for (IGraphNode node : lstNodes) {
+
+ IGraphNode idom = null;
+
+ if (!setRoots.contains(node)) {
+ for (IGraphNode pred : node.getPredecessors()) {
+ if (colOrderedIDoms.getWithKey(pred) != null) {
+ idom = getCommonIDom(idom, pred, colOrderedIDoms);
+ if (idom == null) {
+ break; // no idom found: merging point of two trees
+ }
+ }
+ }
+ }
+
+ if (idom == null) {
+ idom = node;
+ }
+
+ IGraphNode oldidom = colOrderedIDoms.putWithKey(idom, node);
+ if (!idom.equals(oldidom)) { // oldidom is null iff the node is touched for the first time
+ changed = true;
+ }
+ }
+
+ if (!changed) {
+ break;
+ }
+ }
+ }
+
+ public VBStyleCollection<IGraphNode, IGraphNode> getOrderedIDoms() {
+ return colOrderedIDoms;
+ }
+
+ public boolean isDominator(IGraphNode node, IGraphNode dom) {
+
+ while (!node.equals(dom)) {
+
+ IGraphNode idom = colOrderedIDoms.getWithKey(node);
+
+ if (idom == node) {
+ return false; // root node or merging point
+ }
+ else if (idom == null) {
+ throw new RuntimeException("Inconsistent idom sequence discovered!");
+ }
+ else {
+ node = idom;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraph.java b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraph.java
index 8b72a4f..9179f9c 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraph.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraph.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.decompose;
import java.util.List;
@@ -19,8 +20,7 @@ import java.util.Set;
public interface IGraph {
- public List<? extends IGraphNode> getReversePostOrderList();
-
- public Set<? extends IGraphNode> getRoots();
-
+ public List<? extends IGraphNode> getReversePostOrderList();
+
+ public Set<? extends IGraphNode> getRoots();
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraphNode.java b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraphNode.java
index d2d1e0b..191b974 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraphNode.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraphNode.java
@@ -1,23 +1,23 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.decompose;
import java.util.List;
public interface IGraphNode {
- public List<? extends IGraphNode> getPredecessors();
-
+ public List<? extends IGraphNode> getPredecessors();
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java b/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java
index d0f7243..b015230 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java
@@ -1,28 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.deobfuscator;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.code.Instruction;
import org.jetbrains.java.decompiler.code.InstructionSequence;
@@ -35,290 +27,294 @@ import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraph;
import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.*;
+import java.util.Map.Entry;
+
public class ExceptionDeobfuscator {
- public static void restorePopRanges(ControlFlowGraph graph) {
-
- List<Object[]> lstRanges = new ArrayList<Object[]>();
-
- // aggregate ranges
- for(ExceptionRangeCFG range : graph.getExceptions()) {
- boolean found = false;
- for(Object[] arr : lstRanges) {
- if(arr[0] == range.getHandler() && InterpreterUtil.equalObjects(range.getUniqueExceptionsString(),arr[1])) {
- ((HashSet<BasicBlock>)arr[2]).addAll(range.getProtectedRange());
- found = true;
- break;
- }
- }
-
- if(!found) {
- // doesn't matter, which range chosen
- lstRanges.add(new Object[] {range.getHandler(), range.getUniqueExceptionsString(), new HashSet<BasicBlock>(range.getProtectedRange()), range});
- }
- }
-
- // process aggregated ranges
- for(Object[] range : lstRanges) {
-
- if(range[1] != null) {
-
- BasicBlock handler = (BasicBlock)range[0];
- InstructionSequence seq = handler.getSeq();
-
- Instruction firstinstr = null;
- if(seq.length() > 0) {
- firstinstr = seq.getInstr(0);
-
- if(firstinstr.opcode == CodeConstants.opc_pop ||
- firstinstr.opcode == CodeConstants.opc_astore) {
- HashSet<BasicBlock> setrange = new HashSet<BasicBlock>((HashSet<BasicBlock>)range[2]);
-
- for(Object[] range_super : lstRanges) { // finally or strict superset
-
- if(range != range_super) {
-
- HashSet<BasicBlock> setrange_super = new HashSet<BasicBlock>((HashSet<BasicBlock>)range_super[2]);
-
- if(!setrange.contains(range_super[0]) && !setrange_super.contains(handler)
- && (range_super[1] == null || setrange_super.containsAll(setrange))) {
-
- if(range_super[1] == null) {
- setrange_super.retainAll(setrange);
- } else {
- setrange_super.removeAll(setrange);
- }
-
- if(!setrange_super.isEmpty()) {
-
- BasicBlock newblock = handler;
-
- // split the handler
- if(seq.length() > 1) {
- newblock = new BasicBlock(++graph.last_id);
- InstructionSequence newseq = new SimpleInstructionSequence();
- newseq.addInstruction(firstinstr.clone() , -1);
-
- newblock.setSeq(newseq);
- graph.getBlocks().addWithKey(newblock, newblock.id);
-
-
- List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
- lstTemp.addAll(handler.getPreds());
- lstTemp.addAll(handler.getPredExceptions());
-
- // replace predecessors
- for(BasicBlock pred: lstTemp) {
- pred.replaceSuccessor(handler, newblock);
- }
-
- // replace handler
- for(ExceptionRangeCFG range_ext: graph.getExceptions()) {
- if(range_ext.getHandler() == handler) {
- range_ext.setHandler(newblock);
- } else if(range_ext.getProtectedRange().contains(handler)) {
- newblock.addSuccessorException(range_ext.getHandler());
- range_ext.getProtectedRange().add(newblock);
- }
- }
-
- newblock.addSuccessor(handler);
- if(graph.getFirst() == handler) {
- graph.setFirst(newblock);
- }
-
- // remove the first pop in the handler
- seq.removeInstruction(0);
- }
-
-
- newblock.addSuccessorException((BasicBlock)range_super[0]);
- ((ExceptionRangeCFG)range_super[3]).getProtectedRange().add(newblock);
-
- handler = ((ExceptionRangeCFG)range[3]).getHandler();
- seq = handler.getSeq();
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- public static void insertEmptyExceptionHandlerBlocks(ControlFlowGraph graph) {
-
- HashSet<BasicBlock> setVisited = new HashSet<BasicBlock>();
-
- for(ExceptionRangeCFG range : graph.getExceptions()) {
- BasicBlock handler = range.getHandler();
-
- if(setVisited.contains(handler)) {
- continue;
- }
- setVisited.add(handler);
-
- BasicBlock emptyblock = new BasicBlock(++graph.last_id);
- graph.getBlocks().addWithKey(emptyblock, emptyblock.id);
-
- List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
- // only exception predecessors considered
- lstTemp.addAll(handler.getPredExceptions());
-
- // replace predecessors
- for(BasicBlock pred: lstTemp) {
- pred.replaceSuccessor(handler, emptyblock);
- }
-
- // replace handler
- for(ExceptionRangeCFG range_ext: graph.getExceptions()) {
- if(range_ext.getHandler() == handler) {
- range_ext.setHandler(emptyblock);
- } else if(range_ext.getProtectedRange().contains(handler)) {
- emptyblock.addSuccessorException(range_ext.getHandler());
- range_ext.getProtectedRange().add(emptyblock);
- }
- }
-
- emptyblock.addSuccessor(handler);
- if(graph.getFirst() == handler) {
- graph.setFirst(emptyblock);
- }
- }
- }
-
- public static void removeEmptyRanges(ControlFlowGraph graph) {
-
- List<ExceptionRangeCFG> lstRanges = graph.getExceptions();
- for(int i=lstRanges.size()-1;i>=0;i--) {
- ExceptionRangeCFG range = lstRanges.get(i);
-
- boolean isEmpty = true;
- for(BasicBlock block : range.getProtectedRange()) {
- if(!block.getSeq().isEmpty()) {
- isEmpty = false;
- break;
- }
- }
-
- if(isEmpty) {
- for(BasicBlock block : range.getProtectedRange()) {
- block.removeSuccessorException(range.getHandler());
- }
-
- lstRanges.remove(i);
- }
- }
-
- }
-
- public static void removeCircularRanges(final ControlFlowGraph graph) {
-
- GenericDominatorEngine engine = new GenericDominatorEngine(new IGraph() {
- public List<? extends IGraphNode> getReversePostOrderList() {
- return graph.getReversePostOrder();
- }
-
- public Set<? extends IGraphNode> getRoots() {
- return new HashSet<IGraphNode>(Arrays.asList(new IGraphNode[]{graph.getFirst()}));
- }
- });
-
- engine.initialize();
-
- List<ExceptionRangeCFG> lstRanges = graph.getExceptions();
- for(int i=lstRanges.size()-1;i>=0;i--) {
- ExceptionRangeCFG range = lstRanges.get(i);
-
- BasicBlock handler = range.getHandler();
- List<BasicBlock> rangeList = range.getProtectedRange();
-
- if(rangeList.contains(handler)) { // TODO: better removing strategy
-
- List<BasicBlock> lstRemBlocks = getReachableBlocksRestricted(range, engine);
-
- if(lstRemBlocks.size() < rangeList.size() || rangeList.size() == 1) {
- for(BasicBlock block : lstRemBlocks) {
- block.removeSuccessorException(handler);
- rangeList.remove(block);
- }
- }
-
- if(rangeList.isEmpty()) {
- lstRanges.remove(i);
- }
- }
- }
-
- }
-
- private static List<BasicBlock> getReachableBlocksRestricted(ExceptionRangeCFG range, GenericDominatorEngine engine) {
-
- List<BasicBlock> lstRes = new ArrayList<BasicBlock>();
-
- LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
- HashSet<BasicBlock> setVisited = new HashSet<BasicBlock>();
-
- BasicBlock handler = range.getHandler();
- stack.addFirst(handler);
-
- while(!stack.isEmpty()) {
- BasicBlock block = stack.removeFirst();
-
- setVisited.add(block);
-
- if(range.getProtectedRange().contains(block) && engine.isDominator(block, handler)) {
- lstRes.add(block);
-
- List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
- lstSuccs.addAll(block.getSuccExceptions());
-
- for(BasicBlock succ : lstSuccs) {
- if(!setVisited.contains(succ)) {
- stack.add(succ);
- }
- }
- }
- }
-
- return lstRes;
- }
-
-
- public static boolean hasObfuscatedExceptions(ControlFlowGraph graph) {
-
- BasicBlock first = graph.getFirst();
-
- HashMap<BasicBlock, HashSet<BasicBlock>> mapRanges = new HashMap<BasicBlock, HashSet<BasicBlock>>();
- for(ExceptionRangeCFG range : graph.getExceptions()) {
- HashSet<BasicBlock> set = mapRanges.get(range.getHandler());
- if(set == null) {
- mapRanges.put(range.getHandler(), set = new HashSet<BasicBlock>());
- }
- set.addAll(range.getProtectedRange());
-
- }
-
- for(Entry<BasicBlock, HashSet<BasicBlock>> ent : mapRanges.entrySet()) {
- HashSet<BasicBlock> setEntries = new HashSet<BasicBlock>();
-
- for(BasicBlock block : ent.getValue()) {
- HashSet<BasicBlock> setTemp = new HashSet<BasicBlock>(block.getPreds());
- setTemp.removeAll(ent.getValue());
-
- if(!setTemp.isEmpty()) {
- setEntries.add(block);
- }
- }
-
- if(!setEntries.isEmpty()) {
- if(setEntries.size() > 1 /*|| ent.getValue().contains(first)*/) {
- return true;
- }
- }
- }
-
- return false;
- }
+ public static void restorePopRanges(ControlFlowGraph graph) {
+
+ List<Object[]> lstRanges = new ArrayList<Object[]>();
+
+ // aggregate ranges
+ for (ExceptionRangeCFG range : graph.getExceptions()) {
+ boolean found = false;
+ for (Object[] arr : lstRanges) {
+ if (arr[0] == range.getHandler() && InterpreterUtil.equalObjects(range.getUniqueExceptionsString(), arr[1])) {
+ ((HashSet<BasicBlock>)arr[2]).addAll(range.getProtectedRange());
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ // doesn't matter, which range chosen
+ lstRanges.add(
+ new Object[]{range.getHandler(), range.getUniqueExceptionsString(), new HashSet<BasicBlock>(range.getProtectedRange()), range});
+ }
+ }
+
+ // process aggregated ranges
+ for (Object[] range : lstRanges) {
+
+ if (range[1] != null) {
+
+ BasicBlock handler = (BasicBlock)range[0];
+ InstructionSequence seq = handler.getSeq();
+
+ Instruction firstinstr = null;
+ if (seq.length() > 0) {
+ firstinstr = seq.getInstr(0);
+
+ if (firstinstr.opcode == CodeConstants.opc_pop ||
+ firstinstr.opcode == CodeConstants.opc_astore) {
+ HashSet<BasicBlock> setrange = new HashSet<BasicBlock>((HashSet<BasicBlock>)range[2]);
+
+ for (Object[] range_super : lstRanges) { // finally or strict superset
+
+ if (range != range_super) {
+
+ HashSet<BasicBlock> setrange_super = new HashSet<BasicBlock>((HashSet<BasicBlock>)range_super[2]);
+
+ if (!setrange.contains(range_super[0]) && !setrange_super.contains(handler)
+ && (range_super[1] == null || setrange_super.containsAll(setrange))) {
+
+ if (range_super[1] == null) {
+ setrange_super.retainAll(setrange);
+ }
+ else {
+ setrange_super.removeAll(setrange);
+ }
+
+ if (!setrange_super.isEmpty()) {
+
+ BasicBlock newblock = handler;
+
+ // split the handler
+ if (seq.length() > 1) {
+ newblock = new BasicBlock(++graph.last_id);
+ InstructionSequence newseq = new SimpleInstructionSequence();
+ newseq.addInstruction(firstinstr.clone(), -1);
+
+ newblock.setSeq(newseq);
+ graph.getBlocks().addWithKey(newblock, newblock.id);
+
+
+ List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
+ lstTemp.addAll(handler.getPreds());
+ lstTemp.addAll(handler.getPredExceptions());
+
+ // replace predecessors
+ for (BasicBlock pred : lstTemp) {
+ pred.replaceSuccessor(handler, newblock);
+ }
+
+ // replace handler
+ for (ExceptionRangeCFG range_ext : graph.getExceptions()) {
+ if (range_ext.getHandler() == handler) {
+ range_ext.setHandler(newblock);
+ }
+ else if (range_ext.getProtectedRange().contains(handler)) {
+ newblock.addSuccessorException(range_ext.getHandler());
+ range_ext.getProtectedRange().add(newblock);
+ }
+ }
+
+ newblock.addSuccessor(handler);
+ if (graph.getFirst() == handler) {
+ graph.setFirst(newblock);
+ }
+
+ // remove the first pop in the handler
+ seq.removeInstruction(0);
+ }
+
+
+ newblock.addSuccessorException((BasicBlock)range_super[0]);
+ ((ExceptionRangeCFG)range_super[3]).getProtectedRange().add(newblock);
+
+ handler = ((ExceptionRangeCFG)range[3]).getHandler();
+ seq = handler.getSeq();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static void insertEmptyExceptionHandlerBlocks(ControlFlowGraph graph) {
+
+ HashSet<BasicBlock> setVisited = new HashSet<BasicBlock>();
+
+ for (ExceptionRangeCFG range : graph.getExceptions()) {
+ BasicBlock handler = range.getHandler();
+
+ if (setVisited.contains(handler)) {
+ continue;
+ }
+ setVisited.add(handler);
+
+ BasicBlock emptyblock = new BasicBlock(++graph.last_id);
+ graph.getBlocks().addWithKey(emptyblock, emptyblock.id);
+
+ List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
+ // only exception predecessors considered
+ lstTemp.addAll(handler.getPredExceptions());
+
+ // replace predecessors
+ for (BasicBlock pred : lstTemp) {
+ pred.replaceSuccessor(handler, emptyblock);
+ }
+
+ // replace handler
+ for (ExceptionRangeCFG range_ext : graph.getExceptions()) {
+ if (range_ext.getHandler() == handler) {
+ range_ext.setHandler(emptyblock);
+ }
+ else if (range_ext.getProtectedRange().contains(handler)) {
+ emptyblock.addSuccessorException(range_ext.getHandler());
+ range_ext.getProtectedRange().add(emptyblock);
+ }
+ }
+
+ emptyblock.addSuccessor(handler);
+ if (graph.getFirst() == handler) {
+ graph.setFirst(emptyblock);
+ }
+ }
+ }
+
+ public static void removeEmptyRanges(ControlFlowGraph graph) {
+
+ List<ExceptionRangeCFG> lstRanges = graph.getExceptions();
+ for (int i = lstRanges.size() - 1; i >= 0; i--) {
+ ExceptionRangeCFG range = lstRanges.get(i);
+
+ boolean isEmpty = true;
+ for (BasicBlock block : range.getProtectedRange()) {
+ if (!block.getSeq().isEmpty()) {
+ isEmpty = false;
+ break;
+ }
+ }
+
+ if (isEmpty) {
+ for (BasicBlock block : range.getProtectedRange()) {
+ block.removeSuccessorException(range.getHandler());
+ }
+
+ lstRanges.remove(i);
+ }
+ }
+ }
+
+ public static void removeCircularRanges(final ControlFlowGraph graph) {
+
+ GenericDominatorEngine engine = new GenericDominatorEngine(new IGraph() {
+ public List<? extends IGraphNode> getReversePostOrderList() {
+ return graph.getReversePostOrder();
+ }
+
+ public Set<? extends IGraphNode> getRoots() {
+ return new HashSet<IGraphNode>(Arrays.asList(new IGraphNode[]{graph.getFirst()}));
+ }
+ });
+
+ engine.initialize();
+
+ List<ExceptionRangeCFG> lstRanges = graph.getExceptions();
+ for (int i = lstRanges.size() - 1; i >= 0; i--) {
+ ExceptionRangeCFG range = lstRanges.get(i);
+
+ BasicBlock handler = range.getHandler();
+ List<BasicBlock> rangeList = range.getProtectedRange();
+
+ if (rangeList.contains(handler)) { // TODO: better removing strategy
+
+ List<BasicBlock> lstRemBlocks = getReachableBlocksRestricted(range, engine);
+
+ if (lstRemBlocks.size() < rangeList.size() || rangeList.size() == 1) {
+ for (BasicBlock block : lstRemBlocks) {
+ block.removeSuccessorException(handler);
+ rangeList.remove(block);
+ }
+ }
+
+ if (rangeList.isEmpty()) {
+ lstRanges.remove(i);
+ }
+ }
+ }
+ }
+
+ private static List<BasicBlock> getReachableBlocksRestricted(ExceptionRangeCFG range, GenericDominatorEngine engine) {
+
+ List<BasicBlock> lstRes = new ArrayList<BasicBlock>();
+
+ LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
+ HashSet<BasicBlock> setVisited = new HashSet<BasicBlock>();
+
+ BasicBlock handler = range.getHandler();
+ stack.addFirst(handler);
+
+ while (!stack.isEmpty()) {
+ BasicBlock block = stack.removeFirst();
+
+ setVisited.add(block);
+
+ if (range.getProtectedRange().contains(block) && engine.isDominator(block, handler)) {
+ lstRes.add(block);
+
+ List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
+ lstSuccs.addAll(block.getSuccExceptions());
+
+ for (BasicBlock succ : lstSuccs) {
+ if (!setVisited.contains(succ)) {
+ stack.add(succ);
+ }
+ }
+ }
+ }
+
+ return lstRes;
+ }
+
+
+ public static boolean hasObfuscatedExceptions(ControlFlowGraph graph) {
+
+ BasicBlock first = graph.getFirst();
+
+ HashMap<BasicBlock, HashSet<BasicBlock>> mapRanges = new HashMap<BasicBlock, HashSet<BasicBlock>>();
+ for (ExceptionRangeCFG range : graph.getExceptions()) {
+ HashSet<BasicBlock> set = mapRanges.get(range.getHandler());
+ if (set == null) {
+ mapRanges.put(range.getHandler(), set = new HashSet<BasicBlock>());
+ }
+ set.addAll(range.getProtectedRange());
+ }
+
+ for (Entry<BasicBlock, HashSet<BasicBlock>> ent : mapRanges.entrySet()) {
+ HashSet<BasicBlock> setEntries = new HashSet<BasicBlock>();
+
+ for (BasicBlock block : ent.getValue()) {
+ HashSet<BasicBlock> setTemp = new HashSet<BasicBlock>(block.getPreds());
+ setTemp.removeAll(ent.getValue());
+
+ if (!setTemp.isEmpty()) {
+ setEntries.add(block);
+ }
+ }
+
+ if (!setEntries.isEmpty()) {
+ if (setEntries.size() > 1 /*|| ent.getValue().contains(first)*/) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/IrreducibleCFGDeobfuscator.java b/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/IrreducibleCFGDeobfuscator.java
index 250a25e..11f9483 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/IrreducibleCFGDeobfuscator.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/IrreducibleCFGDeobfuscator.java
@@ -1,238 +1,245 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.deobfuscator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
public class IrreducibleCFGDeobfuscator {
-
-
- public static boolean isStatementIrreducible(Statement statement) {
-
- class Node {
- public Integer id;
- public Set<Node> preds = new HashSet<Node>();
- public Set<Node> succs = new HashSet<Node>();
-
- public Node(Integer id) {this.id = id;}
- }
-
- HashMap<Integer, Node> mapNodes = new HashMap<Integer, Node>();
-
- // checking exceptions and creating nodes
- for(Statement stat : statement.getStats()) {
- if(!stat.getSuccessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty()) {
- return false;
- }
-
- mapNodes.put(stat.id, new Node(stat.id));
- }
-
- // connecting nodes
- for(Statement stat : statement.getStats()) {
- Node node = mapNodes.get(stat.id);
-
- for(Statement succ : stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD)) {
- Node nodeSucc = mapNodes.get(succ.id);
-
- node.succs.add(nodeSucc);
- nodeSucc.preds.add(node);
- }
- }
-
- // transforming and reducing the graph
- for(;;) {
- int ttype = 0;
- Node node = null;
-
- for(Node nd : mapNodes.values()) {
- if(nd.succs.contains(nd)) { // T1
- ttype = 1;
- } else if(nd.preds.size() == 1) { // T2
- ttype = 2;
- }
-
- if(ttype != 0) {
- node = nd;
- break;
- }
- }
-
- if(node != null) {
- if(ttype == 1) {
- node.succs.remove(node);
- node.preds.remove(node);
- } else {
- Node pred = node.preds.iterator().next();
-
- pred.succs.addAll(node.succs);
- pred.succs.remove(node);
-
- for(Node succ : node.succs) {
- succ.preds.remove(node);
- succ.preds.add(pred);
- }
-
- mapNodes.remove(node.id);
- }
- } else { // no transformation applicable
- return mapNodes.size() > 1; // reducible iff one node remains
- }
- }
-
- }
-
-
-
-
- private static Statement getCandidateForSplitting(Statement statement) {
-
- Statement candidateForSplitting = null;
- int sizeCandidateForSplitting = Integer.MAX_VALUE;
- int succsCandidateForSplitting = Integer.MAX_VALUE;
-
- for(Statement stat : statement.getStats()) {
-
- Set<Statement> setPreds = stat.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
-
- if(setPreds.size() > 1) {
- int succCount = stat.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD).size();
- if(succCount <= succsCandidateForSplitting) {
- int size = getStatementSize(stat)*(setPreds.size()-1);
-
- if(succCount < succsCandidateForSplitting ||
- size < sizeCandidateForSplitting) {
- candidateForSplitting = stat;
- sizeCandidateForSplitting = size;
- succsCandidateForSplitting = succCount;
- }
- }
- }
- }
-
- return candidateForSplitting;
- }
-
- public static boolean splitIrreducibleNode(Statement statement) {
-
- Statement splitnode = getCandidateForSplitting(statement);
- if(splitnode == null) {
- return false;
- }
-
- StatEdge enteredge = splitnode.getPredecessorEdges(StatEdge.TYPE_REGULAR).iterator().next();
-
- // copy the smallest statement
- Statement splitcopy = copyStatement(splitnode, null, new HashMap<Statement, Statement>());
- initCopiedStatement(splitcopy);
-
- // insert the copy
- splitcopy.setParent(statement);
- statement.getStats().addWithKey(splitcopy, splitcopy.id);
-
- // switch input edges
- for(StatEdge prededge : splitnode.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
- if(prededge.getSource() == enteredge.getSource() ||
- prededge.closure == enteredge.getSource()) {
- splitnode.removePredecessor(prededge);
- prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, splitcopy);
- splitcopy.addPredecessor(prededge);
- }
- }
-
- // connect successors
- for(StatEdge succ : splitnode.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
- splitcopy.addSuccessor(new StatEdge(succ.getType(), splitcopy, succ.getDestination(), succ.closure));
- }
-
- return true;
- }
-
- private static int getStatementSize(Statement statement) {
-
- int res = 0;
-
- if(statement.type == Statement.TYPE_BASICBLOCK) {
- res = ((BasicBlockStatement)statement).getBlock().getSeq().length();
- } else {
- for(Statement stat: statement.getStats()) {
- res+=getStatementSize(stat);
- }
- }
-
- return res;
- }
-
- private static Statement copyStatement(Statement from, Statement to, HashMap<Statement, Statement> mapAltToCopies) {
-
- if(to == null) {
- // first outer invocation
- to = from.getSimpleCopy();
- mapAltToCopies.put(from, to);
- }
-
- // copy statements
- for(Statement st : from.getStats()) {
- Statement stcopy = st.getSimpleCopy();
-
- to.getStats().addWithKey(stcopy, stcopy.id);
- mapAltToCopies.put(st, stcopy);
- }
-
- // copy edges
- for(int i=0;i<from.getStats().size();i++) {
- Statement stold = from.getStats().get(i);
- Statement stnew = to.getStats().get(i);
-
- for(StatEdge edgeold : stold.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
- // type cannot be TYPE_EXCEPTION (checked in isIrreducibleTriangle)
- StatEdge edgenew = new StatEdge(edgeold.getType(), stnew,
- mapAltToCopies.containsKey(edgeold.getDestination())?mapAltToCopies.get(edgeold.getDestination()):edgeold.getDestination(),
- mapAltToCopies.containsKey(edgeold.closure)?mapAltToCopies.get(edgeold.closure):edgeold.closure);
-
- stnew.addSuccessor(edgenew);
- }
- }
-
- // recurse statements
- for(int i=0;i<from.getStats().size();i++) {
- Statement stold = from.getStats().get(i);
- Statement stnew = to.getStats().get(i);
-
- copyStatement(stold, stnew, mapAltToCopies);
- }
-
- return to;
- }
-
- private static void initCopiedStatement(Statement statement) {
-
- statement.initSimpleCopy();
- statement.setCopied(true);
-
- for(Statement st : statement.getStats()) {
- st.setParent(statement);
- initCopiedStatement(st);
- }
- }
-
+
+
+ public static boolean isStatementIrreducible(Statement statement) {
+
+ class Node {
+ public Integer id;
+ public Set<Node> preds = new HashSet<Node>();
+ public Set<Node> succs = new HashSet<Node>();
+
+ public Node(Integer id) {
+ this.id = id;
+ }
+ }
+
+ HashMap<Integer, Node> mapNodes = new HashMap<Integer, Node>();
+
+ // checking exceptions and creating nodes
+ for (Statement stat : statement.getStats()) {
+ if (!stat.getSuccessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty()) {
+ return false;
+ }
+
+ mapNodes.put(stat.id, new Node(stat.id));
+ }
+
+ // connecting nodes
+ for (Statement stat : statement.getStats()) {
+ Node node = mapNodes.get(stat.id);
+
+ for (Statement succ : stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD)) {
+ Node nodeSucc = mapNodes.get(succ.id);
+
+ node.succs.add(nodeSucc);
+ nodeSucc.preds.add(node);
+ }
+ }
+
+ // transforming and reducing the graph
+ for (; ; ) {
+ int ttype = 0;
+ Node node = null;
+
+ for (Node nd : mapNodes.values()) {
+ if (nd.succs.contains(nd)) { // T1
+ ttype = 1;
+ }
+ else if (nd.preds.size() == 1) { // T2
+ ttype = 2;
+ }
+
+ if (ttype != 0) {
+ node = nd;
+ break;
+ }
+ }
+
+ if (node != null) {
+ if (ttype == 1) {
+ node.succs.remove(node);
+ node.preds.remove(node);
+ }
+ else {
+ Node pred = node.preds.iterator().next();
+
+ pred.succs.addAll(node.succs);
+ pred.succs.remove(node);
+
+ for (Node succ : node.succs) {
+ succ.preds.remove(node);
+ succ.preds.add(pred);
+ }
+
+ mapNodes.remove(node.id);
+ }
+ }
+ else { // no transformation applicable
+ return mapNodes.size() > 1; // reducible iff one node remains
+ }
+ }
+ }
+
+
+ private static Statement getCandidateForSplitting(Statement statement) {
+
+ Statement candidateForSplitting = null;
+ int sizeCandidateForSplitting = Integer.MAX_VALUE;
+ int succsCandidateForSplitting = Integer.MAX_VALUE;
+
+ for (Statement stat : statement.getStats()) {
+
+ Set<Statement> setPreds = stat.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
+
+ if (setPreds.size() > 1) {
+ int succCount = stat.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD).size();
+ if (succCount <= succsCandidateForSplitting) {
+ int size = getStatementSize(stat) * (setPreds.size() - 1);
+
+ if (succCount < succsCandidateForSplitting ||
+ size < sizeCandidateForSplitting) {
+ candidateForSplitting = stat;
+ sizeCandidateForSplitting = size;
+ succsCandidateForSplitting = succCount;
+ }
+ }
+ }
+ }
+
+ return candidateForSplitting;
+ }
+
+ public static boolean splitIrreducibleNode(Statement statement) {
+
+ Statement splitnode = getCandidateForSplitting(statement);
+ if (splitnode == null) {
+ return false;
+ }
+
+ StatEdge enteredge = splitnode.getPredecessorEdges(StatEdge.TYPE_REGULAR).iterator().next();
+
+ // copy the smallest statement
+ Statement splitcopy = copyStatement(splitnode, null, new HashMap<Statement, Statement>());
+ initCopiedStatement(splitcopy);
+
+ // insert the copy
+ splitcopy.setParent(statement);
+ statement.getStats().addWithKey(splitcopy, splitcopy.id);
+
+ // switch input edges
+ for (StatEdge prededge : splitnode.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
+ if (prededge.getSource() == enteredge.getSource() ||
+ prededge.closure == enteredge.getSource()) {
+ splitnode.removePredecessor(prededge);
+ prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, splitcopy);
+ splitcopy.addPredecessor(prededge);
+ }
+ }
+
+ // connect successors
+ for (StatEdge succ : splitnode.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
+ splitcopy.addSuccessor(new StatEdge(succ.getType(), splitcopy, succ.getDestination(), succ.closure));
+ }
+
+ return true;
+ }
+
+ private static int getStatementSize(Statement statement) {
+
+ int res = 0;
+
+ if (statement.type == Statement.TYPE_BASICBLOCK) {
+ res = ((BasicBlockStatement)statement).getBlock().getSeq().length();
+ }
+ else {
+ for (Statement stat : statement.getStats()) {
+ res += getStatementSize(stat);
+ }
+ }
+
+ return res;
+ }
+
+ private static Statement copyStatement(Statement from, Statement to, HashMap<Statement, Statement> mapAltToCopies) {
+
+ if (to == null) {
+ // first outer invocation
+ to = from.getSimpleCopy();
+ mapAltToCopies.put(from, to);
+ }
+
+ // copy statements
+ for (Statement st : from.getStats()) {
+ Statement stcopy = st.getSimpleCopy();
+
+ to.getStats().addWithKey(stcopy, stcopy.id);
+ mapAltToCopies.put(st, stcopy);
+ }
+
+ // copy edges
+ for (int i = 0; i < from.getStats().size(); i++) {
+ Statement stold = from.getStats().get(i);
+ Statement stnew = to.getStats().get(i);
+
+ for (StatEdge edgeold : stold.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
+ // type cannot be TYPE_EXCEPTION (checked in isIrreducibleTriangle)
+ StatEdge edgenew = new StatEdge(edgeold.getType(), stnew,
+ mapAltToCopies.containsKey(edgeold.getDestination())
+ ? mapAltToCopies.get(edgeold.getDestination())
+ : edgeold.getDestination(),
+ mapAltToCopies.containsKey(edgeold.closure)
+ ? mapAltToCopies.get(edgeold.closure)
+ : edgeold.closure);
+
+ stnew.addSuccessor(edgenew);
+ }
+ }
+
+ // recurse statements
+ for (int i = 0; i < from.getStats().size(); i++) {
+ Statement stold = from.getStats().get(i);
+ Statement stnew = to.getStats().get(i);
+
+ copyStatement(stold, stnew, mapAltToCopies);
+ }
+
+ return to;
+ }
+
+ private static void initCopiedStatement(Statement statement) {
+
+ statement.initSimpleCopy();
+ statement.setCopied(true);
+
+ for (Statement st : statement.getStats()) {
+ st.setParent(statement);
+ initCopiedStatement(st);
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java
index 2945913..b919548 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java
@@ -1,111 +1,114 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.List;
-
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.List;
+
public class AnnotationExprent extends Exprent {
-
- public static final int ANNOTATION_NORMAL = 1;
- public static final int ANNOTATION_MARKER = 2;
- public static final int ANNOTATION_SINGLE_ELEMENT = 3;
-
-
- private String classname;
-
- private List<String> parnames;
-
- private List<Exprent> parvalues;
-
- {
- this.type = EXPRENT_ANNOTATION;
- }
-
- public AnnotationExprent(String classname, List<String> parnames, List<Exprent> parvalues) {
- this.classname = classname;
- this.parnames = parnames;
- this.parvalues = parvalues;
- }
-
- public String toJava(int indent) {
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- StringBuilder buffer = new StringBuilder();
- String indstr = InterpreterUtil.getIndentString(indent);
-
- buffer.append(indstr);
- buffer.append("@");
- buffer.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
-
- if(!parnames.isEmpty()) {
- buffer.append("(");
- if(parnames.size() == 1 && "value".equals(parnames.get(0))) {
- buffer.append(parvalues.get(0).toJava(indent+1));
- } else {
- String indstr1 = InterpreterUtil.getIndentString(indent+1);
-
- for(int i=0;i<parnames.size();i++) {
- buffer.append(new_line_separator+indstr1);
- buffer.append(parnames.get(i));
- buffer.append(" = ");
- buffer.append(parvalues.get(i).toJava(indent+2));
-
- if(i<parnames.size()-1) {
- buffer.append(",");
- }
- }
- buffer.append(new_line_separator+indstr);
- }
-
- buffer.append(")");
- }
-
- return buffer.toString();
- }
-
- public int getAnnotationType() {
-
- if(parnames.isEmpty()) {
- return ANNOTATION_MARKER;
- } else {
- if(parnames.size() == 1 && "value".equals(parnames.get(0))) {
- return ANNOTATION_SINGLE_ELEMENT;
- } else {
- return ANNOTATION_NORMAL;
- }
- }
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof AnnotationExprent)) return false;
+
+ public static final int ANNOTATION_NORMAL = 1;
+ public static final int ANNOTATION_MARKER = 2;
+ public static final int ANNOTATION_SINGLE_ELEMENT = 3;
+
+
+ private String classname;
+
+ private List<String> parnames;
+
+ private List<Exprent> parvalues;
+
+ {
+ this.type = EXPRENT_ANNOTATION;
+ }
+
+ public AnnotationExprent(String classname, List<String> parnames, List<Exprent> parvalues) {
+ this.classname = classname;
+ this.parnames = parnames;
+ this.parvalues = parvalues;
+ }
+
+ public String toJava(int indent) {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buffer = new StringBuilder();
+ String indstr = InterpreterUtil.getIndentString(indent);
+
+ buffer.append(indstr);
+ buffer.append("@");
+ buffer.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
+
+ if (!parnames.isEmpty()) {
+ buffer.append("(");
+ if (parnames.size() == 1 && "value".equals(parnames.get(0))) {
+ buffer.append(parvalues.get(0).toJava(indent + 1));
+ }
+ else {
+ String indstr1 = InterpreterUtil.getIndentString(indent + 1);
+
+ for (int i = 0; i < parnames.size(); i++) {
+ buffer.append(new_line_separator + indstr1);
+ buffer.append(parnames.get(i));
+ buffer.append(" = ");
+ buffer.append(parvalues.get(i).toJava(indent + 2));
+
+ if (i < parnames.size() - 1) {
+ buffer.append(",");
+ }
+ }
+ buffer.append(new_line_separator + indstr);
+ }
+
+ buffer.append(")");
+ }
+
+ return buffer.toString();
+ }
+
+ public int getAnnotationType() {
+
+ if (parnames.isEmpty()) {
+ return ANNOTATION_MARKER;
+ }
+ else {
+ if (parnames.size() == 1 && "value".equals(parnames.get(0))) {
+ return ANNOTATION_SINGLE_ELEMENT;
+ }
+ else {
+ return ANNOTATION_NORMAL;
+ }
+ }
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof AnnotationExprent)) return false;
AnnotationExprent ann = (AnnotationExprent)o;
return classname.equals(ann.classname) &&
- InterpreterUtil.equalLists(parnames, ann.parnames) &&
- InterpreterUtil.equalLists(parvalues, ann.parvalues);
+ InterpreterUtil.equalLists(parnames, ann.parnames) &&
+ InterpreterUtil.equalLists(parvalues, ann.parvalues);
}
- public String getClassname() {
- return classname;
- }
-
+ public String getClassname() {
+ return classname;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java
index 2f262bd..e5ead9d 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java
@@ -1,125 +1,126 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.List;
+
public class ArrayExprent extends Exprent {
- private Exprent array;
-
- private Exprent index;
-
- private VarType hardtype;
-
- {
- this.type = EXPRENT_ARRAY;
- }
-
- public ArrayExprent(Exprent array, Exprent index, VarType hardtype) {
- this.array = array;
- this.index = index;
- this.hardtype = hardtype;
- }
-
- public Exprent copy() {
- return new ArrayExprent(array.copy(), index.copy(), hardtype);
- }
-
- public VarType getExprType() {
- VarType exprType = array.getExprType().copy();
- if(exprType.equals(VarType.VARTYPE_NULL)) {
- exprType = hardtype.copy();
- } else {
- exprType.decArrayDim();
- }
-
- return exprType;
- }
-
- public int getExprentUse() {
- return array.getExprentUse() & index.getExprentUse() & Exprent.MULTIPLE_USES;
- }
-
- public CheckTypesResult checkExprTypeBounds() {
- CheckTypesResult result = new CheckTypesResult();
-
- result.addMinTypeExprent(index, VarType.VARTYPE_BYTECHAR);
- result.addMaxTypeExprent(index, VarType.VARTYPE_INT);
-
- return result;
- }
-
- public List<Exprent> getAllExprents() {
- List<Exprent> lst = new ArrayList<Exprent>();
- lst.add(array);
- lst.add(index);
- return lst;
- }
-
-
- public String toJava(int indent) {
- String res = array.toJava(indent);
-
- if(array.getPrecedence() > getPrecedence()) { // array precedence equals 0
- res = "("+res+")";
- }
-
- VarType arrtype = array.getExprType();
- if(arrtype.arraydim == 0) {
- VarType objarr = VarType.VARTYPE_OBJECT.copy();
- objarr.arraydim = 1; // type family does not change
-
- res = "(("+ExprProcessor.getCastTypeName(objarr)+")"+res+")";
- }
-
- return res+"["+index.toJava(indent)+"]";
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof ArrayExprent)) return false;
+ private Exprent array;
+
+ private Exprent index;
+
+ private VarType hardtype;
+
+ {
+ this.type = EXPRENT_ARRAY;
+ }
+
+ public ArrayExprent(Exprent array, Exprent index, VarType hardtype) {
+ this.array = array;
+ this.index = index;
+ this.hardtype = hardtype;
+ }
+
+ public Exprent copy() {
+ return new ArrayExprent(array.copy(), index.copy(), hardtype);
+ }
+
+ public VarType getExprType() {
+ VarType exprType = array.getExprType().copy();
+ if (exprType.equals(VarType.VARTYPE_NULL)) {
+ exprType = hardtype.copy();
+ }
+ else {
+ exprType.decArrayDim();
+ }
+
+ return exprType;
+ }
+
+ public int getExprentUse() {
+ return array.getExprentUse() & index.getExprentUse() & Exprent.MULTIPLE_USES;
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ result.addMinTypeExprent(index, VarType.VARTYPE_BYTECHAR);
+ result.addMaxTypeExprent(index, VarType.VARTYPE_INT);
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.add(array);
+ lst.add(index);
+ return lst;
+ }
+
+
+ public String toJava(int indent) {
+ String res = array.toJava(indent);
+
+ if (array.getPrecedence() > getPrecedence()) { // array precedence equals 0
+ res = "(" + res + ")";
+ }
+
+ VarType arrtype = array.getExprType();
+ if (arrtype.arraydim == 0) {
+ VarType objarr = VarType.VARTYPE_OBJECT.copy();
+ objarr.arraydim = 1; // type family does not change
+
+ res = "((" + ExprProcessor.getCastTypeName(objarr) + ")" + res + ")";
+ }
+
+ return res + "[" + index.toJava(indent) + "]";
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof ArrayExprent)) return false;
ArrayExprent arr = (ArrayExprent)o;
return InterpreterUtil.equalObjects(array, arr.getArray()) &&
- InterpreterUtil.equalObjects(index, arr.getIndex());
+ InterpreterUtil.equalObjects(index, arr.getIndex());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == array) {
+ array = newexpr;
+ }
+
+ if (oldexpr == index) {
+ index = newexpr;
+ }
}
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(oldexpr == array) {
- array = newexpr;
- }
-
- if(oldexpr == index) {
- index = newexpr;
- }
- }
-
- public Exprent getArray() {
- return array;
- }
-
- public Exprent getIndex() {
- return index;
- }
-
+ public Exprent getArray() {
+ return array;
+ }
+
+ public Exprent getIndex() {
+ return index;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java
index 03ead80..0983dad 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java
@@ -1,51 +1,51 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
import java.util.List;
public class AssertExprent extends Exprent {
-
- private List<Exprent> parameters;
-
- {
- this.type = EXPRENT_ASSERT;
- }
-
- public AssertExprent(List<Exprent> parameters) {
- this.parameters = parameters;
- }
-
- public String toJava(int indent) {
-
- StringBuilder buffer = new StringBuilder();
-
- buffer.append("assert ");
-
- if(parameters.get(0) == null) {
- buffer.append("false");
- } else {
- buffer.append(parameters.get(0).toJava(indent));
- }
- if(parameters.size() > 1) {
- buffer.append(" : ");
- buffer.append(parameters.get(1).toJava(indent));
- }
-
- return buffer.toString();
- }
-
+ private List<Exprent> parameters;
+
+ {
+ this.type = EXPRENT_ASSERT;
+ }
+
+ public AssertExprent(List<Exprent> parameters) {
+ this.parameters = parameters;
+ }
+
+ public String toJava(int indent) {
+
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append("assert ");
+
+ if (parameters.get(0) == null) {
+ buffer.append("false");
+ }
+ else {
+ buffer.append(parameters.get(0).toJava(indent));
+ }
+ if (parameters.size() > 1) {
+ buffer.append(" : ");
+ buffer.append(parameters.get(1).toJava(indent));
+ }
+
+ return buffer.toString();
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java
index 9c233d4..e8b0b82 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java
@@ -1,25 +1,23 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
import org.jetbrains.java.decompiler.struct.StructClass;
@@ -27,169 +25,177 @@ import org.jetbrains.java.decompiler.struct.StructField;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.List;
+
public class AssignmentExprent extends Exprent {
- public static final int CONDITION_NONE = -1;
-
- private static final String[] funceq = new String[] {
- " += ", // FUNCTION_ADD
- " -= ", // FUNCTION_SUB
- " *= ", // FUNCTION_MUL
- " /= ", // FUNCTION_DIV
- " &= ", // FUNCTION_AND
- " |= ", // FUNCTION_OR
- " ^= ", // FUNCTION_XOR
- " %= ", // FUNCTION_REM
- " <<= ", // FUNCTION_SHL
- " >>= ", // FUNCTION_SHR
- " >>>= " // FUNCTION_USHR
- };
-
-
- private Exprent left;
-
- private Exprent right;
-
- private int condtype = CONDITION_NONE;
-
- {
- this.type = EXPRENT_ASSIGNMENT;
- }
-
-
- public AssignmentExprent(Exprent left, Exprent right) {
- this.left = left;
- this.right = right;
- }
-
-
- public VarType getExprType() {
- return left.getExprType();
- }
-
-
- public CheckTypesResult checkExprTypeBounds() {
- CheckTypesResult result = new CheckTypesResult();
-
- VarType typeleft = left.getExprType();
- VarType typeright = right.getExprType();
-
- if(typeleft.type_family > typeright.type_family) {
- result.addMinTypeExprent(right, VarType.getMinTypeInFamily(typeleft.type_family));
- } else if(typeleft.type_family < typeright.type_family) {
- result.addMinTypeExprent(left, typeright);
- } else {
- result.addMinTypeExprent(left, VarType.getCommonSupertype(typeleft, typeright));
- }
-
- return result;
- }
-
- public List<Exprent> getAllExprents() {
- List<Exprent> lst = new ArrayList<Exprent>();
- lst.add(left);
- lst.add(right);
- return lst;
- }
-
- public Exprent copy() {
- return new AssignmentExprent(left.copy(), right.copy());
- }
-
- public int getPrecedence() {
- return 13;
- }
-
- public String toJava(int indent) {
-
- VarType leftType = left.getExprType();
- VarType rightType = right.getExprType();
-
- String res = right.toJava(indent);
-
- if(condtype == CONDITION_NONE && !leftType.isSuperset(rightType) && (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT)) {
- if(right.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
- res = "("+res+")";
- }
-
- res = "("+ExprProcessor.getCastTypeName(leftType)+")"+res;
- }
-
- StringBuilder buffer = new StringBuilder();
-
- boolean finstat_init = false;
- if(left.type == Exprent.EXPRENT_FIELD) { // first assignment to a final field. Field name without "this" in front of it
- FieldExprent field = (FieldExprent)left;
- if(field.isStatic()) {
- ClassNode node = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE));
- if(node != null) {
- StructClass cl = node.classStruct;
- StructField fd = cl.getField(field.getName(), field.getDescriptor().descriptorString);
-
- if(fd != null && (fd.access_flags & CodeConstants.ACC_FINAL) != 0) {
- finstat_init = true;
- }
- }
- }
- }
-
- if(finstat_init) {
- buffer.append(((FieldExprent)left).getName());
- } else {
- buffer.append(left.toJava(indent));
- }
-
- buffer.append(condtype == CONDITION_NONE ? " = " : funceq[condtype]).append(res);
-
- return buffer.toString();
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof AssignmentExprent)) return false;
+ public static final int CONDITION_NONE = -1;
+
+ private static final String[] funceq = new String[]{
+ " += ", // FUNCTION_ADD
+ " -= ", // FUNCTION_SUB
+ " *= ", // FUNCTION_MUL
+ " /= ", // FUNCTION_DIV
+ " &= ", // FUNCTION_AND
+ " |= ", // FUNCTION_OR
+ " ^= ", // FUNCTION_XOR
+ " %= ", // FUNCTION_REM
+ " <<= ", // FUNCTION_SHL
+ " >>= ", // FUNCTION_SHR
+ " >>>= " // FUNCTION_USHR
+ };
+
+
+ private Exprent left;
+
+ private Exprent right;
+
+ private int condtype = CONDITION_NONE;
+
+ {
+ this.type = EXPRENT_ASSIGNMENT;
+ }
+
+
+ public AssignmentExprent(Exprent left, Exprent right) {
+ this.left = left;
+ this.right = right;
+ }
+
+
+ public VarType getExprType() {
+ return left.getExprType();
+ }
+
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ VarType typeleft = left.getExprType();
+ VarType typeright = right.getExprType();
+
+ if (typeleft.type_family > typeright.type_family) {
+ result.addMinTypeExprent(right, VarType.getMinTypeInFamily(typeleft.type_family));
+ }
+ else if (typeleft.type_family < typeright.type_family) {
+ result.addMinTypeExprent(left, typeright);
+ }
+ else {
+ result.addMinTypeExprent(left, VarType.getCommonSupertype(typeleft, typeright));
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.add(left);
+ lst.add(right);
+ return lst;
+ }
+
+ public Exprent copy() {
+ return new AssignmentExprent(left.copy(), right.copy());
+ }
+
+ public int getPrecedence() {
+ return 13;
+ }
+
+ public String toJava(int indent) {
+
+ VarType leftType = left.getExprType();
+ VarType rightType = right.getExprType();
+
+ String res = right.toJava(indent);
+
+ if (condtype == CONDITION_NONE &&
+ !leftType.isSuperset(rightType) &&
+ (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT)) {
+ if (right.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
+ res = "(" + res + ")";
+ }
+
+ res = "(" + ExprProcessor.getCastTypeName(leftType) + ")" + res;
+ }
+
+ StringBuilder buffer = new StringBuilder();
+
+ boolean finstat_init = false;
+ if (left.type == Exprent.EXPRENT_FIELD) { // first assignment to a final field. Field name without "this" in front of it
+ FieldExprent field = (FieldExprent)left;
+ if (field.isStatic()) {
+ ClassNode node = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE));
+ if (node != null) {
+ StructClass cl = node.classStruct;
+ StructField fd = cl.getField(field.getName(), field.getDescriptor().descriptorString);
+
+ if (fd != null && (fd.access_flags & CodeConstants.ACC_FINAL) != 0) {
+ finstat_init = true;
+ }
+ }
+ }
+ }
+
+ if (finstat_init) {
+ buffer.append(((FieldExprent)left).getName());
+ }
+ else {
+ buffer.append(left.toJava(indent));
+ }
+
+ buffer.append(condtype == CONDITION_NONE ? " = " : funceq[condtype]).append(res);
+
+ return buffer.toString();
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof AssignmentExprent)) return false;
AssignmentExprent as = (AssignmentExprent)o;
return InterpreterUtil.equalObjects(left, as.getLeft()) &&
- InterpreterUtil.equalObjects(right, as.getRight()) &&
- condtype == as.getCondtype();
- }
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(oldexpr == left) {
- left = newexpr;
- }
-
- if(oldexpr == right) {
- right = newexpr;
- }
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public Exprent getLeft() {
- return left;
- }
-
- public void setLeft(Exprent left) {
- this.left = left;
- }
-
- public Exprent getRight() {
- return right;
- }
-
- public void setRight(Exprent right) {
- this.right = right;
- }
-
- public int getCondtype() {
- return condtype;
- }
-
- public void setCondtype(int condtype) {
- this.condtype = condtype;
- }
+ InterpreterUtil.equalObjects(right, as.getRight()) &&
+ condtype == as.getCondtype();
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == left) {
+ left = newexpr;
+ }
+
+ if (oldexpr == right) {
+ right = newexpr;
+ }
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public Exprent getLeft() {
+ return left;
+ }
+
+ public void setLeft(Exprent left) {
+ this.left = left;
+ }
+
+ public Exprent getRight() {
+ return right;
+ }
+
+ public void setRight(Exprent right) {
+ this.right = right;
+ }
+
+ public int getCondtype() {
+ return condtype;
+ }
+
+ public void setCondtype(int condtype) {
+ this.condtype = condtype;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java
index 10fa1d4..ae1747d 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java
@@ -1,23 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
@@ -26,344 +23,380 @@ import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
public class ConstExprent extends Exprent {
- private static final HashMap<Integer, String> escapes = new HashMap<Integer, String>();
-
- static {
- escapes.put(new Integer(0x8), "\\b"); /* \u0008: backspace BS */
- escapes.put(new Integer(0x9), "\\t"); /* \u0009: horizontal tab HT */
- escapes.put(new Integer(0xA), "\\n"); /* \u000a: linefeed LF */
- escapes.put(new Integer(0xC), "\\f"); /* \u000c: form feed FF */
- escapes.put(new Integer(0xD), "\\r"); /* \u000d: carriage return CR */
- escapes.put(new Integer(0x22), "\\\""); /* \u0022: double quote " */
- escapes.put(new Integer(0x27), "\\\'"); /* \u0027: single quote ' */
- escapes.put(new Integer(0x5C), "\\\\"); /* \u005c: backslash \ */
- }
-
-
- private VarType consttype;
-
- private Object value;
-
- private boolean boolPermitted;
-
- {
- this.type = EXPRENT_CONST;
- }
-
- public ConstExprent(int val, boolean boolPermitted) {
-
- this.boolPermitted = boolPermitted;
- if(boolPermitted) {
- consttype = VarType.VARTYPE_BOOLEAN;
- if(val != 0 && val != 1) {
- consttype = consttype.copy();
- consttype.convinfo |= VarType.FALSEBOOLEAN;
- }
- } else {
- if(0 <= val && val <= 127) {
- consttype = VarType.VARTYPE_BYTECHAR;
- } else if(-128 <= val && val <= 127) {
- consttype = VarType.VARTYPE_BYTE;
- } else if(0 <= val && val <= 32767) {
- consttype = VarType.VARTYPE_SHORTCHAR;
- } else if(-32768 <= val && val <= 32767) {
- consttype = VarType.VARTYPE_SHORT;
- } else if(0 <= val && val <= 0xFFFF) {
- consttype = VarType.VARTYPE_CHAR;
- } else {
- consttype = VarType.VARTYPE_INT;
- }
- }
- value = new Integer(val);
- }
-
- public ConstExprent(VarType consttype, Object value) {
- this.consttype = consttype;
- this.value = value;
- }
-
- public Exprent copy() {
- return new ConstExprent(consttype, value);
- }
-
- public VarType getExprType() {
- return consttype;
- }
-
- public int getExprentUse() {
- return Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE;
- }
-
- public List<Exprent> getAllExprents() {
- return new ArrayList<Exprent>();
- }
-
- public String toJava(int indent) {
+ private static final HashMap<Integer, String> escapes = new HashMap<Integer, String>();
+
+ static {
+ escapes.put(new Integer(0x8), "\\b"); /* \u0008: backspace BS */
+ escapes.put(new Integer(0x9), "\\t"); /* \u0009: horizontal tab HT */
+ escapes.put(new Integer(0xA), "\\n"); /* \u000a: linefeed LF */
+ escapes.put(new Integer(0xC), "\\f"); /* \u000c: form feed FF */
+ escapes.put(new Integer(0xD), "\\r"); /* \u000d: carriage return CR */
+ escapes.put(new Integer(0x22), "\\\""); /* \u0022: double quote " */
+ escapes.put(new Integer(0x27), "\\\'"); /* \u0027: single quote ' */
+ escapes.put(new Integer(0x5C), "\\\\"); /* \u005c: backslash \ */
+ }
+
+
+ private VarType consttype;
+
+ private Object value;
+
+ private boolean boolPermitted;
+
+ {
+ this.type = EXPRENT_CONST;
+ }
+
+ public ConstExprent(int val, boolean boolPermitted) {
+
+ this.boolPermitted = boolPermitted;
+ if (boolPermitted) {
+ consttype = VarType.VARTYPE_BOOLEAN;
+ if (val != 0 && val != 1) {
+ consttype = consttype.copy();
+ consttype.convinfo |= VarType.FALSEBOOLEAN;
+ }
+ }
+ else {
+ if (0 <= val && val <= 127) {
+ consttype = VarType.VARTYPE_BYTECHAR;
+ }
+ else if (-128 <= val && val <= 127) {
+ consttype = VarType.VARTYPE_BYTE;
+ }
+ else if (0 <= val && val <= 32767) {
+ consttype = VarType.VARTYPE_SHORTCHAR;
+ }
+ else if (-32768 <= val && val <= 32767) {
+ consttype = VarType.VARTYPE_SHORT;
+ }
+ else if (0 <= val && val <= 0xFFFF) {
+ consttype = VarType.VARTYPE_CHAR;
+ }
+ else {
+ consttype = VarType.VARTYPE_INT;
+ }
+ }
+ value = new Integer(val);
+ }
+
+ public ConstExprent(VarType consttype, Object value) {
+ this.consttype = consttype;
+ this.value = value;
+ }
+
+ public Exprent copy() {
+ return new ConstExprent(consttype, value);
+ }
+
+ public VarType getExprType() {
+ return consttype;
+ }
+
+ public int getExprentUse() {
+ return Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE;
+ }
+
+ public List<Exprent> getAllExprents() {
+ return new ArrayList<Exprent>();
+ }
+
+ public String toJava(int indent) {
boolean literal = DecompilerContext.getOption(IFernflowerPreferences.LITERALS_AS_IS);
boolean ascii = DecompilerContext.getOption(IFernflowerPreferences.ASCII_STRING_CHARACTERS);
- if(consttype.type != CodeConstants.TYPE_NULL && value == null) {
- return ExprProcessor.getCastTypeName(consttype);
- } else {
- switch(consttype.type) {
- case CodeConstants.TYPE_BOOLEAN:
- return new Boolean(((Integer)value).intValue() != 0).toString();
- case CodeConstants.TYPE_CHAR:
- Integer val = (Integer)value;
- String ret = escapes.get(val);
- if(ret == null) {
- char c = (char)val.intValue();
- if(c >= 32 && c < 127 || !ascii && InterpreterUtil.isPrintableUnicode(c)) {
- ret = String.valueOf(c);
- } else {
- ret = InterpreterUtil.charToUnicodeLiteral(c);
- }
- }
- return "\'"+ret+"\'";
- case CodeConstants.TYPE_BYTE:
- case CodeConstants.TYPE_BYTECHAR:
- case CodeConstants.TYPE_SHORT:
- case CodeConstants.TYPE_SHORTCHAR:
- case CodeConstants.TYPE_INT:
- int ival = ((Integer)value).intValue();
-
- String intfield;
- if(literal) {
- return value.toString();
- } else if(ival == Integer.MAX_VALUE) {
- intfield = "MAX_VALUE";
- } else if(ival == Integer.MIN_VALUE) {
- intfield = "MIN_VALUE";
- } else {
- return value.toString();
- }
- return new FieldExprent(intfield, "java/lang/Integer", true, null, FieldDescriptor.INTEGER_DESCRIPTOR).toJava(0);
- case CodeConstants.TYPE_LONG:
- long lval = ((Long)value).longValue();
-
- String longfield;
- if(literal) {
- return value.toString()+"L";
- } else if(lval == Long.MAX_VALUE) {
- longfield = "MAX_VALUE";
- } else if(lval == Long.MIN_VALUE) {
- longfield = "MIN_VALUE";
- } else {
- return value.toString()+"L";
- }
- return new FieldExprent(longfield, "java/lang/Long", true, null, FieldDescriptor.LONG_DESCRIPTOR).toJava(0);
- case CodeConstants.TYPE_DOUBLE:
- double dval = ((Double)value).doubleValue();
-
- String doublefield;
- if(literal) {
- if(Double.isNaN(dval)) {
- return "0.0D / 0.0";
- } else if(dval == Double.POSITIVE_INFINITY) {
- return "1.0D / 0.0";
- } else if(dval == Double.NEGATIVE_INFINITY) {
- return "-1.0D / 0.0";
- } else {
+ if (consttype.type != CodeConstants.TYPE_NULL && value == null) {
+ return ExprProcessor.getCastTypeName(consttype);
+ }
+ else {
+ switch (consttype.type) {
+ case CodeConstants.TYPE_BOOLEAN:
+ return new Boolean(((Integer)value).intValue() != 0).toString();
+ case CodeConstants.TYPE_CHAR:
+ Integer val = (Integer)value;
+ String ret = escapes.get(val);
+ if (ret == null) {
+ char c = (char)val.intValue();
+ if (c >= 32 && c < 127 || !ascii && InterpreterUtil.isPrintableUnicode(c)) {
+ ret = String.valueOf(c);
+ }
+ else {
+ ret = InterpreterUtil.charToUnicodeLiteral(c);
+ }
+ }
+ return "\'" + ret + "\'";
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_BYTECHAR:
+ case CodeConstants.TYPE_SHORT:
+ case CodeConstants.TYPE_SHORTCHAR:
+ case CodeConstants.TYPE_INT:
+ int ival = ((Integer)value).intValue();
+
+ String intfield;
+ if (literal) {
+ return value.toString();
+ }
+ else if (ival == Integer.MAX_VALUE) {
+ intfield = "MAX_VALUE";
+ }
+ else if (ival == Integer.MIN_VALUE) {
+ intfield = "MIN_VALUE";
+ }
+ else {
+ return value.toString();
+ }
+ return new FieldExprent(intfield, "java/lang/Integer", true, null, FieldDescriptor.INTEGER_DESCRIPTOR).toJava(0);
+ case CodeConstants.TYPE_LONG:
+ long lval = ((Long)value).longValue();
+
+ String longfield;
+ if (literal) {
+ return value.toString() + "L";
+ }
+ else if (lval == Long.MAX_VALUE) {
+ longfield = "MAX_VALUE";
+ }
+ else if (lval == Long.MIN_VALUE) {
+ longfield = "MIN_VALUE";
+ }
+ else {
+ return value.toString() + "L";
+ }
+ return new FieldExprent(longfield, "java/lang/Long", true, null, FieldDescriptor.LONG_DESCRIPTOR).toJava(0);
+ case CodeConstants.TYPE_DOUBLE:
+ double dval = ((Double)value).doubleValue();
+
+ String doublefield;
+ if (literal) {
+ if (Double.isNaN(dval)) {
+ return "0.0D / 0.0";
+ }
+ else if (dval == Double.POSITIVE_INFINITY) {
+ return "1.0D / 0.0";
+ }
+ else if (dval == Double.NEGATIVE_INFINITY) {
+ return "-1.0D / 0.0";
+ }
+ else {
+ return value.toString() + "D";
+ }
+ }
+ else if (Double.isNaN(dval)) {
+ doublefield = "NaN";
+ }
+ else if (dval == Double.POSITIVE_INFINITY) {
+ doublefield = "POSITIVE_INFINITY";
+ }
+ else if (dval == Double.NEGATIVE_INFINITY) {
+ doublefield = "NEGATIVE_INFINITY";
+ }
+ else if (dval == Double.MAX_VALUE) {
+ doublefield = "MAX_VALUE";
+ }
+ else if (dval == Double.MIN_VALUE) {
+ doublefield = "MIN_VALUE";
+ }
+ else {
return value.toString() + "D";
}
- } else if(Double.isNaN(dval)) {
- doublefield = "NaN";
- } else if(dval == Double.POSITIVE_INFINITY) {
- doublefield = "POSITIVE_INFINITY";
- } else if(dval == Double.NEGATIVE_INFINITY) {
- doublefield = "NEGATIVE_INFINITY";
- } else if(dval == Double.MAX_VALUE) {
- doublefield = "MAX_VALUE";
- } else if(dval == Double.MIN_VALUE) {
- doublefield = "MIN_VALUE";
- } else {
- return value.toString()+"D";
- }
- return new FieldExprent(doublefield, "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR).toJava(0);
- case CodeConstants.TYPE_FLOAT:
- float fval = ((Float)value).floatValue();
-
- String floatfield;
- if(literal) {
- if(Double.isNaN(fval)) {
- return "0.0F / 0.0";
- } else if(fval == Double.POSITIVE_INFINITY) {
- return "1.0F / 0.0";
- } else if(fval == Double.NEGATIVE_INFINITY) {
- return "-1.0F / 0.0";
- } else {
+ return new FieldExprent(doublefield, "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR).toJava(0);
+ case CodeConstants.TYPE_FLOAT:
+ float fval = ((Float)value).floatValue();
+
+ String floatfield;
+ if (literal) {
+ if (Double.isNaN(fval)) {
+ return "0.0F / 0.0";
+ }
+ else if (fval == Double.POSITIVE_INFINITY) {
+ return "1.0F / 0.0";
+ }
+ else if (fval == Double.NEGATIVE_INFINITY) {
+ return "-1.0F / 0.0";
+ }
+ else {
+ return value.toString() + "F";
+ }
+ }
+ else if (Float.isNaN(fval)) {
+ floatfield = "NaN";
+ }
+ else if (fval == Float.POSITIVE_INFINITY) {
+ floatfield = "POSITIVE_INFINITY";
+ }
+ else if (fval == Float.NEGATIVE_INFINITY) {
+ floatfield = "NEGATIVE_INFINITY";
+ }
+ else if (fval == Float.MAX_VALUE) {
+ floatfield = "MAX_VALUE";
+ }
+ else if (fval == Float.MIN_VALUE) {
+ floatfield = "MIN_VALUE";
+ }
+ else {
return value.toString() + "F";
}
- } else if(Float.isNaN(fval)) {
- floatfield = "NaN";
- } else if(fval == Float.POSITIVE_INFINITY) {
- floatfield = "POSITIVE_INFINITY";
- } else if(fval == Float.NEGATIVE_INFINITY) {
- floatfield = "NEGATIVE_INFINITY";
- } else if(fval == Float.MAX_VALUE) {
- floatfield = "MAX_VALUE";
- } else if(fval == Float.MIN_VALUE) {
- floatfield = "MIN_VALUE";
- } else {
- return value.toString()+"F";
- }
- return new FieldExprent(floatfield, "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR).toJava(0);
- case CodeConstants.TYPE_NULL:
- return "null";
- case CodeConstants.TYPE_OBJECT:
- if(consttype.equals(VarType.VARTYPE_STRING)) {
- return "\""+convertStringToJava(value.toString(), ascii)+"\"";
- } else if(consttype.equals(VarType.VARTYPE_CLASS)) {
- String strval = value.toString();
-
- VarType classtype;
- if(strval.startsWith("[")) { // array of simple type
- classtype = new VarType(strval, false);
- } else { // class
- classtype = new VarType(strval, true);
- }
-
- return ExprProcessor.getCastTypeName(classtype)+".class";
- }
- }
- }
-
- throw new RuntimeException("invalid constant type");
- }
-
- private String convertStringToJava(String value, boolean ascii) {
- char[] arr = value.toCharArray();
- StringBuilder buffer = new StringBuilder(arr.length);
-
- for(char c: arr){
- switch(c) {
- case '\\': // u005c: backslash \
- buffer.append("\\\\");
- break;
- case 0x8: // "\\\\b"); // u0008: backspace BS
- buffer.append("\\b");
- break;
- case 0x9: //"\\\\t"); // u0009: horizontal tab HT
- buffer.append("\\t");
- break;
- case 0xA: //"\\\\n"); // u000a: linefeed LF
- buffer.append("\\n");
- break;
- case 0xC: //"\\\\f"); // u000c: form feed FF
- buffer.append("\\f");
- break;
- case 0xD: //"\\\\r"); // u000d: carriage return CR
- buffer.append("\\r");
- break;
- case 0x22: //"\\\\\""); // u0022: double quote "
- buffer.append("\\\"");
- break;
- case 0x27: //"\\\\'"); // u0027: single quote '
- buffer.append("\\\'");
- break;
- default:
- if(c >= 32 && c < 127 || !ascii && InterpreterUtil.isPrintableUnicode(c)) {
- buffer.append(c);
- } else {
- buffer.append(InterpreterUtil.charToUnicodeLiteral(c));
- }
- }
- }
-
- return buffer.toString();
- }
-
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof ConstExprent)) return false;
+ return new FieldExprent(floatfield, "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR).toJava(0);
+ case CodeConstants.TYPE_NULL:
+ return "null";
+ case CodeConstants.TYPE_OBJECT:
+ if (consttype.equals(VarType.VARTYPE_STRING)) {
+ return "\"" + convertStringToJava(value.toString(), ascii) + "\"";
+ }
+ else if (consttype.equals(VarType.VARTYPE_CLASS)) {
+ String strval = value.toString();
+
+ VarType classtype;
+ if (strval.startsWith("[")) { // array of simple type
+ classtype = new VarType(strval, false);
+ }
+ else { // class
+ classtype = new VarType(strval, true);
+ }
+
+ return ExprProcessor.getCastTypeName(classtype) + ".class";
+ }
+ }
+ }
+
+ throw new RuntimeException("invalid constant type");
+ }
+
+ private String convertStringToJava(String value, boolean ascii) {
+ char[] arr = value.toCharArray();
+ StringBuilder buffer = new StringBuilder(arr.length);
+
+ for (char c : arr) {
+ switch (c) {
+ case '\\': // u005c: backslash \
+ buffer.append("\\\\");
+ break;
+ case 0x8: // "\\\\b"); // u0008: backspace BS
+ buffer.append("\\b");
+ break;
+ case 0x9: //"\\\\t"); // u0009: horizontal tab HT
+ buffer.append("\\t");
+ break;
+ case 0xA: //"\\\\n"); // u000a: linefeed LF
+ buffer.append("\\n");
+ break;
+ case 0xC: //"\\\\f"); // u000c: form feed FF
+ buffer.append("\\f");
+ break;
+ case 0xD: //"\\\\r"); // u000d: carriage return CR
+ buffer.append("\\r");
+ break;
+ case 0x22: //"\\\\\""); // u0022: double quote "
+ buffer.append("\\\"");
+ break;
+ case 0x27: //"\\\\'"); // u0027: single quote '
+ buffer.append("\\\'");
+ break;
+ default:
+ if (c >= 32 && c < 127 || !ascii && InterpreterUtil.isPrintableUnicode(c)) {
+ buffer.append(c);
+ }
+ else {
+ buffer.append(InterpreterUtil.charToUnicodeLiteral(c));
+ }
+ }
+ }
+
+ return buffer.toString();
+ }
+
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof ConstExprent)) return false;
ConstExprent cn = (ConstExprent)o;
return InterpreterUtil.equalObjects(consttype, cn.getConsttype()) &&
- InterpreterUtil.equalObjects(value, cn.getValue());
+ InterpreterUtil.equalObjects(value, cn.getValue());
+ }
+
+ public boolean hasBooleanValue() {
+
+ switch (consttype.type) {
+ case CodeConstants.TYPE_BOOLEAN:
+ case CodeConstants.TYPE_CHAR:
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_BYTECHAR:
+ case CodeConstants.TYPE_SHORT:
+ case CodeConstants.TYPE_SHORTCHAR:
+ case CodeConstants.TYPE_INT:
+ Integer ival = (Integer)value;
+ return ival.intValue() == 0 ||
+ (DecompilerContext.getOption(IFernflowerPreferences.BOOLEAN_TRUE_ONE) && ival.intValue() == 1);
+ }
+
+ return false;
+ }
+
+ public boolean hasValueOne() {
+
+ switch (consttype.type) {
+ case CodeConstants.TYPE_BOOLEAN:
+ case CodeConstants.TYPE_CHAR:
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_BYTECHAR:
+ case CodeConstants.TYPE_SHORT:
+ case CodeConstants.TYPE_SHORTCHAR:
+ case CodeConstants.TYPE_INT:
+ return ((Integer)value).intValue() == 1;
+ case CodeConstants.TYPE_LONG:
+ return ((Long)value).intValue() == 1;
+ case CodeConstants.TYPE_DOUBLE:
+ return ((Double)value).intValue() == 1;
+ case CodeConstants.TYPE_FLOAT:
+ return ((Float)value).intValue() == 1;
+ }
+
+ return false;
+ }
+
+ public static ConstExprent getZeroConstant(int type) {
+
+ switch (type) {
+ case CodeConstants.TYPE_INT:
+ return new ConstExprent(VarType.VARTYPE_INT, new Integer(0));
+ case CodeConstants.TYPE_LONG:
+ return new ConstExprent(VarType.VARTYPE_LONG, new Long(0));
+ case CodeConstants.TYPE_DOUBLE:
+ return new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(0));
+ case CodeConstants.TYPE_FLOAT:
+ return new ConstExprent(VarType.VARTYPE_FLOAT, new Float(0));
+ }
+
+ throw new RuntimeException("Invalid argument!");
+ }
+
+ public VarType getConsttype() {
+ return consttype;
+ }
+
+ public void setConsttype(VarType consttype) {
+ this.consttype = consttype;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public int getIntValue() {
+ return ((Integer)value).intValue();
+ }
+
+ public boolean isBoolPermitted() {
+ return boolPermitted;
+ }
+
+ public void setBoolPermitted(boolean boolPermitted) {
+ this.boolPermitted = boolPermitted;
}
-
- public boolean hasBooleanValue() {
-
- switch(consttype.type) {
- case CodeConstants.TYPE_BOOLEAN:
- case CodeConstants.TYPE_CHAR:
- case CodeConstants.TYPE_BYTE:
- case CodeConstants.TYPE_BYTECHAR:
- case CodeConstants.TYPE_SHORT:
- case CodeConstants.TYPE_SHORTCHAR:
- case CodeConstants.TYPE_INT:
- Integer ival = (Integer)value;
- return ival.intValue() == 0 ||
- (DecompilerContext.getOption(IFernflowerPreferences.BOOLEAN_TRUE_ONE) && ival.intValue() == 1);
- }
-
- return false;
- }
-
- public boolean hasValueOne() {
-
- switch(consttype.type) {
- case CodeConstants.TYPE_BOOLEAN:
- case CodeConstants.TYPE_CHAR:
- case CodeConstants.TYPE_BYTE:
- case CodeConstants.TYPE_BYTECHAR:
- case CodeConstants.TYPE_SHORT:
- case CodeConstants.TYPE_SHORTCHAR:
- case CodeConstants.TYPE_INT:
- return ((Integer)value).intValue() == 1;
- case CodeConstants.TYPE_LONG:
- return ((Long)value).intValue() == 1;
- case CodeConstants.TYPE_DOUBLE:
- return ((Double)value).intValue() == 1;
- case CodeConstants.TYPE_FLOAT:
- return ((Float)value).intValue() == 1;
- }
-
- return false;
- }
-
- public static ConstExprent getZeroConstant(int type) {
-
- switch(type) {
- case CodeConstants.TYPE_INT:
- return new ConstExprent(VarType.VARTYPE_INT, new Integer(0));
- case CodeConstants.TYPE_LONG:
- return new ConstExprent(VarType.VARTYPE_LONG, new Long(0));
- case CodeConstants.TYPE_DOUBLE:
- return new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(0));
- case CodeConstants.TYPE_FLOAT:
- return new ConstExprent(VarType.VARTYPE_FLOAT, new Float(0));
- }
-
- throw new RuntimeException("Invalid argument!");
- }
-
- public VarType getConsttype() {
- return consttype;
- }
-
- public void setConsttype(VarType consttype) {
- this.consttype = consttype;
- }
-
- public Object getValue() {
- return value;
- }
-
- public int getIntValue() {
- return ((Integer)value).intValue();
- }
-
- public boolean isBoolPermitted() {
- return boolPermitted;
- }
-
- public void setBoolPermitted(boolean boolPermitted) {
- this.boolPermitted = boolPermitted;
- }
-
-
-
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java
index ceaae30..e61388d 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java
@@ -1,25 +1,23 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
@@ -27,123 +25,127 @@ import org.jetbrains.java.decompiler.struct.attr.StructExceptionsAttribute;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.List;
+
public class ExitExprent extends Exprent {
-
- public static final int EXIT_RETURN = 0;
- public static final int EXIT_THROW = 1;
-
- // return or throw statement
- private int exittype;
-
- private Exprent value;
-
- private VarType rettype;
-
- {
- this.type = EXPRENT_EXIT;
- }
-
- public ExitExprent(int exittype, Exprent value, VarType rettype) {
- this.exittype = exittype;
- this.value = value;
- this.rettype = rettype;
- }
-
- public Exprent copy() {
- return new ExitExprent(exittype, value==null?null:value.copy(), rettype);
- }
-
- public CheckTypesResult checkExprTypeBounds() {
- CheckTypesResult result = new CheckTypesResult();
-
- if(exittype == EXIT_RETURN && rettype.type!=CodeConstants.TYPE_VOID) {
- result.addMinTypeExprent(value, VarType.getMinTypeInFamily(rettype.type_family));
- result.addMaxTypeExprent(value, rettype);
- }
-
- return result;
- }
-
- public List<Exprent> getAllExprents() {
- List<Exprent> lst = new ArrayList<Exprent>();
- if(value != null) {
- lst.add(value);
- }
- return lst;
- }
-
- public String toJava(int indent) {
- if(exittype == EXIT_RETURN) {
- StringBuilder buffer = new StringBuilder();
-
- if(rettype.type!=CodeConstants.TYPE_VOID) {
- buffer.append(" ");
- ExprProcessor.getCastedExprent(value, rettype, buffer, indent, false);
- }
-
- return "return"+buffer.toString();
- } else {
-
- MethodWrapper meth = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
- ClassNode node = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE));
-
- if(meth != null && node != null) {
- StructExceptionsAttribute attr = (StructExceptionsAttribute)meth.methodStruct.getAttributes().getWithKey("Exceptions");
-
- if(attr != null) {
- String classname = null;
-
- for(int i=0;i<attr.getThrowsExceptions().size();i++) {
- String excclassname = attr.getExcClassname(i, node.classStruct.getPool());
- if("java/lang/Throwable".equals(excclassname)) {
- classname = excclassname;
- break;
- } else if("java/lang/Exception".equals(excclassname)) {
- classname = excclassname;
- }
- }
-
- if(classname != null) {
- VarType exctype = new VarType(classname, true);
-
- StringBuilder buffer = new StringBuilder();
- ExprProcessor.getCastedExprent(value, exctype, buffer, indent, false);
-
- return "throw "+buffer.toString();
- }
- }
- }
-
- return "throw "+value.toJava(indent);
- }
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof ExitExprent)) return false;
+
+ public static final int EXIT_RETURN = 0;
+ public static final int EXIT_THROW = 1;
+
+ // return or throw statement
+ private int exittype;
+
+ private Exprent value;
+
+ private VarType rettype;
+
+ {
+ this.type = EXPRENT_EXIT;
+ }
+
+ public ExitExprent(int exittype, Exprent value, VarType rettype) {
+ this.exittype = exittype;
+ this.value = value;
+ this.rettype = rettype;
+ }
+
+ public Exprent copy() {
+ return new ExitExprent(exittype, value == null ? null : value.copy(), rettype);
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ if (exittype == EXIT_RETURN && rettype.type != CodeConstants.TYPE_VOID) {
+ result.addMinTypeExprent(value, VarType.getMinTypeInFamily(rettype.type_family));
+ result.addMaxTypeExprent(value, rettype);
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ if (value != null) {
+ lst.add(value);
+ }
+ return lst;
+ }
+
+ public String toJava(int indent) {
+ if (exittype == EXIT_RETURN) {
+ StringBuilder buffer = new StringBuilder();
+
+ if (rettype.type != CodeConstants.TYPE_VOID) {
+ buffer.append(" ");
+ ExprProcessor.getCastedExprent(value, rettype, buffer, indent, false);
+ }
+
+ return "return" + buffer.toString();
+ }
+ else {
+
+ MethodWrapper meth = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+ ClassNode node = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE));
+
+ if (meth != null && node != null) {
+ StructExceptionsAttribute attr = (StructExceptionsAttribute)meth.methodStruct.getAttributes().getWithKey("Exceptions");
+
+ if (attr != null) {
+ String classname = null;
+
+ for (int i = 0; i < attr.getThrowsExceptions().size(); i++) {
+ String excclassname = attr.getExcClassname(i, node.classStruct.getPool());
+ if ("java/lang/Throwable".equals(excclassname)) {
+ classname = excclassname;
+ break;
+ }
+ else if ("java/lang/Exception".equals(excclassname)) {
+ classname = excclassname;
+ }
+ }
+
+ if (classname != null) {
+ VarType exctype = new VarType(classname, true);
+
+ StringBuilder buffer = new StringBuilder();
+ ExprProcessor.getCastedExprent(value, exctype, buffer, indent, false);
+
+ return "throw " + buffer.toString();
+ }
+ }
+ }
+
+ return "throw " + value.toJava(indent);
+ }
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof ExitExprent)) return false;
ExitExprent et = (ExitExprent)o;
- return exittype==et.getExittype() &&
- InterpreterUtil.equalObjects(value, et.getValue());
+ return exittype == et.getExittype() &&
+ InterpreterUtil.equalObjects(value, et.getValue());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == value) {
+ value = newexpr;
+ }
}
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(oldexpr == value) {
- value = newexpr;
- }
- }
-
- public int getExittype() {
- return exittype;
- }
-
- public Exprent getValue() {
- return value;
- }
-
- public VarType getRettype() {
- return rettype;
- }
+ public int getExittype() {
+ return exittype;
+ }
+
+ public Exprent getValue() {
+ return value;
+ }
+
+ public VarType getRettype() {
+ return rettype;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java
index 6e15170..63b3a5f 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java
@@ -1,134 +1,133 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
import org.jetbrains.java.decompiler.struct.gen.VarType;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
public class Exprent {
-
- public static final int MULTIPLE_USES = 1;
- public static final int SIDE_EFFECTS_FREE = 2;
- public static final int BOTH_FLAGS = 3;
-
-
- public static final int EXPRENT_ARRAY = 1;
- public static final int EXPRENT_ASSIGNMENT = 2;
- public static final int EXPRENT_CONST = 3;
- public static final int EXPRENT_EXIT = 4;
- public static final int EXPRENT_FIELD = 5;
- public static final int EXPRENT_FUNCTION = 6;
- public static final int EXPRENT_IF = 7;
- public static final int EXPRENT_INVOCATION = 8;
- public static final int EXPRENT_MONITOR = 9;
- public static final int EXPRENT_NEW = 10;
- public static final int EXPRENT_SWITCH = 11;
- public static final int EXPRENT_VAR = 12;
- public static final int EXPRENT_ANNOTATION = 13;
- public static final int EXPRENT_ASSERT = 14;
-
- public int type;
-
- public int id;
-
- {
- // set exprent id
- id = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.EXPRENT_COUNTER);
- }
-
- public int getPrecedence() {
- return 0; // the highest precedence
- }
-
- public VarType getExprType() {
- return VarType.VARTYPE_VOID;
- }
-
- public int getExprentUse() {
- return 0;
- }
-
- public CheckTypesResult checkExprTypeBounds() {
- return new CheckTypesResult();
- }
-
- public boolean containsExprent(Exprent exprent) {
-
- List<Exprent> listTemp = new ArrayList<Exprent>(getAllExprents(true));
- listTemp.add(this);
-
- for(Exprent lstexpr : listTemp) {
- if(lstexpr.equals(exprent)) {
- return true;
- }
- }
-
- return false;
- }
-
- public List<Exprent> getAllExprents(boolean recursive) {
- List<Exprent> lst = getAllExprents();
-
- if(recursive) {
- for(int i=lst.size()-1;i>=0;i--) {
- lst.addAll(lst.get(i).getAllExprents(true));
- }
- }
-
- return lst;
- }
-
- public Set<VarVersionPaar> getAllVariables() {
-
- HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>();
-
- List<Exprent> lstAllExprents = getAllExprents(true);
- lstAllExprents.add(this);
-
- for(Exprent expr : lstAllExprents) {
- if(expr.type == Exprent.EXPRENT_VAR) {
- set.add(new VarVersionPaar((VarExprent)expr));
- }
- }
-
- return set;
- }
-
- public List<Exprent> getAllExprents() {
- throw new RuntimeException("not implemented");
- }
-
- public Exprent copy() {
- throw new RuntimeException("not implemented");
- }
-
- public String toJava(int indent) {
- throw new RuntimeException("not implemented");
- }
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {}
-
-
+
+ public static final int MULTIPLE_USES = 1;
+ public static final int SIDE_EFFECTS_FREE = 2;
+ public static final int BOTH_FLAGS = 3;
+
+
+ public static final int EXPRENT_ARRAY = 1;
+ public static final int EXPRENT_ASSIGNMENT = 2;
+ public static final int EXPRENT_CONST = 3;
+ public static final int EXPRENT_EXIT = 4;
+ public static final int EXPRENT_FIELD = 5;
+ public static final int EXPRENT_FUNCTION = 6;
+ public static final int EXPRENT_IF = 7;
+ public static final int EXPRENT_INVOCATION = 8;
+ public static final int EXPRENT_MONITOR = 9;
+ public static final int EXPRENT_NEW = 10;
+ public static final int EXPRENT_SWITCH = 11;
+ public static final int EXPRENT_VAR = 12;
+ public static final int EXPRENT_ANNOTATION = 13;
+ public static final int EXPRENT_ASSERT = 14;
+
+ public int type;
+
+ public int id;
+
+ {
+ // set exprent id
+ id = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.EXPRENT_COUNTER);
+ }
+
+ public int getPrecedence() {
+ return 0; // the highest precedence
+ }
+
+ public VarType getExprType() {
+ return VarType.VARTYPE_VOID;
+ }
+
+ public int getExprentUse() {
+ return 0;
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ return new CheckTypesResult();
+ }
+
+ public boolean containsExprent(Exprent exprent) {
+
+ List<Exprent> listTemp = new ArrayList<Exprent>(getAllExprents(true));
+ listTemp.add(this);
+
+ for (Exprent lstexpr : listTemp) {
+ if (lstexpr.equals(exprent)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public List<Exprent> getAllExprents(boolean recursive) {
+ List<Exprent> lst = getAllExprents();
+
+ if (recursive) {
+ for (int i = lst.size() - 1; i >= 0; i--) {
+ lst.addAll(lst.get(i).getAllExprents(true));
+ }
+ }
+
+ return lst;
+ }
+
+ public Set<VarVersionPaar> getAllVariables() {
+
+ HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>();
+
+ List<Exprent> lstAllExprents = getAllExprents(true);
+ lstAllExprents.add(this);
+
+ for (Exprent expr : lstAllExprents) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ set.add(new VarVersionPaar((VarExprent)expr));
+ }
+ }
+
+ return set;
+ }
+
+ public List<Exprent> getAllExprents() {
+ throw new RuntimeException("not implemented");
+ }
+
+ public Exprent copy() {
+ throw new RuntimeException("not implemented");
+ }
+
+ public String toJava(int indent) {
+ throw new RuntimeException("not implemented");
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java
index 235ff6f..652f61f 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java
@@ -1,25 +1,23 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
@@ -29,167 +27,174 @@ import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.List;
+
public class FieldExprent extends Exprent {
- private String name;
-
- private String classname;
-
- private boolean isStatic;
-
- private Exprent instance;
-
- private FieldDescriptor descriptor;
-
- {
- this.type = EXPRENT_FIELD;
- }
-
- public FieldExprent(LinkConstant cn, Exprent instance) {
-
- this.instance = instance;
-
- if(instance == null) {
- isStatic = true;
- }
-
- classname = cn.classname;
- name = cn.elementname;
- descriptor = FieldDescriptor.parseDescriptor(cn.descriptor);
- }
-
- public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor) {
- this.name = name;
- this.classname = classname;
- this.isStatic = isStatic;
- this.instance = instance;
- this.descriptor = descriptor;
- }
-
- public VarType getExprType() {
- return descriptor.type;
- }
-
- public int getExprentUse() {
- if(instance == null) {
- return Exprent.MULTIPLE_USES;
- } else {
- return instance.getExprentUse() & Exprent.MULTIPLE_USES;
- }
- }
-
- public List<Exprent> getAllExprents() {
- List<Exprent> lst = new ArrayList<Exprent>();
- if(instance != null) {
- lst.add(instance);
- }
- return lst;
- }
-
- public Exprent copy() {
- return new FieldExprent(name, classname, isStatic, instance==null?null:instance.copy(), descriptor);
- }
-
- public String toJava(int indent) {
- StringBuffer buf = new StringBuffer();
-
-
- if(isStatic) {
- ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
- if(node == null || !classname.equals(node.classStruct.qualifiedName)) {
- buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
- buf.append(".");
- }
- } else {
-
- String super_qualifier = null;
-
- if(instance != null && instance.type == Exprent.EXPRENT_VAR) {
- VarExprent instvar = (VarExprent)instance;
- VarVersionPaar varpaar = new VarVersionPaar(instvar);
-
- MethodWrapper current_meth = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
-
- if(current_meth != null) { // FIXME: remove
- String this_classname = current_meth.varproc.getThisvars().get(varpaar);
-
- if(this_classname != null) {
- if(!classname.equals(this_classname)) { // TODO: direct comparison to the super class?
- super_qualifier = this_classname;
- }
- }
- }
- }
-
- if(super_qualifier != null) {
- StructClass current_class = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE)).classStruct;
-
- if(!super_qualifier.equals(current_class.qualifiedName)) {
- buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(super_qualifier)));
- buf.append(".");
- }
- buf.append("super");
- } else {
- StringBuilder buff = new StringBuilder();
- boolean casted = ExprProcessor.getCastedExprent(instance, new VarType(CodeConstants.TYPE_OBJECT, 0, classname), buff, indent, true);
- String res = buff.toString();
-
- if(casted || instance.getPrecedence() > getPrecedence()) {
- res = "("+res+")";
- }
-
- buf.append(res);
- }
-
- if(buf.toString().equals(VarExprent.VAR_NAMELESS_ENCLOSURE)) { // FIXME: workaround for field access of an anonymous enclosing class. Find a better way.
- buf.setLength(0);
- } else {
- buf.append(".");
- }
- }
-
- buf.append(name);
-
- return buf.toString();
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof FieldExprent)) return false;
+ private String name;
+
+ private String classname;
+
+ private boolean isStatic;
+
+ private Exprent instance;
+
+ private FieldDescriptor descriptor;
+
+ {
+ this.type = EXPRENT_FIELD;
+ }
+
+ public FieldExprent(LinkConstant cn, Exprent instance) {
+
+ this.instance = instance;
+
+ if (instance == null) {
+ isStatic = true;
+ }
+
+ classname = cn.classname;
+ name = cn.elementname;
+ descriptor = FieldDescriptor.parseDescriptor(cn.descriptor);
+ }
+
+ public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor) {
+ this.name = name;
+ this.classname = classname;
+ this.isStatic = isStatic;
+ this.instance = instance;
+ this.descriptor = descriptor;
+ }
+
+ public VarType getExprType() {
+ return descriptor.type;
+ }
+
+ public int getExprentUse() {
+ if (instance == null) {
+ return Exprent.MULTIPLE_USES;
+ }
+ else {
+ return instance.getExprentUse() & Exprent.MULTIPLE_USES;
+ }
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ if (instance != null) {
+ lst.add(instance);
+ }
+ return lst;
+ }
+
+ public Exprent copy() {
+ return new FieldExprent(name, classname, isStatic, instance == null ? null : instance.copy(), descriptor);
+ }
+
+ public String toJava(int indent) {
+ StringBuffer buf = new StringBuffer();
+
+
+ if (isStatic) {
+ ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
+ if (node == null || !classname.equals(node.classStruct.qualifiedName)) {
+ buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
+ buf.append(".");
+ }
+ }
+ else {
+
+ String super_qualifier = null;
+
+ if (instance != null && instance.type == Exprent.EXPRENT_VAR) {
+ VarExprent instvar = (VarExprent)instance;
+ VarVersionPaar varpaar = new VarVersionPaar(instvar);
+
+ MethodWrapper current_meth = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+
+ if (current_meth != null) { // FIXME: remove
+ String this_classname = current_meth.varproc.getThisvars().get(varpaar);
+
+ if (this_classname != null) {
+ if (!classname.equals(this_classname)) { // TODO: direct comparison to the super class?
+ super_qualifier = this_classname;
+ }
+ }
+ }
+ }
+
+ if (super_qualifier != null) {
+ StructClass current_class = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE)).classStruct;
+
+ if (!super_qualifier.equals(current_class.qualifiedName)) {
+ buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(super_qualifier)));
+ buf.append(".");
+ }
+ buf.append("super");
+ }
+ else {
+ StringBuilder buff = new StringBuilder();
+ boolean casted = ExprProcessor.getCastedExprent(instance, new VarType(CodeConstants.TYPE_OBJECT, 0, classname), buff, indent, true);
+ String res = buff.toString();
+
+ if (casted || instance.getPrecedence() > getPrecedence()) {
+ res = "(" + res + ")";
+ }
+
+ buf.append(res);
+ }
+
+ if (buf.toString().equals(
+ VarExprent.VAR_NAMELESS_ENCLOSURE)) { // FIXME: workaround for field access of an anonymous enclosing class. Find a better way.
+ buf.setLength(0);
+ }
+ else {
+ buf.append(".");
+ }
+ }
+
+ buf.append(name);
+
+ return buf.toString();
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FieldExprent)) return false;
FieldExprent ft = (FieldExprent)o;
return InterpreterUtil.equalObjects(name, ft.getName()) &&
- InterpreterUtil.equalObjects(classname, ft.getClassname()) &&
- isStatic == ft.isStatic() &&
- InterpreterUtil.equalObjects(instance, ft.getInstance()) &&
- InterpreterUtil.equalObjects(descriptor, ft.getDescriptor());
+ InterpreterUtil.equalObjects(classname, ft.getClassname()) &&
+ isStatic == ft.isStatic() &&
+ InterpreterUtil.equalObjects(instance, ft.getInstance()) &&
+ InterpreterUtil.equalObjects(descriptor, ft.getDescriptor());
}
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(oldexpr == instance) {
- instance = newexpr;
- }
- }
-
- public String getClassname() {
- return classname;
- }
-
- public FieldDescriptor getDescriptor() {
- return descriptor;
- }
-
- public Exprent getInstance() {
- return instance;
- }
-
- public boolean isStatic() {
- return isStatic;
- }
-
- public String getName() {
- return name;
- }
-
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == instance) {
+ instance = newexpr;
+ }
+ }
+
+ public String getClassname() {
+ return classname;
+ }
+
+ public FieldDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ public Exprent getInstance() {
+ return instance;
+ }
+
+ public boolean isStatic() {
+ return isStatic;
+ }
+
+ public String getName() {
+ return name;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java
index e4c942f..305fd59 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java
@@ -1,24 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
@@ -26,560 +22,597 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.ListStack;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
public class FunctionExprent extends Exprent {
- public static final int FUNCTION_ADD = 0;
- public static final int FUNCTION_SUB = 1;
- public static final int FUNCTION_MUL = 2;
- public static final int FUNCTION_DIV = 3;
-
- public static final int FUNCTION_AND = 4;
- public static final int FUNCTION_OR = 5;
- public static final int FUNCTION_XOR = 6;
-
- public static final int FUNCTION_REM = 7;
-
- public static final int FUNCTION_SHL = 8;
- public static final int FUNCTION_SHR = 9;
- public static final int FUNCTION_USHR = 10;
-
- public static final int FUNCTION_BITNOT = 11;
- public static final int FUNCTION_BOOLNOT = 12;
- public static final int FUNCTION_NEG = 13;
-
- public final static int FUNCTION_I2L = 14;
- public final static int FUNCTION_I2F = 15;
- public final static int FUNCTION_I2D = 16;
- public final static int FUNCTION_L2I = 17;
- public final static int FUNCTION_L2F = 18;
- public final static int FUNCTION_L2D = 19;
- public final static int FUNCTION_F2I = 20;
- public final static int FUNCTION_F2L = 21;
- public final static int FUNCTION_F2D = 22;
- public final static int FUNCTION_D2I = 23;
- public final static int FUNCTION_D2L = 24;
- public final static int FUNCTION_D2F = 25;
- public final static int FUNCTION_I2B = 26;
- public final static int FUNCTION_I2C = 27;
- public final static int FUNCTION_I2S = 28;
-
- public final static int FUNCTION_CAST = 29;
- public final static int FUNCTION_INSTANCEOF = 30;
-
- public final static int FUNCTION_ARRAYLENGTH = 31;
-
- public final static int FUNCTION_IMM = 32;
- public final static int FUNCTION_MMI = 33;
-
- public final static int FUNCTION_IPP = 34;
- public final static int FUNCTION_PPI = 35;
-
- public final static int FUNCTION_IIF = 36;
-
- public final static int FUNCTION_LCMP = 37;
- public final static int FUNCTION_FCMPL = 38;
- public final static int FUNCTION_FCMPG = 39;
- public final static int FUNCTION_DCMPL = 40;
- public final static int FUNCTION_DCMPG = 41;
-
- public static final int FUNCTION_EQ = 42;
- public static final int FUNCTION_NE = 43;
- public static final int FUNCTION_LT = 44;
- public static final int FUNCTION_GE = 45;
- public static final int FUNCTION_GT = 46;
- public static final int FUNCTION_LE = 47;
-
- public static final int FUNCTION_CADD = 48;
- public static final int FUNCTION_COR = 49;
-
- public static final int FUNCTION_STRCONCAT = 50;
-
- private static final VarType[] types = new VarType[] {
- VarType.VARTYPE_LONG,
- VarType.VARTYPE_FLOAT,
- VarType.VARTYPE_DOUBLE,
- VarType.VARTYPE_INT,
- VarType.VARTYPE_FLOAT,
- VarType.VARTYPE_DOUBLE,
- VarType.VARTYPE_INT,
- VarType.VARTYPE_LONG,
- VarType.VARTYPE_DOUBLE,
- VarType.VARTYPE_INT,
- VarType.VARTYPE_LONG,
- VarType.VARTYPE_FLOAT,
- VarType.VARTYPE_BYTE,
- VarType.VARTYPE_CHAR,
- VarType.VARTYPE_SHORT
- };
-
- private static final String[] operators = new String[] {
- " + ",
- " - ",
- " * ",
- " / ",
- " & ",
- " | ",
- " ^ ",
- " % ",
- " << ",
- " >> ",
- " >>> ",
- " == ",
- " != ",
- " < ",
- " >= ",
- " > ",
- " <= ",
- " && ",
- " || ",
- " + "
- };
-
- private static final int[] precedence = new int[] {
- 3, // FUNCTION_ADD
- 3, // FUNCTION_SUB
- 2, // FUNCTION_MUL
- 2, // FUNCTION_DIV
- 7, // FUNCTION_AND
- 9, // FUNCTION_OR
- 8, // FUNCTION_XOR
- 2, // FUNCTION_REM
- 4, // FUNCTION_SHL
- 4, // FUNCTION_SHR
- 4, // FUNCTION_USHR
- 1, // FUNCTION_BITNOT
- 1, // FUNCTION_BOOLNOT
- 1, // FUNCTION_NEG
- 1, // FUNCTION_I2L
- 1, // FUNCTION_I2F
- 1, // FUNCTION_I2D
- 1, // FUNCTION_L2I
- 1, // FUNCTION_L2F
- 1, // FUNCTION_L2D
- 1, // FUNCTION_F2I
- 1, // FUNCTION_F2L
- 1, // FUNCTION_F2D
- 1, // FUNCTION_D2I
- 1, // FUNCTION_D2L
- 1, // FUNCTION_D2F
- 1, // FUNCTION_I2B
- 1, // FUNCTION_I2C
- 1, // FUNCTION_I2S
- 1, // FUNCTION_CAST
- 6, // FUNCTION_INSTANCEOF
- 0, // FUNCTION_ARRAYLENGTH
- 1, // FUNCTION_IMM
- 1, // FUNCTION_MMI
- 1, // FUNCTION_IPP
- 1, // FUNCTION_PPI
- 12, // FUNCTION_IFF
- -1, // FUNCTION_LCMP
- -1, // FUNCTION_FCMPL
- -1, // FUNCTION_FCMPG
- -1, // FUNCTION_DCMPL
- -1, // FUNCTION_DCMPG
- 6, // FUNCTION_EQ = 41;
- 6, // FUNCTION_NE = 42;
- 5, // FUNCTION_LT = 43;
- 5, // FUNCTION_GE = 44;
- 5, // FUNCTION_GT = 45;
- 5, // FUNCTION_LE = 46;
- 10, // FUNCTION_CADD = 47;
- 11, // FUNCTION_COR = 48;
- 3 // FUNCTION_STRCONCAT = 49;
- };
-
- private static final HashSet<Integer> associativity = new HashSet<Integer>(Arrays.asList(new Integer[]{FUNCTION_ADD, FUNCTION_MUL, FUNCTION_AND,
- FUNCTION_OR, FUNCTION_XOR, FUNCTION_CADD, FUNCTION_COR, FUNCTION_STRCONCAT}));
-
- private int functype;
-
- private VarType implicitType;
-
- private List<Exprent> lstOperands = new ArrayList<Exprent>();
-
- {
- this.type = EXPRENT_FUNCTION;
- }
-
- public FunctionExprent(int functype, ListStack<Exprent> stack) {
- this.functype = functype;
- if(functype>=FUNCTION_BITNOT && functype<=FUNCTION_PPI && functype!=FUNCTION_CAST
- && functype!=FUNCTION_INSTANCEOF) {
- lstOperands.add(stack.pop());
- } else if(functype == FUNCTION_IIF) {
- throw new RuntimeException("no direct instantiation possible");
- } else {
- Exprent expr = stack.pop();
- lstOperands.add(stack.pop());
- lstOperands.add(expr);
- }
- }
-
- public FunctionExprent(int functype, List<Exprent> operands) {
- this.functype = functype;
- this.lstOperands = operands;
- }
-
- public VarType getExprType() {
- VarType exprType = null;
-
- if(functype <= FUNCTION_NEG || functype == FUNCTION_IPP || functype == FUNCTION_PPI
- || functype == FUNCTION_IMM || functype == FUNCTION_MMI) {
-
- VarType type1 = lstOperands.get(0).getExprType();
- VarType type2 = null;
- if(lstOperands.size() > 1) {
- type2 = lstOperands.get(1).getExprType();
- }
-
- switch(functype) {
- case FUNCTION_IMM:
- case FUNCTION_MMI:
- case FUNCTION_IPP:
- case FUNCTION_PPI:
- exprType = implicitType;
- break;
- case FUNCTION_BOOLNOT:
- exprType = VarType.VARTYPE_BOOLEAN;
- break;
- case FUNCTION_SHL:
- case FUNCTION_SHR:
- case FUNCTION_USHR:
- case FUNCTION_BITNOT:
- case FUNCTION_NEG:
- exprType = getMaxVarType(new VarType[]{type1});
- break;
- case FUNCTION_ADD:
- case FUNCTION_SUB:
- case FUNCTION_MUL:
- case FUNCTION_DIV:
- case FUNCTION_REM:
- exprType = getMaxVarType(new VarType[]{type1, type2});
- break;
- case FUNCTION_AND:
- case FUNCTION_OR:
- case FUNCTION_XOR:
- if(type1.type == CodeConstants.TYPE_BOOLEAN & type2.type == CodeConstants.TYPE_BOOLEAN) {
- exprType = VarType.VARTYPE_BOOLEAN;
- } else {
- exprType = getMaxVarType(new VarType[]{type1, type2});
- }
- }
- } else if(functype == FUNCTION_CAST){
- exprType = lstOperands.get(1).getExprType();
- } else if(functype == FUNCTION_IIF){
- Exprent param1 = lstOperands.get(1);
- Exprent param2 = lstOperands.get(2);
- VarType supertype = VarType.getCommonSupertype(param1.getExprType(), param2.getExprType());
-
- if(param1.type == Exprent.EXPRENT_CONST && param2.type == Exprent.EXPRENT_CONST &&
- supertype.type != CodeConstants.TYPE_BOOLEAN && VarType.VARTYPE_INT.isSuperset(supertype)) {
- exprType = VarType.VARTYPE_INT;
- } else {
- exprType = supertype;
- }
- } else if(functype == FUNCTION_STRCONCAT){
- exprType = VarType.VARTYPE_STRING;
- } else if(functype >= FUNCTION_EQ){
- exprType = VarType.VARTYPE_BOOLEAN;
- } else if(functype == FUNCTION_INSTANCEOF) {
- exprType = VarType.VARTYPE_BOOLEAN;
- } else if(functype >= FUNCTION_ARRAYLENGTH) {
- exprType = VarType.VARTYPE_INT;
- } else {
- exprType = types[functype - FUNCTION_I2L];
- }
-
- return exprType;
- }
-
- public int getExprentUse() {
-
- if(functype >= FUNCTION_IMM && functype <= FUNCTION_PPI) {
- return 0;
- } else {
- int ret = Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE;
- for(Exprent expr: lstOperands) {
- ret &= expr.getExprentUse();
- }
- return ret;
- }
- }
-
- public CheckTypesResult checkExprTypeBounds() {
- CheckTypesResult result = new CheckTypesResult();
-
- Exprent param1 = lstOperands.get(0);
- VarType type1 = param1.getExprType();
- Exprent param2 = null;
- VarType type2 = null;
-
- if(lstOperands.size() > 1) {
- param2 = lstOperands.get(1);
- type2 = param2.getExprType();
- }
-
- switch(functype) {
- case FUNCTION_IIF:
- VarType supertype = getExprType();
- if(supertype == null) {
- supertype = getExprType();
- }
- result.addMinTypeExprent(param1, VarType.VARTYPE_BOOLEAN);
- result.addMinTypeExprent(param2, VarType.getMinTypeInFamily(supertype.type_family));
- result.addMinTypeExprent(lstOperands.get(2), VarType.getMinTypeInFamily(supertype.type_family));
- break;
- case FUNCTION_I2L:
- case FUNCTION_I2F:
- case FUNCTION_I2D:
- case FUNCTION_I2B:
- case FUNCTION_I2C:
- case FUNCTION_I2S:
- result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
- result.addMaxTypeExprent(param1, VarType.VARTYPE_INT);
- break;
- case FUNCTION_IMM:
- case FUNCTION_IPP:
- case FUNCTION_MMI:
- case FUNCTION_PPI:
- result.addMinTypeExprent(param1, implicitType);
- result.addMaxTypeExprent(param1, implicitType);
- break;
- case FUNCTION_ADD:
- case FUNCTION_SUB:
- case FUNCTION_MUL:
- case FUNCTION_DIV:
- case FUNCTION_REM:
- case FUNCTION_SHL:
- case FUNCTION_SHR:
- case FUNCTION_USHR:
- case FUNCTION_LT:
- case FUNCTION_GE:
- case FUNCTION_GT:
- case FUNCTION_LE:
- result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR);
- case FUNCTION_BITNOT:
- // case FUNCTION_BOOLNOT:
- case FUNCTION_NEG:
- result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
- break;
- case FUNCTION_AND:
- case FUNCTION_OR:
- case FUNCTION_XOR:
- case FUNCTION_EQ:
- case FUNCTION_NE:
- {
- if(type1.type == CodeConstants.TYPE_BOOLEAN) {
-
- if(type2.isStrictSuperset(type1)) {
-
- result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
-
- } else { // both are booleans
-
- boolean param1_false_boolean = type1.isFalseBoolean() || (param1.type == Exprent.EXPRENT_CONST && !((ConstExprent)param1).hasBooleanValue());
- boolean param2_false_boolean = type1.isFalseBoolean() || (param2.type == Exprent.EXPRENT_CONST && !((ConstExprent)param2).hasBooleanValue());
-
- if(param1_false_boolean || param2_false_boolean) {
- result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
- result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR);
- }
- }
-
- } else if(type2.type == CodeConstants.TYPE_BOOLEAN) {
-
- if(type1.isStrictSuperset(type2)) {
- result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR);
- }
- }
- }
- }
-
- return result;
- }
-
- public List<Exprent> getAllExprents() {
- List<Exprent> lst = new ArrayList<Exprent>();
- lst.addAll(lstOperands);
- return lst;
- }
-
- public Exprent copy() {
- List<Exprent> lst = new ArrayList<Exprent>();
- for(Exprent expr: lstOperands) {
- lst.add(expr.copy());
- }
- FunctionExprent func = new FunctionExprent(functype, lst);
- func.setImplicitType(implicitType);
-
- return func;
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof FunctionExprent)) return false;
+ public static final int FUNCTION_ADD = 0;
+ public static final int FUNCTION_SUB = 1;
+ public static final int FUNCTION_MUL = 2;
+ public static final int FUNCTION_DIV = 3;
+
+ public static final int FUNCTION_AND = 4;
+ public static final int FUNCTION_OR = 5;
+ public static final int FUNCTION_XOR = 6;
+
+ public static final int FUNCTION_REM = 7;
+
+ public static final int FUNCTION_SHL = 8;
+ public static final int FUNCTION_SHR = 9;
+ public static final int FUNCTION_USHR = 10;
+
+ public static final int FUNCTION_BITNOT = 11;
+ public static final int FUNCTION_BOOLNOT = 12;
+ public static final int FUNCTION_NEG = 13;
+
+ public final static int FUNCTION_I2L = 14;
+ public final static int FUNCTION_I2F = 15;
+ public final static int FUNCTION_I2D = 16;
+ public final static int FUNCTION_L2I = 17;
+ public final static int FUNCTION_L2F = 18;
+ public final static int FUNCTION_L2D = 19;
+ public final static int FUNCTION_F2I = 20;
+ public final static int FUNCTION_F2L = 21;
+ public final static int FUNCTION_F2D = 22;
+ public final static int FUNCTION_D2I = 23;
+ public final static int FUNCTION_D2L = 24;
+ public final static int FUNCTION_D2F = 25;
+ public final static int FUNCTION_I2B = 26;
+ public final static int FUNCTION_I2C = 27;
+ public final static int FUNCTION_I2S = 28;
+
+ public final static int FUNCTION_CAST = 29;
+ public final static int FUNCTION_INSTANCEOF = 30;
+
+ public final static int FUNCTION_ARRAYLENGTH = 31;
+
+ public final static int FUNCTION_IMM = 32;
+ public final static int FUNCTION_MMI = 33;
+
+ public final static int FUNCTION_IPP = 34;
+ public final static int FUNCTION_PPI = 35;
+
+ public final static int FUNCTION_IIF = 36;
+
+ public final static int FUNCTION_LCMP = 37;
+ public final static int FUNCTION_FCMPL = 38;
+ public final static int FUNCTION_FCMPG = 39;
+ public final static int FUNCTION_DCMPL = 40;
+ public final static int FUNCTION_DCMPG = 41;
+
+ public static final int FUNCTION_EQ = 42;
+ public static final int FUNCTION_NE = 43;
+ public static final int FUNCTION_LT = 44;
+ public static final int FUNCTION_GE = 45;
+ public static final int FUNCTION_GT = 46;
+ public static final int FUNCTION_LE = 47;
+
+ public static final int FUNCTION_CADD = 48;
+ public static final int FUNCTION_COR = 49;
+
+ public static final int FUNCTION_STRCONCAT = 50;
+
+ private static final VarType[] types = new VarType[]{
+ VarType.VARTYPE_LONG,
+ VarType.VARTYPE_FLOAT,
+ VarType.VARTYPE_DOUBLE,
+ VarType.VARTYPE_INT,
+ VarType.VARTYPE_FLOAT,
+ VarType.VARTYPE_DOUBLE,
+ VarType.VARTYPE_INT,
+ VarType.VARTYPE_LONG,
+ VarType.VARTYPE_DOUBLE,
+ VarType.VARTYPE_INT,
+ VarType.VARTYPE_LONG,
+ VarType.VARTYPE_FLOAT,
+ VarType.VARTYPE_BYTE,
+ VarType.VARTYPE_CHAR,
+ VarType.VARTYPE_SHORT
+ };
+
+ private static final String[] operators = new String[]{
+ " + ",
+ " - ",
+ " * ",
+ " / ",
+ " & ",
+ " | ",
+ " ^ ",
+ " % ",
+ " << ",
+ " >> ",
+ " >>> ",
+ " == ",
+ " != ",
+ " < ",
+ " >= ",
+ " > ",
+ " <= ",
+ " && ",
+ " || ",
+ " + "
+ };
+
+ private static final int[] precedence = new int[]{
+ 3, // FUNCTION_ADD
+ 3, // FUNCTION_SUB
+ 2, // FUNCTION_MUL
+ 2, // FUNCTION_DIV
+ 7, // FUNCTION_AND
+ 9, // FUNCTION_OR
+ 8, // FUNCTION_XOR
+ 2, // FUNCTION_REM
+ 4, // FUNCTION_SHL
+ 4, // FUNCTION_SHR
+ 4, // FUNCTION_USHR
+ 1, // FUNCTION_BITNOT
+ 1, // FUNCTION_BOOLNOT
+ 1, // FUNCTION_NEG
+ 1, // FUNCTION_I2L
+ 1, // FUNCTION_I2F
+ 1, // FUNCTION_I2D
+ 1, // FUNCTION_L2I
+ 1, // FUNCTION_L2F
+ 1, // FUNCTION_L2D
+ 1, // FUNCTION_F2I
+ 1, // FUNCTION_F2L
+ 1, // FUNCTION_F2D
+ 1, // FUNCTION_D2I
+ 1, // FUNCTION_D2L
+ 1, // FUNCTION_D2F
+ 1, // FUNCTION_I2B
+ 1, // FUNCTION_I2C
+ 1, // FUNCTION_I2S
+ 1, // FUNCTION_CAST
+ 6, // FUNCTION_INSTANCEOF
+ 0, // FUNCTION_ARRAYLENGTH
+ 1, // FUNCTION_IMM
+ 1, // FUNCTION_MMI
+ 1, // FUNCTION_IPP
+ 1, // FUNCTION_PPI
+ 12, // FUNCTION_IFF
+ -1, // FUNCTION_LCMP
+ -1, // FUNCTION_FCMPL
+ -1, // FUNCTION_FCMPG
+ -1, // FUNCTION_DCMPL
+ -1, // FUNCTION_DCMPG
+ 6, // FUNCTION_EQ = 41;
+ 6, // FUNCTION_NE = 42;
+ 5, // FUNCTION_LT = 43;
+ 5, // FUNCTION_GE = 44;
+ 5, // FUNCTION_GT = 45;
+ 5, // FUNCTION_LE = 46;
+ 10, // FUNCTION_CADD = 47;
+ 11, // FUNCTION_COR = 48;
+ 3 // FUNCTION_STRCONCAT = 49;
+ };
+
+ private static final HashSet<Integer> associativity =
+ new HashSet<Integer>(Arrays.asList(new Integer[]{FUNCTION_ADD, FUNCTION_MUL, FUNCTION_AND,
+ FUNCTION_OR, FUNCTION_XOR, FUNCTION_CADD, FUNCTION_COR, FUNCTION_STRCONCAT}));
+
+ private int functype;
+
+ private VarType implicitType;
+
+ private List<Exprent> lstOperands = new ArrayList<Exprent>();
+
+ {
+ this.type = EXPRENT_FUNCTION;
+ }
+
+ public FunctionExprent(int functype, ListStack<Exprent> stack) {
+ this.functype = functype;
+ if (functype >= FUNCTION_BITNOT && functype <= FUNCTION_PPI && functype != FUNCTION_CAST
+ && functype != FUNCTION_INSTANCEOF) {
+ lstOperands.add(stack.pop());
+ }
+ else if (functype == FUNCTION_IIF) {
+ throw new RuntimeException("no direct instantiation possible");
+ }
+ else {
+ Exprent expr = stack.pop();
+ lstOperands.add(stack.pop());
+ lstOperands.add(expr);
+ }
+ }
+
+ public FunctionExprent(int functype, List<Exprent> operands) {
+ this.functype = functype;
+ this.lstOperands = operands;
+ }
+
+ public VarType getExprType() {
+ VarType exprType = null;
+
+ if (functype <= FUNCTION_NEG || functype == FUNCTION_IPP || functype == FUNCTION_PPI
+ || functype == FUNCTION_IMM || functype == FUNCTION_MMI) {
+
+ VarType type1 = lstOperands.get(0).getExprType();
+ VarType type2 = null;
+ if (lstOperands.size() > 1) {
+ type2 = lstOperands.get(1).getExprType();
+ }
+
+ switch (functype) {
+ case FUNCTION_IMM:
+ case FUNCTION_MMI:
+ case FUNCTION_IPP:
+ case FUNCTION_PPI:
+ exprType = implicitType;
+ break;
+ case FUNCTION_BOOLNOT:
+ exprType = VarType.VARTYPE_BOOLEAN;
+ break;
+ case FUNCTION_SHL:
+ case FUNCTION_SHR:
+ case FUNCTION_USHR:
+ case FUNCTION_BITNOT:
+ case FUNCTION_NEG:
+ exprType = getMaxVarType(new VarType[]{type1});
+ break;
+ case FUNCTION_ADD:
+ case FUNCTION_SUB:
+ case FUNCTION_MUL:
+ case FUNCTION_DIV:
+ case FUNCTION_REM:
+ exprType = getMaxVarType(new VarType[]{type1, type2});
+ break;
+ case FUNCTION_AND:
+ case FUNCTION_OR:
+ case FUNCTION_XOR:
+ if (type1.type == CodeConstants.TYPE_BOOLEAN & type2.type == CodeConstants.TYPE_BOOLEAN) {
+ exprType = VarType.VARTYPE_BOOLEAN;
+ }
+ else {
+ exprType = getMaxVarType(new VarType[]{type1, type2});
+ }
+ }
+ }
+ else if (functype == FUNCTION_CAST) {
+ exprType = lstOperands.get(1).getExprType();
+ }
+ else if (functype == FUNCTION_IIF) {
+ Exprent param1 = lstOperands.get(1);
+ Exprent param2 = lstOperands.get(2);
+ VarType supertype = VarType.getCommonSupertype(param1.getExprType(), param2.getExprType());
+
+ if (param1.type == Exprent.EXPRENT_CONST && param2.type == Exprent.EXPRENT_CONST &&
+ supertype.type != CodeConstants.TYPE_BOOLEAN && VarType.VARTYPE_INT.isSuperset(supertype)) {
+ exprType = VarType.VARTYPE_INT;
+ }
+ else {
+ exprType = supertype;
+ }
+ }
+ else if (functype == FUNCTION_STRCONCAT) {
+ exprType = VarType.VARTYPE_STRING;
+ }
+ else if (functype >= FUNCTION_EQ) {
+ exprType = VarType.VARTYPE_BOOLEAN;
+ }
+ else if (functype == FUNCTION_INSTANCEOF) {
+ exprType = VarType.VARTYPE_BOOLEAN;
+ }
+ else if (functype >= FUNCTION_ARRAYLENGTH) {
+ exprType = VarType.VARTYPE_INT;
+ }
+ else {
+ exprType = types[functype - FUNCTION_I2L];
+ }
+
+ return exprType;
+ }
+
+ public int getExprentUse() {
+
+ if (functype >= FUNCTION_IMM && functype <= FUNCTION_PPI) {
+ return 0;
+ }
+ else {
+ int ret = Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE;
+ for (Exprent expr : lstOperands) {
+ ret &= expr.getExprentUse();
+ }
+ return ret;
+ }
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ Exprent param1 = lstOperands.get(0);
+ VarType type1 = param1.getExprType();
+ Exprent param2 = null;
+ VarType type2 = null;
+
+ if (lstOperands.size() > 1) {
+ param2 = lstOperands.get(1);
+ type2 = param2.getExprType();
+ }
+
+ switch (functype) {
+ case FUNCTION_IIF:
+ VarType supertype = getExprType();
+ if (supertype == null) {
+ supertype = getExprType();
+ }
+ result.addMinTypeExprent(param1, VarType.VARTYPE_BOOLEAN);
+ result.addMinTypeExprent(param2, VarType.getMinTypeInFamily(supertype.type_family));
+ result.addMinTypeExprent(lstOperands.get(2), VarType.getMinTypeInFamily(supertype.type_family));
+ break;
+ case FUNCTION_I2L:
+ case FUNCTION_I2F:
+ case FUNCTION_I2D:
+ case FUNCTION_I2B:
+ case FUNCTION_I2C:
+ case FUNCTION_I2S:
+ result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
+ result.addMaxTypeExprent(param1, VarType.VARTYPE_INT);
+ break;
+ case FUNCTION_IMM:
+ case FUNCTION_IPP:
+ case FUNCTION_MMI:
+ case FUNCTION_PPI:
+ result.addMinTypeExprent(param1, implicitType);
+ result.addMaxTypeExprent(param1, implicitType);
+ break;
+ case FUNCTION_ADD:
+ case FUNCTION_SUB:
+ case FUNCTION_MUL:
+ case FUNCTION_DIV:
+ case FUNCTION_REM:
+ case FUNCTION_SHL:
+ case FUNCTION_SHR:
+ case FUNCTION_USHR:
+ case FUNCTION_LT:
+ case FUNCTION_GE:
+ case FUNCTION_GT:
+ case FUNCTION_LE:
+ result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR);
+ case FUNCTION_BITNOT:
+ // case FUNCTION_BOOLNOT:
+ case FUNCTION_NEG:
+ result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
+ break;
+ case FUNCTION_AND:
+ case FUNCTION_OR:
+ case FUNCTION_XOR:
+ case FUNCTION_EQ:
+ case FUNCTION_NE: {
+ if (type1.type == CodeConstants.TYPE_BOOLEAN) {
+
+ if (type2.isStrictSuperset(type1)) {
+
+ result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
+ }
+ else { // both are booleans
+
+ boolean param1_false_boolean =
+ type1.isFalseBoolean() || (param1.type == Exprent.EXPRENT_CONST && !((ConstExprent)param1).hasBooleanValue());
+ boolean param2_false_boolean =
+ type1.isFalseBoolean() || (param2.type == Exprent.EXPRENT_CONST && !((ConstExprent)param2).hasBooleanValue());
+
+ if (param1_false_boolean || param2_false_boolean) {
+ result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
+ result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR);
+ }
+ }
+ }
+ else if (type2.type == CodeConstants.TYPE_BOOLEAN) {
+
+ if (type1.isStrictSuperset(type2)) {
+ result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.addAll(lstOperands);
+ return lst;
+ }
+
+ public Exprent copy() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ for (Exprent expr : lstOperands) {
+ lst.add(expr.copy());
+ }
+ FunctionExprent func = new FunctionExprent(functype, lst);
+ func.setImplicitType(implicitType);
+
+ return func;
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FunctionExprent)) return false;
FunctionExprent fe = (FunctionExprent)o;
- return functype==fe.getFunctype() &&
- InterpreterUtil.equalLists(lstOperands, fe.getLstOperands()); // TODO: order of operands insignificant
+ return functype == fe.getFunctype() &&
+ InterpreterUtil.equalLists(lstOperands, fe.getLstOperands()); // TODO: order of operands insignificant
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ for (int i = 0; i < lstOperands.size(); i++) {
+ if (oldexpr == lstOperands.get(i)) {
+ lstOperands.set(i, newexpr);
+ }
+ }
+ }
+
+ public String toJava(int indent) {
+
+ if (functype <= FUNCTION_USHR) {
+ return wrapOperandString(lstOperands.get(0), false, indent) + operators[functype] +
+ wrapOperandString(lstOperands.get(1), true, indent);
+ }
+
+ if (functype >= FUNCTION_EQ) {
+ return wrapOperandString(lstOperands.get(0), false, indent) + operators[functype - FUNCTION_EQ + 11] +
+ wrapOperandString(lstOperands.get(1), true, indent);
+ }
+
+ switch (functype) {
+ case FUNCTION_BITNOT:
+ return "~" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_BOOLNOT:
+ return "!" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_NEG:
+ return "-" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_CAST:
+ return "(" + lstOperands.get(1).toJava(indent) + ")" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_ARRAYLENGTH:
+ Exprent arr = lstOperands.get(0);
+
+ String res = wrapOperandString(arr, false, indent);
+ if (arr.getExprType().arraydim == 0) {
+ VarType objarr = VarType.VARTYPE_OBJECT.copy();
+ objarr.arraydim = 1; // type family does not change
+
+ res = "((" + ExprProcessor.getCastTypeName(objarr) + ")" + res + ")";
+ }
+ return res + ".length";
+ case FUNCTION_IIF:
+ return wrapOperandString(lstOperands.get(0), true, indent) + "?" + wrapOperandString(lstOperands.get(1), true, indent) + ":" +
+ wrapOperandString(lstOperands.get(2), true, indent);
+ case FUNCTION_IPP:
+ return wrapOperandString(lstOperands.get(0), true, indent) + "++";
+ case FUNCTION_PPI:
+ return "++" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_IMM:
+ return wrapOperandString(lstOperands.get(0), true, indent) + "--";
+ case FUNCTION_MMI:
+ return "--" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_INSTANCEOF:
+ return wrapOperandString(lstOperands.get(0), true, indent) + " instanceof " + wrapOperandString(lstOperands.get(1), true, indent);
+ case FUNCTION_LCMP: // shouldn't appear in the final code
+ return "__lcmp__(" +
+ wrapOperandString(lstOperands.get(0), true, indent) +
+ "," +
+ wrapOperandString(lstOperands.get(1), true, indent) +
+ ")";
+ case FUNCTION_FCMPL: // shouldn't appear in the final code
+ return "__fcmpl__(" +
+ wrapOperandString(lstOperands.get(0), true, indent) +
+ "," +
+ wrapOperandString(lstOperands.get(1), true, indent) +
+ ")";
+ case FUNCTION_FCMPG: // shouldn't appear in the final code
+ return "__fcmpg__(" +
+ wrapOperandString(lstOperands.get(0), true, indent) +
+ "," +
+ wrapOperandString(lstOperands.get(1), true, indent) +
+ ")";
+ case FUNCTION_DCMPL: // shouldn't appear in the final code
+ return "__dcmpl__(" +
+ wrapOperandString(lstOperands.get(0), true, indent) +
+ "," +
+ wrapOperandString(lstOperands.get(1), true, indent) +
+ ")";
+ case FUNCTION_DCMPG: // shouldn't appear in the final code
+ return "__dcmpg__(" +
+ wrapOperandString(lstOperands.get(0), true, indent) +
+ "," +
+ wrapOperandString(lstOperands.get(1), true, indent) +
+ ")";
+ }
+
+ if (functype <= FUNCTION_I2S) {
+ return "(" + ExprProcessor.getTypeName(types[functype - FUNCTION_I2L]) + ")" + wrapOperandString(lstOperands.get(0), true, indent);
+ }
+
+ // return "<unknown function>";
+ throw new RuntimeException("invalid function");
+ }
+
+ public int getPrecedence() {
+ return getPrecedence(functype);
+ }
+
+ public static int getPrecedence(int func) {
+ return precedence[func];
+ }
+
+ public VarType getSimpleCastType() {
+ return types[functype - FUNCTION_I2L];
+ }
+
+ private String wrapOperandString(Exprent expr, boolean eq, int indent) {
+
+ int myprec = getPrecedence();
+ int exprprec = expr.getPrecedence();
+
+ boolean parentheses = exprprec > myprec;
+ if (!parentheses && eq) {
+ parentheses = (exprprec == myprec);
+ if (parentheses) {
+ if (expr.type == Exprent.EXPRENT_FUNCTION &&
+ ((FunctionExprent)expr).getFunctype() == functype) {
+ parentheses = !associativity.contains(functype);
+ }
+ }
+ }
+
+ String res = expr.toJava(indent);
+
+ if (parentheses) {
+ res = "(" + res + ")";
+ }
+
+ return res;
+ }
+
+ private VarType getMaxVarType(VarType[] arr) {
+
+ int[] types = new int[]{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_LONG};
+ VarType[] vartypes = new VarType[]{VarType.VARTYPE_DOUBLE, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG};
+
+ for (int i = 0; i < types.length; i++) {
+ for (int j = 0; j < arr.length; j++) {
+ if (arr[j].type == types[i]) {
+ return vartypes[i];
+ }
+ }
+ }
+
+ return VarType.VARTYPE_INT;
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public int getFunctype() {
+ return functype;
+ }
+
+ public void setFunctype(int functype) {
+ this.functype = functype;
+ }
+
+ public List<Exprent> getLstOperands() {
+ return lstOperands;
+ }
+
+ public void setLstOperands(List<Exprent> lstOperands) {
+ this.lstOperands = lstOperands;
+ }
+
+ public VarType getImplicitType() {
+ return implicitType;
+ }
+
+ public void setImplicitType(VarType implicitType) {
+ this.implicitType = implicitType;
}
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- for(int i=0;i<lstOperands.size();i++) {
- if(oldexpr == lstOperands.get(i)) {
- lstOperands.set(i, newexpr);
- }
- }
- }
-
- public String toJava(int indent) {
-
- if(functype <= FUNCTION_USHR) {
- return wrapOperandString(lstOperands.get(0), false, indent)+operators[functype]+
- wrapOperandString(lstOperands.get(1), true, indent);
- }
-
- if(functype >= FUNCTION_EQ) {
- return wrapOperandString(lstOperands.get(0), false, indent)+operators[functype-FUNCTION_EQ+11]+
- wrapOperandString(lstOperands.get(1), true, indent);
- }
-
- switch(functype) {
- case FUNCTION_BITNOT:
- return "~"+wrapOperandString(lstOperands.get(0), true, indent);
- case FUNCTION_BOOLNOT:
- return "!"+wrapOperandString(lstOperands.get(0), true, indent);
- case FUNCTION_NEG:
- return "-"+wrapOperandString(lstOperands.get(0), true, indent);
- case FUNCTION_CAST:
- return "("+lstOperands.get(1).toJava(indent)+")"+wrapOperandString(lstOperands.get(0), true, indent);
- case FUNCTION_ARRAYLENGTH:
- Exprent arr = lstOperands.get(0);
-
- String res = wrapOperandString(arr, false, indent);
- if(arr.getExprType().arraydim == 0) {
- VarType objarr = VarType.VARTYPE_OBJECT.copy();
- objarr.arraydim = 1; // type family does not change
-
- res = "(("+ExprProcessor.getCastTypeName(objarr)+")"+res+")";
- }
- return res+".length";
- case FUNCTION_IIF:
- return wrapOperandString(lstOperands.get(0), true, indent)+"?"+wrapOperandString(lstOperands.get(1), true, indent)+":"+
- wrapOperandString(lstOperands.get(2), true, indent);
- case FUNCTION_IPP:
- return wrapOperandString(lstOperands.get(0), true, indent)+"++";
- case FUNCTION_PPI:
- return "++"+wrapOperandString(lstOperands.get(0), true, indent);
- case FUNCTION_IMM:
- return wrapOperandString(lstOperands.get(0), true, indent)+"--";
- case FUNCTION_MMI:
- return "--"+wrapOperandString(lstOperands.get(0), true, indent);
- case FUNCTION_INSTANCEOF:
- return wrapOperandString(lstOperands.get(0), true, indent)+" instanceof "+wrapOperandString(lstOperands.get(1), true, indent);
- case FUNCTION_LCMP: // shouldn't appear in the final code
- return "__lcmp__("+wrapOperandString(lstOperands.get(0), true, indent)+","+wrapOperandString(lstOperands.get(1), true, indent)+")";
- case FUNCTION_FCMPL: // shouldn't appear in the final code
- return "__fcmpl__("+wrapOperandString(lstOperands.get(0), true, indent)+","+wrapOperandString(lstOperands.get(1), true, indent)+")";
- case FUNCTION_FCMPG: // shouldn't appear in the final code
- return "__fcmpg__("+wrapOperandString(lstOperands.get(0), true, indent)+","+wrapOperandString(lstOperands.get(1), true, indent)+")";
- case FUNCTION_DCMPL: // shouldn't appear in the final code
- return "__dcmpl__("+wrapOperandString(lstOperands.get(0), true, indent)+","+wrapOperandString(lstOperands.get(1), true, indent)+")";
- case FUNCTION_DCMPG: // shouldn't appear in the final code
- return "__dcmpg__("+wrapOperandString(lstOperands.get(0), true, indent)+","+wrapOperandString(lstOperands.get(1), true, indent)+")";
- }
-
- if(functype <= FUNCTION_I2S) {
- return "("+ExprProcessor.getTypeName(types[functype - FUNCTION_I2L])+")"+wrapOperandString(lstOperands.get(0), true, indent);
- }
-
-// return "<unknown function>";
- throw new RuntimeException("invalid function");
- }
-
- public int getPrecedence() {
- return getPrecedence(functype);
- }
-
- public static int getPrecedence(int func) {
- return precedence[func];
- }
-
- public VarType getSimpleCastType() {
- return types[functype - FUNCTION_I2L];
- }
-
- private String wrapOperandString(Exprent expr, boolean eq, int indent) {
-
- int myprec = getPrecedence();
- int exprprec = expr.getPrecedence();
-
- boolean parentheses = exprprec > myprec;
- if(!parentheses && eq) {
- parentheses = (exprprec == myprec);
- if(parentheses) {
- if(expr.type == Exprent.EXPRENT_FUNCTION &&
- ((FunctionExprent)expr).getFunctype() == functype) {
- parentheses = !associativity.contains(functype);
- }
- }
- }
-
- String res = expr.toJava(indent);
-
- if(parentheses) {
- res = "("+res+")";
- }
-
- return res;
- }
-
- private VarType getMaxVarType(VarType[] arr) {
-
- int[] types = new int[] {CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_LONG};
- VarType[] vartypes = new VarType[] {VarType.VARTYPE_DOUBLE, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG};
-
- for(int i=0;i<types.length;i++) {
- for(int j=0;j<arr.length;j++) {
- if(arr[j].type == types[i]) {
- return vartypes[i];
- }
- }
- }
-
- return VarType.VARTYPE_INT;
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public int getFunctype() {
- return functype;
- }
-
- public void setFunctype(int functype) {
- this.functype = functype;
- }
-
- public List<Exprent> getLstOperands() {
- return lstOperands;
- }
-
- public void setLstOperands(List<Exprent> lstOperands) {
- this.lstOperands = lstOperands;
- }
-
- public VarType getImplicitType() {
- return implicitType;
- }
-
- public void setImplicitType(VarType implicitType) {
- this.implicitType = implicitType;
- }
-
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java
index 15e39ba..030fe9a 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java
@@ -1,146 +1,149 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.ListStack;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
public class IfExprent extends Exprent {
-
- public static final int IF_EQ = 0;
- public static final int IF_NE = 1;
- public static final int IF_LT = 2;
- public static final int IF_GE = 3;
- public static final int IF_GT = 4;
- public static final int IF_LE = 5;
-
- public static final int IF_NULL = 6;
- public static final int IF_NONNULL = 7;
-
- public static final int IF_ICMPEQ = 8;
- public static final int IF_ICMPNE = 9;
- public static final int IF_ICMPLT = 10;
- public static final int IF_ICMPGE = 11;
- public static final int IF_ICMPGT = 12;
- public static final int IF_ICMPLE = 13;
- public static final int IF_ACMPEQ = 14;
- public static final int IF_ACMPNE = 15;
-
- public static final int IF_CAND = 16;
- public static final int IF_COR = 17;
-
- public static final int IF_NOT = 18;
- public static final int IF_VALUE = 19;
-
- private static final int[] functypes = new int[] {
- FunctionExprent.FUNCTION_EQ,
- FunctionExprent.FUNCTION_NE,
- FunctionExprent.FUNCTION_LT,
- FunctionExprent.FUNCTION_GE,
- FunctionExprent.FUNCTION_GT,
- FunctionExprent.FUNCTION_LE,
- FunctionExprent.FUNCTION_EQ,
- FunctionExprent.FUNCTION_NE,
- FunctionExprent.FUNCTION_EQ,
- FunctionExprent.FUNCTION_NE,
- FunctionExprent.FUNCTION_LT,
- FunctionExprent.FUNCTION_GE,
- FunctionExprent.FUNCTION_GT,
- FunctionExprent.FUNCTION_LE,
- FunctionExprent.FUNCTION_EQ,
- FunctionExprent.FUNCTION_NE,
- FunctionExprent.FUNCTION_CADD,
- FunctionExprent.FUNCTION_COR,
- FunctionExprent.FUNCTION_BOOLNOT,
- -1
- };
-
- private Exprent condition;
-
- {
- this.type = EXPRENT_IF;
- }
-
- public IfExprent(int iftype, ListStack<Exprent> stack) {
-
- if(iftype <= IF_LE) {
- stack.push(new ConstExprent(0, true));
- } else if(iftype <= IF_NONNULL) {
- stack.push(new ConstExprent(VarType.VARTYPE_NULL, null));
- }
-
- if(iftype == IF_VALUE) {
- condition = stack.pop();
- } else {
- condition = new FunctionExprent(functypes[iftype], stack);
- }
- }
-
- private IfExprent(Exprent condition) {
- this.condition = condition;
- }
-
- public Exprent copy() {
- return new IfExprent(condition.copy());
- }
-
- public List<Exprent> getAllExprents() {
- List<Exprent> lst = new ArrayList<Exprent>();
- lst.add(condition);
- return lst;
- }
-
- public String toJava(int indent) {
- StringBuffer buf = new StringBuffer("if(");
- buf.append(condition.toJava(indent));
- buf.append(")");
-
- return buf.toString();
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof IfExprent)) return false;
+
+ public static final int IF_EQ = 0;
+ public static final int IF_NE = 1;
+ public static final int IF_LT = 2;
+ public static final int IF_GE = 3;
+ public static final int IF_GT = 4;
+ public static final int IF_LE = 5;
+
+ public static final int IF_NULL = 6;
+ public static final int IF_NONNULL = 7;
+
+ public static final int IF_ICMPEQ = 8;
+ public static final int IF_ICMPNE = 9;
+ public static final int IF_ICMPLT = 10;
+ public static final int IF_ICMPGE = 11;
+ public static final int IF_ICMPGT = 12;
+ public static final int IF_ICMPLE = 13;
+ public static final int IF_ACMPEQ = 14;
+ public static final int IF_ACMPNE = 15;
+
+ public static final int IF_CAND = 16;
+ public static final int IF_COR = 17;
+
+ public static final int IF_NOT = 18;
+ public static final int IF_VALUE = 19;
+
+ private static final int[] functypes = new int[]{
+ FunctionExprent.FUNCTION_EQ,
+ FunctionExprent.FUNCTION_NE,
+ FunctionExprent.FUNCTION_LT,
+ FunctionExprent.FUNCTION_GE,
+ FunctionExprent.FUNCTION_GT,
+ FunctionExprent.FUNCTION_LE,
+ FunctionExprent.FUNCTION_EQ,
+ FunctionExprent.FUNCTION_NE,
+ FunctionExprent.FUNCTION_EQ,
+ FunctionExprent.FUNCTION_NE,
+ FunctionExprent.FUNCTION_LT,
+ FunctionExprent.FUNCTION_GE,
+ FunctionExprent.FUNCTION_GT,
+ FunctionExprent.FUNCTION_LE,
+ FunctionExprent.FUNCTION_EQ,
+ FunctionExprent.FUNCTION_NE,
+ FunctionExprent.FUNCTION_CADD,
+ FunctionExprent.FUNCTION_COR,
+ FunctionExprent.FUNCTION_BOOLNOT,
+ -1
+ };
+
+ private Exprent condition;
+
+ {
+ this.type = EXPRENT_IF;
+ }
+
+ public IfExprent(int iftype, ListStack<Exprent> stack) {
+
+ if (iftype <= IF_LE) {
+ stack.push(new ConstExprent(0, true));
+ }
+ else if (iftype <= IF_NONNULL) {
+ stack.push(new ConstExprent(VarType.VARTYPE_NULL, null));
+ }
+
+ if (iftype == IF_VALUE) {
+ condition = stack.pop();
+ }
+ else {
+ condition = new FunctionExprent(functypes[iftype], stack);
+ }
+ }
+
+ private IfExprent(Exprent condition) {
+ this.condition = condition;
+ }
+
+ public Exprent copy() {
+ return new IfExprent(condition.copy());
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.add(condition);
+ return lst;
+ }
+
+ public String toJava(int indent) {
+ StringBuffer buf = new StringBuffer("if(");
+ buf.append(condition.toJava(indent));
+ buf.append(")");
+
+ return buf.toString();
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof IfExprent)) return false;
IfExprent ie = (IfExprent)o;
return InterpreterUtil.equalObjects(condition, ie.getCondition());
}
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(oldexpr == condition) {
- condition = newexpr;
- }
- }
-
- public IfExprent negateIf() {
- condition = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
- Arrays.asList(new Exprent[]{condition}));
- return this;
- }
-
- public Exprent getCondition() {
- return condition;
- }
-
- public void setCondition(Exprent condition) {
- this.condition = condition;
- }
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == condition) {
+ condition = newexpr;
+ }
+ }
+
+ public IfExprent negateIf() {
+ condition = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
+ Arrays.asList(new Exprent[]{condition}));
+ return this;
+ }
+
+ public Exprent getCondition() {
+ return condition;
+ }
+
+ public void setCondition(Exprent condition) {
+ this.condition = condition;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java
index 835e96e..c19052d 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java
@@ -1,21 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.*;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.DecompilerContext;
@@ -33,472 +32,485 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.ListStack;
+import java.util.*;
+
public class InvocationExprent extends Exprent {
- public static final int INVOKE_SPECIAL = 1;
- public static final int INVOKE_VIRTUAL = 2;
- public static final int INVOKE_STATIC = 3;
- public static final int INVOKE_INTERFACE = 4;
- public static final int INVOKE_DYNAMIC = 5;
-
- public static final int TYP_GENERAL = 1;
- public static final int TYP_INIT = 2;
- public static final int TYP_CLINIT = 3;
-
- public static final int CONSTRUCTOR_NOT = 0;
- public static final int CONSTRUCTOR_THIS = 1;
- public static final int CONSTRUCTOR_SUPER = 2;
-
- private String name;
-
- private String classname;
-
- private boolean isStatic;
-
- private int functype = TYP_GENERAL;
-
- private Exprent instance;
-
- private MethodDescriptor descriptor;
-
- private String stringDescriptor;
-
- private String invoke_dynamic_classsuffix;
-
- private int invocationTyp = INVOKE_VIRTUAL;
-
- private List<Exprent> lstParameters = new ArrayList<Exprent>();
-
- {
- this.type = EXPRENT_INVOCATION;
- }
-
- public InvocationExprent() {}
-
- public InvocationExprent(int opcode, LinkConstant cn, ListStack<Exprent> stack, int dynamic_invokation_type) {
-
- name = cn.elementname;
- classname = cn.classname;
-
- switch(opcode) {
- case CodeConstants.opc_invokestatic:
- invocationTyp = INVOKE_STATIC;
- break;
- case CodeConstants.opc_invokespecial:
- invocationTyp = INVOKE_SPECIAL;
- break;
- case CodeConstants.opc_invokevirtual:
- invocationTyp = INVOKE_VIRTUAL;
- break;
- case CodeConstants.opc_invokeinterface:
- invocationTyp = INVOKE_INTERFACE;
- break;
- case CodeConstants.opc_invokedynamic:
- invocationTyp = INVOKE_DYNAMIC;
-
- classname = "java/lang/Class"; // dummy class name
- invoke_dynamic_classsuffix = "##Lambda_" + cn.index1 + "_" + cn.index2;
-
- }
-
- if("<init>".equals(name)) {
- functype = TYP_INIT;
- }else if("<clinit>".equals(name)) {
- functype = TYP_CLINIT;
- }
-
- stringDescriptor = cn.descriptor;
- descriptor = MethodDescriptor.parseDescriptor(cn.descriptor);
-
- for(int i=0;i<descriptor.params.length;i++) {
- lstParameters.add(0, stack.pop());
- }
-
- if(opcode == CodeConstants.opc_invokedynamic) {
- if(dynamic_invokation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic) {
- isStatic = true;
- } else {
- instance = lstParameters.get(0); // FIXME: remove the first parameter completely from the list. It's the object type for a virtual lambda method.
- }
- } else if(opcode == CodeConstants.opc_invokestatic) {
- isStatic = true;
- } else {
- instance = stack.pop();
- }
- }
-
- private InvocationExprent(InvocationExprent expr) {
- name = expr.getName();
- classname = expr.getClassname();
- isStatic = expr.isStatic();
- functype = expr.getFunctype();
- instance = expr.getInstance();
- if(instance != null) {
- instance = instance.copy();
- }
- invocationTyp = expr.getInvocationTyp();
- stringDescriptor = expr.getStringDescriptor();
- descriptor = expr.getDescriptor();
- lstParameters = new ArrayList<Exprent>(expr.getLstParameters());
- for(int i=0;i<lstParameters.size();i++) {
- lstParameters.set(i, lstParameters.get(i).copy());
- }
- }
-
-
- public VarType getExprType() {
- return descriptor.ret;
- }
-
- public CheckTypesResult checkExprTypeBounds() {
- CheckTypesResult result = new CheckTypesResult();
-
- for(int i=0;i<lstParameters.size();i++) {
- Exprent parameter = lstParameters.get(i);
-
- VarType leftType = descriptor.params[i];
-
- result.addMinTypeExprent(parameter, VarType.getMinTypeInFamily(leftType.type_family));
- result.addMaxTypeExprent(parameter, leftType);
- }
-
- return result;
- }
-
- public List<Exprent> getAllExprents() {
- List<Exprent> lst = new ArrayList<Exprent>();
- if(instance != null) {
- lst.add(instance);
- }
- lst.addAll(lstParameters);
- return lst;
- }
-
-
- public Exprent copy() {
- return new InvocationExprent(this);
- }
-
- public String toJava(int indent) {
- StringBuilder buf = new StringBuilder("");
-
- String super_qualifier = null;
- boolean isInstanceThis = false;
-
- if(invocationTyp == INVOKE_DYNAMIC) {
-// ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
-//
-// if(node != null) {
-// ClassNode lambda_node = DecompilerContext.getClassprocessor().getMapRootClasses().get(node.classStruct.qualifiedName + invoke_dynamic_classsuffix);
-// if(lambda_node != null) {
-//
-// String typename = ExprProcessor.getCastTypeName(lambda_node.anonimousClassType);
-//
-// StringWriter strwriter = new StringWriter();
-// BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
-//
-// ClassWriter clwriter = new ClassWriter();
-//
-// try {
-// bufstrwriter.write("new " + typename + "() {");
-// bufstrwriter.newLine();
-//
-//
-//
-// bufstrwriter.flush();
-// } catch(IOException ex) {
-// throw new RuntimeException(ex);
-// }
-//
-// buf.append(strwriter.toString());
-//
-// }
-// }
-
- } else if(isStatic) {
-
- ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
- if(node == null || !classname.equals(node.classStruct.qualifiedName)) {
- buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
- }
-
- } else {
-
- if(instance != null && instance.type == Exprent.EXPRENT_VAR) {
- VarExprent instvar = (VarExprent)instance;
- VarVersionPaar varpaar = new VarVersionPaar(instvar);
-
- VarProcessor vproc = instvar.getProcessor();
- if(vproc == null) {
- MethodWrapper current_meth = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
- if(current_meth != null) {
- vproc = current_meth.varproc;
- }
- }
-
- String this_classname = null;
- if(vproc != null) {
- this_classname = vproc.getThisvars().get(varpaar);
- }
-
- if(this_classname != null) {
- isInstanceThis = true;
-
- if(invocationTyp == INVOKE_SPECIAL) {
- if(!classname.equals(this_classname)) { // TODO: direct comparison to the super class?
- super_qualifier = this_classname;
- }
- }
- }
- }
-
- if(functype == TYP_GENERAL){
- if(super_qualifier != null) {
- StructClass current_class = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE)).classStruct;
-
- if(!super_qualifier.equals(current_class.qualifiedName)) {
- buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(super_qualifier)));
- buf.append(".");
- }
- buf.append("super");
- } else {
- String res = instance.toJava(indent);
-
- VarType rightType = instance.getExprType();
- VarType leftType = new VarType(CodeConstants.TYPE_OBJECT, 0, classname);
-
- if(rightType.equals(VarType.VARTYPE_OBJECT) && !leftType.equals(rightType)) {
- buf.append("(("+ExprProcessor.getCastTypeName(leftType)+")");
-
- if(instance.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
- res = "("+res+")";
- }
- buf.append(res+")");
- } else if(instance.getPrecedence() > getPrecedence()) {
- buf.append("("+res+")");
- } else {
- buf.append(res);
- }
- }
- }
- }
-
- switch(functype) {
- case TYP_GENERAL:
- if(VarExprent.VAR_NAMELESS_ENCLOSURE.equals(buf.toString())) {
- buf = new StringBuilder("");
- }
-
- if(buf.length() > 0) {
- buf.append(".");
- }
-
- buf.append(name);
- if(invocationTyp == INVOKE_DYNAMIC) {
- buf.append("<invokedynamic>");
- }
- buf.append("(");
-
- break;
- case TYP_CLINIT:
- throw new RuntimeException("Explicite invocation of <clinit>");
- case TYP_INIT:
- if(super_qualifier != null) {
- buf.append("super(");
- } else if(isInstanceThis) {
- buf.append("this(");
- } else {
- buf.append(instance.toJava(indent));
- buf.append(".<init>(");
-// throw new RuntimeException("Unrecognized invocation of <init>"); // FIXME: activate
- }
- }
-
- List<VarVersionPaar> sigFields = null;
+ public static final int INVOKE_SPECIAL = 1;
+ public static final int INVOKE_VIRTUAL = 2;
+ public static final int INVOKE_STATIC = 3;
+ public static final int INVOKE_INTERFACE = 4;
+ public static final int INVOKE_DYNAMIC = 5;
+
+ public static final int TYP_GENERAL = 1;
+ public static final int TYP_INIT = 2;
+ public static final int TYP_CLINIT = 3;
+
+ public static final int CONSTRUCTOR_NOT = 0;
+ public static final int CONSTRUCTOR_THIS = 1;
+ public static final int CONSTRUCTOR_SUPER = 2;
+
+ private String name;
+
+ private String classname;
+
+ private boolean isStatic;
+
+ private int functype = TYP_GENERAL;
+
+ private Exprent instance;
+
+ private MethodDescriptor descriptor;
+
+ private String stringDescriptor;
+
+ private String invoke_dynamic_classsuffix;
+
+ private int invocationTyp = INVOKE_VIRTUAL;
+
+ private List<Exprent> lstParameters = new ArrayList<Exprent>();
+
+ {
+ this.type = EXPRENT_INVOCATION;
+ }
+
+ public InvocationExprent() {
+ }
+
+ public InvocationExprent(int opcode, LinkConstant cn, ListStack<Exprent> stack, int dynamic_invokation_type) {
+
+ name = cn.elementname;
+ classname = cn.classname;
+
+ switch (opcode) {
+ case CodeConstants.opc_invokestatic:
+ invocationTyp = INVOKE_STATIC;
+ break;
+ case CodeConstants.opc_invokespecial:
+ invocationTyp = INVOKE_SPECIAL;
+ break;
+ case CodeConstants.opc_invokevirtual:
+ invocationTyp = INVOKE_VIRTUAL;
+ break;
+ case CodeConstants.opc_invokeinterface:
+ invocationTyp = INVOKE_INTERFACE;
+ break;
+ case CodeConstants.opc_invokedynamic:
+ invocationTyp = INVOKE_DYNAMIC;
+
+ classname = "java/lang/Class"; // dummy class name
+ invoke_dynamic_classsuffix = "##Lambda_" + cn.index1 + "_" + cn.index2;
+ }
+
+ if ("<init>".equals(name)) {
+ functype = TYP_INIT;
+ }
+ else if ("<clinit>".equals(name)) {
+ functype = TYP_CLINIT;
+ }
+
+ stringDescriptor = cn.descriptor;
+ descriptor = MethodDescriptor.parseDescriptor(cn.descriptor);
+
+ for (int i = 0; i < descriptor.params.length; i++) {
+ lstParameters.add(0, stack.pop());
+ }
+
+ if (opcode == CodeConstants.opc_invokedynamic) {
+ if (dynamic_invokation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic) {
+ isStatic = true;
+ }
+ else {
+ instance = lstParameters
+ .get(0); // FIXME: remove the first parameter completely from the list. It's the object type for a virtual lambda method.
+ }
+ }
+ else if (opcode == CodeConstants.opc_invokestatic) {
+ isStatic = true;
+ }
+ else {
+ instance = stack.pop();
+ }
+ }
+
+ private InvocationExprent(InvocationExprent expr) {
+ name = expr.getName();
+ classname = expr.getClassname();
+ isStatic = expr.isStatic();
+ functype = expr.getFunctype();
+ instance = expr.getInstance();
+ if (instance != null) {
+ instance = instance.copy();
+ }
+ invocationTyp = expr.getInvocationTyp();
+ stringDescriptor = expr.getStringDescriptor();
+ descriptor = expr.getDescriptor();
+ lstParameters = new ArrayList<Exprent>(expr.getLstParameters());
+ for (int i = 0; i < lstParameters.size(); i++) {
+ lstParameters.set(i, lstParameters.get(i).copy());
+ }
+ }
+
+
+ public VarType getExprType() {
+ return descriptor.ret;
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ for (int i = 0; i < lstParameters.size(); i++) {
+ Exprent parameter = lstParameters.get(i);
+
+ VarType leftType = descriptor.params[i];
+
+ result.addMinTypeExprent(parameter, VarType.getMinTypeInFamily(leftType.type_family));
+ result.addMaxTypeExprent(parameter, leftType);
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ if (instance != null) {
+ lst.add(instance);
+ }
+ lst.addAll(lstParameters);
+ return lst;
+ }
+
+
+ public Exprent copy() {
+ return new InvocationExprent(this);
+ }
+
+ public String toJava(int indent) {
+ StringBuilder buf = new StringBuilder("");
+
+ String super_qualifier = null;
+ boolean isInstanceThis = false;
+
+ if (invocationTyp == INVOKE_DYNAMIC) {
+ // ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
+ //
+ // if(node != null) {
+ // ClassNode lambda_node = DecompilerContext.getClassprocessor().getMapRootClasses().get(node.classStruct.qualifiedName + invoke_dynamic_classsuffix);
+ // if(lambda_node != null) {
+ //
+ // String typename = ExprProcessor.getCastTypeName(lambda_node.anonimousClassType);
+ //
+ // StringWriter strwriter = new StringWriter();
+ // BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+ //
+ // ClassWriter clwriter = new ClassWriter();
+ //
+ // try {
+ // bufstrwriter.write("new " + typename + "() {");
+ // bufstrwriter.newLine();
+ //
+ //
+ //
+ // bufstrwriter.flush();
+ // } catch(IOException ex) {
+ // throw new RuntimeException(ex);
+ // }
+ //
+ // buf.append(strwriter.toString());
+ //
+ // }
+ // }
+
+ }
+ else if (isStatic) {
+
+ ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
+ if (node == null || !classname.equals(node.classStruct.qualifiedName)) {
+ buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
+ }
+ }
+ else {
+
+ if (instance != null && instance.type == Exprent.EXPRENT_VAR) {
+ VarExprent instvar = (VarExprent)instance;
+ VarVersionPaar varpaar = new VarVersionPaar(instvar);
+
+ VarProcessor vproc = instvar.getProcessor();
+ if (vproc == null) {
+ MethodWrapper current_meth = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+ if (current_meth != null) {
+ vproc = current_meth.varproc;
+ }
+ }
+
+ String this_classname = null;
+ if (vproc != null) {
+ this_classname = vproc.getThisvars().get(varpaar);
+ }
+
+ if (this_classname != null) {
+ isInstanceThis = true;
+
+ if (invocationTyp == INVOKE_SPECIAL) {
+ if (!classname.equals(this_classname)) { // TODO: direct comparison to the super class?
+ super_qualifier = this_classname;
+ }
+ }
+ }
+ }
+
+ if (functype == TYP_GENERAL) {
+ if (super_qualifier != null) {
+ StructClass current_class = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE)).classStruct;
+
+ if (!super_qualifier.equals(current_class.qualifiedName)) {
+ buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(super_qualifier)));
+ buf.append(".");
+ }
+ buf.append("super");
+ }
+ else {
+ String res = instance.toJava(indent);
+
+ VarType rightType = instance.getExprType();
+ VarType leftType = new VarType(CodeConstants.TYPE_OBJECT, 0, classname);
+
+ if (rightType.equals(VarType.VARTYPE_OBJECT) && !leftType.equals(rightType)) {
+ buf.append("((" + ExprProcessor.getCastTypeName(leftType) + ")");
+
+ if (instance.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
+ res = "(" + res + ")";
+ }
+ buf.append(res + ")");
+ }
+ else if (instance.getPrecedence() > getPrecedence()) {
+ buf.append("(" + res + ")");
+ }
+ else {
+ buf.append(res);
+ }
+ }
+ }
+ }
+
+ switch (functype) {
+ case TYP_GENERAL:
+ if (VarExprent.VAR_NAMELESS_ENCLOSURE.equals(buf.toString())) {
+ buf = new StringBuilder("");
+ }
+
+ if (buf.length() > 0) {
+ buf.append(".");
+ }
+
+ buf.append(name);
+ if (invocationTyp == INVOKE_DYNAMIC) {
+ buf.append("<invokedynamic>");
+ }
+ buf.append("(");
+
+ break;
+ case TYP_CLINIT:
+ throw new RuntimeException("Explicite invocation of <clinit>");
+ case TYP_INIT:
+ if (super_qualifier != null) {
+ buf.append("super(");
+ }
+ else if (isInstanceThis) {
+ buf.append("this(");
+ }
+ else {
+ buf.append(instance.toJava(indent));
+ buf.append(".<init>(");
+ // throw new RuntimeException("Unrecognized invocation of <init>"); // FIXME: activate
+ }
+ }
+
+ List<VarVersionPaar> sigFields = null;
boolean isEnum = false;
- if(functype == TYP_INIT) {
- ClassNode newnode = DecompilerContext.getClassprocessor().getMapRootClasses().get(classname);
-
- if(newnode != null) { // own class
- if(newnode.wrapper != null) {
- sigFields = newnode.wrapper.getMethodWrapper("<init>", stringDescriptor).signatureFields;
- } else {
- if(newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0) { // non-static member class
- sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(lstParameters.size(), (VarVersionPaar)null));
- sigFields.set(0, new VarVersionPaar(-1, 0));
- }
- }
+ if (functype == TYP_INIT) {
+ ClassNode newnode = DecompilerContext.getClassprocessor().getMapRootClasses().get(classname);
+
+ if (newnode != null) { // own class
+ if (newnode.wrapper != null) {
+ sigFields = newnode.wrapper.getMethodWrapper("<init>", stringDescriptor).signatureFields;
+ }
+ else {
+ if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0) { // non-static member class
+ sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(lstParameters.size(), (VarVersionPaar)null));
+ sigFields.set(0, new VarVersionPaar(-1, 0));
+ }
+ }
isEnum = (newnode.classStruct.access_flags & CodeConstants.ACC_ENUM) != 0 &&
- DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
- }
- }
-
- Set<Integer> setAmbiguousParameters = getAmbiguousParameters();
-
- boolean firstpar = true;
+ DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
+ }
+ }
+
+ Set<Integer> setAmbiguousParameters = getAmbiguousParameters();
+
+ boolean firstpar = true;
int start = isEnum ? 2 : 0;
- for(int i=start;i<lstParameters.size();i++) {
- if(sigFields == null || sigFields.get(i) == null) {
- if(!firstpar) {
- buf.append(", ");
- }
-
- StringBuilder buff = new StringBuilder();
- ExprProcessor.getCastedExprent(lstParameters.get(i), descriptor.params[i], buff, indent, true, setAmbiguousParameters.contains(i));
-
- buf.append(buff);
- firstpar = false;
- }
- }
- buf.append(")");
-
- return buf.toString();
- }
-
- private Set<Integer> getAmbiguousParameters() {
-
- Set<Integer> ret = new HashSet<Integer>();
-
- StructClass cstr = DecompilerContext.getStructcontext().getClass(classname);
- if(cstr != null) {
- List<MethodDescriptor> lstMethods = new ArrayList<MethodDescriptor>();
- for(StructMethod meth : cstr.getMethods()) {
- if(name.equals(meth.getName())) {
- MethodDescriptor md = MethodDescriptor.parseDescriptor(meth.getDescriptor());
- if(md.params.length == descriptor.params.length) {
- boolean equals = true;
- for(int i=0;i<md.params.length;i++) {
- if(md.params[i].type_family != descriptor.params[i].type_family) {
- equals = false;
- break;
- }
- }
-
- if(equals) {
- lstMethods.add(md);
- }
- }
- }
- }
-
- if(lstMethods.size() > 1) {
- for(int i=0;i<descriptor.params.length;i++) {
- VarType partype = descriptor.params[i];
-
- for(MethodDescriptor md : lstMethods) {
- if(!partype.equals(md.params[i])) {
- ret.add(i);
- break;
- }
- }
- }
- }
- }
-
- return ret;
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof InvocationExprent)) return false;
+ for (int i = start; i < lstParameters.size(); i++) {
+ if (sigFields == null || sigFields.get(i) == null) {
+ if (!firstpar) {
+ buf.append(", ");
+ }
+
+ StringBuilder buff = new StringBuilder();
+ ExprProcessor.getCastedExprent(lstParameters.get(i), descriptor.params[i], buff, indent, true, setAmbiguousParameters.contains(i));
+
+ buf.append(buff);
+ firstpar = false;
+ }
+ }
+ buf.append(")");
+
+ return buf.toString();
+ }
+
+ private Set<Integer> getAmbiguousParameters() {
+
+ Set<Integer> ret = new HashSet<Integer>();
+
+ StructClass cstr = DecompilerContext.getStructcontext().getClass(classname);
+ if (cstr != null) {
+ List<MethodDescriptor> lstMethods = new ArrayList<MethodDescriptor>();
+ for (StructMethod meth : cstr.getMethods()) {
+ if (name.equals(meth.getName())) {
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(meth.getDescriptor());
+ if (md.params.length == descriptor.params.length) {
+ boolean equals = true;
+ for (int i = 0; i < md.params.length; i++) {
+ if (md.params[i].type_family != descriptor.params[i].type_family) {
+ equals = false;
+ break;
+ }
+ }
+
+ if (equals) {
+ lstMethods.add(md);
+ }
+ }
+ }
+ }
+
+ if (lstMethods.size() > 1) {
+ for (int i = 0; i < descriptor.params.length; i++) {
+ VarType partype = descriptor.params[i];
+
+ for (MethodDescriptor md : lstMethods) {
+ if (!partype.equals(md.params[i])) {
+ ret.add(i);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof InvocationExprent)) return false;
InvocationExprent it = (InvocationExprent)o;
return InterpreterUtil.equalObjects(name, it.getName()) &&
- InterpreterUtil.equalObjects(classname, it.getClassname()) &&
- isStatic == it.isStatic() &&
- InterpreterUtil.equalObjects(instance, it.getInstance()) &&
- InterpreterUtil.equalObjects(descriptor, it.getDescriptor()) &&
- functype == it.getFunctype() &&
- InterpreterUtil.equalLists(lstParameters, it.getLstParameters());
+ InterpreterUtil.equalObjects(classname, it.getClassname()) &&
+ isStatic == it.isStatic() &&
+ InterpreterUtil.equalObjects(instance, it.getInstance()) &&
+ InterpreterUtil.equalObjects(descriptor, it.getDescriptor()) &&
+ functype == it.getFunctype() &&
+ InterpreterUtil.equalLists(lstParameters, it.getLstParameters());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == instance) {
+ instance = newexpr;
+ }
+
+ for (int i = 0; i < lstParameters.size(); i++) {
+ if (oldexpr == lstParameters.get(i)) {
+ lstParameters.set(i, newexpr);
+ }
+ }
+ }
+
+ public List<Exprent> getLstParameters() {
+ return lstParameters;
+ }
+
+ public void setLstParameters(List<Exprent> lstParameters) {
+ this.lstParameters = lstParameters;
+ }
+
+ public MethodDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ public void setDescriptor(MethodDescriptor descriptor) {
+ this.descriptor = descriptor;
+ }
+
+ public String getClassname() {
+ return classname;
+ }
+
+ public void setClassname(String classname) {
+ this.classname = classname;
+ }
+
+ public int getFunctype() {
+ return functype;
+ }
+
+ public void setFunctype(int functype) {
+ this.functype = functype;
+ }
+
+ public Exprent getInstance() {
+ return instance;
+ }
+
+ public void setInstance(Exprent instance) {
+ this.instance = instance;
+ }
+
+ public boolean isStatic() {
+ return isStatic;
+ }
+
+ public void setStatic(boolean isStatic) {
+ this.isStatic = isStatic;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getStringDescriptor() {
+ return stringDescriptor;
+ }
+
+ public void setStringDescriptor(String stringDescriptor) {
+ this.stringDescriptor = stringDescriptor;
+ }
+
+ public int getInvocationTyp() {
+ return invocationTyp;
+ }
+
+ public void setInvocationTyp(int invocationTyp) {
+ this.invocationTyp = invocationTyp;
+ }
+
+ public String getInvokeDynamicClassSuffix() {
+ return invoke_dynamic_classsuffix;
}
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(oldexpr == instance) {
- instance = newexpr;
- }
-
- for(int i=0;i<lstParameters.size();i++) {
- if(oldexpr == lstParameters.get(i)) {
- lstParameters.set(i, newexpr);
- }
- }
- }
-
- public List<Exprent> getLstParameters() {
- return lstParameters;
- }
-
- public void setLstParameters(List<Exprent> lstParameters) {
- this.lstParameters = lstParameters;
- }
-
- public MethodDescriptor getDescriptor() {
- return descriptor;
- }
-
- public void setDescriptor(MethodDescriptor descriptor) {
- this.descriptor = descriptor;
- }
-
- public String getClassname() {
- return classname;
- }
-
- public void setClassname(String classname) {
- this.classname = classname;
- }
-
- public int getFunctype() {
- return functype;
- }
-
- public void setFunctype(int functype) {
- this.functype = functype;
- }
-
- public Exprent getInstance() {
- return instance;
- }
-
- public void setInstance(Exprent instance) {
- this.instance = instance;
- }
-
- public boolean isStatic() {
- return isStatic;
- }
-
- public void setStatic(boolean isStatic) {
- this.isStatic = isStatic;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getStringDescriptor() {
- return stringDescriptor;
- }
-
- public void setStringDescriptor(String stringDescriptor) {
- this.stringDescriptor = stringDescriptor;
- }
-
- public int getInvocationTyp() {
- return invocationTyp;
- }
-
- public void setInvocationTyp(int invocationTyp) {
- this.invocationTyp = invocationTyp;
- }
-
- public String getInvokeDynamicClassSuffix() {
- return invoke_dynamic_classsuffix;
- }
-
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java
index d231af0..9a1945e 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java
@@ -1,82 +1,83 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.util.InterpreterUtil;
-
public class MonitorExprent extends Exprent {
- public static final int MONITOR_ENTER = 0;
- public static final int MONITOR_EXIT = 1;
-
- private int montype;
-
- private Exprent value;
-
- {
- this.type = EXPRENT_MONITOR;
- }
-
- public MonitorExprent(int montype, Exprent value) {
- this.montype = montype;
- this.value = value;
- }
-
- public Exprent copy() {
- return new MonitorExprent(montype, value.copy());
- }
-
- public List<Exprent> getAllExprents() {
- List<Exprent> lst = new ArrayList<Exprent>();
- lst.add(value);
- return lst;
- }
-
- public String toJava(int indent) {
- if(montype == MONITOR_ENTER) {
- return "synchronized("+value.toJava(indent)+")";
- } else {
- return "";
- }
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof MonitorExprent)) return false;
+ public static final int MONITOR_ENTER = 0;
+ public static final int MONITOR_EXIT = 1;
+
+ private int montype;
+
+ private Exprent value;
+
+ {
+ this.type = EXPRENT_MONITOR;
+ }
+
+ public MonitorExprent(int montype, Exprent value) {
+ this.montype = montype;
+ this.value = value;
+ }
+
+ public Exprent copy() {
+ return new MonitorExprent(montype, value.copy());
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.add(value);
+ return lst;
+ }
+
+ public String toJava(int indent) {
+ if (montype == MONITOR_ENTER) {
+ return "synchronized(" + value.toJava(indent) + ")";
+ }
+ else {
+ return "";
+ }
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof MonitorExprent)) return false;
MonitorExprent me = (MonitorExprent)o;
return montype == me.getMontype() &&
- InterpreterUtil.equalObjects(value, me.getValue());
+ InterpreterUtil.equalObjects(value, me.getValue());
}
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(oldexpr == value) {
- value = newexpr;
- }
- }
-
- public int getMontype() {
- return montype;
- }
-
- public Exprent getValue() {
- return value;
- }
-
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == value) {
+ value = newexpr;
+ }
+ }
+
+ public int getMontype() {
+ return montype;
+ }
+
+ public Exprent getValue() {
+ return value;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
index 0d1814a..f71df1a 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
@@ -1,30 +1,24 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassWriter;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
@@ -34,479 +28,496 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.ListStack;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
public class NewExprent extends Exprent {
- private InvocationExprent constructor;
-
- private VarType newtype;
-
- private List<Exprent> lstDims = new ArrayList<Exprent>();
-
- private List<Exprent> lstArrayElements = new ArrayList<Exprent>();
-
- private boolean directArrayInit;
-
- private boolean anonymous;
-
- private boolean lambda;
-
- private boolean enumconst;
-
- {
- this.type = EXPRENT_NEW;
- }
-
- public NewExprent(VarType newtype, ListStack<Exprent> stack, int arraydim) {
- this.newtype = newtype;
- for(int i=0;i<arraydim;i++) {
- lstDims.add(0, stack.pop());
- }
-
- setAnonymous();
- }
-
- public NewExprent(VarType newtype, List<Exprent> lstDims) {
- this.newtype = newtype;
- this.lstDims = lstDims;
-
- setAnonymous();
- }
-
- private void setAnonymous() {
-
- anonymous = false;
- lambda = false;
-
- if(newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0) {
- ClassNode node = DecompilerContext.getClassprocessor().getMapRootClasses().get(newtype.value);
-
- if(node != null && (node.type == ClassNode.CLASS_ANONYMOUS || node.type == ClassNode.CLASS_LAMBDA)) {
- anonymous = true;
-
- if(node.type == ClassNode.CLASS_LAMBDA) {
- lambda = true;
- }
- }
- }
- }
-
- public VarType getExprType() {
-
- if(anonymous) {
- ClassNode node = DecompilerContext.getClassprocessor().getMapRootClasses().get(newtype.value);
-
- return node.anonimousClassType;
- } else {
- return newtype;
- }
- }
-
- public CheckTypesResult checkExprTypeBounds() {
- CheckTypesResult result = new CheckTypesResult();
-
- if(newtype.arraydim != 0) {
- for(Exprent dim: lstDims) {
- result.addMinTypeExprent(dim, VarType.VARTYPE_BYTECHAR);
- result.addMaxTypeExprent(dim, VarType.VARTYPE_INT);
- }
-
- if(newtype.arraydim == 1) {
-
- VarType leftType = newtype.copy();
- leftType.decArrayDim();
-
- for(Exprent element: lstArrayElements) {
- result.addMinTypeExprent(element, VarType.getMinTypeInFamily(leftType.type_family));
- result.addMaxTypeExprent(element, leftType);
- }
- }
- } else {
- if(constructor != null) {
- return constructor.checkExprTypeBounds();
- }
- }
-
- return result;
- }
-
- public List<Exprent> getAllExprents() {
- List<Exprent> lst = new ArrayList<Exprent>();
- if(newtype.arraydim == 0) {
- if(constructor != null) {
- Exprent constructor_instance = constructor.getInstance();
-
- if(constructor_instance != null) { // should be true only for a lambda expression with a virtual content method
- lst.add(constructor_instance);
- }
-
- lst.addAll(constructor.getLstParameters());
- }
- } else {
- lst.addAll(lstDims);
- lst.addAll(lstArrayElements);
- }
-
- return lst;
- }
-
- public Exprent copy() {
- List<Exprent> lst = new ArrayList<Exprent>();
- for(Exprent expr: lstDims) {
- lst.add(expr.copy());
- }
-
- NewExprent ret = new NewExprent(newtype, lst);
- ret.setConstructor(constructor==null?null:(InvocationExprent)constructor.copy());
- ret.setLstArrayElements(lstArrayElements);
- ret.setDirectArrayInit(directArrayInit);
- ret.setAnonymous(anonymous);
- ret.setEnumconst(enumconst);
- return ret;
- }
-
- public int getPrecedence() {
- return 1; // precedence of new
- }
-
- public String toJava(int indent) {
- StringBuilder buf = new StringBuilder();
-
- if (anonymous) {
-
- ClassNode child = DecompilerContext.getClassprocessor().getMapRootClasses().get(newtype.value);
-
- buf.append("(");
-
- if (!lambda && constructor != null) {
-
- InvocationExprent invsuper = child.superInvocation;
-
- ClassNode newnode = DecompilerContext.getClassprocessor().getMapRootClasses().get(invsuper.getClassname());
-
- List<VarVersionPaar> sigFields = null;
- if (newnode != null) { // own class
- if (newnode.wrapper != null) {
- sigFields = newnode.wrapper.getMethodWrapper("<init>", invsuper.getStringDescriptor()).signatureFields;
- } else {
- if(newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0 &&
- !constructor.getLstParameters().isEmpty()) { // member non-static class invoked with enclosing class instance
- sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(constructor.getLstParameters().size(), (VarVersionPaar)null));
- sigFields.set(0, new VarVersionPaar(-1, 0));
- }
- }
- }
-
- boolean firstpar = true;
- int start = 0, end = invsuper.getLstParameters().size();
- if (enumconst) {
- start += 2;
- end -= 1;
- }
- for(int i = start; i < end; i++) {
- if (sigFields == null || sigFields.get(i) == null) {
- if (!firstpar) {
- buf.append(", ");
- }
-
- Exprent param = invsuper.getLstParameters().get(i);
- if (param.type == Exprent.EXPRENT_VAR) {
- int varindex = ((VarExprent) param).getIndex();
- if (varindex > 0 && varindex <= constructor.getLstParameters().size()) {
- param = constructor.getLstParameters().get(varindex - 1);
- }
- }
-
- StringBuilder buff = new StringBuilder();
- ExprProcessor.getCastedExprent(param, invsuper.getDescriptor().params[i], buff, indent, true);
-
- buf.append(buff);
- firstpar = false;
- }
- }
-
- }
-
- if (!enumconst) {
- String enclosing = null;
- if (!lambda && constructor != null) {
- enclosing = getQualifiedNewInstance(child.anonimousClassType.value, constructor.getLstParameters(), indent);
- }
-
- String typename = ExprProcessor.getCastTypeName(child.anonimousClassType);
-
- if (enclosing != null) {
- ClassNode anonimousNode = DecompilerContext.getClassprocessor().getMapRootClasses().get(child.anonimousClassType.value);
- if (anonimousNode != null) {
- typename = anonimousNode.simpleName;
- } else {
- typename = typename.substring(typename.lastIndexOf('.') + 1);
- }
- }
- buf.insert(0, "new " + typename);
-
- if (enclosing != null) {
- buf.insert(0, enclosing + ".");
- }
- }
-
- buf.append(")");
-
- if (enumconst && buf.length() == 2) {
- buf.setLength(0);
- }
-
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
-
- ClassWriter clwriter = new ClassWriter();
- try {
- if (lambda) {
- clwriter.classLambdaToJava(child, bufstrwriter, (constructor == null ? null : constructor.getInstance()), indent);
- } else {
- clwriter.classToJava(child, bufstrwriter, indent);
- }
- bufstrwriter.flush();
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
-
- if (lambda && !DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) {
- buf.setLength(0); // remove the usual 'new <class>()', it will
- // be replaced with lambda style '() ->'
- }
-
- buf.append(strwriter.toString());
-
- } else if (directArrayInit) {
- VarType leftType = newtype.copy();
- leftType.decArrayDim();
-
- buf.append("{");
- for(int i = 0; i < lstArrayElements.size(); i++) {
- if (i > 0) {
- buf.append(", ");
- }
- StringBuilder buff = new StringBuilder();
- ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buff, indent, false);
-
- buf.append(buff);
- }
- buf.append("}");
- } else {
- if (newtype.arraydim == 0) {
-
- if (constructor != null) {
-
- List<Exprent> lstParameters = constructor.getLstParameters();
-
- ClassNode newnode = DecompilerContext.getClassprocessor().getMapRootClasses().get(constructor.getClassname());
-
- List<VarVersionPaar> sigFields = null;
- if (newnode != null) { // own class
- if (newnode.wrapper != null) {
- sigFields = newnode.wrapper.getMethodWrapper("<init>", constructor.getStringDescriptor()).signatureFields;
- } else {
- if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0 &&
- !constructor.getLstParameters().isEmpty()) { // member non-static class invoked with enclosing class instance
- sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(lstParameters.size(), (VarVersionPaar) null));
- sigFields.set(0, new VarVersionPaar(-1, 0));
- }
- }
- }
-
- int start = enumconst ? 2 : 0;
- if (!enumconst || start < lstParameters.size()) {
- buf.append("(");
-
- boolean firstpar = true;
- for(int i = start; i < lstParameters.size(); i++) {
- if (sigFields == null || sigFields.get(i) == null) {
- if (!firstpar) {
- buf.append(", ");
- }
-
- StringBuilder buff = new StringBuilder();
- ExprProcessor.getCastedExprent(lstParameters.get(i), constructor.getDescriptor().params[i], buff, indent, true);
-
- buf.append(buff);
- firstpar = false;
- }
- }
- buf.append(")");
- }
- }
-
- if (!enumconst) {
- String enclosing = null;
- if (constructor != null) {
- enclosing = getQualifiedNewInstance(newtype.value, constructor.getLstParameters(), indent);
- }
-
- String typename = ExprProcessor.getTypeName(newtype);
-
- if (enclosing != null) {
- ClassNode newNode = DecompilerContext.getClassprocessor().getMapRootClasses().get(newtype.value);
- if (newNode != null) {
- typename = newNode.simpleName;
- } else {
- typename = typename.substring(typename.lastIndexOf('.') + 1);
- }
- }
- buf.insert(0, "new " + typename);
-
- if (enclosing != null) {
- buf.insert(0, enclosing + ".");
- }
- }
-
- } else {
- buf.append("new ").append(ExprProcessor.getTypeName(newtype));
-
- if (lstArrayElements.isEmpty()) {
- for(int i = 0; i < newtype.arraydim; i++) {
- buf.append("[").append(i < lstDims.size() ? lstDims.get(i).toJava(indent) : "").append("]");
- }
- } else {
- for(int i = 0; i < newtype.arraydim; i++) {
- buf.append("[]");
- }
-
- VarType leftType = newtype.copy();
- leftType.decArrayDim();
-
- buf.append("{");
- for(int i = 0; i < lstArrayElements.size(); i++) {
- if (i > 0) {
- buf.append(", ");
- }
- StringBuilder buff = new StringBuilder();
- ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buff, indent, false);
-
- buf.append(buff);
- }
- buf.append("}");
- }
- }
- }
- return buf.toString();
- }
-
- private String getQualifiedNewInstance(String classname, List<Exprent> lstParams, int indent) {
-
- ClassNode node = DecompilerContext.getClassprocessor().getMapRootClasses().get(classname);
-
- if(node != null && node.type != ClassNode.CLASS_ROOT && (node.access & CodeConstants.ACC_STATIC) == 0) {
- if(!lstParams.isEmpty()) {
- Exprent enclosing = lstParams.get(0);
-
- boolean isQualifiedNew = false;
-
- if(enclosing.type == Exprent.EXPRENT_VAR) {
- VarExprent varEnclosing = (VarExprent)enclosing;
-
- StructClass current_class = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE)).classStruct;
- String this_classname = varEnclosing.getProcessor().getThisvars().get(new VarVersionPaar(varEnclosing));
-
- if(!current_class.qualifiedName.equals(this_classname)) {
- isQualifiedNew = true;
- }
- } else {
- isQualifiedNew = true;
- }
-
- if(isQualifiedNew) {
- return enclosing.toJava(indent);
- }
- }
- }
-
- return null;
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof NewExprent)) return false;
+ private InvocationExprent constructor;
+
+ private VarType newtype;
+
+ private List<Exprent> lstDims = new ArrayList<Exprent>();
+
+ private List<Exprent> lstArrayElements = new ArrayList<Exprent>();
+
+ private boolean directArrayInit;
+
+ private boolean anonymous;
+
+ private boolean lambda;
+
+ private boolean enumconst;
+
+ {
+ this.type = EXPRENT_NEW;
+ }
+
+ public NewExprent(VarType newtype, ListStack<Exprent> stack, int arraydim) {
+ this.newtype = newtype;
+ for (int i = 0; i < arraydim; i++) {
+ lstDims.add(0, stack.pop());
+ }
+
+ setAnonymous();
+ }
+
+ public NewExprent(VarType newtype, List<Exprent> lstDims) {
+ this.newtype = newtype;
+ this.lstDims = lstDims;
+
+ setAnonymous();
+ }
+
+ private void setAnonymous() {
+
+ anonymous = false;
+ lambda = false;
+
+ if (newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0) {
+ ClassNode node = DecompilerContext.getClassprocessor().getMapRootClasses().get(newtype.value);
+
+ if (node != null && (node.type == ClassNode.CLASS_ANONYMOUS || node.type == ClassNode.CLASS_LAMBDA)) {
+ anonymous = true;
+
+ if (node.type == ClassNode.CLASS_LAMBDA) {
+ lambda = true;
+ }
+ }
+ }
+ }
+
+ public VarType getExprType() {
+
+ if (anonymous) {
+ ClassNode node = DecompilerContext.getClassprocessor().getMapRootClasses().get(newtype.value);
+
+ return node.anonimousClassType;
+ }
+ else {
+ return newtype;
+ }
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ if (newtype.arraydim != 0) {
+ for (Exprent dim : lstDims) {
+ result.addMinTypeExprent(dim, VarType.VARTYPE_BYTECHAR);
+ result.addMaxTypeExprent(dim, VarType.VARTYPE_INT);
+ }
+
+ if (newtype.arraydim == 1) {
+
+ VarType leftType = newtype.copy();
+ leftType.decArrayDim();
+
+ for (Exprent element : lstArrayElements) {
+ result.addMinTypeExprent(element, VarType.getMinTypeInFamily(leftType.type_family));
+ result.addMaxTypeExprent(element, leftType);
+ }
+ }
+ }
+ else {
+ if (constructor != null) {
+ return constructor.checkExprTypeBounds();
+ }
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ if (newtype.arraydim == 0) {
+ if (constructor != null) {
+ Exprent constructor_instance = constructor.getInstance();
+
+ if (constructor_instance != null) { // should be true only for a lambda expression with a virtual content method
+ lst.add(constructor_instance);
+ }
+
+ lst.addAll(constructor.getLstParameters());
+ }
+ }
+ else {
+ lst.addAll(lstDims);
+ lst.addAll(lstArrayElements);
+ }
+
+ return lst;
+ }
+
+ public Exprent copy() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ for (Exprent expr : lstDims) {
+ lst.add(expr.copy());
+ }
+
+ NewExprent ret = new NewExprent(newtype, lst);
+ ret.setConstructor(constructor == null ? null : (InvocationExprent)constructor.copy());
+ ret.setLstArrayElements(lstArrayElements);
+ ret.setDirectArrayInit(directArrayInit);
+ ret.setAnonymous(anonymous);
+ ret.setEnumconst(enumconst);
+ return ret;
+ }
+
+ public int getPrecedence() {
+ return 1; // precedence of new
+ }
+
+ public String toJava(int indent) {
+ StringBuilder buf = new StringBuilder();
+
+ if (anonymous) {
+
+ ClassNode child = DecompilerContext.getClassprocessor().getMapRootClasses().get(newtype.value);
+
+ buf.append("(");
+
+ if (!lambda && constructor != null) {
+
+ InvocationExprent invsuper = child.superInvocation;
+
+ ClassNode newnode = DecompilerContext.getClassprocessor().getMapRootClasses().get(invsuper.getClassname());
+
+ List<VarVersionPaar> sigFields = null;
+ if (newnode != null) { // own class
+ if (newnode.wrapper != null) {
+ sigFields = newnode.wrapper.getMethodWrapper("<init>", invsuper.getStringDescriptor()).signatureFields;
+ }
+ else {
+ if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0 &&
+ !constructor.getLstParameters().isEmpty()) { // member non-static class invoked with enclosing class instance
+ sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(constructor.getLstParameters().size(), (VarVersionPaar)null));
+ sigFields.set(0, new VarVersionPaar(-1, 0));
+ }
+ }
+ }
+
+ boolean firstpar = true;
+ int start = 0, end = invsuper.getLstParameters().size();
+ if (enumconst) {
+ start += 2;
+ end -= 1;
+ }
+ for (int i = start; i < end; i++) {
+ if (sigFields == null || sigFields.get(i) == null) {
+ if (!firstpar) {
+ buf.append(", ");
+ }
+
+ Exprent param = invsuper.getLstParameters().get(i);
+ if (param.type == Exprent.EXPRENT_VAR) {
+ int varindex = ((VarExprent)param).getIndex();
+ if (varindex > 0 && varindex <= constructor.getLstParameters().size()) {
+ param = constructor.getLstParameters().get(varindex - 1);
+ }
+ }
+
+ StringBuilder buff = new StringBuilder();
+ ExprProcessor.getCastedExprent(param, invsuper.getDescriptor().params[i], buff, indent, true);
+
+ buf.append(buff);
+ firstpar = false;
+ }
+ }
+ }
+
+ if (!enumconst) {
+ String enclosing = null;
+ if (!lambda && constructor != null) {
+ enclosing = getQualifiedNewInstance(child.anonimousClassType.value, constructor.getLstParameters(), indent);
+ }
+
+ String typename = ExprProcessor.getCastTypeName(child.anonimousClassType);
+
+ if (enclosing != null) {
+ ClassNode anonimousNode = DecompilerContext.getClassprocessor().getMapRootClasses().get(child.anonimousClassType.value);
+ if (anonimousNode != null) {
+ typename = anonimousNode.simpleName;
+ }
+ else {
+ typename = typename.substring(typename.lastIndexOf('.') + 1);
+ }
+ }
+ buf.insert(0, "new " + typename);
+
+ if (enclosing != null) {
+ buf.insert(0, enclosing + ".");
+ }
+ }
+
+ buf.append(")");
+
+ if (enumconst && buf.length() == 2) {
+ buf.setLength(0);
+ }
+
+ StringWriter strwriter = new StringWriter();
+ BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+
+ ClassWriter clwriter = new ClassWriter();
+ try {
+ if (lambda) {
+ clwriter.classLambdaToJava(child, bufstrwriter, (constructor == null ? null : constructor.getInstance()), indent);
+ }
+ else {
+ clwriter.classToJava(child, bufstrwriter, indent);
+ }
+ bufstrwriter.flush();
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ if (lambda && !DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) {
+ buf.setLength(0); // remove the usual 'new <class>()', it will
+ // be replaced with lambda style '() ->'
+ }
+
+ buf.append(strwriter.toString());
+ }
+ else if (directArrayInit) {
+ VarType leftType = newtype.copy();
+ leftType.decArrayDim();
+
+ buf.append("{");
+ for (int i = 0; i < lstArrayElements.size(); i++) {
+ if (i > 0) {
+ buf.append(", ");
+ }
+ StringBuilder buff = new StringBuilder();
+ ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buff, indent, false);
+
+ buf.append(buff);
+ }
+ buf.append("}");
+ }
+ else {
+ if (newtype.arraydim == 0) {
+
+ if (constructor != null) {
+
+ List<Exprent> lstParameters = constructor.getLstParameters();
+
+ ClassNode newnode = DecompilerContext.getClassprocessor().getMapRootClasses().get(constructor.getClassname());
+
+ List<VarVersionPaar> sigFields = null;
+ if (newnode != null) { // own class
+ if (newnode.wrapper != null) {
+ sigFields = newnode.wrapper.getMethodWrapper("<init>", constructor.getStringDescriptor()).signatureFields;
+ }
+ else {
+ if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0 &&
+ !constructor.getLstParameters().isEmpty()) { // member non-static class invoked with enclosing class instance
+ sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(lstParameters.size(), (VarVersionPaar)null));
+ sigFields.set(0, new VarVersionPaar(-1, 0));
+ }
+ }
+ }
+
+ int start = enumconst ? 2 : 0;
+ if (!enumconst || start < lstParameters.size()) {
+ buf.append("(");
+
+ boolean firstpar = true;
+ for (int i = start; i < lstParameters.size(); i++) {
+ if (sigFields == null || sigFields.get(i) == null) {
+ if (!firstpar) {
+ buf.append(", ");
+ }
+
+ StringBuilder buff = new StringBuilder();
+ ExprProcessor.getCastedExprent(lstParameters.get(i), constructor.getDescriptor().params[i], buff, indent, true);
+
+ buf.append(buff);
+ firstpar = false;
+ }
+ }
+ buf.append(")");
+ }
+ }
+
+ if (!enumconst) {
+ String enclosing = null;
+ if (constructor != null) {
+ enclosing = getQualifiedNewInstance(newtype.value, constructor.getLstParameters(), indent);
+ }
+
+ String typename = ExprProcessor.getTypeName(newtype);
+
+ if (enclosing != null) {
+ ClassNode newNode = DecompilerContext.getClassprocessor().getMapRootClasses().get(newtype.value);
+ if (newNode != null) {
+ typename = newNode.simpleName;
+ }
+ else {
+ typename = typename.substring(typename.lastIndexOf('.') + 1);
+ }
+ }
+ buf.insert(0, "new " + typename);
+
+ if (enclosing != null) {
+ buf.insert(0, enclosing + ".");
+ }
+ }
+ }
+ else {
+ buf.append("new ").append(ExprProcessor.getTypeName(newtype));
+
+ if (lstArrayElements.isEmpty()) {
+ for (int i = 0; i < newtype.arraydim; i++) {
+ buf.append("[").append(i < lstDims.size() ? lstDims.get(i).toJava(indent) : "").append("]");
+ }
+ }
+ else {
+ for (int i = 0; i < newtype.arraydim; i++) {
+ buf.append("[]");
+ }
+
+ VarType leftType = newtype.copy();
+ leftType.decArrayDim();
+
+ buf.append("{");
+ for (int i = 0; i < lstArrayElements.size(); i++) {
+ if (i > 0) {
+ buf.append(", ");
+ }
+ StringBuilder buff = new StringBuilder();
+ ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buff, indent, false);
+
+ buf.append(buff);
+ }
+ buf.append("}");
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ private String getQualifiedNewInstance(String classname, List<Exprent> lstParams, int indent) {
+
+ ClassNode node = DecompilerContext.getClassprocessor().getMapRootClasses().get(classname);
+
+ if (node != null && node.type != ClassNode.CLASS_ROOT && (node.access & CodeConstants.ACC_STATIC) == 0) {
+ if (!lstParams.isEmpty()) {
+ Exprent enclosing = lstParams.get(0);
+
+ boolean isQualifiedNew = false;
+
+ if (enclosing.type == Exprent.EXPRENT_VAR) {
+ VarExprent varEnclosing = (VarExprent)enclosing;
+
+ StructClass current_class = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE)).classStruct;
+ String this_classname = varEnclosing.getProcessor().getThisvars().get(new VarVersionPaar(varEnclosing));
+
+ if (!current_class.qualifiedName.equals(this_classname)) {
+ isQualifiedNew = true;
+ }
+ }
+ else {
+ isQualifiedNew = true;
+ }
+
+ if (isQualifiedNew) {
+ return enclosing.toJava(indent);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof NewExprent)) return false;
NewExprent ne = (NewExprent)o;
return InterpreterUtil.equalObjects(newtype, ne.getNewtype()) &&
- InterpreterUtil.equalLists(lstDims, ne.getLstDims()) &&
- InterpreterUtil.equalObjects(constructor, ne.getConstructor()) &&
- directArrayInit == ne.directArrayInit &&
- InterpreterUtil.equalLists(lstArrayElements, ne.getLstArrayElements());
+ InterpreterUtil.equalLists(lstDims, ne.getLstDims()) &&
+ InterpreterUtil.equalObjects(constructor, ne.getConstructor()) &&
+ directArrayInit == ne.directArrayInit &&
+ InterpreterUtil.equalLists(lstArrayElements, ne.getLstArrayElements());
}
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(oldexpr == constructor) {
- constructor = (InvocationExprent)newexpr;
- }
-
- if(constructor != null) {
- constructor.replaceExprent(oldexpr, newexpr);
- }
-
- for(int i=0;i<lstDims.size();i++) {
- if(oldexpr == lstDims.get(i)) {
- lstDims.set(i, newexpr);
- }
- }
-
- for(int i=0;i<lstArrayElements.size();i++) {
- if(oldexpr == lstArrayElements.get(i)) {
- lstArrayElements.set(i, newexpr);
- }
- }
- }
-
- public InvocationExprent getConstructor() {
- return constructor;
- }
-
- public void setConstructor(InvocationExprent constructor) {
- this.constructor = constructor;
- }
-
- public List<Exprent> getLstDims() {
- return lstDims;
- }
-
- public VarType getNewtype() {
- return newtype;
- }
-
- public List<Exprent> getLstArrayElements() {
- return lstArrayElements;
- }
-
- public void setLstArrayElements(List<Exprent> lstArrayElements) {
- this.lstArrayElements = lstArrayElements;
- }
-
- public boolean isDirectArrayInit() {
- return directArrayInit;
- }
-
- public void setDirectArrayInit(boolean directArrayInit) {
- this.directArrayInit = directArrayInit;
- }
-
- public boolean isLambda() {
- return lambda;
- }
-
- public boolean isAnonymous() {
- return anonymous;
- }
-
- public void setAnonymous(boolean anonymous) {
- this.anonymous = anonymous;
- }
-
- public boolean isEnumconst() {
- return enumconst;
- }
-
- public void setEnumconst(boolean enumconst) {
- this.enumconst = enumconst;
- }
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == constructor) {
+ constructor = (InvocationExprent)newexpr;
+ }
+
+ if (constructor != null) {
+ constructor.replaceExprent(oldexpr, newexpr);
+ }
+
+ for (int i = 0; i < lstDims.size(); i++) {
+ if (oldexpr == lstDims.get(i)) {
+ lstDims.set(i, newexpr);
+ }
+ }
+
+ for (int i = 0; i < lstArrayElements.size(); i++) {
+ if (oldexpr == lstArrayElements.get(i)) {
+ lstArrayElements.set(i, newexpr);
+ }
+ }
+ }
+
+ public InvocationExprent getConstructor() {
+ return constructor;
+ }
+
+ public void setConstructor(InvocationExprent constructor) {
+ this.constructor = constructor;
+ }
+
+ public List<Exprent> getLstDims() {
+ return lstDims;
+ }
+
+ public VarType getNewtype() {
+ return newtype;
+ }
+
+ public List<Exprent> getLstArrayElements() {
+ return lstArrayElements;
+ }
+
+ public void setLstArrayElements(List<Exprent> lstArrayElements) {
+ this.lstArrayElements = lstArrayElements;
+ }
+
+ public boolean isDirectArrayInit() {
+ return directArrayInit;
+ }
+
+ public void setDirectArrayInit(boolean directArrayInit) {
+ this.directArrayInit = directArrayInit;
+ }
+
+ public boolean isLambda() {
+ return lambda;
+ }
+
+ public boolean isAnonymous() {
+ return anonymous;
+ }
+
+ public void setAnonymous(boolean anonymous) {
+ this.anonymous = anonymous;
+ }
+
+ public boolean isEnumconst() {
+ return enumconst;
+ }
+
+ public void setEnumconst(boolean enumconst) {
+ this.enumconst = enumconst;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java
index 13bd3b4..36bead2 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java
@@ -1,113 +1,114 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.List;
+
public class SwitchExprent extends Exprent {
- private Exprent value;
-
- private List<List<ConstExprent>> caseValues = new ArrayList<List<ConstExprent>>();
-
- {
- this.type = EXPRENT_SWITCH;
- }
-
- public SwitchExprent(Exprent value) {
- this.value = value;
- }
-
- public Exprent copy() {
- SwitchExprent swexpr = new SwitchExprent(value.copy());
-
- List<List<ConstExprent>> lstCaseValues = new ArrayList<List<ConstExprent>>();
- for(List<ConstExprent> lst: caseValues) {
- lstCaseValues.add(new ArrayList<ConstExprent>(lst));
- }
- swexpr.setCaseValues(lstCaseValues);
-
- return swexpr;
- }
-
- public VarType getExprType() {
- return value.getExprType();
- }
-
- public CheckTypesResult checkExprTypeBounds() {
- CheckTypesResult result = new CheckTypesResult();
-
- result.addMinTypeExprent(value, VarType.VARTYPE_BYTECHAR);
- result.addMaxTypeExprent(value, VarType.VARTYPE_INT);
-
- VarType valtype = value.getExprType();
- for(List<ConstExprent> lst: caseValues) {
- for(ConstExprent expr: lst) {
- if(expr != null) {
- VarType casetype = expr.getExprType();
- if(!casetype.equals(valtype)) {
- valtype = VarType.getCommonSupertype(casetype, valtype);
- result.addMinTypeExprent(value, valtype);
- }
- }
- }
- }
-
- return result;
- }
-
- public List<Exprent> getAllExprents() {
- List<Exprent> lst = new ArrayList<Exprent>();
- lst.add(value);
- return lst;
- }
-
- public String toJava(int indent) {
- return "switch("+value.toJava(indent)+")";
- }
-
- public boolean equals(Object o) {
- if(o == this) {
- return true;
- }
-
- if(o == null || !(o instanceof SwitchExprent)) {
- return false;
- }
-
- SwitchExprent sw = (SwitchExprent) o;
- return InterpreterUtil.equalObjects(value, sw.getValue());
- }
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(oldexpr == value) {
- value = newexpr;
- }
- }
-
- public Exprent getValue() {
- return value;
- }
-
- public void setCaseValues(List<List<ConstExprent>> caseValues) {
- this.caseValues = caseValues;
- }
+ private Exprent value;
+
+ private List<List<ConstExprent>> caseValues = new ArrayList<List<ConstExprent>>();
+
+ {
+ this.type = EXPRENT_SWITCH;
+ }
+
+ public SwitchExprent(Exprent value) {
+ this.value = value;
+ }
+
+ public Exprent copy() {
+ SwitchExprent swexpr = new SwitchExprent(value.copy());
+
+ List<List<ConstExprent>> lstCaseValues = new ArrayList<List<ConstExprent>>();
+ for (List<ConstExprent> lst : caseValues) {
+ lstCaseValues.add(new ArrayList<ConstExprent>(lst));
+ }
+ swexpr.setCaseValues(lstCaseValues);
+
+ return swexpr;
+ }
+
+ public VarType getExprType() {
+ return value.getExprType();
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ result.addMinTypeExprent(value, VarType.VARTYPE_BYTECHAR);
+ result.addMaxTypeExprent(value, VarType.VARTYPE_INT);
+
+ VarType valtype = value.getExprType();
+ for (List<ConstExprent> lst : caseValues) {
+ for (ConstExprent expr : lst) {
+ if (expr != null) {
+ VarType casetype = expr.getExprType();
+ if (!casetype.equals(valtype)) {
+ valtype = VarType.getCommonSupertype(casetype, valtype);
+ result.addMinTypeExprent(value, valtype);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.add(value);
+ return lst;
+ }
+
+ public String toJava(int indent) {
+ return "switch(" + value.toJava(indent) + ")";
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o == null || !(o instanceof SwitchExprent)) {
+ return false;
+ }
+
+ SwitchExprent sw = (SwitchExprent)o;
+ return InterpreterUtil.equalObjects(value, sw.getValue());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == value) {
+ value = newexpr;
+ }
+ }
+
+ public Exprent getValue() {
+ return value;
+ }
+
+ public void setCaseValues(List<List<ConstExprent>> caseValues) {
+ this.caseValues = caseValues;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
index c2356ca..cd75f1f 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
@@ -1,29 +1,24 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassWriter;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor;
@@ -31,168 +26,177 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
public class VarExprent extends Exprent {
- public static final int STACK_BASE = 10000;
-
- public static final String VAR_NAMELESS_ENCLOSURE = "<VAR_NAMELESS_ENCLOSURE>";
-
- private int index;
-
- private VarType vartype;
-
- private boolean definition = false;;
-
- private VarProcessor processor;
-
- private int version = 0;
-
- private boolean classdef = false;
-
- private boolean stack = false;;
-
- {
- this.type = EXPRENT_VAR;
- }
-
- public VarExprent(int index, VarType vartype, VarProcessor processor) {
- this.index = index;
- this.vartype = vartype;
- this.processor = processor;
- }
-
- public VarType getExprType() {
- return getVartype();
- }
-
- public int getExprentUse() {
- return Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE;
- }
-
- public List<Exprent> getAllExprents() {
- return new ArrayList<Exprent>();
- }
-
- public Exprent copy() {
- VarExprent var = new VarExprent(index, getVartype(), processor);
- var.setDefinition(definition);
- var.setVersion(version);
- var.setClassdef(classdef);
- var.setStack(stack);
- return var;
- }
-
- public String toJava(int indent) {
-
- if(classdef) {
-
- ClassNode child = DecompilerContext.getClassprocessor().getMapRootClasses().get(vartype.value);
-
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
-
- ClassWriter clwriter = new ClassWriter();
- try {
- clwriter.classToJava(child, bufstrwriter, indent);
- bufstrwriter.flush();
- } catch(IOException ex) {
- throw new RuntimeException(ex);
- }
-
- return strwriter.toString();
-
- } else {
- String name = null;
- if(processor != null) {
- name = processor.getVarName(new VarVersionPaar(index, version));
- }
-
- StringBuilder buf = new StringBuilder();
-
- if(definition) {
- if(processor != null && processor.getVarFinal(new VarVersionPaar(index, version)) == VarTypeProcessor.VAR_FINALEXPLICIT) {
- buf.append("final ");
- }
- buf.append(ExprProcessor.getCastTypeName(getVartype())+" ");
- }
- buf.append(name==null?("var"+index+(version==0?"":"_"+version)):name);
-
- return buf.toString();
- }
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof VarExprent)) return false;
+ public static final int STACK_BASE = 10000;
+
+ public static final String VAR_NAMELESS_ENCLOSURE = "<VAR_NAMELESS_ENCLOSURE>";
+
+ private int index;
+
+ private VarType vartype;
+
+ private boolean definition = false;
+ ;
+
+ private VarProcessor processor;
+
+ private int version = 0;
+
+ private boolean classdef = false;
+
+ private boolean stack = false;
+ ;
+
+ {
+ this.type = EXPRENT_VAR;
+ }
+
+ public VarExprent(int index, VarType vartype, VarProcessor processor) {
+ this.index = index;
+ this.vartype = vartype;
+ this.processor = processor;
+ }
+
+ public VarType getExprType() {
+ return getVartype();
+ }
+
+ public int getExprentUse() {
+ return Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE;
+ }
+
+ public List<Exprent> getAllExprents() {
+ return new ArrayList<Exprent>();
+ }
+
+ public Exprent copy() {
+ VarExprent var = new VarExprent(index, getVartype(), processor);
+ var.setDefinition(definition);
+ var.setVersion(version);
+ var.setClassdef(classdef);
+ var.setStack(stack);
+ return var;
+ }
+
+ public String toJava(int indent) {
+
+ if (classdef) {
+
+ ClassNode child = DecompilerContext.getClassprocessor().getMapRootClasses().get(vartype.value);
+
+ StringWriter strwriter = new StringWriter();
+ BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+
+ ClassWriter clwriter = new ClassWriter();
+ try {
+ clwriter.classToJava(child, bufstrwriter, indent);
+ bufstrwriter.flush();
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ return strwriter.toString();
+ }
+ else {
+ String name = null;
+ if (processor != null) {
+ name = processor.getVarName(new VarVersionPaar(index, version));
+ }
+
+ StringBuilder buf = new StringBuilder();
+
+ if (definition) {
+ if (processor != null && processor.getVarFinal(new VarVersionPaar(index, version)) == VarTypeProcessor.VAR_FINALEXPLICIT) {
+ buf.append("final ");
+ }
+ buf.append(ExprProcessor.getCastTypeName(getVartype()) + " ");
+ }
+ buf.append(name == null ? ("var" + index + (version == 0 ? "" : "_" + version)) : name);
+
+ return buf.toString();
+ }
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof VarExprent)) return false;
VarExprent ve = (VarExprent)o;
return index == ve.getIndex() &&
- version == ve.getVersion() &&
- InterpreterUtil.equalObjects(getVartype(), ve.getVartype()); // FIXME: vartype comparison redundant?
- }
-
- public int getIndex() {
- return index;
- }
-
- public void setIndex(int index) {
- this.index = index;
- }
-
- public VarType getVartype() {
- VarType vt = null;
- if(processor != null) {
- vt = processor.getVarType(new VarVersionPaar(index, version));
- }
-
- if(vt == null || (vartype != null && vartype.type != CodeConstants.TYPE_UNKNOWN)) {
- vt = vartype;
- }
-
- return vt==null?VarType.VARTYPE_UNKNOWN:vt;
- }
-
- public void setVartype(VarType vartype) {
- this.vartype = vartype;
- }
-
- public boolean isDefinition() {
- return definition;
- }
-
- public void setDefinition(boolean definition) {
- this.definition = definition;
- }
-
- public VarProcessor getProcessor() {
- return processor;
- }
-
- public void setProcessor(VarProcessor processor) {
- this.processor = processor;
- }
-
- public int getVersion() {
- return version;
- }
-
- public void setVersion(int version) {
- this.version = version;
- }
-
- public boolean isClassdef() {
- return classdef;
- }
-
- public void setClassdef(boolean classdef) {
- this.classdef = classdef;
- }
-
- public boolean isStack() {
- return stack;
- }
-
- public void setStack(boolean stack) {
- this.stack = stack;
- }
+ version == ve.getVersion() &&
+ InterpreterUtil.equalObjects(getVartype(), ve.getVartype()); // FIXME: vartype comparison redundant?
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public VarType getVartype() {
+ VarType vt = null;
+ if (processor != null) {
+ vt = processor.getVarType(new VarVersionPaar(index, version));
+ }
+
+ if (vt == null || (vartype != null && vartype.type != CodeConstants.TYPE_UNKNOWN)) {
+ vt = vartype;
+ }
+
+ return vt == null ? VarType.VARTYPE_UNKNOWN : vt;
+ }
+
+ public void setVartype(VarType vartype) {
+ this.vartype = vartype;
+ }
+
+ public boolean isDefinition() {
+ return definition;
+ }
+
+ public void setDefinition(boolean definition) {
+ this.definition = definition;
+ }
+
+ public VarProcessor getProcessor() {
+ return processor;
+ }
+
+ public void setProcessor(VarProcessor processor) {
+ this.processor = processor;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ public boolean isClassdef() {
+ return classdef;
+ }
+
+ public void setClassdef(boolean classdef) {
+ this.classdef = classdef;
+ }
+
+ public boolean isStack() {
+ return stack;
+ }
+
+ public void setStack(boolean stack) {
+ this.stack = stack;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java
index b35f801..1fc568f 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java
@@ -1,136 +1,136 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.sforms;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper.FinallyPathWrapper;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper.FinallyPathWrapper;
-import org.jetbrains.java.decompiler.util.VBStyleCollection;
-
public class DirectGraph {
- public VBStyleCollection<DirectNode, String> nodes = new VBStyleCollection<DirectNode, String>();
-
- public DirectNode first;
-
- // exit, [source, destination]
- public HashMap<String, List<FinallyPathWrapper>> mapShortRangeFinallyPaths = new HashMap<String, List<FinallyPathWrapper>>();
-
- // exit, [source, destination]
- public HashMap<String, List<FinallyPathWrapper>> mapLongRangeFinallyPaths = new HashMap<String, List<FinallyPathWrapper>>();
-
- // negative if branches (recorded for handling of && and ||)
- public HashMap<String, String> mapNegIfBranch = new HashMap<String, String>();
-
- // nodes, that are exception exits of a finally block with monitor variable
- public HashMap<String, String> mapFinallyMonitorExceptionPathExits = new HashMap<String, String>();
-
- public void sortReversePostOrder() {
- LinkedList<DirectNode> res = new LinkedList<DirectNode>();
- addToReversePostOrderListIterative(first, res);
-
- nodes.clear();
- for(DirectNode node: res) {
- nodes.addWithKey(node, node.id);
- }
- }
-
- private void addToReversePostOrderListIterative(DirectNode root, List<DirectNode> lst) {
-
- LinkedList<DirectNode> stackNode = new LinkedList<DirectNode>();
- LinkedList<Integer> stackIndex = new LinkedList<Integer>();
-
- HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
-
- stackNode.add(root);
- stackIndex.add(0);
-
- while(!stackNode.isEmpty()) {
-
- DirectNode node = stackNode.getLast();
- int index = stackIndex.removeLast();
-
- setVisited.add(node);
-
- for(;index<node.succs.size();index++) {
- DirectNode succ = node.succs.get(index);
-
- if(!setVisited.contains(succ)) {
- stackIndex.add(index+1);
-
- stackNode.add(succ);
- stackIndex.add(0);
-
- break;
- }
- }
-
- if(index == node.succs.size()) {
- lst.add(0, node);
-
- stackNode.removeLast();
- }
- }
-
- }
-
-
- public boolean iterateExprents(ExprentIterator iter) {
-
- LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
- stack.add(first);
-
- HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
-
- while(!stack.isEmpty()) {
-
- DirectNode node = stack.removeFirst();
-
- if(setVisited.contains(node)) {
- continue;
- }
- setVisited.add(node);
-
- for(int i=0;i<node.exprents.size();i++) {
- int res = iter.processExprent(node.exprents.get(i));
-
- if(res == 1) {
- return false;
- }
-
- if(res == 2) {
- node.exprents.remove(i);
- i--;
- }
- }
-
- stack.addAll(node.succs);
- }
-
- return true;
- }
-
- public interface ExprentIterator {
- // 0 - success, do nothing
- // 1 - cancel iteration
- // 2 - success, delete exprent
- public int processExprent(Exprent exprent);
- }
+ public VBStyleCollection<DirectNode, String> nodes = new VBStyleCollection<DirectNode, String>();
+
+ public DirectNode first;
+
+ // exit, [source, destination]
+ public HashMap<String, List<FinallyPathWrapper>> mapShortRangeFinallyPaths = new HashMap<String, List<FinallyPathWrapper>>();
+
+ // exit, [source, destination]
+ public HashMap<String, List<FinallyPathWrapper>> mapLongRangeFinallyPaths = new HashMap<String, List<FinallyPathWrapper>>();
+
+ // negative if branches (recorded for handling of && and ||)
+ public HashMap<String, String> mapNegIfBranch = new HashMap<String, String>();
+
+ // nodes, that are exception exits of a finally block with monitor variable
+ public HashMap<String, String> mapFinallyMonitorExceptionPathExits = new HashMap<String, String>();
+
+ public void sortReversePostOrder() {
+ LinkedList<DirectNode> res = new LinkedList<DirectNode>();
+ addToReversePostOrderListIterative(first, res);
+
+ nodes.clear();
+ for (DirectNode node : res) {
+ nodes.addWithKey(node, node.id);
+ }
+ }
+
+ private void addToReversePostOrderListIterative(DirectNode root, List<DirectNode> lst) {
+
+ LinkedList<DirectNode> stackNode = new LinkedList<DirectNode>();
+ LinkedList<Integer> stackIndex = new LinkedList<Integer>();
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+
+ stackNode.add(root);
+ stackIndex.add(0);
+
+ while (!stackNode.isEmpty()) {
+
+ DirectNode node = stackNode.getLast();
+ int index = stackIndex.removeLast();
+
+ setVisited.add(node);
+
+ for (; index < node.succs.size(); index++) {
+ DirectNode succ = node.succs.get(index);
+
+ if (!setVisited.contains(succ)) {
+ stackIndex.add(index + 1);
+
+ stackNode.add(succ);
+ stackIndex.add(0);
+
+ break;
+ }
+ }
+
+ if (index == node.succs.size()) {
+ lst.add(0, node);
+
+ stackNode.removeLast();
+ }
+ }
+ }
+
+
+ public boolean iterateExprents(ExprentIterator iter) {
+
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ stack.add(first);
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+
+ while (!stack.isEmpty()) {
+
+ DirectNode node = stack.removeFirst();
+
+ if (setVisited.contains(node)) {
+ continue;
+ }
+ setVisited.add(node);
+
+ for (int i = 0; i < node.exprents.size(); i++) {
+ int res = iter.processExprent(node.exprents.get(i));
+
+ if (res == 1) {
+ return false;
+ }
+
+ if (res == 2) {
+ node.exprents.remove(i);
+ i--;
+ }
+ }
+
+ stack.addAll(node.succs);
+ }
+
+ return true;
+ }
+
+ public interface ExprentIterator {
+ // 0 - success, do nothing
+ // 1 - cancel iteration
+ // 2 - success, delete exprent
+ public int processExprent(Exprent exprent);
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectNode.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectNode.java
index ebad3eb..73303ec 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectNode.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectNode.java
@@ -1,68 +1,67 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.sforms;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
public class DirectNode {
-
- public static final int NODE_DIRECT = 1;
- public static final int NODE_TAIL = 2;
- public static final int NODE_INIT = 3;
- public static final int NODE_CONDITION = 4;
- public static final int NODE_INCREMENT = 5;
- public static final int NODE_TRY = 6;
-
- public int type;
-
- public String id;
-
- public BasicBlockStatement block;
-
- public Statement statement;
-
- public List<Exprent> exprents = new ArrayList<Exprent>();
-
- public List<DirectNode> succs = new ArrayList<DirectNode>();
-
- public List<DirectNode> preds = new ArrayList<DirectNode>();
-
- public DirectNode(int type, Statement statement, String id) {
- this.type = type;
- this.statement = statement;
- this.id = id;
- }
-
- public DirectNode(int type, Statement statement, BasicBlockStatement block) {
- this.type = type;
- this.statement = statement;
-
- this.id = block.id.toString();
- this.block = block;
- }
-
- @Override
- public String toString() {
- return id;
- }
-
-
+
+ public static final int NODE_DIRECT = 1;
+ public static final int NODE_TAIL = 2;
+ public static final int NODE_INIT = 3;
+ public static final int NODE_CONDITION = 4;
+ public static final int NODE_INCREMENT = 5;
+ public static final int NODE_TRY = 6;
+
+ public int type;
+
+ public String id;
+
+ public BasicBlockStatement block;
+
+ public Statement statement;
+
+ public List<Exprent> exprents = new ArrayList<Exprent>();
+
+ public List<DirectNode> succs = new ArrayList<DirectNode>();
+
+ public List<DirectNode> preds = new ArrayList<DirectNode>();
+
+ public DirectNode(int type, Statement statement, String id) {
+ this.type = type;
+ this.statement = statement;
+ this.id = id;
+ }
+
+ public DirectNode(int type, Statement statement, BasicBlockStatement block) {
+ this.type = type;
+ this.statement = statement;
+
+ this.id = block.id.toString();
+ this.block = block;
+ }
+
+ @Override
+ public String toString() {
+ return id;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java
index 9388073..1eb79e9 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java
@@ -1,562 +1,575 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.sforms;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SwitchStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+
+import java.util.*;
+import java.util.Map.Entry;
public class FlattenStatementsHelper {
- // statement.id, node.id(direct), node.id(continue)
- private HashMap<Integer, String[]> mapDestinationNodes = new HashMap<Integer, String[]>();
-
- // node.id(source), statement.id(destination), edge type
- private List<Edge> listEdges = new ArrayList<Edge>();
-
- // node.id(exit), [node.id(source), statement.id(destination)]
- public HashMap<String, List<String[]>> mapShortRangeFinallyPathIds = new HashMap<String, List<String[]>>();
-
- // node.id(exit), [node.id(source), statement.id(destination)]
- public HashMap<String, List<String[]>> mapLongRangeFinallyPathIds = new HashMap<String, List<String[]>>();
-
- // positive if branches
- public HashMap<String, String> mapPosIfBranch = new HashMap<String, String>();
-
-
- private DirectGraph graph;
-
- private RootStatement root;
-
- public DirectGraph buildDirectGraph(RootStatement root) {
-
- this.root = root;
-
- graph = new DirectGraph();
-
- flattenStatement();
-
- // dummy exit node
- Statement dummyexit = root.getDummyExit();
- DirectNode node = new DirectNode(DirectNode.NODE_DIRECT, dummyexit, dummyexit.id.toString());
- node.exprents = new ArrayList<Exprent>();
- graph.nodes.addWithKey(node, node.id);
- mapDestinationNodes.put(dummyexit.id, new String[] {node.id, null});
-
- setEdges();
-
- graph.first = graph.nodes.getWithKey(mapDestinationNodes.get(root.id)[0]);
- graph.sortReversePostOrder();
-
- return graph;
- }
-
- private void flattenStatement() {
-
- class StatementStackEntry {
- public Statement statement;
- public LinkedList<StackEntry> stackFinally;
- public List<Exprent> tailExprents;
-
- public int statementIndex;
- public int edgeIndex;
- public List<StatEdge> succEdges;
-
- public StatementStackEntry(Statement statement, LinkedList<StackEntry> stackFinally, List<Exprent> tailExprents) {
- this.statement = statement;
- this.stackFinally = stackFinally;
- this.tailExprents = tailExprents;
- }
- }
-
- LinkedList<StatementStackEntry> lstStackStatements = new LinkedList<StatementStackEntry>();
-
- lstStackStatements.add(new StatementStackEntry(root, new LinkedList<StackEntry>(), null));
-
- mainloop:
- while(!lstStackStatements.isEmpty()) {
-
- StatementStackEntry statEntry = lstStackStatements.removeFirst();
-
- Statement stat = statEntry.statement;
- LinkedList<StackEntry> stackFinally = statEntry.stackFinally;
- int statementBreakIndex = statEntry.statementIndex;
-
- DirectNode node = null, nd = null;
-
- List<StatEdge> lstSuccEdges = new ArrayList<StatEdge>();
- DirectNode sourcenode = null;
-
- if(statEntry.succEdges == null) {
-
- switch(stat.type) {
- case Statement.TYPE_BASICBLOCK:
- node = new DirectNode(DirectNode.NODE_DIRECT, stat, (BasicBlockStatement)stat);
- if(stat.getExprents() != null) {
- node.exprents = stat.getExprents();
- }
- graph.nodes.putWithKey(node, node.id);
- mapDestinationNodes.put(stat.id, new String[] {node.id, null});
-
- lstSuccEdges.addAll(stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL));
- sourcenode = node;
-
- List<Exprent> tailExprentList = statEntry.tailExprents;
-
- if(tailExprentList != null) {
- DirectNode tail = new DirectNode(DirectNode.NODE_TAIL, stat, stat.id+"_tail");
- tail.exprents = tailExprentList;
- graph.nodes.putWithKey(tail, tail.id);
-
- mapDestinationNodes.put(-stat.id, new String[] {tail.id, null});
- listEdges.add(new Edge(node.id, -stat.id, StatEdge.TYPE_REGULAR));
-
- sourcenode = tail;
- }
-
- // 'if' statement: record positive branch
- if(stat.getLastBasicType() == Statement.LASTBASICTYPE_IF) {
- mapPosIfBranch.put(sourcenode.id, lstSuccEdges.get(0).getDestination().id.toString());
- }
-
- break;
- case Statement.TYPE_CATCHALL:
- case Statement.TYPE_TRYCATCH:
- DirectNode firstnd = new DirectNode(DirectNode.NODE_TRY, stat, stat.id+"_try");
-
- mapDestinationNodes.put(stat.id, new String[] {firstnd.id, null});
- graph.nodes.putWithKey(firstnd, firstnd.id);
-
- LinkedList<StatementStackEntry> lst = new LinkedList<StatementStackEntry>();
-
- for(Statement st: stat.getStats()) {
- listEdges.add(new Edge(firstnd.id, st.id, StatEdge.TYPE_REGULAR));
-
- LinkedList<StackEntry> stack = stackFinally;
- if(stat.type == Statement.TYPE_CATCHALL && ((CatchAllStatement)stat).isFinally()) {
- stack = new LinkedList<StackEntry>(stackFinally);
-
- if(st == stat.getFirst()) { // catch head
- stack.add(new StackEntry((CatchAllStatement)stat, Boolean.FALSE));
- } else { // handler
- stack.add(new StackEntry((CatchAllStatement)stat, Boolean.TRUE, StatEdge.TYPE_BREAK,
- root.getDummyExit(), st, st, firstnd, firstnd, true));
- }
- }
- lst.add(new StatementStackEntry(st, stack, null));
- }
-
- lstStackStatements.addAll(0, lst);
- break;
- case Statement.TYPE_DO:
- if(statementBreakIndex == 0) {
- statEntry.statementIndex = 1;
- lstStackStatements.addFirst(statEntry);
- lstStackStatements.addFirst(new StatementStackEntry(stat.getFirst(), stackFinally, null));
-
- continue mainloop;
- }
-
- nd = graph.nodes.getWithKey(mapDestinationNodes.get(stat.getFirst().id)[0]);
-
- DoStatement dostat = (DoStatement)stat;
- int looptype = dostat.getLooptype();
-
- if(looptype == DoStatement.LOOP_DO) {
- mapDestinationNodes.put(stat.id, new String[] {nd.id, nd.id});
- break;
- }
-
- lstSuccEdges.add(stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0)); // exactly one edge
-
- switch(looptype) {
- case DoStatement.LOOP_WHILE:
- case DoStatement.LOOP_DOWHILE:
- node = new DirectNode(DirectNode.NODE_CONDITION, stat, stat.id+"_cond");
- node.exprents = dostat.getConditionExprentList();
- graph.nodes.putWithKey(node, node.id);
-
- listEdges.add(new Edge(node.id, stat.getFirst().id, StatEdge.TYPE_REGULAR));
-
- if(looptype == DoStatement.LOOP_WHILE) {
- mapDestinationNodes.put(stat.id, new String[] {node.id, node.id});
- } else {
- mapDestinationNodes.put(stat.id, new String[] {nd.id, node.id});
-
- boolean found = false;
- for(Edge edge: listEdges) {
- if(edge.statid.equals(stat.id) && edge.edgetype == StatEdge.TYPE_CONTINUE) {
- found = true;
- break;
- }
- }
- if(!found) {
- listEdges.add(new Edge(nd.id, stat.id, StatEdge.TYPE_CONTINUE));
- }
- }
- sourcenode = node;
- break;
- case DoStatement.LOOP_FOR:
- DirectNode nodeinit = new DirectNode(DirectNode.NODE_INIT, stat, stat.id+"_init");
- if(dostat.getInitExprent() != null) {
- nodeinit.exprents = dostat.getInitExprentList();
- }
- graph.nodes.putWithKey(nodeinit, nodeinit.id);
-
- DirectNode nodecond = new DirectNode(DirectNode.NODE_CONDITION, stat, stat.id+"_cond");
- nodecond.exprents = dostat.getConditionExprentList();
- graph.nodes.putWithKey(nodecond, nodecond.id);
-
- DirectNode nodeinc = new DirectNode(DirectNode.NODE_INCREMENT, stat, stat.id+"_inc");
- nodeinc.exprents = dostat.getIncExprentList();
- graph.nodes.putWithKey(nodeinc, nodeinc.id);
-
- mapDestinationNodes.put(stat.id, new String[] {nodeinit.id, nodeinc.id});
- mapDestinationNodes.put(-stat.id, new String[] {nodecond.id, null});
-
- listEdges.add(new Edge(nodecond.id, stat.getFirst().id, StatEdge.TYPE_REGULAR));
- listEdges.add(new Edge(nodeinit.id, -stat.id, StatEdge.TYPE_REGULAR));
- listEdges.add(new Edge(nodeinc.id, -stat.id, StatEdge.TYPE_REGULAR));
-
- boolean found = false;
- for(Edge edge: listEdges) {
- if(edge.statid.equals(stat.id) && edge.edgetype == StatEdge.TYPE_CONTINUE) {
- found = true;
- break;
- }
- }
- if(!found) {
- listEdges.add(new Edge(nd.id, stat.id, StatEdge.TYPE_CONTINUE));
- }
-
- sourcenode = nodecond;
- }
- break;
- case Statement.TYPE_SYNCRONIZED:
- case Statement.TYPE_SWITCH:
- case Statement.TYPE_IF:
- case Statement.TYPE_SEQUENCE:
- case Statement.TYPE_ROOT:
- int statsize = stat.getStats().size();
- if(stat.type == Statement.TYPE_SYNCRONIZED) {
- statsize = 2; // exclude the handler if synchronized
- }
-
- if(statementBreakIndex <= statsize) {
- List<Exprent> tailexprlst = null;
-
- switch(stat.type) {
- case Statement.TYPE_SYNCRONIZED:
- tailexprlst = ((SynchronizedStatement)stat).getHeadexprentList();
- break;
- case Statement.TYPE_SWITCH:
- tailexprlst = ((SwitchStatement)stat).getHeadexprentList();
- break;
- case Statement.TYPE_IF:
- tailexprlst = ((IfStatement)stat).getHeadexprentList();
- }
-
- for(int i=statementBreakIndex; i < statsize; i++) {
- statEntry.statementIndex = i+1;
- lstStackStatements.addFirst(statEntry);
- lstStackStatements.addFirst(
- new StatementStackEntry(stat.getStats().get(i), stackFinally,
- (i==0 && tailexprlst != null && tailexprlst.get(0)!=null)?tailexprlst:null));
-
- continue mainloop;
- }
-
- node = graph.nodes.getWithKey(mapDestinationNodes.get(stat.getFirst().id)[0]);
- mapDestinationNodes.put(stat.id, new String[] {node.id, null});
-
- if(stat.type == Statement.TYPE_IF && ((IfStatement)stat).iftype == IfStatement.IFTYPE_IF) {
- lstSuccEdges.add(stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0)); // exactly one edge
- sourcenode = tailexprlst.get(0)==null?node:graph.nodes.getWithKey(node.id+"_tail");
- }
- }
- }
- }
-
- // no successor edges
- if(sourcenode != null) {
-
- if(statEntry.succEdges != null) {
- lstSuccEdges = statEntry.succEdges;
- }
-
- for(int edgeindex = statEntry.edgeIndex; edgeindex < lstSuccEdges.size(); edgeindex++) {
-
- StatEdge edge = lstSuccEdges.get(edgeindex);
-
- LinkedList<StackEntry> stack = new LinkedList<StackEntry>(stackFinally);
-
- int edgetype = edge.getType();
- Statement destination = edge.getDestination();
-
- DirectNode finallyShortRangeSource = sourcenode;
- DirectNode finallyLongRangeSource = sourcenode;
- Statement finallyShortRangeEntry = null;
- Statement finallyLongRangeEntry = null;
-
- boolean isFinallyMonitorExceptionPath = false;
-
- boolean isFinallyExit = false;
-
- for(;;) {
-
- StackEntry entry = null;
- if(!stack.isEmpty()) {
- entry = stack.getLast();
- }
-
- boolean created = true;
-
- if(entry == null) {
- saveEdge(sourcenode, destination, edgetype, isFinallyExit?finallyShortRangeSource:null, finallyLongRangeSource, finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
- } else {
-
- CatchAllStatement catchall = entry.catchstatement;
-
- if(entry.state) { // finally handler statement
- if(edgetype == StatEdge.TYPE_FINALLYEXIT) {
-
- stack.removeLast();
- destination = entry.destination;
- edgetype = entry.edgetype;
-
- finallyShortRangeSource = entry.finallyShortRangeSource;
- finallyLongRangeSource = entry.finallyLongRangeSource;
- finallyShortRangeEntry = entry.finallyShortRangeEntry;
- finallyLongRangeEntry = entry.finallyLongRangeEntry;
-
- isFinallyExit = true;
- isFinallyMonitorExceptionPath = (catchall.getMonitor() != null) & entry.isFinallyExceptionPath;
-
- created = false;
- } else {
- if(!catchall.containsStatementStrict(destination)) {
- stack.removeLast();
- created = false;
- } else {
- saveEdge(sourcenode, destination, edgetype, isFinallyExit?finallyShortRangeSource:null, finallyLongRangeSource, finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
- }
- }
- } else { // finally protected try statement
- if(!catchall.containsStatementStrict(destination)) {
- saveEdge(sourcenode, catchall.getHandler(), StatEdge.TYPE_REGULAR, isFinallyExit?finallyShortRangeSource:null, finallyLongRangeSource, finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
-
- stack.removeLast();
- stack.add(new StackEntry(catchall, Boolean.TRUE, edgetype, destination, catchall.getHandler(), finallyLongRangeEntry==null?catchall.getHandler():finallyLongRangeEntry,
- sourcenode, finallyLongRangeSource, false));
-
- statEntry.edgeIndex = edgeindex+1;
- statEntry.succEdges = lstSuccEdges;
- lstStackStatements.addFirst(statEntry);
- lstStackStatements.addFirst(new StatementStackEntry(catchall.getHandler(), stack, null));
-
- continue mainloop;
- } else {
- saveEdge(sourcenode, destination, edgetype, isFinallyExit?finallyShortRangeSource:null, finallyLongRangeSource, finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
- }
- }
- }
-
- if(created) {
- break;
- }
- }
- }
- }
-
- }
-
- }
-
- private void saveEdge(DirectNode sourcenode, Statement destination, int edgetype, DirectNode finallyShortRangeSource,
- DirectNode finallyLongRangeSource, Statement finallyShortRangeEntry, Statement finallyLongRangeEntry, boolean isFinallyMonitorExceptionPath) {
-
- if(edgetype != StatEdge.TYPE_FINALLYEXIT) {
- listEdges.add(new Edge(sourcenode.id, destination.id, edgetype));
- }
-
- if(finallyShortRangeSource != null) {
-
- boolean isContinueEdge = (edgetype == StatEdge.TYPE_CONTINUE);
-
- List<String[]> lst = mapShortRangeFinallyPathIds.get(sourcenode.id);
- if(lst == null) {
- mapShortRangeFinallyPathIds.put(sourcenode.id, lst = new ArrayList<String[]>());
- }
- lst.add(new String[]{finallyShortRangeSource.id, destination.id.toString(), finallyShortRangeEntry.id.toString(), isFinallyMonitorExceptionPath?"1":null, isContinueEdge?"1":null});
-
- lst = mapLongRangeFinallyPathIds.get(sourcenode.id);
- if(lst == null) {
- mapLongRangeFinallyPathIds.put(sourcenode.id, lst = new ArrayList<String[]>());
- }
- lst.add(new String[]{finallyLongRangeSource.id, destination.id.toString(), finallyLongRangeEntry.id.toString(), isContinueEdge?"1":null});
- }
-
- }
-
- private void setEdges() {
-
- for(Edge edge : listEdges) {
-
- String sourceid = edge.sourceid;
- Integer statid = edge.statid;
-
- DirectNode source = graph.nodes.getWithKey(sourceid);
-
- DirectNode dest = graph.nodes.getWithKey(mapDestinationNodes.get(statid)[edge.edgetype==StatEdge.TYPE_CONTINUE?1:0]);
-
- if(!source.succs.contains(dest)) {
- source.succs.add(dest);
- }
-
- if(!dest.preds.contains(source)) {
- dest.preds.add(source);
- }
-
- if(mapPosIfBranch.containsKey(sourceid) && !statid.equals(mapPosIfBranch.get(sourceid))) {
- graph.mapNegIfBranch.put(sourceid, dest.id);
- }
- }
-
- for(int i=0;i<2;i++) {
- for(Entry<String, List<String[]>> ent : (i==0?mapShortRangeFinallyPathIds:mapLongRangeFinallyPathIds).entrySet()) {
-
- List<FinallyPathWrapper> newLst = new ArrayList<FinallyPathWrapper>();
-
- List<String[]> lst = ent.getValue();
- for(String[] arr : lst) {
-
- boolean isContinueEdge = arr[i==0?4:3] != null;
-
- DirectNode dest = graph.nodes.getWithKey(mapDestinationNodes.get(Integer.parseInt(arr[1]))[isContinueEdge?1:0]);
- DirectNode enter = graph.nodes.getWithKey(mapDestinationNodes.get(Integer.parseInt(arr[2]))[0]);
-
- newLst.add(new FinallyPathWrapper(arr[0], dest.id, enter.id));
-
- if(i==0 && arr[3] != null) {
- graph.mapFinallyMonitorExceptionPathExits.put(ent.getKey(), dest.id);
- }
- }
-
- if(!newLst.isEmpty()) {
- (i==0?graph.mapShortRangeFinallyPaths:graph.mapLongRangeFinallyPaths).put(ent.getKey(),
- new ArrayList<FinallyPathWrapper>(new HashSet<FinallyPathWrapper>(newLst)));
- }
- }
- }
-
- }
-
- public HashMap<Integer, String[]> getMapDestinationNodes() {
- return mapDestinationNodes;
- }
-
- public static class FinallyPathWrapper {
- public String source;
- public String destination;
- public String entry;
-
- private FinallyPathWrapper(String source, String destination, String entry) {
- this.source = source;
- this.destination = destination;
- this.entry = entry;
- }
-
- @Override
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof FinallyPathWrapper)) return false;
+ // statement.id, node.id(direct), node.id(continue)
+ private HashMap<Integer, String[]> mapDestinationNodes = new HashMap<Integer, String[]>();
+
+ // node.id(source), statement.id(destination), edge type
+ private List<Edge> listEdges = new ArrayList<Edge>();
+
+ // node.id(exit), [node.id(source), statement.id(destination)]
+ public HashMap<String, List<String[]>> mapShortRangeFinallyPathIds = new HashMap<String, List<String[]>>();
+
+ // node.id(exit), [node.id(source), statement.id(destination)]
+ public HashMap<String, List<String[]>> mapLongRangeFinallyPathIds = new HashMap<String, List<String[]>>();
+
+ // positive if branches
+ public HashMap<String, String> mapPosIfBranch = new HashMap<String, String>();
+
+
+ private DirectGraph graph;
+
+ private RootStatement root;
+
+ public DirectGraph buildDirectGraph(RootStatement root) {
+
+ this.root = root;
+
+ graph = new DirectGraph();
+
+ flattenStatement();
+
+ // dummy exit node
+ Statement dummyexit = root.getDummyExit();
+ DirectNode node = new DirectNode(DirectNode.NODE_DIRECT, dummyexit, dummyexit.id.toString());
+ node.exprents = new ArrayList<Exprent>();
+ graph.nodes.addWithKey(node, node.id);
+ mapDestinationNodes.put(dummyexit.id, new String[]{node.id, null});
+
+ setEdges();
+
+ graph.first = graph.nodes.getWithKey(mapDestinationNodes.get(root.id)[0]);
+ graph.sortReversePostOrder();
+
+ return graph;
+ }
+
+ private void flattenStatement() {
+
+ class StatementStackEntry {
+ public Statement statement;
+ public LinkedList<StackEntry> stackFinally;
+ public List<Exprent> tailExprents;
+
+ public int statementIndex;
+ public int edgeIndex;
+ public List<StatEdge> succEdges;
+
+ public StatementStackEntry(Statement statement, LinkedList<StackEntry> stackFinally, List<Exprent> tailExprents) {
+ this.statement = statement;
+ this.stackFinally = stackFinally;
+ this.tailExprents = tailExprents;
+ }
+ }
+
+ LinkedList<StatementStackEntry> lstStackStatements = new LinkedList<StatementStackEntry>();
+
+ lstStackStatements.add(new StatementStackEntry(root, new LinkedList<StackEntry>(), null));
+
+ mainloop:
+ while (!lstStackStatements.isEmpty()) {
+
+ StatementStackEntry statEntry = lstStackStatements.removeFirst();
+
+ Statement stat = statEntry.statement;
+ LinkedList<StackEntry> stackFinally = statEntry.stackFinally;
+ int statementBreakIndex = statEntry.statementIndex;
+
+ DirectNode node = null, nd = null;
+
+ List<StatEdge> lstSuccEdges = new ArrayList<StatEdge>();
+ DirectNode sourcenode = null;
+
+ if (statEntry.succEdges == null) {
+
+ switch (stat.type) {
+ case Statement.TYPE_BASICBLOCK:
+ node = new DirectNode(DirectNode.NODE_DIRECT, stat, (BasicBlockStatement)stat);
+ if (stat.getExprents() != null) {
+ node.exprents = stat.getExprents();
+ }
+ graph.nodes.putWithKey(node, node.id);
+ mapDestinationNodes.put(stat.id, new String[]{node.id, null});
+
+ lstSuccEdges.addAll(stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL));
+ sourcenode = node;
+
+ List<Exprent> tailExprentList = statEntry.tailExprents;
+
+ if (tailExprentList != null) {
+ DirectNode tail = new DirectNode(DirectNode.NODE_TAIL, stat, stat.id + "_tail");
+ tail.exprents = tailExprentList;
+ graph.nodes.putWithKey(tail, tail.id);
+
+ mapDestinationNodes.put(-stat.id, new String[]{tail.id, null});
+ listEdges.add(new Edge(node.id, -stat.id, StatEdge.TYPE_REGULAR));
+
+ sourcenode = tail;
+ }
+
+ // 'if' statement: record positive branch
+ if (stat.getLastBasicType() == Statement.LASTBASICTYPE_IF) {
+ mapPosIfBranch.put(sourcenode.id, lstSuccEdges.get(0).getDestination().id.toString());
+ }
+
+ break;
+ case Statement.TYPE_CATCHALL:
+ case Statement.TYPE_TRYCATCH:
+ DirectNode firstnd = new DirectNode(DirectNode.NODE_TRY, stat, stat.id + "_try");
+
+ mapDestinationNodes.put(stat.id, new String[]{firstnd.id, null});
+ graph.nodes.putWithKey(firstnd, firstnd.id);
+
+ LinkedList<StatementStackEntry> lst = new LinkedList<StatementStackEntry>();
+
+ for (Statement st : stat.getStats()) {
+ listEdges.add(new Edge(firstnd.id, st.id, StatEdge.TYPE_REGULAR));
+
+ LinkedList<StackEntry> stack = stackFinally;
+ if (stat.type == Statement.TYPE_CATCHALL && ((CatchAllStatement)stat).isFinally()) {
+ stack = new LinkedList<StackEntry>(stackFinally);
+
+ if (st == stat.getFirst()) { // catch head
+ stack.add(new StackEntry((CatchAllStatement)stat, Boolean.FALSE));
+ }
+ else { // handler
+ stack.add(new StackEntry((CatchAllStatement)stat, Boolean.TRUE, StatEdge.TYPE_BREAK,
+ root.getDummyExit(), st, st, firstnd, firstnd, true));
+ }
+ }
+ lst.add(new StatementStackEntry(st, stack, null));
+ }
+
+ lstStackStatements.addAll(0, lst);
+ break;
+ case Statement.TYPE_DO:
+ if (statementBreakIndex == 0) {
+ statEntry.statementIndex = 1;
+ lstStackStatements.addFirst(statEntry);
+ lstStackStatements.addFirst(new StatementStackEntry(stat.getFirst(), stackFinally, null));
+
+ continue mainloop;
+ }
+
+ nd = graph.nodes.getWithKey(mapDestinationNodes.get(stat.getFirst().id)[0]);
+
+ DoStatement dostat = (DoStatement)stat;
+ int looptype = dostat.getLooptype();
+
+ if (looptype == DoStatement.LOOP_DO) {
+ mapDestinationNodes.put(stat.id, new String[]{nd.id, nd.id});
+ break;
+ }
+
+ lstSuccEdges.add(stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0)); // exactly one edge
+
+ switch (looptype) {
+ case DoStatement.LOOP_WHILE:
+ case DoStatement.LOOP_DOWHILE:
+ node = new DirectNode(DirectNode.NODE_CONDITION, stat, stat.id + "_cond");
+ node.exprents = dostat.getConditionExprentList();
+ graph.nodes.putWithKey(node, node.id);
+
+ listEdges.add(new Edge(node.id, stat.getFirst().id, StatEdge.TYPE_REGULAR));
+
+ if (looptype == DoStatement.LOOP_WHILE) {
+ mapDestinationNodes.put(stat.id, new String[]{node.id, node.id});
+ }
+ else {
+ mapDestinationNodes.put(stat.id, new String[]{nd.id, node.id});
+
+ boolean found = false;
+ for (Edge edge : listEdges) {
+ if (edge.statid.equals(stat.id) && edge.edgetype == StatEdge.TYPE_CONTINUE) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ listEdges.add(new Edge(nd.id, stat.id, StatEdge.TYPE_CONTINUE));
+ }
+ }
+ sourcenode = node;
+ break;
+ case DoStatement.LOOP_FOR:
+ DirectNode nodeinit = new DirectNode(DirectNode.NODE_INIT, stat, stat.id + "_init");
+ if (dostat.getInitExprent() != null) {
+ nodeinit.exprents = dostat.getInitExprentList();
+ }
+ graph.nodes.putWithKey(nodeinit, nodeinit.id);
+
+ DirectNode nodecond = new DirectNode(DirectNode.NODE_CONDITION, stat, stat.id + "_cond");
+ nodecond.exprents = dostat.getConditionExprentList();
+ graph.nodes.putWithKey(nodecond, nodecond.id);
+
+ DirectNode nodeinc = new DirectNode(DirectNode.NODE_INCREMENT, stat, stat.id + "_inc");
+ nodeinc.exprents = dostat.getIncExprentList();
+ graph.nodes.putWithKey(nodeinc, nodeinc.id);
+
+ mapDestinationNodes.put(stat.id, new String[]{nodeinit.id, nodeinc.id});
+ mapDestinationNodes.put(-stat.id, new String[]{nodecond.id, null});
+
+ listEdges.add(new Edge(nodecond.id, stat.getFirst().id, StatEdge.TYPE_REGULAR));
+ listEdges.add(new Edge(nodeinit.id, -stat.id, StatEdge.TYPE_REGULAR));
+ listEdges.add(new Edge(nodeinc.id, -stat.id, StatEdge.TYPE_REGULAR));
+
+ boolean found = false;
+ for (Edge edge : listEdges) {
+ if (edge.statid.equals(stat.id) && edge.edgetype == StatEdge.TYPE_CONTINUE) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ listEdges.add(new Edge(nd.id, stat.id, StatEdge.TYPE_CONTINUE));
+ }
+
+ sourcenode = nodecond;
+ }
+ break;
+ case Statement.TYPE_SYNCRONIZED:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_IF:
+ case Statement.TYPE_SEQUENCE:
+ case Statement.TYPE_ROOT:
+ int statsize = stat.getStats().size();
+ if (stat.type == Statement.TYPE_SYNCRONIZED) {
+ statsize = 2; // exclude the handler if synchronized
+ }
+
+ if (statementBreakIndex <= statsize) {
+ List<Exprent> tailexprlst = null;
+
+ switch (stat.type) {
+ case Statement.TYPE_SYNCRONIZED:
+ tailexprlst = ((SynchronizedStatement)stat).getHeadexprentList();
+ break;
+ case Statement.TYPE_SWITCH:
+ tailexprlst = ((SwitchStatement)stat).getHeadexprentList();
+ break;
+ case Statement.TYPE_IF:
+ tailexprlst = ((IfStatement)stat).getHeadexprentList();
+ }
+
+ for (int i = statementBreakIndex; i < statsize; i++) {
+ statEntry.statementIndex = i + 1;
+ lstStackStatements.addFirst(statEntry);
+ lstStackStatements.addFirst(
+ new StatementStackEntry(stat.getStats().get(i), stackFinally,
+ (i == 0 && tailexprlst != null && tailexprlst.get(0) != null) ? tailexprlst : null));
+
+ continue mainloop;
+ }
+
+ node = graph.nodes.getWithKey(mapDestinationNodes.get(stat.getFirst().id)[0]);
+ mapDestinationNodes.put(stat.id, new String[]{node.id, null});
+
+ if (stat.type == Statement.TYPE_IF && ((IfStatement)stat).iftype == IfStatement.IFTYPE_IF) {
+ lstSuccEdges.add(stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0)); // exactly one edge
+ sourcenode = tailexprlst.get(0) == null ? node : graph.nodes.getWithKey(node.id + "_tail");
+ }
+ }
+ }
+ }
+
+ // no successor edges
+ if (sourcenode != null) {
+
+ if (statEntry.succEdges != null) {
+ lstSuccEdges = statEntry.succEdges;
+ }
+
+ for (int edgeindex = statEntry.edgeIndex; edgeindex < lstSuccEdges.size(); edgeindex++) {
+
+ StatEdge edge = lstSuccEdges.get(edgeindex);
+
+ LinkedList<StackEntry> stack = new LinkedList<StackEntry>(stackFinally);
+
+ int edgetype = edge.getType();
+ Statement destination = edge.getDestination();
+
+ DirectNode finallyShortRangeSource = sourcenode;
+ DirectNode finallyLongRangeSource = sourcenode;
+ Statement finallyShortRangeEntry = null;
+ Statement finallyLongRangeEntry = null;
+
+ boolean isFinallyMonitorExceptionPath = false;
+
+ boolean isFinallyExit = false;
+
+ for (; ; ) {
+
+ StackEntry entry = null;
+ if (!stack.isEmpty()) {
+ entry = stack.getLast();
+ }
+
+ boolean created = true;
+
+ if (entry == null) {
+ saveEdge(sourcenode, destination, edgetype, isFinallyExit ? finallyShortRangeSource : null, finallyLongRangeSource,
+ finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
+ }
+ else {
+
+ CatchAllStatement catchall = entry.catchstatement;
+
+ if (entry.state) { // finally handler statement
+ if (edgetype == StatEdge.TYPE_FINALLYEXIT) {
+
+ stack.removeLast();
+ destination = entry.destination;
+ edgetype = entry.edgetype;
+
+ finallyShortRangeSource = entry.finallyShortRangeSource;
+ finallyLongRangeSource = entry.finallyLongRangeSource;
+ finallyShortRangeEntry = entry.finallyShortRangeEntry;
+ finallyLongRangeEntry = entry.finallyLongRangeEntry;
+
+ isFinallyExit = true;
+ isFinallyMonitorExceptionPath = (catchall.getMonitor() != null) & entry.isFinallyExceptionPath;
+
+ created = false;
+ }
+ else {
+ if (!catchall.containsStatementStrict(destination)) {
+ stack.removeLast();
+ created = false;
+ }
+ else {
+ saveEdge(sourcenode, destination, edgetype, isFinallyExit ? finallyShortRangeSource : null, finallyLongRangeSource,
+ finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
+ }
+ }
+ }
+ else { // finally protected try statement
+ if (!catchall.containsStatementStrict(destination)) {
+ saveEdge(sourcenode, catchall.getHandler(), StatEdge.TYPE_REGULAR, isFinallyExit ? finallyShortRangeSource : null,
+ finallyLongRangeSource, finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
+
+ stack.removeLast();
+ stack.add(new StackEntry(catchall, Boolean.TRUE, edgetype, destination, catchall.getHandler(),
+ finallyLongRangeEntry == null ? catchall.getHandler() : finallyLongRangeEntry,
+ sourcenode, finallyLongRangeSource, false));
+
+ statEntry.edgeIndex = edgeindex + 1;
+ statEntry.succEdges = lstSuccEdges;
+ lstStackStatements.addFirst(statEntry);
+ lstStackStatements.addFirst(new StatementStackEntry(catchall.getHandler(), stack, null));
+
+ continue mainloop;
+ }
+ else {
+ saveEdge(sourcenode, destination, edgetype, isFinallyExit ? finallyShortRangeSource : null, finallyLongRangeSource,
+ finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
+ }
+ }
+ }
+
+ if (created) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void saveEdge(DirectNode sourcenode,
+ Statement destination,
+ int edgetype,
+ DirectNode finallyShortRangeSource,
+ DirectNode finallyLongRangeSource,
+ Statement finallyShortRangeEntry,
+ Statement finallyLongRangeEntry,
+ boolean isFinallyMonitorExceptionPath) {
+
+ if (edgetype != StatEdge.TYPE_FINALLYEXIT) {
+ listEdges.add(new Edge(sourcenode.id, destination.id, edgetype));
+ }
+
+ if (finallyShortRangeSource != null) {
+
+ boolean isContinueEdge = (edgetype == StatEdge.TYPE_CONTINUE);
+
+ List<String[]> lst = mapShortRangeFinallyPathIds.get(sourcenode.id);
+ if (lst == null) {
+ mapShortRangeFinallyPathIds.put(sourcenode.id, lst = new ArrayList<String[]>());
+ }
+ lst.add(new String[]{finallyShortRangeSource.id, destination.id.toString(), finallyShortRangeEntry.id.toString(),
+ isFinallyMonitorExceptionPath ? "1" : null, isContinueEdge ? "1" : null});
+
+ lst = mapLongRangeFinallyPathIds.get(sourcenode.id);
+ if (lst == null) {
+ mapLongRangeFinallyPathIds.put(sourcenode.id, lst = new ArrayList<String[]>());
+ }
+ lst.add(new String[]{finallyLongRangeSource.id, destination.id.toString(), finallyLongRangeEntry.id.toString(),
+ isContinueEdge ? "1" : null});
+ }
+ }
+
+ private void setEdges() {
+
+ for (Edge edge : listEdges) {
+
+ String sourceid = edge.sourceid;
+ Integer statid = edge.statid;
+
+ DirectNode source = graph.nodes.getWithKey(sourceid);
+
+ DirectNode dest = graph.nodes.getWithKey(mapDestinationNodes.get(statid)[edge.edgetype == StatEdge.TYPE_CONTINUE ? 1 : 0]);
+
+ if (!source.succs.contains(dest)) {
+ source.succs.add(dest);
+ }
+
+ if (!dest.preds.contains(source)) {
+ dest.preds.add(source);
+ }
+
+ if (mapPosIfBranch.containsKey(sourceid) && !statid.equals(mapPosIfBranch.get(sourceid))) {
+ graph.mapNegIfBranch.put(sourceid, dest.id);
+ }
+ }
+
+ for (int i = 0; i < 2; i++) {
+ for (Entry<String, List<String[]>> ent : (i == 0 ? mapShortRangeFinallyPathIds : mapLongRangeFinallyPathIds).entrySet()) {
+
+ List<FinallyPathWrapper> newLst = new ArrayList<FinallyPathWrapper>();
+
+ List<String[]> lst = ent.getValue();
+ for (String[] arr : lst) {
+
+ boolean isContinueEdge = arr[i == 0 ? 4 : 3] != null;
+
+ DirectNode dest = graph.nodes.getWithKey(mapDestinationNodes.get(Integer.parseInt(arr[1]))[isContinueEdge ? 1 : 0]);
+ DirectNode enter = graph.nodes.getWithKey(mapDestinationNodes.get(Integer.parseInt(arr[2]))[0]);
+
+ newLst.add(new FinallyPathWrapper(arr[0], dest.id, enter.id));
+
+ if (i == 0 && arr[3] != null) {
+ graph.mapFinallyMonitorExceptionPathExits.put(ent.getKey(), dest.id);
+ }
+ }
+
+ if (!newLst.isEmpty()) {
+ (i == 0 ? graph.mapShortRangeFinallyPaths : graph.mapLongRangeFinallyPaths).put(ent.getKey(),
+ new ArrayList<FinallyPathWrapper>(
+ new HashSet<FinallyPathWrapper>(newLst)));
+ }
+ }
+ }
+ }
+
+ public HashMap<Integer, String[]> getMapDestinationNodes() {
+ return mapDestinationNodes;
+ }
+
+ public static class FinallyPathWrapper {
+ public String source;
+ public String destination;
+ public String entry;
+
+ private FinallyPathWrapper(String source, String destination, String entry) {
+ this.source = source;
+ this.destination = destination;
+ this.entry = entry;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FinallyPathWrapper)) return false;
FinallyPathWrapper fpw = (FinallyPathWrapper)o;
- return (source+":"+destination+":"+entry).equals(fpw.source+":"+fpw.destination+":"+fpw.entry);
+ return (source + ":" + destination + ":" + entry).equals(fpw.source + ":" + fpw.destination + ":" + fpw.entry);
}
- @Override
- public int hashCode() {
- return (source+":"+destination+":"+entry).hashCode();
- }
+ @Override
+ public int hashCode() {
+ return (source + ":" + destination + ":" + entry).hashCode();
+ }
@Override
- public String toString() {
- return source + "->(" + entry + ")->" + destination;
- }
- }
-
-
- private static class StackEntry {
-
- public CatchAllStatement catchstatement;
- public boolean state;
- public int edgetype;
- public boolean isFinallyExceptionPath;
-
- public Statement destination;
- public Statement finallyShortRangeEntry;
- public Statement finallyLongRangeEntry;
- public DirectNode finallyShortRangeSource;
- public DirectNode finallyLongRangeSource;
-
- public StackEntry(CatchAllStatement catchstatement, boolean state, int edgetype, Statement destination,
- Statement finallyShortRangeEntry, Statement finallyLongRangeEntry, DirectNode finallyShortRangeSource, DirectNode finallyLongRangeSource, boolean isFinallyExceptionPath) {
-
- this.catchstatement=catchstatement;
- this.state=state;
- this.edgetype=edgetype;
- this.isFinallyExceptionPath = isFinallyExceptionPath;
-
- this.destination=destination;
- this.finallyShortRangeEntry=finallyShortRangeEntry;
- this.finallyLongRangeEntry=finallyLongRangeEntry;
- this.finallyShortRangeSource=finallyShortRangeSource;
- this.finallyLongRangeSource=finallyLongRangeSource;
- }
-
- public StackEntry(CatchAllStatement catchstatement, boolean state) {
- this(catchstatement, state, -1, null, null, null, null, null, false);
- }
-
- }
-
- private static class Edge {
- public String sourceid;
- public Integer statid;
- public int edgetype;
-
- public Edge(String sourceid, Integer statid, int edgetype) {
- this.sourceid = sourceid;
- this.statid = statid;
- this.edgetype = edgetype;
- }
- }
+ public String toString() {
+ return source + "->(" + entry + ")->" + destination;
+ }
+ }
+
+
+ private static class StackEntry {
+
+ public CatchAllStatement catchstatement;
+ public boolean state;
+ public int edgetype;
+ public boolean isFinallyExceptionPath;
+
+ public Statement destination;
+ public Statement finallyShortRangeEntry;
+ public Statement finallyLongRangeEntry;
+ public DirectNode finallyShortRangeSource;
+ public DirectNode finallyLongRangeSource;
+
+ public StackEntry(CatchAllStatement catchstatement,
+ boolean state,
+ int edgetype,
+ Statement destination,
+ Statement finallyShortRangeEntry,
+ Statement finallyLongRangeEntry,
+ DirectNode finallyShortRangeSource,
+ DirectNode finallyLongRangeSource,
+ boolean isFinallyExceptionPath) {
+
+ this.catchstatement = catchstatement;
+ this.state = state;
+ this.edgetype = edgetype;
+ this.isFinallyExceptionPath = isFinallyExceptionPath;
+
+ this.destination = destination;
+ this.finallyShortRangeEntry = finallyShortRangeEntry;
+ this.finallyLongRangeEntry = finallyLongRangeEntry;
+ this.finallyShortRangeSource = finallyShortRangeSource;
+ this.finallyLongRangeSource = finallyLongRangeSource;
+ }
+
+ public StackEntry(CatchAllStatement catchstatement, boolean state) {
+ this(catchstatement, state, -1, null, null, null, null, null, false);
+ }
+ }
+
+ private static class Edge {
+ public String sourceid;
+ public Integer statid;
+ public int edgetype;
+
+ public Edge(String sourceid, Integer statid, int edgetype) {
+ this.sourceid = sourceid;
+ this.statid = statid;
+ this.edgetype = edgetype;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java
index e21f38a..5a6cb9d 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java
@@ -1,26 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.sforms;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
@@ -39,476 +33,498 @@ import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
-public class SSAConstructorSparseEx {
-
- // node id, var, version
- private HashMap<String, SFormsFastMapDirect> inVarVersions = new HashMap<String, SFormsFastMapDirect>();
-
- // node id, var, version (direct branch)
- private HashMap<String, SFormsFastMapDirect> outVarVersions = new HashMap<String, SFormsFastMapDirect>();
-
- // node id, var, version (negative branch)
- private HashMap<String, SFormsFastMapDirect> outNegVarVersions = new HashMap<String, SFormsFastMapDirect>();
-
- // node id, var, version
- private HashMap<String, SFormsFastMapDirect> extraVarVersions = new HashMap<String, SFormsFastMapDirect>();
-
- // (var, version), version
- private HashMap<VarVersionPaar, FastSparseSet<Integer>> phi = new HashMap<VarVersionPaar, FastSparseSet<Integer>>();
-
- // var, version
- private HashMap<Integer, Integer> lastversion = new HashMap<Integer, Integer>();
-
- private List<VarVersionPaar> startVars = new ArrayList<VarVersionPaar>();
-
- // set factory
- private FastSparseSetFactory<Integer> factory;
-
- public void splitVariables(RootStatement root, StructMethod mt) {
-
- FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
- DirectGraph dgraph = flatthelper.buildDirectGraph(root);
-
- // try {
- // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
- // } catch(Exception ex) {ex.printStackTrace();}
-
- HashSet<Integer> setInit = new HashSet<Integer>();
- for(int i = 0; i < 64; i++) {
- setInit.add(i);
- }
- factory = new FastSparseSetFactory<Integer>(setInit);
-
- SFormsFastMapDirect firstmap = createFirstMap(mt);
- extraVarVersions.put(dgraph.first.id, firstmap);
-
- setCatchMaps(root, dgraph, flatthelper);
-
- HashSet<String> updated = new HashSet<String>();
- do {
- // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
- ssaStatements(dgraph, updated);
- // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
- } while (!updated.isEmpty());
- }
-
- private void ssaStatements(DirectGraph dgraph, HashSet<String> updated) {
-
- // try {
- // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot"));
- // } catch(Exception ex) {ex.printStackTrace();}
-
- for(DirectNode node : dgraph.nodes) {
-
-// if (node.id.endsWith("_inc")) {
-// System.out.println();
-//
-// try {
-// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot"));
-// } catch (Exception ex) {
-// ex.printStackTrace();
-// }
-// }
-
- updated.remove(node.id);
- mergeInVarMaps(node, dgraph);
-
- SFormsFastMapDirect varmap = inVarVersions.get(node.id);
- varmap = new SFormsFastMapDirect(varmap);
-
- SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[] { varmap, null };
-
- if (node.exprents != null) {
- for(Exprent expr : node.exprents) {
- processExprent(expr, varmaparr);
- }
- }
-
- if (varmaparr[1] == null) {
- varmaparr[1] = varmaparr[0];
- }
-
- boolean this_updated = !mapsEqual(varmaparr[0], outVarVersions.get(node.id))
- || (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
-
- if (this_updated) {
- outVarVersions.put(node.id, varmaparr[0]);
- if (dgraph.mapNegIfBranch.containsKey(node.id)) {
- outNegVarVersions.put(node.id, varmaparr[1]);
- }
-
- for(DirectNode nd : node.succs) {
- updated.add(nd.id);
- }
- }
- }
-
- }
-
- private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr) {
-
- if (expr == null) {
- return;
- }
-
- VarExprent varassign = null;
- boolean finished = false;
-
- switch (expr.type) {
- case Exprent.EXPRENT_ASSIGNMENT:
- AssignmentExprent assexpr = (AssignmentExprent) expr;
- if (assexpr.getCondtype() == AssignmentExprent.CONDITION_NONE) {
- Exprent dest = assexpr.getLeft();
- if (dest.type == Exprent.EXPRENT_VAR) {
- varassign = (VarExprent) dest;
- }
- }
- break;
- case Exprent.EXPRENT_FUNCTION:
- FunctionExprent func = (FunctionExprent) expr;
- switch (func.getFunctype()) {
- case FunctionExprent.FUNCTION_IIF:
- processExprent(func.getLstOperands().get(0), varmaparr);
-
- SFormsFastMapDirect varmapFalse;
- if (varmaparr[1] == null) {
- varmapFalse = new SFormsFastMapDirect(varmaparr[0]);
- } else {
- varmapFalse = varmaparr[1];
- varmaparr[1] = null;
- }
-
- processExprent(func.getLstOperands().get(1), varmaparr);
-
- SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[] { varmapFalse, null };
- processExprent(func.getLstOperands().get(2), varmaparrNeg);
-
- mergeMaps(varmaparr[0], varmaparrNeg[0]);
- varmaparr[1] = null;
-
- finished = true;
- break;
- case FunctionExprent.FUNCTION_CADD:
- processExprent(func.getLstOperands().get(0), varmaparr);
-
- SFormsFastMapDirect[] varmaparrAnd = new SFormsFastMapDirect[] { new SFormsFastMapDirect(varmaparr[0]), null };
-
- processExprent(func.getLstOperands().get(1), varmaparrAnd);
-
- // false map
- varmaparr[1] = mergeMaps(varmaparr[varmaparr[1] == null ? 0 : 1], varmaparrAnd[varmaparrAnd[1] == null ? 0 : 1]);
- // true map
- varmaparr[0] = varmaparrAnd[0];
-
- finished = true;
- break;
- case FunctionExprent.FUNCTION_COR:
- processExprent(func.getLstOperands().get(0), varmaparr);
-
- SFormsFastMapDirect[] varmaparrOr = new SFormsFastMapDirect[] { new SFormsFastMapDirect(varmaparr[varmaparr[1] == null ? 0 : 1]), null };
-
- processExprent(func.getLstOperands().get(1), varmaparrOr);
-
- // false map
- varmaparr[1] = varmaparrOr[varmaparrOr[1] == null ? 0 : 1];
- // true map
- varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]);
-
- finished = true;
- }
- }
-
- if (finished) {
- return;
- }
-
- List<Exprent> lst = expr.getAllExprents();
- lst.remove(varassign);
-
- for(Exprent ex : lst) {
- processExprent(ex, varmaparr);
- }
-
- SFormsFastMapDirect varmap = varmaparr[0];
-
- if (varassign != null) {
-
- Integer varindex = varassign.getIndex();
-
- if (varassign.getVersion() == 0) {
- // get next version
- Integer nextver = getNextFreeVersion(varindex);
-
- // set version
- varassign.setVersion(nextver);
-
- setCurrentVar(varmap, varindex, nextver);
- } else {
- setCurrentVar(varmap, varindex, varassign.getVersion());
- }
-
- } else if (expr.type == Exprent.EXPRENT_VAR) {
-
- VarExprent vardest = (VarExprent) expr;
- Integer varindex = vardest.getIndex();
- FastSparseSet<Integer> vers = varmap.get(varindex);
-
- int cardinality = vers.getCardinality();
- if (cardinality == 1) { // == 1
- // set version
- Integer it = vers.iterator().next();
- vardest.setVersion(it.intValue());
- } else if (cardinality == 2) { // size > 1
- Integer current_vers = vardest.getVersion();
-
- VarVersionPaar currpaar = new VarVersionPaar(varindex, current_vers);
- if (current_vers != 0 && phi.containsKey(currpaar)) {
- setCurrentVar(varmap, varindex, current_vers);
- // update phi node
- phi.get(currpaar).union(vers);
- } else {
- // increase version
- Integer nextver = getNextFreeVersion(varindex);
- // set version
- vardest.setVersion(nextver);
-
- setCurrentVar(varmap, varindex, nextver);
- // create new phi node
- phi.put(new VarVersionPaar(varindex, nextver), vers);
-
- }
- } // 0 means uninitialized variable, which is impossible
- }
- }
-
- private Integer getNextFreeVersion(Integer var) {
- Integer nextver = lastversion.get(var);
- if (nextver == null) {
- nextver = new Integer(1);
- } else {
- nextver = new Integer(nextver.intValue() + 1);
- }
- lastversion.put(var, nextver);
- return nextver;
- }
-
- private void mergeInVarMaps(DirectNode node, DirectGraph dgraph) {
-
- SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
-
- for(DirectNode pred : node.preds) {
- SFormsFastMapDirect mapOut = getFilteredOutMap(node.id, pred.id, dgraph, node.id);
- if (mapNew.isEmpty()) {
- mapNew = mapOut.getCopy();
- } else {
- mergeMaps(mapNew, mapOut);
- }
- }
-
- if (extraVarVersions.containsKey(node.id)) {
- SFormsFastMapDirect mapExtra = extraVarVersions.get(node.id);
- if (mapNew.isEmpty()) {
- mapNew = mapExtra.getCopy();
- } else {
- mergeMaps(mapNew, mapExtra);
- }
- }
-
- inVarVersions.put(node.id, mapNew);
- }
-
- private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph, String destid) {
-
- SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
-
- if (nodeid.equals(dgraph.mapNegIfBranch.get(predid))) {
- if (outNegVarVersions.containsKey(predid)) {
- mapNew = outNegVarVersions.get(predid).getCopy();
- }
- } else if (outVarVersions.containsKey(predid)) {
- mapNew = outVarVersions.get(predid).getCopy();
- }
-
- boolean isFinallyExit = dgraph.mapShortRangeFinallyPaths.containsKey(predid);
-
- if (isFinallyExit && !mapNew.isEmpty()) {
-
- SFormsFastMapDirect mapNewTemp = mapNew.getCopy();
-
- SFormsFastMapDirect mapTrueSource = new SFormsFastMapDirect();
-
- String exceptionDest = dgraph.mapFinallyMonitorExceptionPathExits.get(predid);
- boolean isExceptionMonitorExit = (exceptionDest != null && !nodeid.equals(exceptionDest));
-
- HashSet<String> setLongPathWrapper = new HashSet<String>();
- for(FinallyPathWrapper finwraplong : dgraph.mapLongRangeFinallyPaths.get(predid)) {
- setLongPathWrapper.add(finwraplong.destination + "##" + finwraplong.source);
- }
-
- for(FinallyPathWrapper finwrap : dgraph.mapShortRangeFinallyPaths.get(predid)) {
- SFormsFastMapDirect map;
-
- boolean recFinally = dgraph.mapShortRangeFinallyPaths.containsKey(finwrap.source);
-
- if (recFinally) {
- // recursion
- map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid);
- } else {
- if (finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) {
- map = outNegVarVersions.get(finwrap.source);
- } else {
- map = outVarVersions.get(finwrap.source);
- }
- }
-
- // false path?
- boolean isFalsePath = true;
-
- if (recFinally) {
- isFalsePath = !finwrap.destination.equals(nodeid);
- } else {
- isFalsePath = !setLongPathWrapper.contains(destid + "##" + finwrap.source);
- }
-
- if (isFalsePath) {
- mapNewTemp.complement(map);
- } else {
- if (mapTrueSource.isEmpty()) {
- if (map != null) {
- mapTrueSource = map.getCopy();
- }
- } else {
- mergeMaps(mapTrueSource, map);
- }
- }
- }
-
- if (isExceptionMonitorExit) {
-
- mapNew = mapTrueSource;
-
- } else {
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
- mapNewTemp.union(mapTrueSource);
+public class SSAConstructorSparseEx {
- SFormsFastMapDirect oldInMap = inVarVersions.get(nodeid);
- if (oldInMap != null) {
- mapNewTemp.union(oldInMap);
- }
-
- mapNew.intersection(mapNewTemp);
- }
- }
-
- return mapNew;
- }
+ // node id, var, version
+ private HashMap<String, SFormsFastMapDirect> inVarVersions = new HashMap<String, SFormsFastMapDirect>();
- private SFormsFastMapDirect mergeMaps(SFormsFastMapDirect mapTo, SFormsFastMapDirect map2) {
+ // node id, var, version (direct branch)
+ private HashMap<String, SFormsFastMapDirect> outVarVersions = new HashMap<String, SFormsFastMapDirect>();
- if (map2 != null && !map2.isEmpty()) {
- mapTo.union(map2);
- }
+ // node id, var, version (negative branch)
+ private HashMap<String, SFormsFastMapDirect> outNegVarVersions = new HashMap<String, SFormsFastMapDirect>();
- return mapTo;
- }
+ // node id, var, version
+ private HashMap<String, SFormsFastMapDirect> extraVarVersions = new HashMap<String, SFormsFastMapDirect>();
- private boolean mapsEqual(SFormsFastMapDirect map1, SFormsFastMapDirect map2) {
+ // (var, version), version
+ private HashMap<VarVersionPaar, FastSparseSet<Integer>> phi = new HashMap<VarVersionPaar, FastSparseSet<Integer>>();
- if (map1 == null) {
- return map2 == null;
- } else if (map2 == null) {
- return false;
- }
+ // var, version
+ private HashMap<Integer, Integer> lastversion = new HashMap<Integer, Integer>();
- if (map1.size() != map2.size()) {
- return false;
- }
+ private List<VarVersionPaar> startVars = new ArrayList<VarVersionPaar>();
- for(Entry<Integer, FastSparseSet<Integer>> ent2 : map2.entryList()) {
- if (!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) {
- return false;
- }
- }
+ // set factory
+ private FastSparseSetFactory<Integer> factory;
- return true;
- }
+ public void splitVariables(RootStatement root, StructMethod mt) {
- private void setCurrentVar(SFormsFastMapDirect varmap, Integer var, Integer vers) {
- FastSparseSet<Integer> set = factory.spawnEmptySet();
- set.add(vers);
- varmap.put(var, set);
- }
-
- private void setCatchMaps(Statement stat, DirectGraph dgraph, FlattenStatementsHelper flatthelper) {
-
- SFormsFastMapDirect map;
-
- switch (stat.type) {
- case Statement.TYPE_CATCHALL:
- case Statement.TYPE_TRYCATCH:
-
- List<VarExprent> lstVars;
- if (stat.type == Statement.TYPE_CATCHALL) {
- lstVars = ((CatchAllStatement) stat).getVars();
- } else {
- lstVars = ((CatchStatement) stat).getVars();
- }
-
- for(int i = 1; i < stat.getStats().size(); i++) {
- int varindex = lstVars.get(i - 1).getIndex();
- int version = getNextFreeVersion(varindex); // == 1
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
+ HashSet<Integer> setInit = new HashSet<Integer>();
+ for (int i = 0; i < 64; i++) {
+ setInit.add(i);
+ }
+ factory = new FastSparseSetFactory<Integer>(setInit);
+
+ SFormsFastMapDirect firstmap = createFirstMap(mt);
+ extraVarVersions.put(dgraph.first.id, firstmap);
+
+ setCatchMaps(root, dgraph, flatthelper);
+
+ HashSet<String> updated = new HashSet<String>();
+ do {
+ // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ ssaStatements(dgraph, updated);
+ // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ }
+ while (!updated.isEmpty());
+ }
+
+ private void ssaStatements(DirectGraph dgraph, HashSet<String> updated) {
- map = new SFormsFastMapDirect();
- setCurrentVar(map, varindex, version);
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
- extraVarVersions.put(dgraph.nodes.getWithKey(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0]).id, map);
- startVars.add(new VarVersionPaar(varindex, version));
- }
- }
+ for (DirectNode node : dgraph.nodes) {
- for(Statement st : stat.getStats()) {
- setCatchMaps(st, dgraph, flatthelper);
- }
- }
+ // if (node.id.endsWith("_inc")) {
+ // System.out.println();
+ //
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot"));
+ // } catch (Exception ex) {
+ // ex.printStackTrace();
+ // }
+ // }
- private SFormsFastMapDirect createFirstMap(StructMethod mt) {
+ updated.remove(node.id);
+ mergeInVarMaps(node, dgraph);
- boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
+ SFormsFastMapDirect varmap = inVarVersions.get(node.id);
+ varmap = new SFormsFastMapDirect(varmap);
- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+ SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[]{varmap, null};
- int paramcount = md.params.length + (thisvar ? 1 : 0);
+ if (node.exprents != null) {
+ for (Exprent expr : node.exprents) {
+ processExprent(expr, varmaparr);
+ }
+ }
- int varindex = 0;
- SFormsFastMapDirect map = new SFormsFastMapDirect();
- for(int i = 0; i < paramcount; i++) {
- int version = getNextFreeVersion(varindex); // == 1
+ if (varmaparr[1] == null) {
+ varmaparr[1] = varmaparr[0];
+ }
- FastSparseSet<Integer> set = factory.spawnEmptySet();
- set.add(version);
- map.put(varindex, set);
- startVars.add(new VarVersionPaar(varindex, version));
+ boolean this_updated = !mapsEqual(varmaparr[0], outVarVersions.get(node.id))
+ || (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
- if (thisvar) {
- if (i == 0) {
- varindex++;
- } else {
- varindex += md.params[i - 1].stack_size;
- }
- } else {
- varindex += md.params[i].stack_size;
- }
- }
+ if (this_updated) {
+ outVarVersions.put(node.id, varmaparr[0]);
+ if (dgraph.mapNegIfBranch.containsKey(node.id)) {
+ outNegVarVersions.put(node.id, varmaparr[1]);
+ }
- return map;
- }
+ for (DirectNode nd : node.succs) {
+ updated.add(nd.id);
+ }
+ }
+ }
+ }
- public HashMap<VarVersionPaar, FastSparseSet<Integer>> getPhi() {
- return phi;
- }
+ private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr) {
- public List<VarVersionPaar> getStartVars() {
- return startVars;
- }
+ if (expr == null) {
+ return;
+ }
+
+ VarExprent varassign = null;
+ boolean finished = false;
+
+ switch (expr.type) {
+ case Exprent.EXPRENT_ASSIGNMENT:
+ AssignmentExprent assexpr = (AssignmentExprent)expr;
+ if (assexpr.getCondtype() == AssignmentExprent.CONDITION_NONE) {
+ Exprent dest = assexpr.getLeft();
+ if (dest.type == Exprent.EXPRENT_VAR) {
+ varassign = (VarExprent)dest;
+ }
+ }
+ break;
+ case Exprent.EXPRENT_FUNCTION:
+ FunctionExprent func = (FunctionExprent)expr;
+ switch (func.getFunctype()) {
+ case FunctionExprent.FUNCTION_IIF:
+ processExprent(func.getLstOperands().get(0), varmaparr);
+
+ SFormsFastMapDirect varmapFalse;
+ if (varmaparr[1] == null) {
+ varmapFalse = new SFormsFastMapDirect(varmaparr[0]);
+ }
+ else {
+ varmapFalse = varmaparr[1];
+ varmaparr[1] = null;
+ }
+
+ processExprent(func.getLstOperands().get(1), varmaparr);
+
+ SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[]{varmapFalse, null};
+ processExprent(func.getLstOperands().get(2), varmaparrNeg);
+
+ mergeMaps(varmaparr[0], varmaparrNeg[0]);
+ varmaparr[1] = null;
+
+ finished = true;
+ break;
+ case FunctionExprent.FUNCTION_CADD:
+ processExprent(func.getLstOperands().get(0), varmaparr);
+
+ SFormsFastMapDirect[] varmaparrAnd = new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[0]), null};
+
+ processExprent(func.getLstOperands().get(1), varmaparrAnd);
+
+ // false map
+ varmaparr[1] = mergeMaps(varmaparr[varmaparr[1] == null ? 0 : 1], varmaparrAnd[varmaparrAnd[1] == null ? 0 : 1]);
+ // true map
+ varmaparr[0] = varmaparrAnd[0];
+
+ finished = true;
+ break;
+ case FunctionExprent.FUNCTION_COR:
+ processExprent(func.getLstOperands().get(0), varmaparr);
+
+ SFormsFastMapDirect[] varmaparrOr =
+ new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[varmaparr[1] == null ? 0 : 1]), null};
+
+ processExprent(func.getLstOperands().get(1), varmaparrOr);
+
+ // false map
+ varmaparr[1] = varmaparrOr[varmaparrOr[1] == null ? 0 : 1];
+ // true map
+ varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]);
+
+ finished = true;
+ }
+ }
+
+ if (finished) {
+ return;
+ }
+
+ List<Exprent> lst = expr.getAllExprents();
+ lst.remove(varassign);
+
+ for (Exprent ex : lst) {
+ processExprent(ex, varmaparr);
+ }
+
+ SFormsFastMapDirect varmap = varmaparr[0];
+
+ if (varassign != null) {
+
+ Integer varindex = varassign.getIndex();
+
+ if (varassign.getVersion() == 0) {
+ // get next version
+ Integer nextver = getNextFreeVersion(varindex);
+
+ // set version
+ varassign.setVersion(nextver);
+
+ setCurrentVar(varmap, varindex, nextver);
+ }
+ else {
+ setCurrentVar(varmap, varindex, varassign.getVersion());
+ }
+ }
+ else if (expr.type == Exprent.EXPRENT_VAR) {
+
+ VarExprent vardest = (VarExprent)expr;
+ Integer varindex = vardest.getIndex();
+ FastSparseSet<Integer> vers = varmap.get(varindex);
+
+ int cardinality = vers.getCardinality();
+ if (cardinality == 1) { // == 1
+ // set version
+ Integer it = vers.iterator().next();
+ vardest.setVersion(it.intValue());
+ }
+ else if (cardinality == 2) { // size > 1
+ Integer current_vers = vardest.getVersion();
+
+ VarVersionPaar currpaar = new VarVersionPaar(varindex, current_vers);
+ if (current_vers != 0 && phi.containsKey(currpaar)) {
+ setCurrentVar(varmap, varindex, current_vers);
+ // update phi node
+ phi.get(currpaar).union(vers);
+ }
+ else {
+ // increase version
+ Integer nextver = getNextFreeVersion(varindex);
+ // set version
+ vardest.setVersion(nextver);
+
+ setCurrentVar(varmap, varindex, nextver);
+ // create new phi node
+ phi.put(new VarVersionPaar(varindex, nextver), vers);
+ }
+ } // 0 means uninitialized variable, which is impossible
+ }
+ }
+
+ private Integer getNextFreeVersion(Integer var) {
+ Integer nextver = lastversion.get(var);
+ if (nextver == null) {
+ nextver = new Integer(1);
+ }
+ else {
+ nextver = new Integer(nextver.intValue() + 1);
+ }
+ lastversion.put(var, nextver);
+ return nextver;
+ }
+
+ private void mergeInVarMaps(DirectNode node, DirectGraph dgraph) {
+
+ SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
+
+ for (DirectNode pred : node.preds) {
+ SFormsFastMapDirect mapOut = getFilteredOutMap(node.id, pred.id, dgraph, node.id);
+ if (mapNew.isEmpty()) {
+ mapNew = mapOut.getCopy();
+ }
+ else {
+ mergeMaps(mapNew, mapOut);
+ }
+ }
+
+ if (extraVarVersions.containsKey(node.id)) {
+ SFormsFastMapDirect mapExtra = extraVarVersions.get(node.id);
+ if (mapNew.isEmpty()) {
+ mapNew = mapExtra.getCopy();
+ }
+ else {
+ mergeMaps(mapNew, mapExtra);
+ }
+ }
+
+ inVarVersions.put(node.id, mapNew);
+ }
+
+ private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph, String destid) {
+
+ SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
+
+ if (nodeid.equals(dgraph.mapNegIfBranch.get(predid))) {
+ if (outNegVarVersions.containsKey(predid)) {
+ mapNew = outNegVarVersions.get(predid).getCopy();
+ }
+ }
+ else if (outVarVersions.containsKey(predid)) {
+ mapNew = outVarVersions.get(predid).getCopy();
+ }
+
+ boolean isFinallyExit = dgraph.mapShortRangeFinallyPaths.containsKey(predid);
+
+ if (isFinallyExit && !mapNew.isEmpty()) {
+
+ SFormsFastMapDirect mapNewTemp = mapNew.getCopy();
+
+ SFormsFastMapDirect mapTrueSource = new SFormsFastMapDirect();
+
+ String exceptionDest = dgraph.mapFinallyMonitorExceptionPathExits.get(predid);
+ boolean isExceptionMonitorExit = (exceptionDest != null && !nodeid.equals(exceptionDest));
+
+ HashSet<String> setLongPathWrapper = new HashSet<String>();
+ for (FinallyPathWrapper finwraplong : dgraph.mapLongRangeFinallyPaths.get(predid)) {
+ setLongPathWrapper.add(finwraplong.destination + "##" + finwraplong.source);
+ }
+
+ for (FinallyPathWrapper finwrap : dgraph.mapShortRangeFinallyPaths.get(predid)) {
+ SFormsFastMapDirect map;
+
+ boolean recFinally = dgraph.mapShortRangeFinallyPaths.containsKey(finwrap.source);
+
+ if (recFinally) {
+ // recursion
+ map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid);
+ }
+ else {
+ if (finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) {
+ map = outNegVarVersions.get(finwrap.source);
+ }
+ else {
+ map = outVarVersions.get(finwrap.source);
+ }
+ }
+
+ // false path?
+ boolean isFalsePath = true;
+
+ if (recFinally) {
+ isFalsePath = !finwrap.destination.equals(nodeid);
+ }
+ else {
+ isFalsePath = !setLongPathWrapper.contains(destid + "##" + finwrap.source);
+ }
+
+ if (isFalsePath) {
+ mapNewTemp.complement(map);
+ }
+ else {
+ if (mapTrueSource.isEmpty()) {
+ if (map != null) {
+ mapTrueSource = map.getCopy();
+ }
+ }
+ else {
+ mergeMaps(mapTrueSource, map);
+ }
+ }
+ }
+
+ if (isExceptionMonitorExit) {
+
+ mapNew = mapTrueSource;
+ }
+ else {
+
+ mapNewTemp.union(mapTrueSource);
+
+ SFormsFastMapDirect oldInMap = inVarVersions.get(nodeid);
+ if (oldInMap != null) {
+ mapNewTemp.union(oldInMap);
+ }
+
+ mapNew.intersection(mapNewTemp);
+ }
+ }
+
+ return mapNew;
+ }
+
+ private SFormsFastMapDirect mergeMaps(SFormsFastMapDirect mapTo, SFormsFastMapDirect map2) {
+
+ if (map2 != null && !map2.isEmpty()) {
+ mapTo.union(map2);
+ }
+
+ return mapTo;
+ }
+
+ private boolean mapsEqual(SFormsFastMapDirect map1, SFormsFastMapDirect map2) {
+
+ if (map1 == null) {
+ return map2 == null;
+ }
+ else if (map2 == null) {
+ return false;
+ }
+
+ if (map1.size() != map2.size()) {
+ return false;
+ }
+
+ for (Entry<Integer, FastSparseSet<Integer>> ent2 : map2.entryList()) {
+ if (!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void setCurrentVar(SFormsFastMapDirect varmap, Integer var, Integer vers) {
+ FastSparseSet<Integer> set = factory.spawnEmptySet();
+ set.add(vers);
+ varmap.put(var, set);
+ }
+
+ private void setCatchMaps(Statement stat, DirectGraph dgraph, FlattenStatementsHelper flatthelper) {
+
+ SFormsFastMapDirect map;
+
+ switch (stat.type) {
+ case Statement.TYPE_CATCHALL:
+ case Statement.TYPE_TRYCATCH:
+
+ List<VarExprent> lstVars;
+ if (stat.type == Statement.TYPE_CATCHALL) {
+ lstVars = ((CatchAllStatement)stat).getVars();
+ }
+ else {
+ lstVars = ((CatchStatement)stat).getVars();
+ }
+
+ for (int i = 1; i < stat.getStats().size(); i++) {
+ int varindex = lstVars.get(i - 1).getIndex();
+ int version = getNextFreeVersion(varindex); // == 1
+
+ map = new SFormsFastMapDirect();
+ setCurrentVar(map, varindex, version);
+
+ extraVarVersions.put(dgraph.nodes.getWithKey(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0]).id, map);
+ startVars.add(new VarVersionPaar(varindex, version));
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ setCatchMaps(st, dgraph, flatthelper);
+ }
+ }
+
+ private SFormsFastMapDirect createFirstMap(StructMethod mt) {
+
+ boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int paramcount = md.params.length + (thisvar ? 1 : 0);
+ int varindex = 0;
+ SFormsFastMapDirect map = new SFormsFastMapDirect();
+ for (int i = 0; i < paramcount; i++) {
+ int version = getNextFreeVersion(varindex); // == 1
+
+ FastSparseSet<Integer> set = factory.spawnEmptySet();
+ set.add(version);
+ map.put(varindex, set);
+ startVars.add(new VarVersionPaar(varindex, version));
+
+ if (thisvar) {
+ if (i == 0) {
+ varindex++;
+ }
+ else {
+ varindex += md.params[i - 1].stack_size;
+ }
+ }
+ else {
+ varindex += md.params[i].stack_size;
+ }
+ }
+
+ return map;
+ }
+
+ public HashMap<VarVersionPaar, FastSparseSet<Integer>> getPhi() {
+ return phi;
+ }
+
+ public List<VarVersionPaar> getStartVars() {
+ return startVars;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java
index a59780f..596da31 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java
@@ -1,37 +1,24 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.sforms;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper.FinallyPathWrapper;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionEdge;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionNode;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
@@ -39,795 +26,820 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionsGraph;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.util.FastSparseSetFactory;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
-import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
public class SSAUConstructorSparseEx {
-
- // node id, var, version
- private HashMap<String, SFormsFastMapDirect> inVarVersions = new HashMap<String, SFormsFastMapDirect>();
- //private HashMap<String, HashMap<Integer, FastSet<Integer>>> inVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
-
- // node id, var, version (direct branch)
- private HashMap<String, SFormsFastMapDirect> outVarVersions = new HashMap<String, SFormsFastMapDirect>();
- //private HashMap<String, HashMap<Integer, FastSet<Integer>>> outVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
-
- // node id, var, version (negative branch)
- private HashMap<String, SFormsFastMapDirect> outNegVarVersions = new HashMap<String, SFormsFastMapDirect>();
- //private HashMap<String, HashMap<Integer, FastSet<Integer>>> outNegVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
-
- // node id, var, version
- private HashMap<String, SFormsFastMapDirect> extraVarVersions = new HashMap<String, SFormsFastMapDirect>();
- //private HashMap<String, HashMap<Integer, FastSet<Integer>>> extraVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
-
- // (var, version), version
- private HashMap<VarVersionPaar, HashSet<Integer>> phi = new HashMap<VarVersionPaar, HashSet<Integer>>();
-
- // var, version
- private HashMap<Integer, Integer> lastversion = new HashMap<Integer, Integer>();
-
- // version, protected ranges (catch, finally)
- private HashMap<VarVersionPaar, Integer> mapVersionFirstRange = new HashMap<VarVersionPaar, Integer>();
-
- // version, version
- private HashMap<VarVersionPaar, VarVersionPaar> phantomppnodes = new HashMap<VarVersionPaar, VarVersionPaar>(); // ++ and --
-
- // node.id, version, version
- private HashMap<String, HashMap<VarVersionPaar, VarVersionPaar>> phantomexitnodes = new HashMap<String, HashMap<VarVersionPaar, VarVersionPaar>>(); // finally exits
-
- // versions memory dependencies
- private VarVersionsGraph ssuversions = new VarVersionsGraph();
-
- // field access vars (exprent id, var id)
- private HashMap<Integer, Integer> mapFieldVars = new HashMap<Integer, Integer>();
-
- // field access counter
- private int fieldvarcounter = -1;
-
- // set factory
- private FastSparseSetFactory<Integer> factory;
-
- public void splitVariables(RootStatement root, StructMethod mt) {
-
- FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
- DirectGraph dgraph = flatthelper.buildDirectGraph(root);
-
- HashSet<Integer> setInit = new HashSet<Integer>();
- for(int i=0;i<64;i++) {
- setInit.add(i);
- }
- factory = new FastSparseSetFactory<Integer>(setInit);
-
- extraVarVersions.put(dgraph.first.id, createFirstMap(mt, root));
-
- setCatchMaps(root, dgraph, flatthelper);
-
-// try {
-// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
-// } catch(Exception ex) {ex.printStackTrace();}
-
- HashSet<String> updated = new HashSet<String>();
- do {
-// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
- ssaStatements(dgraph, updated, false);
-// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
- } while(!updated.isEmpty());
-
-
- ssaStatements(dgraph, updated, true);
-
- ssuversions.initDominators();
- }
-
- private void ssaStatements(DirectGraph dgraph, HashSet<String> updated, boolean calcLiveVars) {
-
- for(DirectNode node: dgraph.nodes) {
-
- updated.remove(node.id);
- mergeInVarMaps(node, dgraph);
-
- SFormsFastMapDirect varmap = new SFormsFastMapDirect(inVarVersions.get(node.id));
-
- SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[] {varmap, null};
-
- if(node.exprents != null) {
- for(Exprent expr: node.exprents) {
- processExprent(expr, varmaparr, node.statement, calcLiveVars);
- }
- }
-
- if(varmaparr[1] == null) {
- varmaparr[1] = varmaparr[0];
- }
-
- // quick solution: 'dummy' field variables should not cross basic block borders (otherwise problems e.g. with finally loops - usage without assignment in a loop)
- // For the full solution consider adding a dummy assignment at the entry point of the method
- boolean allow_field_propagation = node.succs.isEmpty() || (node.succs.size() == 1 && node.succs.get(0).preds.size() == 1);
-
- if(!allow_field_propagation && varmaparr[0] != null) {
- varmaparr[0].removeAllFields();
- varmaparr[1].removeAllFields();
- }
-
- boolean this_updated = !mapsEqual(varmaparr[0], outVarVersions.get(node.id))
- || (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
-
- if(this_updated) {
-
- outVarVersions.put(node.id, varmaparr[0]);
- if(dgraph.mapNegIfBranch.containsKey(node.id)) {
- outNegVarVersions.put(node.id, varmaparr[1]);
- }
-
- for(DirectNode nd: node.succs) {
- updated.add(nd.id);
- }
- }
- }
-
- }
-
-
- private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr, Statement stat, boolean calcLiveVars) {
-
- if(expr == null) {
- return;
- }
-
-
- VarExprent varassign = null;
- boolean finished = false;
-
- switch(expr.type) {
- case Exprent.EXPRENT_ASSIGNMENT:
- AssignmentExprent assexpr = (AssignmentExprent)expr;
- if(assexpr.getCondtype() == AssignmentExprent.CONDITION_NONE) {
- Exprent dest = assexpr.getLeft();
- if(dest.type == Exprent.EXPRENT_VAR) {
- varassign = (VarExprent)dest;
- }
- }
- break;
- case Exprent.EXPRENT_FUNCTION:
- FunctionExprent func = (FunctionExprent)expr;
- switch(func.getFunctype()) {
- case FunctionExprent.FUNCTION_IIF:
- processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
-
- SFormsFastMapDirect varmapFalse;
- if(varmaparr[1] == null) {
- varmapFalse = new SFormsFastMapDirect(varmaparr[0]);
- } else {
- varmapFalse = varmaparr[1];
- varmaparr[1] = null;
- }
-
- processExprent(func.getLstOperands().get(1), varmaparr, stat, calcLiveVars);
-
- SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[] {varmapFalse, null};
- processExprent(func.getLstOperands().get(2), varmaparrNeg, stat, calcLiveVars);
-
- mergeMaps(varmaparr[0], varmaparrNeg[0]);
- varmaparr[1] = null;
-
- finished = true;
- break;
- case FunctionExprent.FUNCTION_CADD:
- processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
-
- SFormsFastMapDirect[] varmaparrAnd = new SFormsFastMapDirect[] {new SFormsFastMapDirect(varmaparr[0]), null};
-
- processExprent(func.getLstOperands().get(1), varmaparrAnd, stat, calcLiveVars);
-
- // false map
- varmaparr[1] = mergeMaps(varmaparr[varmaparr[1]==null?0:1], varmaparrAnd[varmaparrAnd[1]==null?0:1]);
- // true map
- varmaparr[0] = varmaparrAnd[0];
-
- finished = true;
- break;
- case FunctionExprent.FUNCTION_COR:
- processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
-
- SFormsFastMapDirect[] varmaparrOr = new SFormsFastMapDirect[] {new SFormsFastMapDirect(varmaparr[varmaparr[1]==null?0:1]), null};
-
- processExprent(func.getLstOperands().get(1), varmaparrOr, stat, calcLiveVars);
-
- // false map
- varmaparr[1] = varmaparrOr[varmaparrOr[1]==null?0:1];
- // true map
- varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]);
-
- finished = true;
- }
- }
-
- if(!finished) {
- List<Exprent> lst = expr.getAllExprents();
- lst.remove(varassign);
-
- for(Exprent ex: lst) {
- processExprent(ex, varmaparr, stat, calcLiveVars);
- }
- }
-
-
- SFormsFastMapDirect varmap = varmaparr[0];
-
- // field access
- if(expr.type == Exprent.EXPRENT_FIELD) {
-
- int index;
- if(mapFieldVars.containsKey(expr.id)) {
- index = mapFieldVars.get(expr.id);
- } else {
- index = fieldvarcounter--;
- mapFieldVars.put(expr.id, index);
-
- // ssu graph
- ssuversions.createNode(new VarVersionPaar(index, 1));
- }
-
- setCurrentVar(varmap, index, 1);
-
- } else if(expr.type == Exprent.EXPRENT_INVOCATION ||
- (expr.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)expr).getLeft().type == Exprent.EXPRENT_FIELD) ||
- (expr.type == Exprent.EXPRENT_NEW && ((NewExprent)expr).getNewtype().type == CodeConstants.TYPE_OBJECT) ||
- expr.type == Exprent.EXPRENT_FUNCTION) {
-
- boolean ismmpp = true;
-
- if(expr.type == Exprent.EXPRENT_FUNCTION) {
-
- ismmpp = false;
-
- FunctionExprent fexpr = (FunctionExprent)expr;
- if(fexpr.getFunctype() >= FunctionExprent.FUNCTION_IMM && fexpr.getFunctype() <= FunctionExprent.FUNCTION_PPI) {
- if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
- ismmpp = true;
- }
- }
- }
-
- if(ismmpp) {
- varmap.removeAllFields();
- }
- }
-
-
- if(varassign != null) {
-
- Integer varindex = varassign.getIndex();
-
- if(varassign.getVersion() == 0) {
- // get next version
- Integer nextver = getNextFreeVersion(varindex, stat);
-
- // set version
- varassign.setVersion(nextver);
-
- // ssu graph
- ssuversions.createNode(new VarVersionPaar(varindex, nextver));
-
- setCurrentVar(varmap, varindex, nextver);
- } else {
- if(calcLiveVars) {
- varMapToGraph(new VarVersionPaar(varindex.intValue(), varassign.getVersion()), varmap);
- }
- setCurrentVar(varmap, varindex, varassign.getVersion());
- }
- } else if(expr.type == Exprent.EXPRENT_FUNCTION) { // MM or PP function
- FunctionExprent func = (FunctionExprent)expr;
-
- switch(func.getFunctype()) {
- case FunctionExprent.FUNCTION_IMM:
- case FunctionExprent.FUNCTION_MMI:
- case FunctionExprent.FUNCTION_IPP:
- case FunctionExprent.FUNCTION_PPI:
-
- if(func.getLstOperands().get(0).type == Exprent.EXPRENT_VAR) {
- VarExprent var = (VarExprent)func.getLstOperands().get(0);
- Integer varindex = var.getIndex();
- VarVersionPaar varpaar = new VarVersionPaar(varindex.intValue(), var.getVersion());
-
- // ssu graph
- VarVersionPaar phantomver = phantomppnodes.get(varpaar);
- if(phantomver == null) {
- // get next version
- Integer nextver = getNextFreeVersion(varindex, null);
- phantomver = new VarVersionPaar(varindex, nextver);
- //ssuversions.createOrGetNode(phantomver);
- ssuversions.createNode(phantomver);
-
- VarVersionNode vernode = ssuversions.nodes.getWithKey(varpaar);
-
- FastSparseSet<Integer> vers = factory.spawnEmptySet();
- if(vernode.preds.size() == 1) {
- vers.add(vernode.preds.iterator().next().source.version);
- } else {
- for(VarVersionEdge edge: vernode.preds) {
- vers.add(edge.source.preds.iterator().next().source.version);
- }
- }
- vers.add(nextver);
- createOrUpdatePhiNode(varpaar, vers, stat);
- phantomppnodes.put(varpaar, phantomver);
- }
- if(calcLiveVars) {
- varMapToGraph(varpaar, varmap);
- }
- setCurrentVar(varmap, varindex.intValue(), var.getVersion());
- }
-
- }
- } else if(expr.type == Exprent.EXPRENT_VAR) {
-
- VarExprent vardest = (VarExprent)expr;
-
- Integer varindex = vardest.getIndex();
- Integer current_vers = vardest.getVersion();
-
- FastSparseSet<Integer> vers = varmap.get(varindex);
-
- int cardinality = vers.getCardinality();
- if(cardinality == 1) { // size == 1
- if(current_vers.intValue() != 0) {
- if(calcLiveVars) {
- varMapToGraph(new VarVersionPaar(varindex, current_vers), varmap);
- }
- setCurrentVar(varmap, varindex, current_vers);
- } else {
- // split last version
- Integer usever = getNextFreeVersion(varindex, stat);
-
- // set version
- vardest.setVersion(usever);
- setCurrentVar(varmap, varindex, usever);
-
- // ssu graph
- Integer lastver = vers.iterator().next();
- VarVersionNode prenode = ssuversions.nodes.getWithKey(new VarVersionPaar(varindex, lastver));
- VarVersionNode usenode = ssuversions.createNode(new VarVersionPaar(varindex, usever));
- VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, prenode, usenode);
- prenode.addSuccessor(edge);
- usenode.addPredecessor(edge);
- }
- } else if(cardinality == 2) { // size > 1
-
- if(current_vers.intValue() != 0) {
- if(calcLiveVars) {
- varMapToGraph(new VarVersionPaar(varindex, current_vers), varmap);
- }
- setCurrentVar(varmap, varindex, current_vers);
- } else {
- // split version
- Integer usever = getNextFreeVersion(varindex, stat);
- // set version
- vardest.setVersion(usever);
-
- // ssu node
- ssuversions.createNode(new VarVersionPaar(varindex, usever));
-
- setCurrentVar(varmap, varindex, usever);
-
- current_vers = usever;
- }
-
- createOrUpdatePhiNode(new VarVersionPaar(varindex, current_vers), vers, stat);
-
- } // vers.size() == 0 means uninitialized variable, which is impossible
- }
-
-
- }
-
- private void createOrUpdatePhiNode(VarVersionPaar phivar, FastSparseSet<Integer> vers, Statement stat) {
-
- FastSparseSet<Integer> versCopy = vers.getCopy();
- HashSet<Integer> phiVers = new HashSet<Integer>();
-
- // take into account the corresponding mm/pp node if existing
- int ppvers = phantomppnodes.containsKey(phivar) ? phantomppnodes.get(phivar).version : -1;
-
- // ssu graph
- VarVersionNode phinode = ssuversions.nodes.getWithKey(phivar);
- List<VarVersionEdge> lstPreds = new ArrayList<VarVersionEdge>(phinode.preds);
- if(lstPreds.size() == 1) {
- // not yet a phi node
- VarVersionEdge edge = lstPreds.get(0);
- edge.source.removeSuccessor(edge);
- phinode.removePredecessor(edge);
- } else {
- for(VarVersionEdge edge: lstPreds) {
- int verssrc = edge.source.preds.iterator().next().source.version;
- if(!vers.contains(verssrc) && verssrc != ppvers) {
- edge.source.removeSuccessor(edge);
- phinode.removePredecessor(edge);
- } else {
- versCopy.remove(verssrc);
- phiVers.add(verssrc);
- }
- }
- }
-
- List<VarVersionNode> colnodes = new ArrayList<VarVersionNode>();
- List<VarVersionPaar> colpaars = new ArrayList<VarVersionPaar>();
-
- for(Integer ver: versCopy) {
-
- VarVersionNode prenode = ssuversions.nodes.getWithKey(new VarVersionPaar(phivar.var, ver.intValue()));
-
- Integer tempver = getNextFreeVersion(phivar.var, stat);
-
- VarVersionNode tempnode = new VarVersionNode(phivar.var, tempver.intValue());
-
- colnodes.add(tempnode);
- colpaars.add(new VarVersionPaar(phivar.var, tempver.intValue()));
-
- VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, prenode, tempnode);
-
- prenode.addSuccessor(edge);
- tempnode.addPredecessor(edge);
-
-
- edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, tempnode, phinode);
- tempnode.addSuccessor(edge);
- phinode.addPredecessor(edge);
-
- phiVers.add(tempver);
-
- }
-
- ssuversions.addNodes(colnodes, colpaars);
-
- // update phi node
- phi.put(phivar, phiVers);
- }
-
- private void varMapToGraph(VarVersionPaar varpaar, SFormsFastMapDirect varmap) {
-
- VBStyleCollection<VarVersionNode, VarVersionPaar> nodes = ssuversions.nodes;
-
- VarVersionNode node = nodes.getWithKey(varpaar);
-
- node.live = new SFormsFastMapDirect(varmap);
- }
-
- private Integer getNextFreeVersion(Integer var, Statement stat) {
-
- Integer nextver = lastversion.get(var);
-
- if(nextver==null) {
- nextver = new Integer(1);
- } else {
- nextver = new Integer(nextver.intValue()+1);
- }
- lastversion.put(var, nextver);
-
- // save the first protected range, containing current statement
- if(stat != null) { // null iff phantom version
- Integer firstRangeId = getFirstProtectedRange(stat);
- if(firstRangeId != null) {
- mapVersionFirstRange.put(new VarVersionPaar(var, nextver), firstRangeId);
- }
- }
-
- return nextver;
- }
-
- private void mergeInVarMaps(DirectNode node, DirectGraph dgraph) {
-
-
- SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
-
- for(DirectNode pred: node.preds) {
- SFormsFastMapDirect mapOut = getFilteredOutMap(node.id, pred.id, dgraph, node.id);
- if(mapNew.isEmpty()) {
- mapNew = mapOut.getCopy();
- } else {
- mergeMaps(mapNew, mapOut);
- }
- }
-
- if(extraVarVersions.containsKey(node.id)) {
- SFormsFastMapDirect mapExtra = extraVarVersions.get(node.id);
- if(mapNew.isEmpty()) {
- mapNew = mapExtra.getCopy();
- } else {
- mergeMaps(mapNew, mapExtra);
- }
- }
-
- inVarVersions.put(node.id, mapNew);
-
- }
-
- private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph, String destid) {
-
- SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
-
- boolean isFinallyExit = dgraph.mapShortRangeFinallyPaths.containsKey(predid);
-
- if(nodeid.equals(dgraph.mapNegIfBranch.get(predid))) {
- if(outNegVarVersions.containsKey(predid)) {
- mapNew = outNegVarVersions.get(predid).getCopy();
- }
- } else if(outVarVersions.containsKey(predid)) {
- mapNew = outVarVersions.get(predid).getCopy();
- }
-
- if(isFinallyExit) {
-
- SFormsFastMapDirect mapNewTemp = mapNew.getCopy();
-
- SFormsFastMapDirect mapTrueSource = new SFormsFastMapDirect();
-
- String exceptionDest = dgraph.mapFinallyMonitorExceptionPathExits.get(predid);
- boolean isExceptionMonitorExit = (exceptionDest != null && !nodeid.equals(exceptionDest));
-
- HashSet<String> setLongPathWrapper = new HashSet<String>();
- for(List<FinallyPathWrapper> lstwrapper : dgraph.mapLongRangeFinallyPaths.values()) {
- for(FinallyPathWrapper finwraplong : lstwrapper) {
- setLongPathWrapper.add(finwraplong.destination+"##"+finwraplong.source);
- }
- }
-
- for(FinallyPathWrapper finwrap : dgraph.mapShortRangeFinallyPaths.get(predid)) {
- SFormsFastMapDirect map;
-
- boolean recFinally = dgraph.mapShortRangeFinallyPaths.containsKey(finwrap.source);
-
- if(recFinally) {
- // recursion
- map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid);
- } else {
- if(finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) {
- map = outNegVarVersions.get(finwrap.source);
- } else {
- map = outVarVersions.get(finwrap.source);
- }
- }
-
- // false path?
- boolean isFalsePath = true;
-
- if(recFinally) {
- isFalsePath = !finwrap.destination.equals(nodeid);
- } else {
- isFalsePath = !setLongPathWrapper.contains(destid+"##"+finwrap.source);
- }
-
- if(isFalsePath) {
- mapNewTemp.complement(map);
- } else {
- if(mapTrueSource.isEmpty()) {
- if(map != null) {
- mapTrueSource = map.getCopy();
- }
- } else {
- mergeMaps(mapTrueSource, map);
- }
- }
-
- }
-
- if(isExceptionMonitorExit) {
-
- mapNew = mapTrueSource;
-
- } else {
-
- mapNewTemp.union(mapTrueSource);
- mapNew.intersection(mapNewTemp);
-
- if(!mapTrueSource.isEmpty() && !mapNew.isEmpty()) { // FIXME: what for??
-
- // replace phi versions with corresponding phantom ones
- HashMap<VarVersionPaar, VarVersionPaar> mapPhantom = phantomexitnodes.get(predid);
- if(mapPhantom == null) {
- mapPhantom = new HashMap<VarVersionPaar, VarVersionPaar>();
- }
-
- SFormsFastMapDirect mapExitVar = mapNew.getCopy();
- mapExitVar.complement(mapTrueSource);
-
- for(Entry<Integer, FastSparseSet<Integer>> ent : mapExitVar.entryList()) {
- for(Integer version : ent.getValue()) {
-
- Integer varindex = ent.getKey();
- VarVersionPaar exitvar = new VarVersionPaar(varindex, version);
- FastSparseSet<Integer> newSet = mapNew.get(varindex);
-
- // remove the actual exit version
- newSet.remove(version);
-
- // get or create phantom version
- VarVersionPaar phantomvar = mapPhantom.get(exitvar);
- if(phantomvar == null) {
- Integer newversion = getNextFreeVersion(exitvar.var, null);
- phantomvar = new VarVersionPaar(exitvar.var, newversion.intValue());
-
- VarVersionNode exitnode = ssuversions.nodes.getWithKey(exitvar);
- VarVersionNode phantomnode = ssuversions.createNode(phantomvar);
- phantomnode.flags |= VarVersionNode.FLAG_PHANTOM_FINEXIT;
-
- VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_PHANTOM, exitnode, phantomnode);
- exitnode.addSuccessor(edge);
- phantomnode.addPredecessor(edge);
-
- mapPhantom.put(exitvar, phantomvar);
- }
-
- // add phantom version
- newSet.add(phantomvar.version);
- }
- }
-
- if(!mapPhantom.isEmpty()) {
- phantomexitnodes.put(predid, mapPhantom);
- }
- }
- }
-
- }
-
- return mapNew;
- }
-
- private SFormsFastMapDirect mergeMaps(SFormsFastMapDirect mapTo, SFormsFastMapDirect map2) {
-
- if(map2 != null && !map2.isEmpty()) {
- mapTo.union(map2);
- }
-
- return mapTo;
- }
-
- private boolean mapsEqual(SFormsFastMapDirect map1, SFormsFastMapDirect map2) {
-
- if(map1 == null) {
- return map2 == null;
- } else if (map2 == null) {
- return false;
- }
-
- if(map1.size() != map2.size()) {
- return false;
- }
-
- for(Entry<Integer, FastSparseSet<Integer>> ent2: map2.entryList()) {
- if(!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) {
- return false;
- }
- }
-
- return true;
- }
-
-
- private void setCurrentVar(SFormsFastMapDirect varmap, Integer var, Integer vers) {
- FastSparseSet<Integer> set = factory.spawnEmptySet();
- set.add(vers);
- varmap.put(var, set);
- }
-
- private void setCatchMaps(Statement stat, DirectGraph dgraph, FlattenStatementsHelper flatthelper) {
-
- SFormsFastMapDirect map;
-
- switch(stat.type) {
- case Statement.TYPE_CATCHALL:
- case Statement.TYPE_TRYCATCH:
-
- List<VarExprent> lstVars;
- if(stat.type == Statement.TYPE_CATCHALL) {
- lstVars = ((CatchAllStatement)stat).getVars();
- } else {
- lstVars = ((CatchStatement)stat).getVars();
- }
-
- for(int i=1;i<stat.getStats().size();i++) {
- int varindex = lstVars.get(i-1).getIndex();
- int version = getNextFreeVersion(varindex, stat); // == 1
-
- map = new SFormsFastMapDirect();
- setCurrentVar(map, varindex, version);
-
- extraVarVersions.put(dgraph.nodes.getWithKey(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0]).id, map);
- //ssuversions.createOrGetNode(new VarVersionPaar(varindex, version));
- ssuversions.createNode(new VarVersionPaar(varindex, version));
- }
- }
-
- for(Statement st: stat.getStats()) {
- setCatchMaps(st, dgraph, flatthelper);
- }
- }
-
- private SFormsFastMapDirect createFirstMap(StructMethod mt, RootStatement root) {
-
- boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
-
- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
-
- int paramcount = md.params.length + (thisvar?1:0);
-
- int varindex = 0;
- SFormsFastMapDirect map = new SFormsFastMapDirect();
- for(int i=0;i<paramcount;i++) {
- int version = getNextFreeVersion(varindex, root); // == 1
-
- FastSparseSet<Integer> set = factory.spawnEmptySet();
- set.add(version);
- map.put(varindex, set);
- ssuversions.createNode(new VarVersionPaar(varindex, version));
-
- if(thisvar) {
- if(i==0) {
- varindex++;
- } else {
- varindex+=md.params[i-1].stack_size;
- }
- } else {
- varindex+=md.params[i].stack_size;
- }
- }
-
- return map;
- }
-
- private Integer getFirstProtectedRange(Statement stat) {
-
- for(;;) {
- Statement parent = stat.getParent();
-
- if(parent == null) {
- break;
- }
-
- if(parent.type == Statement.TYPE_CATCHALL ||
- parent.type == Statement.TYPE_TRYCATCH) {
- if(parent.getFirst() == stat) {
- return parent.id;
- }
- } else if(parent.type == Statement.TYPE_SYNCRONIZED) {
- if(((SynchronizedStatement)parent).getBody() == stat) {
- return parent.id;
- }
- }
-
- stat = parent;
- }
-
- return null;
- }
-
- public HashMap<VarVersionPaar, HashSet<Integer>> getPhi() {
- return phi;
- }
-
- public VarVersionsGraph getSsuversions() {
- return ssuversions;
- }
-
- public SFormsFastMapDirect getLiveVarVersionsMap(VarVersionPaar varpaar) {
-
-
- VarVersionNode node = ssuversions.nodes.getWithKey(varpaar);
- if(node != null) {
- return node.live;
- }
-
- return null;
- }
-
- public HashMap<VarVersionPaar, Integer> getMapVersionFirstRange() {
- return mapVersionFirstRange;
- }
-
- public HashMap<Integer, Integer> getMapFieldVars() {
- return mapFieldVars;
- }
+
+ // node id, var, version
+ private HashMap<String, SFormsFastMapDirect> inVarVersions = new HashMap<String, SFormsFastMapDirect>();
+ //private HashMap<String, HashMap<Integer, FastSet<Integer>>> inVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
+
+ // node id, var, version (direct branch)
+ private HashMap<String, SFormsFastMapDirect> outVarVersions = new HashMap<String, SFormsFastMapDirect>();
+ //private HashMap<String, HashMap<Integer, FastSet<Integer>>> outVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
+
+ // node id, var, version (negative branch)
+ private HashMap<String, SFormsFastMapDirect> outNegVarVersions = new HashMap<String, SFormsFastMapDirect>();
+ //private HashMap<String, HashMap<Integer, FastSet<Integer>>> outNegVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
+
+ // node id, var, version
+ private HashMap<String, SFormsFastMapDirect> extraVarVersions = new HashMap<String, SFormsFastMapDirect>();
+ //private HashMap<String, HashMap<Integer, FastSet<Integer>>> extraVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
+
+ // (var, version), version
+ private HashMap<VarVersionPaar, HashSet<Integer>> phi = new HashMap<VarVersionPaar, HashSet<Integer>>();
+
+ // var, version
+ private HashMap<Integer, Integer> lastversion = new HashMap<Integer, Integer>();
+
+ // version, protected ranges (catch, finally)
+ private HashMap<VarVersionPaar, Integer> mapVersionFirstRange = new HashMap<VarVersionPaar, Integer>();
+
+ // version, version
+ private HashMap<VarVersionPaar, VarVersionPaar> phantomppnodes = new HashMap<VarVersionPaar, VarVersionPaar>(); // ++ and --
+
+ // node.id, version, version
+ private HashMap<String, HashMap<VarVersionPaar, VarVersionPaar>> phantomexitnodes =
+ new HashMap<String, HashMap<VarVersionPaar, VarVersionPaar>>(); // finally exits
+
+ // versions memory dependencies
+ private VarVersionsGraph ssuversions = new VarVersionsGraph();
+
+ // field access vars (exprent id, var id)
+ private HashMap<Integer, Integer> mapFieldVars = new HashMap<Integer, Integer>();
+
+ // field access counter
+ private int fieldvarcounter = -1;
+
+ // set factory
+ private FastSparseSetFactory<Integer> factory;
+
+ public void splitVariables(RootStatement root, StructMethod mt) {
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ HashSet<Integer> setInit = new HashSet<Integer>();
+ for (int i = 0; i < 64; i++) {
+ setInit.add(i);
+ }
+ factory = new FastSparseSetFactory<Integer>(setInit);
+
+ extraVarVersions.put(dgraph.first.id, createFirstMap(mt, root));
+
+ setCatchMaps(root, dgraph, flatthelper);
+
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
+ HashSet<String> updated = new HashSet<String>();
+ do {
+ // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ ssaStatements(dgraph, updated, false);
+ // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ }
+ while (!updated.isEmpty());
+
+
+ ssaStatements(dgraph, updated, true);
+
+ ssuversions.initDominators();
+ }
+
+ private void ssaStatements(DirectGraph dgraph, HashSet<String> updated, boolean calcLiveVars) {
+
+ for (DirectNode node : dgraph.nodes) {
+
+ updated.remove(node.id);
+ mergeInVarMaps(node, dgraph);
+
+ SFormsFastMapDirect varmap = new SFormsFastMapDirect(inVarVersions.get(node.id));
+
+ SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[]{varmap, null};
+
+ if (node.exprents != null) {
+ for (Exprent expr : node.exprents) {
+ processExprent(expr, varmaparr, node.statement, calcLiveVars);
+ }
+ }
+
+ if (varmaparr[1] == null) {
+ varmaparr[1] = varmaparr[0];
+ }
+
+ // quick solution: 'dummy' field variables should not cross basic block borders (otherwise problems e.g. with finally loops - usage without assignment in a loop)
+ // For the full solution consider adding a dummy assignment at the entry point of the method
+ boolean allow_field_propagation = node.succs.isEmpty() || (node.succs.size() == 1 && node.succs.get(0).preds.size() == 1);
+
+ if (!allow_field_propagation && varmaparr[0] != null) {
+ varmaparr[0].removeAllFields();
+ varmaparr[1].removeAllFields();
+ }
+
+ boolean this_updated = !mapsEqual(varmaparr[0], outVarVersions.get(node.id))
+ || (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
+
+ if (this_updated) {
+
+ outVarVersions.put(node.id, varmaparr[0]);
+ if (dgraph.mapNegIfBranch.containsKey(node.id)) {
+ outNegVarVersions.put(node.id, varmaparr[1]);
+ }
+
+ for (DirectNode nd : node.succs) {
+ updated.add(nd.id);
+ }
+ }
+ }
+ }
+
+
+ private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr, Statement stat, boolean calcLiveVars) {
+
+ if (expr == null) {
+ return;
+ }
+
+
+ VarExprent varassign = null;
+ boolean finished = false;
+
+ switch (expr.type) {
+ case Exprent.EXPRENT_ASSIGNMENT:
+ AssignmentExprent assexpr = (AssignmentExprent)expr;
+ if (assexpr.getCondtype() == AssignmentExprent.CONDITION_NONE) {
+ Exprent dest = assexpr.getLeft();
+ if (dest.type == Exprent.EXPRENT_VAR) {
+ varassign = (VarExprent)dest;
+ }
+ }
+ break;
+ case Exprent.EXPRENT_FUNCTION:
+ FunctionExprent func = (FunctionExprent)expr;
+ switch (func.getFunctype()) {
+ case FunctionExprent.FUNCTION_IIF:
+ processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
+
+ SFormsFastMapDirect varmapFalse;
+ if (varmaparr[1] == null) {
+ varmapFalse = new SFormsFastMapDirect(varmaparr[0]);
+ }
+ else {
+ varmapFalse = varmaparr[1];
+ varmaparr[1] = null;
+ }
+
+ processExprent(func.getLstOperands().get(1), varmaparr, stat, calcLiveVars);
+
+ SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[]{varmapFalse, null};
+ processExprent(func.getLstOperands().get(2), varmaparrNeg, stat, calcLiveVars);
+
+ mergeMaps(varmaparr[0], varmaparrNeg[0]);
+ varmaparr[1] = null;
+
+ finished = true;
+ break;
+ case FunctionExprent.FUNCTION_CADD:
+ processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
+
+ SFormsFastMapDirect[] varmaparrAnd = new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[0]), null};
+
+ processExprent(func.getLstOperands().get(1), varmaparrAnd, stat, calcLiveVars);
+
+ // false map
+ varmaparr[1] = mergeMaps(varmaparr[varmaparr[1] == null ? 0 : 1], varmaparrAnd[varmaparrAnd[1] == null ? 0 : 1]);
+ // true map
+ varmaparr[0] = varmaparrAnd[0];
+
+ finished = true;
+ break;
+ case FunctionExprent.FUNCTION_COR:
+ processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
+
+ SFormsFastMapDirect[] varmaparrOr =
+ new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[varmaparr[1] == null ? 0 : 1]), null};
+
+ processExprent(func.getLstOperands().get(1), varmaparrOr, stat, calcLiveVars);
+
+ // false map
+ varmaparr[1] = varmaparrOr[varmaparrOr[1] == null ? 0 : 1];
+ // true map
+ varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]);
+
+ finished = true;
+ }
+ }
+
+ if (!finished) {
+ List<Exprent> lst = expr.getAllExprents();
+ lst.remove(varassign);
+
+ for (Exprent ex : lst) {
+ processExprent(ex, varmaparr, stat, calcLiveVars);
+ }
+ }
+
+
+ SFormsFastMapDirect varmap = varmaparr[0];
+
+ // field access
+ if (expr.type == Exprent.EXPRENT_FIELD) {
+
+ int index;
+ if (mapFieldVars.containsKey(expr.id)) {
+ index = mapFieldVars.get(expr.id);
+ }
+ else {
+ index = fieldvarcounter--;
+ mapFieldVars.put(expr.id, index);
+
+ // ssu graph
+ ssuversions.createNode(new VarVersionPaar(index, 1));
+ }
+
+ setCurrentVar(varmap, index, 1);
+ }
+ else if (expr.type == Exprent.EXPRENT_INVOCATION ||
+ (expr.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)expr).getLeft().type == Exprent.EXPRENT_FIELD) ||
+ (expr.type == Exprent.EXPRENT_NEW && ((NewExprent)expr).getNewtype().type == CodeConstants.TYPE_OBJECT) ||
+ expr.type == Exprent.EXPRENT_FUNCTION) {
+
+ boolean ismmpp = true;
+
+ if (expr.type == Exprent.EXPRENT_FUNCTION) {
+
+ ismmpp = false;
+
+ FunctionExprent fexpr = (FunctionExprent)expr;
+ if (fexpr.getFunctype() >= FunctionExprent.FUNCTION_IMM && fexpr.getFunctype() <= FunctionExprent.FUNCTION_PPI) {
+ if (fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
+ ismmpp = true;
+ }
+ }
+ }
+
+ if (ismmpp) {
+ varmap.removeAllFields();
+ }
+ }
+
+
+ if (varassign != null) {
+
+ Integer varindex = varassign.getIndex();
+
+ if (varassign.getVersion() == 0) {
+ // get next version
+ Integer nextver = getNextFreeVersion(varindex, stat);
+
+ // set version
+ varassign.setVersion(nextver);
+
+ // ssu graph
+ ssuversions.createNode(new VarVersionPaar(varindex, nextver));
+
+ setCurrentVar(varmap, varindex, nextver);
+ }
+ else {
+ if (calcLiveVars) {
+ varMapToGraph(new VarVersionPaar(varindex.intValue(), varassign.getVersion()), varmap);
+ }
+ setCurrentVar(varmap, varindex, varassign.getVersion());
+ }
+ }
+ else if (expr.type == Exprent.EXPRENT_FUNCTION) { // MM or PP function
+ FunctionExprent func = (FunctionExprent)expr;
+
+ switch (func.getFunctype()) {
+ case FunctionExprent.FUNCTION_IMM:
+ case FunctionExprent.FUNCTION_MMI:
+ case FunctionExprent.FUNCTION_IPP:
+ case FunctionExprent.FUNCTION_PPI:
+
+ if (func.getLstOperands().get(0).type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)func.getLstOperands().get(0);
+ Integer varindex = var.getIndex();
+ VarVersionPaar varpaar = new VarVersionPaar(varindex.intValue(), var.getVersion());
+
+ // ssu graph
+ VarVersionPaar phantomver = phantomppnodes.get(varpaar);
+ if (phantomver == null) {
+ // get next version
+ Integer nextver = getNextFreeVersion(varindex, null);
+ phantomver = new VarVersionPaar(varindex, nextver);
+ //ssuversions.createOrGetNode(phantomver);
+ ssuversions.createNode(phantomver);
+
+ VarVersionNode vernode = ssuversions.nodes.getWithKey(varpaar);
+
+ FastSparseSet<Integer> vers = factory.spawnEmptySet();
+ if (vernode.preds.size() == 1) {
+ vers.add(vernode.preds.iterator().next().source.version);
+ }
+ else {
+ for (VarVersionEdge edge : vernode.preds) {
+ vers.add(edge.source.preds.iterator().next().source.version);
+ }
+ }
+ vers.add(nextver);
+ createOrUpdatePhiNode(varpaar, vers, stat);
+ phantomppnodes.put(varpaar, phantomver);
+ }
+ if (calcLiveVars) {
+ varMapToGraph(varpaar, varmap);
+ }
+ setCurrentVar(varmap, varindex.intValue(), var.getVersion());
+ }
+ }
+ }
+ else if (expr.type == Exprent.EXPRENT_VAR) {
+
+ VarExprent vardest = (VarExprent)expr;
+
+ Integer varindex = vardest.getIndex();
+ Integer current_vers = vardest.getVersion();
+
+ FastSparseSet<Integer> vers = varmap.get(varindex);
+
+ int cardinality = vers.getCardinality();
+ if (cardinality == 1) { // size == 1
+ if (current_vers.intValue() != 0) {
+ if (calcLiveVars) {
+ varMapToGraph(new VarVersionPaar(varindex, current_vers), varmap);
+ }
+ setCurrentVar(varmap, varindex, current_vers);
+ }
+ else {
+ // split last version
+ Integer usever = getNextFreeVersion(varindex, stat);
+
+ // set version
+ vardest.setVersion(usever);
+ setCurrentVar(varmap, varindex, usever);
+
+ // ssu graph
+ Integer lastver = vers.iterator().next();
+ VarVersionNode prenode = ssuversions.nodes.getWithKey(new VarVersionPaar(varindex, lastver));
+ VarVersionNode usenode = ssuversions.createNode(new VarVersionPaar(varindex, usever));
+ VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, prenode, usenode);
+ prenode.addSuccessor(edge);
+ usenode.addPredecessor(edge);
+ }
+ }
+ else if (cardinality == 2) { // size > 1
+
+ if (current_vers.intValue() != 0) {
+ if (calcLiveVars) {
+ varMapToGraph(new VarVersionPaar(varindex, current_vers), varmap);
+ }
+ setCurrentVar(varmap, varindex, current_vers);
+ }
+ else {
+ // split version
+ Integer usever = getNextFreeVersion(varindex, stat);
+ // set version
+ vardest.setVersion(usever);
+
+ // ssu node
+ ssuversions.createNode(new VarVersionPaar(varindex, usever));
+
+ setCurrentVar(varmap, varindex, usever);
+
+ current_vers = usever;
+ }
+
+ createOrUpdatePhiNode(new VarVersionPaar(varindex, current_vers), vers, stat);
+ } // vers.size() == 0 means uninitialized variable, which is impossible
+ }
+ }
+
+ private void createOrUpdatePhiNode(VarVersionPaar phivar, FastSparseSet<Integer> vers, Statement stat) {
+
+ FastSparseSet<Integer> versCopy = vers.getCopy();
+ HashSet<Integer> phiVers = new HashSet<Integer>();
+
+ // take into account the corresponding mm/pp node if existing
+ int ppvers = phantomppnodes.containsKey(phivar) ? phantomppnodes.get(phivar).version : -1;
+
+ // ssu graph
+ VarVersionNode phinode = ssuversions.nodes.getWithKey(phivar);
+ List<VarVersionEdge> lstPreds = new ArrayList<VarVersionEdge>(phinode.preds);
+ if (lstPreds.size() == 1) {
+ // not yet a phi node
+ VarVersionEdge edge = lstPreds.get(0);
+ edge.source.removeSuccessor(edge);
+ phinode.removePredecessor(edge);
+ }
+ else {
+ for (VarVersionEdge edge : lstPreds) {
+ int verssrc = edge.source.preds.iterator().next().source.version;
+ if (!vers.contains(verssrc) && verssrc != ppvers) {
+ edge.source.removeSuccessor(edge);
+ phinode.removePredecessor(edge);
+ }
+ else {
+ versCopy.remove(verssrc);
+ phiVers.add(verssrc);
+ }
+ }
+ }
+
+ List<VarVersionNode> colnodes = new ArrayList<VarVersionNode>();
+ List<VarVersionPaar> colpaars = new ArrayList<VarVersionPaar>();
+
+ for (Integer ver : versCopy) {
+
+ VarVersionNode prenode = ssuversions.nodes.getWithKey(new VarVersionPaar(phivar.var, ver.intValue()));
+
+ Integer tempver = getNextFreeVersion(phivar.var, stat);
+
+ VarVersionNode tempnode = new VarVersionNode(phivar.var, tempver.intValue());
+
+ colnodes.add(tempnode);
+ colpaars.add(new VarVersionPaar(phivar.var, tempver.intValue()));
+
+ VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, prenode, tempnode);
+
+ prenode.addSuccessor(edge);
+ tempnode.addPredecessor(edge);
+
+
+ edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, tempnode, phinode);
+ tempnode.addSuccessor(edge);
+ phinode.addPredecessor(edge);
+
+ phiVers.add(tempver);
+ }
+
+ ssuversions.addNodes(colnodes, colpaars);
+
+ // update phi node
+ phi.put(phivar, phiVers);
+ }
+
+ private void varMapToGraph(VarVersionPaar varpaar, SFormsFastMapDirect varmap) {
+
+ VBStyleCollection<VarVersionNode, VarVersionPaar> nodes = ssuversions.nodes;
+
+ VarVersionNode node = nodes.getWithKey(varpaar);
+
+ node.live = new SFormsFastMapDirect(varmap);
+ }
+
+ private Integer getNextFreeVersion(Integer var, Statement stat) {
+
+ Integer nextver = lastversion.get(var);
+
+ if (nextver == null) {
+ nextver = new Integer(1);
+ }
+ else {
+ nextver = new Integer(nextver.intValue() + 1);
+ }
+ lastversion.put(var, nextver);
+
+ // save the first protected range, containing current statement
+ if (stat != null) { // null iff phantom version
+ Integer firstRangeId = getFirstProtectedRange(stat);
+ if (firstRangeId != null) {
+ mapVersionFirstRange.put(new VarVersionPaar(var, nextver), firstRangeId);
+ }
+ }
+
+ return nextver;
+ }
+
+ private void mergeInVarMaps(DirectNode node, DirectGraph dgraph) {
+
+
+ SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
+
+ for (DirectNode pred : node.preds) {
+ SFormsFastMapDirect mapOut = getFilteredOutMap(node.id, pred.id, dgraph, node.id);
+ if (mapNew.isEmpty()) {
+ mapNew = mapOut.getCopy();
+ }
+ else {
+ mergeMaps(mapNew, mapOut);
+ }
+ }
+
+ if (extraVarVersions.containsKey(node.id)) {
+ SFormsFastMapDirect mapExtra = extraVarVersions.get(node.id);
+ if (mapNew.isEmpty()) {
+ mapNew = mapExtra.getCopy();
+ }
+ else {
+ mergeMaps(mapNew, mapExtra);
+ }
+ }
+
+ inVarVersions.put(node.id, mapNew);
+ }
+
+ private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph, String destid) {
+
+ SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
+
+ boolean isFinallyExit = dgraph.mapShortRangeFinallyPaths.containsKey(predid);
+
+ if (nodeid.equals(dgraph.mapNegIfBranch.get(predid))) {
+ if (outNegVarVersions.containsKey(predid)) {
+ mapNew = outNegVarVersions.get(predid).getCopy();
+ }
+ }
+ else if (outVarVersions.containsKey(predid)) {
+ mapNew = outVarVersions.get(predid).getCopy();
+ }
+
+ if (isFinallyExit) {
+
+ SFormsFastMapDirect mapNewTemp = mapNew.getCopy();
+
+ SFormsFastMapDirect mapTrueSource = new SFormsFastMapDirect();
+
+ String exceptionDest = dgraph.mapFinallyMonitorExceptionPathExits.get(predid);
+ boolean isExceptionMonitorExit = (exceptionDest != null && !nodeid.equals(exceptionDest));
+
+ HashSet<String> setLongPathWrapper = new HashSet<String>();
+ for (List<FinallyPathWrapper> lstwrapper : dgraph.mapLongRangeFinallyPaths.values()) {
+ for (FinallyPathWrapper finwraplong : lstwrapper) {
+ setLongPathWrapper.add(finwraplong.destination + "##" + finwraplong.source);
+ }
+ }
+
+ for (FinallyPathWrapper finwrap : dgraph.mapShortRangeFinallyPaths.get(predid)) {
+ SFormsFastMapDirect map;
+
+ boolean recFinally = dgraph.mapShortRangeFinallyPaths.containsKey(finwrap.source);
+
+ if (recFinally) {
+ // recursion
+ map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid);
+ }
+ else {
+ if (finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) {
+ map = outNegVarVersions.get(finwrap.source);
+ }
+ else {
+ map = outVarVersions.get(finwrap.source);
+ }
+ }
+
+ // false path?
+ boolean isFalsePath = true;
+
+ if (recFinally) {
+ isFalsePath = !finwrap.destination.equals(nodeid);
+ }
+ else {
+ isFalsePath = !setLongPathWrapper.contains(destid + "##" + finwrap.source);
+ }
+
+ if (isFalsePath) {
+ mapNewTemp.complement(map);
+ }
+ else {
+ if (mapTrueSource.isEmpty()) {
+ if (map != null) {
+ mapTrueSource = map.getCopy();
+ }
+ }
+ else {
+ mergeMaps(mapTrueSource, map);
+ }
+ }
+ }
+
+ if (isExceptionMonitorExit) {
+
+ mapNew = mapTrueSource;
+ }
+ else {
+
+ mapNewTemp.union(mapTrueSource);
+ mapNew.intersection(mapNewTemp);
+
+ if (!mapTrueSource.isEmpty() && !mapNew.isEmpty()) { // FIXME: what for??
+
+ // replace phi versions with corresponding phantom ones
+ HashMap<VarVersionPaar, VarVersionPaar> mapPhantom = phantomexitnodes.get(predid);
+ if (mapPhantom == null) {
+ mapPhantom = new HashMap<VarVersionPaar, VarVersionPaar>();
+ }
+
+ SFormsFastMapDirect mapExitVar = mapNew.getCopy();
+ mapExitVar.complement(mapTrueSource);
+
+ for (Entry<Integer, FastSparseSet<Integer>> ent : mapExitVar.entryList()) {
+ for (Integer version : ent.getValue()) {
+
+ Integer varindex = ent.getKey();
+ VarVersionPaar exitvar = new VarVersionPaar(varindex, version);
+ FastSparseSet<Integer> newSet = mapNew.get(varindex);
+
+ // remove the actual exit version
+ newSet.remove(version);
+
+ // get or create phantom version
+ VarVersionPaar phantomvar = mapPhantom.get(exitvar);
+ if (phantomvar == null) {
+ Integer newversion = getNextFreeVersion(exitvar.var, null);
+ phantomvar = new VarVersionPaar(exitvar.var, newversion.intValue());
+
+ VarVersionNode exitnode = ssuversions.nodes.getWithKey(exitvar);
+ VarVersionNode phantomnode = ssuversions.createNode(phantomvar);
+ phantomnode.flags |= VarVersionNode.FLAG_PHANTOM_FINEXIT;
+
+ VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_PHANTOM, exitnode, phantomnode);
+ exitnode.addSuccessor(edge);
+ phantomnode.addPredecessor(edge);
+
+ mapPhantom.put(exitvar, phantomvar);
+ }
+
+ // add phantom version
+ newSet.add(phantomvar.version);
+ }
+ }
+
+ if (!mapPhantom.isEmpty()) {
+ phantomexitnodes.put(predid, mapPhantom);
+ }
+ }
+ }
+ }
+
+ return mapNew;
+ }
+
+ private SFormsFastMapDirect mergeMaps(SFormsFastMapDirect mapTo, SFormsFastMapDirect map2) {
+
+ if (map2 != null && !map2.isEmpty()) {
+ mapTo.union(map2);
+ }
+
+ return mapTo;
+ }
+
+ private boolean mapsEqual(SFormsFastMapDirect map1, SFormsFastMapDirect map2) {
+
+ if (map1 == null) {
+ return map2 == null;
+ }
+ else if (map2 == null) {
+ return false;
+ }
+
+ if (map1.size() != map2.size()) {
+ return false;
+ }
+
+ for (Entry<Integer, FastSparseSet<Integer>> ent2 : map2.entryList()) {
+ if (!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ private void setCurrentVar(SFormsFastMapDirect varmap, Integer var, Integer vers) {
+ FastSparseSet<Integer> set = factory.spawnEmptySet();
+ set.add(vers);
+ varmap.put(var, set);
+ }
+
+ private void setCatchMaps(Statement stat, DirectGraph dgraph, FlattenStatementsHelper flatthelper) {
+
+ SFormsFastMapDirect map;
+
+ switch (stat.type) {
+ case Statement.TYPE_CATCHALL:
+ case Statement.TYPE_TRYCATCH:
+
+ List<VarExprent> lstVars;
+ if (stat.type == Statement.TYPE_CATCHALL) {
+ lstVars = ((CatchAllStatement)stat).getVars();
+ }
+ else {
+ lstVars = ((CatchStatement)stat).getVars();
+ }
+
+ for (int i = 1; i < stat.getStats().size(); i++) {
+ int varindex = lstVars.get(i - 1).getIndex();
+ int version = getNextFreeVersion(varindex, stat); // == 1
+
+ map = new SFormsFastMapDirect();
+ setCurrentVar(map, varindex, version);
+
+ extraVarVersions.put(dgraph.nodes.getWithKey(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0]).id, map);
+ //ssuversions.createOrGetNode(new VarVersionPaar(varindex, version));
+ ssuversions.createNode(new VarVersionPaar(varindex, version));
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ setCatchMaps(st, dgraph, flatthelper);
+ }
+ }
+
+ private SFormsFastMapDirect createFirstMap(StructMethod mt, RootStatement root) {
+
+ boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int paramcount = md.params.length + (thisvar ? 1 : 0);
+
+ int varindex = 0;
+ SFormsFastMapDirect map = new SFormsFastMapDirect();
+ for (int i = 0; i < paramcount; i++) {
+ int version = getNextFreeVersion(varindex, root); // == 1
+
+ FastSparseSet<Integer> set = factory.spawnEmptySet();
+ set.add(version);
+ map.put(varindex, set);
+ ssuversions.createNode(new VarVersionPaar(varindex, version));
+
+ if (thisvar) {
+ if (i == 0) {
+ varindex++;
+ }
+ else {
+ varindex += md.params[i - 1].stack_size;
+ }
+ }
+ else {
+ varindex += md.params[i].stack_size;
+ }
+ }
+
+ return map;
+ }
+
+ private Integer getFirstProtectedRange(Statement stat) {
+
+ for (; ; ) {
+ Statement parent = stat.getParent();
+
+ if (parent == null) {
+ break;
+ }
+
+ if (parent.type == Statement.TYPE_CATCHALL ||
+ parent.type == Statement.TYPE_TRYCATCH) {
+ if (parent.getFirst() == stat) {
+ return parent.id;
+ }
+ }
+ else if (parent.type == Statement.TYPE_SYNCRONIZED) {
+ if (((SynchronizedStatement)parent).getBody() == stat) {
+ return parent.id;
+ }
+ }
+
+ stat = parent;
+ }
+
+ return null;
+ }
+
+ public HashMap<VarVersionPaar, HashSet<Integer>> getPhi() {
+ return phi;
+ }
+
+ public VarVersionsGraph getSsuversions() {
+ return ssuversions;
+ }
+
+ public SFormsFastMapDirect getLiveVarVersionsMap(VarVersionPaar varpaar) {
+
+
+ VarVersionNode node = ssuversions.nodes.getWithKey(varpaar);
+ if (node != null) {
+ return node.live;
+ }
+
+ return null;
+ }
+
+ public HashMap<VarVersionPaar, Integer> getMapVersionFirstRange() {
+ return mapVersionFirstRange;
+ }
+
+ public HashMap<Integer, Integer> getMapFieldVars() {
+ return mapFieldVars;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java
index 5cfa634..ddac0c5 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
import org.jetbrains.java.decompiler.code.CodeConstants;
@@ -23,73 +24,73 @@ import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
public class BasicBlockStatement extends Statement {
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private BasicBlock block;
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public BasicBlockStatement(BasicBlock block) {
-
- type = Statement.TYPE_BASICBLOCK;
-
- this.block = block;
-
- id = block.id;
- CounterContainer coun = DecompilerContext.getCountercontainer();
- if(id>=coun.getCounter(CounterContainer.STATEMENT_COUNTER)) {
- coun.setCounter(CounterContainer.STATEMENT_COUNTER, id+1);
- }
-
- Instruction instr = block.getLastInstruction();
- if(instr != null) {
- if(instr.group==CodeConstants.GROUP_JUMP && instr.opcode != CodeConstants.opc_goto) {
- lastBasicType = LASTBASICTYPE_IF;
- } else if(instr.group==CodeConstants.GROUP_SWITCH) {
- lastBasicType = LASTBASICTYPE_SWITCH;
- }
- }
-
- // monitorenter and monitorexits
- buildMonitorFlags();
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public String toJava(int indent) {
- return ExprProcessor.listToJava(varDefinitions, indent)+
- ExprProcessor.listToJava(exprents, indent);
- }
-
- public Statement getSimpleCopy() {
-
- BasicBlock newblock = new BasicBlock(
- DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER));
-
- SimpleInstructionSequence seq = new SimpleInstructionSequence();
- for(int i=0;i<block.getSeq().length();i++) {
- seq.addInstruction(block.getSeq().getInstr(i).clone(), -1);
- }
-
- newblock.setSeq(seq);
-
- return new BasicBlockStatement(newblock);
- }
-
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public BasicBlock getBlock() {
- return block;
- }
-
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private BasicBlock block;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public BasicBlockStatement(BasicBlock block) {
+
+ type = Statement.TYPE_BASICBLOCK;
+
+ this.block = block;
+
+ id = block.id;
+ CounterContainer coun = DecompilerContext.getCountercontainer();
+ if (id >= coun.getCounter(CounterContainer.STATEMENT_COUNTER)) {
+ coun.setCounter(CounterContainer.STATEMENT_COUNTER, id + 1);
+ }
+
+ Instruction instr = block.getLastInstruction();
+ if (instr != null) {
+ if (instr.group == CodeConstants.GROUP_JUMP && instr.opcode != CodeConstants.opc_goto) {
+ lastBasicType = LASTBASICTYPE_IF;
+ }
+ else if (instr.group == CodeConstants.GROUP_SWITCH) {
+ lastBasicType = LASTBASICTYPE_SWITCH;
+ }
+ }
+
+ // monitorenter and monitorexits
+ buildMonitorFlags();
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public String toJava(int indent) {
+ return ExprProcessor.listToJava(varDefinitions, indent) +
+ ExprProcessor.listToJava(exprents, indent);
+ }
+
+ public Statement getSimpleCopy() {
+
+ BasicBlock newblock = new BasicBlock(
+ DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER));
+
+ SimpleInstructionSequence seq = new SimpleInstructionSequence();
+ for (int i = 0; i < block.getSeq().length(); i++) {
+ seq.addInstruction(block.getSeq().getInstr(i).clone(), -1);
+ }
+
+ newblock.setSeq(seq);
+
+ return new BasicBlockStatement(newblock);
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public BasicBlock getBlock() {
+ return block;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java
index 25adb29..9f1a3f5 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java
@@ -1,24 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
@@ -30,204 +26,210 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
public class CatchAllStatement extends Statement {
-
- private Statement handler;
-
- private boolean isFinally;
-
- private VarExprent monitor;
-
- private List<VarExprent> vars = new ArrayList<VarExprent>();
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- private CatchAllStatement(){
- type = Statement.TYPE_CATCHALL;
- };
-
- private CatchAllStatement(Statement head, Statement handler) {
-
- this();
-
- first = head;
- stats.addWithKey(head, head.id);
-
- this.handler = handler;
- stats.addWithKey(handler, handler.id);
-
- List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- if(!lstSuccs.isEmpty()) {
- StatEdge edge = lstSuccs.get(0);
- if(edge.getType() == StatEdge.TYPE_REGULAR) {
- post = edge.getDestination();
- }
- }
-
- vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
- new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"),
- (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
-
- }
-
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public static Statement isHead(Statement head) {
-
- if(head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) {
- return null;
- }
-
- HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head);
-
- if(setHandlers.size() != 1) {
- return null;
- }
-
- for(StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) {
- Statement exc = edge.getDestination();
-
- if(edge.getExceptions() == null && setHandlers.contains(exc) && exc.getLastBasicType() == LASTBASICTYPE_GENERAL) {
- List<StatEdge> lstSuccs = exc.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- if(lstSuccs.isEmpty() || lstSuccs.get(0).getType() != StatEdge.TYPE_REGULAR) {
-
- if(head.isMonitorEnter() || exc.isMonitorEnter()) {
- return null;
- }
-
- if(DecHelper.checkStatementExceptions(Arrays.asList(new Statement[] {head, exc}))) {
- return new CatchAllStatement(head, exc);
- }
- }
- }
- }
-
- return null;
- }
-
- public String toJava(int indent) {
- String indstr = InterpreterUtil.getIndentString(indent);
- String indstr1 = null;
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- StringBuffer buf = new StringBuffer();
-
- buf.append(ExprProcessor.listToJava(varDefinitions, indent));
-
- boolean labeled = isLabeled();
- if(labeled) {
- buf.append(indstr+"label"+this.id+":" + new_line_separator);
- }
-
- List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- if(first.type == TYPE_TRYCATCH && first.varDefinitions.isEmpty() && isFinally &&
- !labeled && !first.isLabeled() && (lstSuccs.isEmpty() || !lstSuccs.get(0).explicit)) {
- String content = ExprProcessor.jmpWrapper(first, indent, true);
- content = content.substring(0, content.length()-new_line_separator.length());
-
- buf.append(content);
- } else {
- buf.append(indstr+"try {" + new_line_separator);
- buf.append(ExprProcessor.jmpWrapper(first, indent+1, true));
- buf.append(indstr+"}");
- }
-
- buf.append((isFinally?" finally":
- " catch ("+vars.get(0).toJava(indent)+")")+" {" + new_line_separator);
-
- if(monitor != null) {
- indstr1 = InterpreterUtil.getIndentString(indent+1);
- buf.append(indstr1+"if("+monitor.toJava(indent)+") {" + new_line_separator);
- }
-
- buf.append(ExprProcessor.jmpWrapper(handler, indent+1+(monitor != null?1:0), true));
-
- if(monitor != null) {
- buf.append(indstr1+"}" + new_line_separator);
- }
-
- buf.append(indstr+"}" + new_line_separator);
-
- return buf.toString();
- }
-
- public void replaceStatement(Statement oldstat, Statement newstat) {
-
- if(handler == oldstat) {
- handler = newstat;
- }
-
- super.replaceStatement(oldstat, newstat);
- }
-
- public Statement getSimpleCopy() {
-
- CatchAllStatement cas = new CatchAllStatement();
-
- cas.isFinally = this.isFinally;
-
- if(this.monitor != null) {
- cas.monitor = new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
- VarType.VARTYPE_INT,
- (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR));
- }
-
- if(!this.vars.isEmpty()) {
- // FIXME: WTF??? vars?!
- vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
- new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"),
- (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
- }
-
- return cas;
- }
-
- public void initSimpleCopy() {
- first = stats.get(0);
- handler = stats.get(1);
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public Statement getHandler() {
- return handler;
- }
-
-
- public void setHandler(Statement handler) {
- this.handler = handler;
- }
-
-
- public boolean isFinally() {
- return isFinally;
- }
-
-
- public void setFinally(boolean isFinally) {
- this.isFinally = isFinally;
- }
-
-
- public VarExprent getMonitor() {
- return monitor;
- }
-
-
- public void setMonitor(VarExprent monitor) {
- this.monitor = monitor;
- }
-
- public List<VarExprent> getVars() {
- return vars;
- }
-
+
+ private Statement handler;
+
+ private boolean isFinally;
+
+ private VarExprent monitor;
+
+ private List<VarExprent> vars = new ArrayList<VarExprent>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private CatchAllStatement() {
+ type = Statement.TYPE_CATCHALL;
+ }
+
+ ;
+
+ private CatchAllStatement(Statement head, Statement handler) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(head, head.id);
+
+ this.handler = handler;
+ stats.addWithKey(handler, handler.id);
+
+ List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstSuccs.isEmpty()) {
+ StatEdge edge = lstSuccs.get(0);
+ if (edge.getType() == StatEdge.TYPE_REGULAR) {
+ post = edge.getDestination();
+ }
+ }
+
+ vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"),
+ (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead(Statement head) {
+
+ if (head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) {
+ return null;
+ }
+
+ HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head);
+
+ if (setHandlers.size() != 1) {
+ return null;
+ }
+
+ for (StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) {
+ Statement exc = edge.getDestination();
+
+ if (edge.getExceptions() == null && setHandlers.contains(exc) && exc.getLastBasicType() == LASTBASICTYPE_GENERAL) {
+ List<StatEdge> lstSuccs = exc.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (lstSuccs.isEmpty() || lstSuccs.get(0).getType() != StatEdge.TYPE_REGULAR) {
+
+ if (head.isMonitorEnter() || exc.isMonitorEnter()) {
+ return null;
+ }
+
+ if (DecHelper.checkStatementExceptions(Arrays.asList(new Statement[]{head, exc}))) {
+ return new CatchAllStatement(head, exc);
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+ String indstr1 = null;
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuffer buf = new StringBuffer();
+
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+
+ boolean labeled = isLabeled();
+ if (labeled) {
+ buf.append(indstr + "label" + this.id + ":" + new_line_separator);
+ }
+
+ List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (first.type == TYPE_TRYCATCH && first.varDefinitions.isEmpty() && isFinally &&
+ !labeled && !first.isLabeled() && (lstSuccs.isEmpty() || !lstSuccs.get(0).explicit)) {
+ String content = ExprProcessor.jmpWrapper(first, indent, true);
+ content = content.substring(0, content.length() - new_line_separator.length());
+
+ buf.append(content);
+ }
+ else {
+ buf.append(indstr + "try {" + new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr + "}");
+ }
+
+ buf.append((isFinally ? " finally" :
+ " catch (" + vars.get(0).toJava(indent) + ")") + " {" + new_line_separator);
+
+ if (monitor != null) {
+ indstr1 = InterpreterUtil.getIndentString(indent + 1);
+ buf.append(indstr1 + "if(" + monitor.toJava(indent) + ") {" + new_line_separator);
+ }
+
+ buf.append(ExprProcessor.jmpWrapper(handler, indent + 1 + (monitor != null ? 1 : 0), true));
+
+ if (monitor != null) {
+ buf.append(indstr1 + "}" + new_line_separator);
+ }
+
+ buf.append(indstr + "}" + new_line_separator);
+
+ return buf.toString();
+ }
+
+ public void replaceStatement(Statement oldstat, Statement newstat) {
+
+ if (handler == oldstat) {
+ handler = newstat;
+ }
+
+ super.replaceStatement(oldstat, newstat);
+ }
+
+ public Statement getSimpleCopy() {
+
+ CatchAllStatement cas = new CatchAllStatement();
+
+ cas.isFinally = this.isFinally;
+
+ if (this.monitor != null) {
+ cas.monitor = new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ VarType.VARTYPE_INT,
+ (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR));
+ }
+
+ if (!this.vars.isEmpty()) {
+ // FIXME: WTF??? vars?!
+ vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"),
+ (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
+ }
+
+ return cas;
+ }
+
+ public void initSimpleCopy() {
+ first = stats.get(0);
+ handler = stats.get(1);
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public Statement getHandler() {
+ return handler;
+ }
+
+
+ public void setHandler(Statement handler) {
+ this.handler = handler;
+ }
+
+
+ public boolean isFinally() {
+ return isFinally;
+ }
+
+
+ public void setFinally(boolean isFinally) {
+ this.isFinally = isFinally;
+ }
+
+
+ public VarExprent getMonitor() {
+ return monitor;
+ }
+
+
+ public void setMonitor(VarExprent monitor) {
+ this.monitor = monitor;
+ }
+
+ public List<VarExprent> getVars() {
+ return vars;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java
index 6387d45..17f5636 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java
@@ -1,23 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
@@ -29,178 +26,184 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
public class CatchStatement extends Statement {
-
- private List<List<String>> exctstrings = new ArrayList<List<String>>();
-
- private List<VarExprent> vars = new ArrayList<VarExprent>();
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- private CatchStatement() {
- type = TYPE_TRYCATCH;
- }
-
- private CatchStatement(Statement head, Statement next, HashSet<Statement> setHandlers) {
-
- this();
-
- first = head;
- stats.addWithKey(first, first.id);
-
- for(StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) {
- Statement stat = edge.getDestination();
-
- if(setHandlers.contains(stat)) {
- stats.addWithKey(stat, stat.id);
- exctstrings.add(new ArrayList<String>(edge.getExceptions()));
-
- vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
- new VarType(CodeConstants.TYPE_OBJECT, 0, edge.getExceptions().get(0)), // FIXME: for now simply the first type. Should get the first common superclass when possible.
- (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
- }
- }
-
- if(next != null) {
- post = next;
- }
-
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public static Statement isHead(Statement head) {
-
- if(head.getLastBasicType() != LASTBASICTYPE_GENERAL) {
- return null;
- }
-
- HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head);
-
- if(!setHandlers.isEmpty()) {
-
- int hnextcount = 0; // either no statements with connection to next, or more than 1
-
- Statement next = null;
- List<StatEdge> lstHeadSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- if(!lstHeadSuccs.isEmpty() && lstHeadSuccs.get(0).getType() == StatEdge.TYPE_REGULAR) {
- next = lstHeadSuccs.get(0).getDestination();
- hnextcount = 2;
- }
-
- for(StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) {
- Statement stat = edge.getDestination();
-
- boolean handlerok = true;
-
- if(edge.getExceptions() != null && setHandlers.contains(stat)) {
- if(stat.getLastBasicType() != LASTBASICTYPE_GENERAL) {
- handlerok = false;
- } else {
- List<StatEdge> lstStatSuccs = stat.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- if(!lstStatSuccs.isEmpty() && lstStatSuccs.get(0).getType() == StatEdge.TYPE_REGULAR) {
-
- Statement statn = lstStatSuccs.get(0).getDestination();
-
- if(next == null) {
- next = statn;
- } else if(next != statn) {
- handlerok = false;
- }
-
- if(handlerok) {
- hnextcount++;
- }
- }
- }
- } else {
- handlerok = false;
- }
-
- if(!handlerok) {
- setHandlers.remove(stat);
- }
- }
-
- if(hnextcount != 1 && !setHandlers.isEmpty()) {
- List<Statement> lst = new ArrayList<Statement>();
- lst.add(head);
- lst.addAll(setHandlers);
-
- for(Statement st : lst) {
- if(st.isMonitorEnter()) {
- return null;
- }
- }
-
- if(DecHelper.checkStatementExceptions(lst)) {
- return new CatchStatement(head, next, setHandlers);
- }
- }
- }
- return null;
- }
-
- public String toJava(int indent) {
- String indstr = InterpreterUtil.getIndentString(indent);
- StringBuffer buf = new StringBuffer();
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- buf.append(ExprProcessor.listToJava(varDefinitions, indent));
-
- if(isLabeled()) {
- buf.append(indstr+"label"+this.id+":" + new_line_separator);
- }
-
- buf.append(indstr+"try {" + new_line_separator);
- buf.append(ExprProcessor.jmpWrapper(first, indent+1, true));
- buf.append(indstr+"}");
-
- for(int i=1;i<stats.size();i++) {
- List<String> exception_types = exctstrings.get(i - 1);
-
- buf.append(" catch (");
- if(exception_types.size() > 1) { // multi-catch, Java 7 style
- for(int exc_index = 1; exc_index < exception_types.size(); ++exc_index) {
- VarType exc_type = new VarType(CodeConstants.TYPE_OBJECT, 0, exception_types.get(exc_index));
- String exc_type_name = ExprProcessor.getCastTypeName(exc_type);
-
- buf.append(exc_type_name + " | ");
- }
- }
- buf.append(vars.get(i-1).toJava(indent));
- buf.append(") {"+new_line_separator+ExprProcessor.jmpWrapper(stats.get(i), indent+1, true)+indstr+"}");
- }
- buf.append(new_line_separator);
-
- return buf.toString();
- }
-
- public Statement getSimpleCopy() {
-
- CatchStatement cs = new CatchStatement();
-
- for(List<String> exc : this.exctstrings) {
- cs.exctstrings.add(new ArrayList<String>(exc));
- cs.vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
- new VarType(CodeConstants.TYPE_OBJECT, 0, exc.get(0)),
- (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
- }
-
- return cs;
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public List<VarExprent> getVars() {
- return vars;
- }
-
+
+ private List<List<String>> exctstrings = new ArrayList<List<String>>();
+
+ private List<VarExprent> vars = new ArrayList<VarExprent>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private CatchStatement() {
+ type = TYPE_TRYCATCH;
+ }
+
+ private CatchStatement(Statement head, Statement next, HashSet<Statement> setHandlers) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(first, first.id);
+
+ for (StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) {
+ Statement stat = edge.getDestination();
+
+ if (setHandlers.contains(stat)) {
+ stats.addWithKey(stat, stat.id);
+ exctstrings.add(new ArrayList<String>(edge.getExceptions()));
+
+ vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ new VarType(CodeConstants.TYPE_OBJECT, 0, edge.getExceptions().get(0)),
+ // FIXME: for now simply the first type. Should get the first common superclass when possible.
+ (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
+ }
+ }
+
+ if (next != null) {
+ post = next;
+ }
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead(Statement head) {
+
+ if (head.getLastBasicType() != LASTBASICTYPE_GENERAL) {
+ return null;
+ }
+
+ HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head);
+
+ if (!setHandlers.isEmpty()) {
+
+ int hnextcount = 0; // either no statements with connection to next, or more than 1
+
+ Statement next = null;
+ List<StatEdge> lstHeadSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstHeadSuccs.isEmpty() && lstHeadSuccs.get(0).getType() == StatEdge.TYPE_REGULAR) {
+ next = lstHeadSuccs.get(0).getDestination();
+ hnextcount = 2;
+ }
+
+ for (StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) {
+ Statement stat = edge.getDestination();
+
+ boolean handlerok = true;
+
+ if (edge.getExceptions() != null && setHandlers.contains(stat)) {
+ if (stat.getLastBasicType() != LASTBASICTYPE_GENERAL) {
+ handlerok = false;
+ }
+ else {
+ List<StatEdge> lstStatSuccs = stat.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstStatSuccs.isEmpty() && lstStatSuccs.get(0).getType() == StatEdge.TYPE_REGULAR) {
+
+ Statement statn = lstStatSuccs.get(0).getDestination();
+
+ if (next == null) {
+ next = statn;
+ }
+ else if (next != statn) {
+ handlerok = false;
+ }
+
+ if (handlerok) {
+ hnextcount++;
+ }
+ }
+ }
+ }
+ else {
+ handlerok = false;
+ }
+
+ if (!handlerok) {
+ setHandlers.remove(stat);
+ }
+ }
+
+ if (hnextcount != 1 && !setHandlers.isEmpty()) {
+ List<Statement> lst = new ArrayList<Statement>();
+ lst.add(head);
+ lst.addAll(setHandlers);
+
+ for (Statement st : lst) {
+ if (st.isMonitorEnter()) {
+ return null;
+ }
+ }
+
+ if (DecHelper.checkStatementExceptions(lst)) {
+ return new CatchStatement(head, next, setHandlers);
+ }
+ }
+ }
+ return null;
+ }
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+ StringBuffer buf = new StringBuffer();
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+
+ if (isLabeled()) {
+ buf.append(indstr + "label" + this.id + ":" + new_line_separator);
+ }
+
+ buf.append(indstr + "try {" + new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr + "}");
+
+ for (int i = 1; i < stats.size(); i++) {
+ List<String> exception_types = exctstrings.get(i - 1);
+
+ buf.append(" catch (");
+ if (exception_types.size() > 1) { // multi-catch, Java 7 style
+ for (int exc_index = 1; exc_index < exception_types.size(); ++exc_index) {
+ VarType exc_type = new VarType(CodeConstants.TYPE_OBJECT, 0, exception_types.get(exc_index));
+ String exc_type_name = ExprProcessor.getCastTypeName(exc_type);
+
+ buf.append(exc_type_name + " | ");
+ }
+ }
+ buf.append(vars.get(i - 1).toJava(indent));
+ buf.append(") {" + new_line_separator + ExprProcessor.jmpWrapper(stats.get(i), indent + 1, true) + indstr + "}");
+ }
+ buf.append(new_line_separator);
+
+ return buf.toString();
+ }
+
+ public Statement getSimpleCopy() {
+
+ CatchStatement cs = new CatchStatement();
+
+ for (List<String> exc : this.exctstrings) {
+ cs.exctstrings.add(new ArrayList<String>(exc));
+ cs.vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ new VarType(CodeConstants.TYPE_OBJECT, 0, exc.get(0)),
+ (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
+ }
+
+ return cs;
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public List<VarExprent> getVars() {
+ return vars;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java
index 604e36f..2bd8e3a 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java
@@ -1,221 +1,221 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.List;
+
public class DoStatement extends Statement {
-
- public static final int LOOP_DO = 0;
- public static final int LOOP_DOWHILE = 1;
- public static final int LOOP_WHILE = 2;
- public static final int LOOP_FOR = 3;
-
- private int looptype;
-
- private List<Exprent> initExprent = new ArrayList<Exprent>();
- private List<Exprent> conditionExprent = new ArrayList<Exprent>();
- private List<Exprent> incExprent = new ArrayList<Exprent>();
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- private DoStatement() {
- type = Statement.TYPE_DO;
- looptype = LOOP_DO;
-
- initExprent.add(null);
- conditionExprent.add(null);
- incExprent.add(null);
- }
-
- private DoStatement(Statement head) {
-
- this();
-
- first = head;
- stats.addWithKey(first, first.id);
-
- // post is always null!
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public static Statement isHead(Statement head) {
-
- if(head.getLastBasicType() == LASTBASICTYPE_GENERAL && !head.isMonitorEnter()) {
-
- // at most one outgoing edge
- StatEdge edge = null;
- List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- if(!lstSuccs.isEmpty()) {
- edge = lstSuccs.get(0);
- }
-
- // regular loop
- if(edge!=null && edge.getType() == StatEdge.TYPE_REGULAR && edge.getDestination() == head) {
- return new DoStatement(head);
- }
-
- // continues
- if(head.type != TYPE_DO && (edge == null || edge.getType() != StatEdge.TYPE_REGULAR) &&
- head.getContinueSet().contains(head.getBasichead())) {
- return new DoStatement(head);
- }
- }
-
- return null;
- }
-
- public String toJava(int indent) {
- String indstr = InterpreterUtil.getIndentString(indent);
- StringBuffer buf = new StringBuffer();
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- buf.append(ExprProcessor.listToJava(varDefinitions, indent));
-
- if(isLabeled()) {
- buf.append(indstr+"label"+this.id+":" + new_line_separator);
- }
-
- switch(looptype) {
- case LOOP_DO:
- buf.append(indstr+"while(true) {" + new_line_separator);
- buf.append(ExprProcessor.jmpWrapper(first, indent+1, true));
- buf.append(indstr+"}" + new_line_separator);
- break;
- case LOOP_DOWHILE:
- buf.append(indstr+"do {" + new_line_separator);
- buf.append(ExprProcessor.jmpWrapper(first, indent+1, true));
- buf.append(indstr+"} while("+conditionExprent.get(0).toJava(indent)+");" + new_line_separator);
- break;
- case LOOP_WHILE:
- buf.append(indstr+"while("+conditionExprent.get(0).toJava(indent)+") {" + new_line_separator);
- buf.append(ExprProcessor.jmpWrapper(first, indent+1, true));
- buf.append(indstr+"}" + new_line_separator);
- break;
- case LOOP_FOR:
- buf.append(indstr+"for("+(initExprent.get(0)==null?"":initExprent.get(0).toJava(indent))+
- "; "+conditionExprent.get(0).toJava(indent)+"; "+incExprent.get(0).toJava(indent)+") {" + new_line_separator);
- buf.append(ExprProcessor.jmpWrapper(first, indent+1, true));
- buf.append(indstr+"}" + new_line_separator);
- }
-
- return buf.toString();
- }
-
- public List<Object> getSequentialObjects() {
-
- List<Object> lst = new ArrayList<Object>();
-
- switch(looptype) {
- case LOOP_FOR:
- if(getInitExprent() != null) {
- lst.add(getInitExprent());
- }
- case LOOP_WHILE:
- lst.add(getConditionExprent());
- }
-
- lst.add(first);
-
- switch(looptype) {
- case LOOP_DOWHILE:
- lst.add(getConditionExprent());
- break;
- case LOOP_FOR:
- lst.add(getIncExprent());
- }
-
- return lst;
- }
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(initExprent.get(0) == oldexpr) {
- initExprent.set(0, newexpr);
- }
- if(conditionExprent.get(0) == oldexpr) {
- conditionExprent.set(0, newexpr);
- }
- if(incExprent.get(0) == oldexpr) {
- incExprent.set(0, newexpr);
- }
- }
-
- public Statement getSimpleCopy() {
- return new DoStatement();
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public List<Exprent> getInitExprentList() {
- return initExprent;
- }
-
- public List<Exprent> getConditionExprentList() {
- return conditionExprent;
- }
-
- public List<Exprent> getIncExprentList() {
- return incExprent;
- }
-
- public Exprent getConditionExprent() {
- return conditionExprent.get(0);
- }
-
- public void setConditionExprent(Exprent conditionExprent) {
- this.conditionExprent.set(0, conditionExprent);
- }
-
- public Exprent getIncExprent() {
- return incExprent.get(0);
- }
-
- public void setIncExprent(Exprent incExprent) {
- this.incExprent.set(0, incExprent);
- }
-
- public Exprent getInitExprent() {
- return initExprent.get(0);
- }
-
- public void setInitExprent(Exprent initExprent) {
- this.initExprent.set(0, initExprent);
- }
-
- public int getLooptype() {
- return looptype;
- }
-
- public void setLooptype(int looptype) {
- this.looptype = looptype;
- }
-
+
+ public static final int LOOP_DO = 0;
+ public static final int LOOP_DOWHILE = 1;
+ public static final int LOOP_WHILE = 2;
+ public static final int LOOP_FOR = 3;
+
+ private int looptype;
+
+ private List<Exprent> initExprent = new ArrayList<Exprent>();
+ private List<Exprent> conditionExprent = new ArrayList<Exprent>();
+ private List<Exprent> incExprent = new ArrayList<Exprent>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private DoStatement() {
+ type = Statement.TYPE_DO;
+ looptype = LOOP_DO;
+
+ initExprent.add(null);
+ conditionExprent.add(null);
+ incExprent.add(null);
+ }
+
+ private DoStatement(Statement head) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(first, first.id);
+
+ // post is always null!
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead(Statement head) {
+
+ if (head.getLastBasicType() == LASTBASICTYPE_GENERAL && !head.isMonitorEnter()) {
+
+ // at most one outgoing edge
+ StatEdge edge = null;
+ List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstSuccs.isEmpty()) {
+ edge = lstSuccs.get(0);
+ }
+
+ // regular loop
+ if (edge != null && edge.getType() == StatEdge.TYPE_REGULAR && edge.getDestination() == head) {
+ return new DoStatement(head);
+ }
+
+ // continues
+ if (head.type != TYPE_DO && (edge == null || edge.getType() != StatEdge.TYPE_REGULAR) &&
+ head.getContinueSet().contains(head.getBasichead())) {
+ return new DoStatement(head);
+ }
+ }
+
+ return null;
+ }
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+ StringBuffer buf = new StringBuffer();
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+
+ if (isLabeled()) {
+ buf.append(indstr + "label" + this.id + ":" + new_line_separator);
+ }
+
+ switch (looptype) {
+ case LOOP_DO:
+ buf.append(indstr + "while(true) {" + new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr + "}" + new_line_separator);
+ break;
+ case LOOP_DOWHILE:
+ buf.append(indstr + "do {" + new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr + "} while(" + conditionExprent.get(0).toJava(indent) + ");" + new_line_separator);
+ break;
+ case LOOP_WHILE:
+ buf.append(indstr + "while(" + conditionExprent.get(0).toJava(indent) + ") {" + new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr + "}" + new_line_separator);
+ break;
+ case LOOP_FOR:
+ buf.append(indstr + "for(" + (initExprent.get(0) == null ? "" : initExprent.get(0).toJava(indent)) +
+ "; " + conditionExprent.get(0).toJava(indent) + "; " + incExprent.get(0).toJava(indent) + ") {" + new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr + "}" + new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public List<Object> getSequentialObjects() {
+
+ List<Object> lst = new ArrayList<Object>();
+
+ switch (looptype) {
+ case LOOP_FOR:
+ if (getInitExprent() != null) {
+ lst.add(getInitExprent());
+ }
+ case LOOP_WHILE:
+ lst.add(getConditionExprent());
+ }
+
+ lst.add(first);
+
+ switch (looptype) {
+ case LOOP_DOWHILE:
+ lst.add(getConditionExprent());
+ break;
+ case LOOP_FOR:
+ lst.add(getIncExprent());
+ }
+
+ return lst;
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (initExprent.get(0) == oldexpr) {
+ initExprent.set(0, newexpr);
+ }
+ if (conditionExprent.get(0) == oldexpr) {
+ conditionExprent.set(0, newexpr);
+ }
+ if (incExprent.get(0) == oldexpr) {
+ incExprent.set(0, newexpr);
+ }
+ }
+
+ public Statement getSimpleCopy() {
+ return new DoStatement();
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public List<Exprent> getInitExprentList() {
+ return initExprent;
+ }
+
+ public List<Exprent> getConditionExprentList() {
+ return conditionExprent;
+ }
+
+ public List<Exprent> getIncExprentList() {
+ return incExprent;
+ }
+
+ public Exprent getConditionExprent() {
+ return conditionExprent.get(0);
+ }
+
+ public void setConditionExprent(Exprent conditionExprent) {
+ this.conditionExprent.set(0, conditionExprent);
+ }
+
+ public Exprent getIncExprent() {
+ return incExprent.get(0);
+ }
+
+ public void setIncExprent(Exprent incExprent) {
+ this.incExprent.set(0, incExprent);
+ }
+
+ public Exprent getInitExprent() {
+ return initExprent.get(0);
+ }
+
+ public void setInitExprent(Exprent initExprent) {
+ this.initExprent.set(0, initExprent);
+ }
+
+ public int getLooptype() {
+ return looptype;
+ }
+
+ public void setLooptype(int looptype) {
+ this.looptype = looptype;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java
index 9cfaeb4..9988881 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java
@@ -1,75 +1,74 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
-import java.util.Collection;
-import java.util.HashSet;
-
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.Collection;
+import java.util.HashSet;
public class GeneralStatement extends Statement {
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- private GeneralStatement() {
- type = Statement.TYPE_GENERAL;
- }
-
- public GeneralStatement(Statement head, Collection<Statement> statements, Statement post) {
-
- this();
-
- first = head;
- stats.addWithKey(head, head.id);
-
- HashSet<Statement> set = new HashSet<Statement>(statements);
- set.remove(head);
-
- for(Statement st : set) {
- stats.addWithKey(st, st.id);
- }
-
- this.post = post;
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public String toJava(int indent) {
- String indstr = InterpreterUtil.getIndentString(indent);
- StringBuffer buf = new StringBuffer();
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- if(isLabeled()) {
- buf.append(indstr+"label"+this.id+":" + new_line_separator);
- }
-
- buf.append(indstr+"abstract statement {" + new_line_separator);
- for(int i=0;i<stats.size();i++) {
- buf.append(stats.get(i).toJava(indent+1));
- }
- buf.append(indstr+"}");
-
- return buf.toString();
- }
-
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private GeneralStatement() {
+ type = Statement.TYPE_GENERAL;
+ }
+
+ public GeneralStatement(Statement head, Collection<Statement> statements, Statement post) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(head, head.id);
+
+ HashSet<Statement> set = new HashSet<Statement>(statements);
+ set.remove(head);
+
+ for (Statement st : set) {
+ stats.addWithKey(st, st.id);
+ }
+
+ this.post = post;
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+ StringBuffer buf = new StringBuffer();
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ if (isLabeled()) {
+ buf.append(indstr + "label" + this.id + ":" + new_line_separator);
+ }
+
+ buf.append(indstr + "abstract statement {" + new_line_separator);
+ for (int i = 0; i < stats.size(); i++) {
+ buf.append(stats.get(i).toJava(indent + 1));
+ }
+ buf.append(indstr + "}");
+
+ return buf.toString();
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java
index 3e3e20b..0b05981 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java
@@ -1,22 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.decompiler.DecHelper;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
@@ -25,380 +23,394 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.List;
+
public class IfStatement extends Statement {
- public static int IFTYPE_IF = 0;
- public static int IFTYPE_IFELSE = 1;
-
- public int iftype;
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private Statement ifstat;
- private Statement elsestat;
-
- private StatEdge ifedge;
- private StatEdge elseedge;
-
- private boolean negated = false;
-
- private boolean iffflag;
-
- private List<Exprent> headexprent = new ArrayList<Exprent>(); // contains IfExprent
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- private IfStatement() {
- type = TYPE_IF;
-
- headexprent.add(null);
- }
-
- private IfStatement(Statement head, int regedges, Statement postst) {
-
- this();
-
- first = head;
- stats.addWithKey(head, head.id);
-
- List<StatEdge> lstHeadSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
-
- switch(regedges) {
- case 0:
- ifstat = null;
- elsestat = null;
-
- break;
- case 1:
- ifstat = null;
- elsestat = null;
-
- StatEdge edgeif = lstHeadSuccs.get(1);
- if(edgeif.getType() != StatEdge.TYPE_REGULAR) {
- post = lstHeadSuccs.get(0).getDestination();
- } else {
- post = edgeif.getDestination();
- negated = true;
- }
- break;
- case 2:
- elsestat = lstHeadSuccs.get(0).getDestination();
- ifstat = lstHeadSuccs.get(1).getDestination();
-
- List<StatEdge> lstSucc = ifstat.getSuccessorEdges(StatEdge.TYPE_REGULAR);
- List<StatEdge> lstSucc1 = elsestat.getSuccessorEdges(StatEdge.TYPE_REGULAR);
-
- if(ifstat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size()>1 || lstSucc.size()>1) {
- post = ifstat;
- } else if(elsestat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size()>1 || lstSucc1.size()>1) {
- post = elsestat;
- } else {
- if(lstSucc.size() == 0){
- post = elsestat;
- } else if(lstSucc1.size() == 0){
- post = ifstat;
- }
- }
-
- if(ifstat == post) {
- if(elsestat != post) {
- ifstat = elsestat;
- negated = true;
- } else {
- ifstat = null;
- }
- elsestat = null;
- } else if(elsestat == post) {
- elsestat = null;
- } else {
- post = postst;
- }
-
- if(elsestat == null) {
- regedges = 1; // if without else
- }
- }
-
- ifedge = lstHeadSuccs.get(negated?0:1);
- elseedge = (regedges == 2)?lstHeadSuccs.get(negated?1:0):null;
-
- iftype = (regedges == 2)?IFTYPE_IFELSE:IFTYPE_IF;
-
- if(iftype == IFTYPE_IF) {
- if(regedges == 0) {
- StatEdge edge = lstHeadSuccs.get(0);
- head.removeSuccessor(edge);
- edge.setSource(this);
- this.addSuccessor(edge);
- } else if(regedges == 1) {
- StatEdge edge = lstHeadSuccs.get(negated?1:0);
- head.removeSuccessor(edge);
- }
- }
-
- if(ifstat != null) {
- stats.addWithKey(ifstat, ifstat.id);
- }
-
- if(elsestat != null) {
- stats.addWithKey(elsestat, elsestat.id);
- }
-
- if(post == head) {
- post = this;
- }
-
- }
-
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public static Statement isHead(Statement head) {
-
- if(head.type == TYPE_BASICBLOCK && head.getLastBasicType() == LASTBASICTYPE_IF) {
- int regsize = head.getSuccessorEdges(StatEdge.TYPE_REGULAR).size();
-
- Statement p = null;
-
- boolean ok = (regsize < 2);
- if(!ok) {
- List<Statement> lst = new ArrayList<Statement>();
- if(DecHelper.isChoiceStatement(head, lst)) {
- p = lst.remove(0);
-
- for(Statement st : lst) {
- if(st.isMonitorEnter()) {
- return null;
- }
- }
-
- ok = DecHelper.checkStatementExceptions(lst);
- }
- }
-
- if(ok) {
- return new IfStatement(head, regsize, p);
- }
- }
-
- return null;
- }
-
- public String toJava(int indent) {
- String indstr = InterpreterUtil.getIndentString(indent);
- StringBuffer buf = new StringBuffer();
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- buf.append(ExprProcessor.listToJava(varDefinitions, indent));
- buf.append(first.toJava(indent));
-
- if(isLabeled()) {
- buf.append(indstr+"label"+this.id+":" + new_line_separator);
- }
-
- buf.append(indstr+headexprent.get(0).toJava(indent)+" {" + new_line_separator);
-
- if(ifstat==null) {
- buf.append(InterpreterUtil.getIndentString(indent+1));
-
- if(ifedge.explicit) {
- if(ifedge.getType() == StatEdge.TYPE_BREAK) {
- // break
- buf.append("break");
- } else {
- // continue
- buf.append("continue");
- }
-
- if(ifedge.labeled) {
- buf.append(" label"+ifedge.closure.id);
- }
- }
- buf.append(";" + new_line_separator);
- } else {
- buf.append(ExprProcessor.jmpWrapper(ifstat, indent+1, true));
- }
-
- boolean elseif = false;
-
- if(elsestat != null) {
- if(elsestat.type == Statement.TYPE_IF
- && elsestat.varDefinitions.isEmpty() && elsestat.getFirst().getExprents().isEmpty() &&
- !elsestat.isLabeled() &&
- (elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).isEmpty()
- || !elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).get(0).explicit)) { // else if
- String content = ExprProcessor.jmpWrapper(elsestat, indent, false);
- content = content.substring(indstr.length());
-
- buf.append(indstr+"} else ");
- buf.append(content);
-
- elseif = true;
- } else {
- String content = ExprProcessor.jmpWrapper(elsestat, indent+1, false);
-
- if(content.length() > 0) {
- buf.append(indstr+"} else {" + new_line_separator);
- buf.append(content);
- }
- }
- }
-
- if(!elseif) {
- buf.append(indstr+"}" + new_line_separator);
- }
-
- return buf.toString();
- }
-
- public void initExprents() {
-
- IfExprent ifexpr = (IfExprent)first.getExprents().remove(first.getExprents().size()-1);
-
- if(negated) {
- ifexpr = (IfExprent)ifexpr.copy();
- ifexpr.negateIf();
- }
-
- headexprent.set(0, ifexpr);
- }
-
- public List<Object> getSequentialObjects() {
-
- List<Object> lst = new ArrayList<Object>(stats);
- lst.add(1, headexprent.get(0));
-
- return lst;
- }
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(headexprent.get(0) == oldexpr) {
- headexprent.set(0, newexpr);
- }
- }
-
- public void replaceStatement(Statement oldstat, Statement newstat) {
-
- super.replaceStatement(oldstat, newstat);
-
- if(ifstat == oldstat) {
- ifstat = newstat;
- }
-
- if(elsestat == oldstat) {
- elsestat = newstat;
- }
-
- List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
-
- if(iftype == IFTYPE_IF) {
- ifedge = lstSuccs.get(0);
- elseedge = null;
- } else {
- StatEdge edge0 = lstSuccs.get(0);
- StatEdge edge1 = lstSuccs.get(1);
- if(edge0.getDestination() == ifstat) {
- ifedge = edge0;
- elseedge = edge1;
- } else {
- ifedge = edge1;
- elseedge = edge0;
- }
- }
- }
-
- public Statement getSimpleCopy() {
-
- IfStatement is = new IfStatement();
- is.iftype = this.iftype;
- is.negated = this.negated;
- is.iffflag = this.iffflag;
-
- return is;
- }
-
- public void initSimpleCopy() {
-
- first = stats.get(0);
-
- List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- ifedge = lstSuccs.get((iftype == IFTYPE_IF || negated)?0:1);
- if(stats.size() > 1) {
- ifstat = stats.get(1);
- }
-
- if(iftype == IFTYPE_IFELSE) {
- elseedge = lstSuccs.get(negated?1:0);
- elsestat = stats.get(2);
- }
-
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public Statement getElsestat() {
- return elsestat;
- }
-
- public void setElsestat(Statement elsestat) {
- this.elsestat = elsestat;
- }
-
- public Statement getIfstat() {
- return ifstat;
- }
-
- public void setIfstat(Statement ifstat) {
- this.ifstat = ifstat;
- }
-
- public boolean isNegated() {
- return negated;
- }
-
- public void setNegated(boolean negated) {
- this.negated = negated;
- }
-
- public List<Exprent> getHeadexprentList() {
- return headexprent;
- }
-
- public IfExprent getHeadexprent() {
- return (IfExprent)headexprent.get(0);
- }
-
- public boolean isIffflag() {
- return iffflag;
- }
-
- public void setIffflag(boolean iffflag) {
- this.iffflag = iffflag;
- }
-
- public void setElseEdge(StatEdge elseedge) {
- this.elseedge = elseedge;
- }
-
- public void setIfEdge(StatEdge ifedge) {
- this.ifedge = ifedge;
- }
-
- public StatEdge getIfEdge() {
- return ifedge;
- }
-
- public StatEdge getElseEdge() {
- return elseedge;
- }
+ public static int IFTYPE_IF = 0;
+ public static int IFTYPE_IFELSE = 1;
+
+ public int iftype;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private Statement ifstat;
+ private Statement elsestat;
+
+ private StatEdge ifedge;
+ private StatEdge elseedge;
+
+ private boolean negated = false;
+
+ private boolean iffflag;
+
+ private List<Exprent> headexprent = new ArrayList<Exprent>(); // contains IfExprent
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private IfStatement() {
+ type = TYPE_IF;
+
+ headexprent.add(null);
+ }
+
+ private IfStatement(Statement head, int regedges, Statement postst) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(head, head.id);
+
+ List<StatEdge> lstHeadSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+
+ switch (regedges) {
+ case 0:
+ ifstat = null;
+ elsestat = null;
+
+ break;
+ case 1:
+ ifstat = null;
+ elsestat = null;
+
+ StatEdge edgeif = lstHeadSuccs.get(1);
+ if (edgeif.getType() != StatEdge.TYPE_REGULAR) {
+ post = lstHeadSuccs.get(0).getDestination();
+ }
+ else {
+ post = edgeif.getDestination();
+ negated = true;
+ }
+ break;
+ case 2:
+ elsestat = lstHeadSuccs.get(0).getDestination();
+ ifstat = lstHeadSuccs.get(1).getDestination();
+
+ List<StatEdge> lstSucc = ifstat.getSuccessorEdges(StatEdge.TYPE_REGULAR);
+ List<StatEdge> lstSucc1 = elsestat.getSuccessorEdges(StatEdge.TYPE_REGULAR);
+
+ if (ifstat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() > 1 || lstSucc.size() > 1) {
+ post = ifstat;
+ }
+ else if (elsestat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() > 1 || lstSucc1.size() > 1) {
+ post = elsestat;
+ }
+ else {
+ if (lstSucc.size() == 0) {
+ post = elsestat;
+ }
+ else if (lstSucc1.size() == 0) {
+ post = ifstat;
+ }
+ }
+
+ if (ifstat == post) {
+ if (elsestat != post) {
+ ifstat = elsestat;
+ negated = true;
+ }
+ else {
+ ifstat = null;
+ }
+ elsestat = null;
+ }
+ else if (elsestat == post) {
+ elsestat = null;
+ }
+ else {
+ post = postst;
+ }
+
+ if (elsestat == null) {
+ regedges = 1; // if without else
+ }
+ }
+
+ ifedge = lstHeadSuccs.get(negated ? 0 : 1);
+ elseedge = (regedges == 2) ? lstHeadSuccs.get(negated ? 1 : 0) : null;
+
+ iftype = (regedges == 2) ? IFTYPE_IFELSE : IFTYPE_IF;
+
+ if (iftype == IFTYPE_IF) {
+ if (regedges == 0) {
+ StatEdge edge = lstHeadSuccs.get(0);
+ head.removeSuccessor(edge);
+ edge.setSource(this);
+ this.addSuccessor(edge);
+ }
+ else if (regedges == 1) {
+ StatEdge edge = lstHeadSuccs.get(negated ? 1 : 0);
+ head.removeSuccessor(edge);
+ }
+ }
+
+ if (ifstat != null) {
+ stats.addWithKey(ifstat, ifstat.id);
+ }
+
+ if (elsestat != null) {
+ stats.addWithKey(elsestat, elsestat.id);
+ }
+
+ if (post == head) {
+ post = this;
+ }
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead(Statement head) {
+
+ if (head.type == TYPE_BASICBLOCK && head.getLastBasicType() == LASTBASICTYPE_IF) {
+ int regsize = head.getSuccessorEdges(StatEdge.TYPE_REGULAR).size();
+
+ Statement p = null;
+
+ boolean ok = (regsize < 2);
+ if (!ok) {
+ List<Statement> lst = new ArrayList<Statement>();
+ if (DecHelper.isChoiceStatement(head, lst)) {
+ p = lst.remove(0);
+
+ for (Statement st : lst) {
+ if (st.isMonitorEnter()) {
+ return null;
+ }
+ }
+
+ ok = DecHelper.checkStatementExceptions(lst);
+ }
+ }
+
+ if (ok) {
+ return new IfStatement(head, regsize, p);
+ }
+ }
+
+ return null;
+ }
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+ StringBuffer buf = new StringBuffer();
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+ buf.append(first.toJava(indent));
+
+ if (isLabeled()) {
+ buf.append(indstr + "label" + this.id + ":" + new_line_separator);
+ }
+
+ buf.append(indstr + headexprent.get(0).toJava(indent) + " {" + new_line_separator);
+
+ if (ifstat == null) {
+ buf.append(InterpreterUtil.getIndentString(indent + 1));
+
+ if (ifedge.explicit) {
+ if (ifedge.getType() == StatEdge.TYPE_BREAK) {
+ // break
+ buf.append("break");
+ }
+ else {
+ // continue
+ buf.append("continue");
+ }
+
+ if (ifedge.labeled) {
+ buf.append(" label" + ifedge.closure.id);
+ }
+ }
+ buf.append(";" + new_line_separator);
+ }
+ else {
+ buf.append(ExprProcessor.jmpWrapper(ifstat, indent + 1, true));
+ }
+
+ boolean elseif = false;
+
+ if (elsestat != null) {
+ if (elsestat.type == Statement.TYPE_IF
+ && elsestat.varDefinitions.isEmpty() && elsestat.getFirst().getExprents().isEmpty() &&
+ !elsestat.isLabeled() &&
+ (elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).isEmpty()
+ || !elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).get(0).explicit)) { // else if
+ String content = ExprProcessor.jmpWrapper(elsestat, indent, false);
+ content = content.substring(indstr.length());
+
+ buf.append(indstr + "} else ");
+ buf.append(content);
+
+ elseif = true;
+ }
+ else {
+ String content = ExprProcessor.jmpWrapper(elsestat, indent + 1, false);
+
+ if (content.length() > 0) {
+ buf.append(indstr + "} else {" + new_line_separator);
+ buf.append(content);
+ }
+ }
+ }
+
+ if (!elseif) {
+ buf.append(indstr + "}" + new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public void initExprents() {
+
+ IfExprent ifexpr = (IfExprent)first.getExprents().remove(first.getExprents().size() - 1);
+
+ if (negated) {
+ ifexpr = (IfExprent)ifexpr.copy();
+ ifexpr.negateIf();
+ }
+
+ headexprent.set(0, ifexpr);
+ }
+
+ public List<Object> getSequentialObjects() {
+
+ List<Object> lst = new ArrayList<Object>(stats);
+ lst.add(1, headexprent.get(0));
+
+ return lst;
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (headexprent.get(0) == oldexpr) {
+ headexprent.set(0, newexpr);
+ }
+ }
+
+ public void replaceStatement(Statement oldstat, Statement newstat) {
+
+ super.replaceStatement(oldstat, newstat);
+
+ if (ifstat == oldstat) {
+ ifstat = newstat;
+ }
+
+ if (elsestat == oldstat) {
+ elsestat = newstat;
+ }
+
+ List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+
+ if (iftype == IFTYPE_IF) {
+ ifedge = lstSuccs.get(0);
+ elseedge = null;
+ }
+ else {
+ StatEdge edge0 = lstSuccs.get(0);
+ StatEdge edge1 = lstSuccs.get(1);
+ if (edge0.getDestination() == ifstat) {
+ ifedge = edge0;
+ elseedge = edge1;
+ }
+ else {
+ ifedge = edge1;
+ elseedge = edge0;
+ }
+ }
+ }
+
+ public Statement getSimpleCopy() {
+
+ IfStatement is = new IfStatement();
+ is.iftype = this.iftype;
+ is.negated = this.negated;
+ is.iffflag = this.iffflag;
+
+ return is;
+ }
+
+ public void initSimpleCopy() {
+
+ first = stats.get(0);
+
+ List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ ifedge = lstSuccs.get((iftype == IFTYPE_IF || negated) ? 0 : 1);
+ if (stats.size() > 1) {
+ ifstat = stats.get(1);
+ }
+
+ if (iftype == IFTYPE_IFELSE) {
+ elseedge = lstSuccs.get(negated ? 1 : 0);
+ elsestat = stats.get(2);
+ }
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public Statement getElsestat() {
+ return elsestat;
+ }
+
+ public void setElsestat(Statement elsestat) {
+ this.elsestat = elsestat;
+ }
+
+ public Statement getIfstat() {
+ return ifstat;
+ }
+
+ public void setIfstat(Statement ifstat) {
+ this.ifstat = ifstat;
+ }
+
+ public boolean isNegated() {
+ return negated;
+ }
+
+ public void setNegated(boolean negated) {
+ this.negated = negated;
+ }
+
+ public List<Exprent> getHeadexprentList() {
+ return headexprent;
+ }
+
+ public IfExprent getHeadexprent() {
+ return (IfExprent)headexprent.get(0);
+ }
+
+ public boolean isIffflag() {
+ return iffflag;
+ }
+
+ public void setIffflag(boolean iffflag) {
+ this.iffflag = iffflag;
+ }
+
+ public void setElseEdge(StatEdge elseedge) {
+ this.elseedge = elseedge;
+ }
+
+ public void setIfEdge(StatEdge ifedge) {
+ this.ifedge = ifedge;
+ }
+
+ public StatEdge getIfEdge() {
+ return ifedge;
+ }
+
+ public StatEdge getElseEdge() {
+ return elseedge;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java
index c34888e..2a69447 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
@@ -19,31 +20,29 @@ import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
public class RootStatement extends Statement {
- private Statement dummyExit;
-
- public RootStatement(Statement head, Statement dummyExit) {
-
- type = Statement.TYPE_ROOT;
-
- first = head;
- this.dummyExit = dummyExit;
-
- stats.addWithKey(first, first.id);
- first.setParent(this);
-
- }
-
- public String toJava(int indent) {
- return ExprProcessor.listToJava(varDefinitions, indent)+
- first.toJava(indent);
- }
-
- public Statement getDummyExit() {
- return dummyExit;
- }
-
- public void setDummyExit(Statement dummyExit) {
- this.dummyExit = dummyExit;
- }
-
+ private Statement dummyExit;
+
+ public RootStatement(Statement head, Statement dummyExit) {
+
+ type = Statement.TYPE_ROOT;
+
+ first = head;
+ this.dummyExit = dummyExit;
+
+ stats.addWithKey(first, first.id);
+ first.setParent(this);
+ }
+
+ public String toJava(int indent) {
+ return ExprProcessor.listToJava(varDefinitions, indent) +
+ first.toJava(indent);
+ }
+
+ public Statement getDummyExit() {
+ return dummyExit;
+ }
+
+ public void setDummyExit(Statement dummyExit) {
+ this.dummyExit = dummyExit;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java
index 79b0b19..8fd8a43 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java
@@ -1,144 +1,144 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
-import java.util.Arrays;
-import java.util.List;
-
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.decompiler.DecHelper;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.Arrays;
+import java.util.List;
+
public class SequenceStatement extends Statement {
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- private SequenceStatement() {
- type = Statement.TYPE_SEQUENCE;
- }
-
- public SequenceStatement(List<Statement> lst) {
-
- this();
-
- lastBasicType = lst.get(lst.size()-1).getLastBasicType();
-
- for(Statement st: lst) {
- stats.addWithKey(st, st.id);
- }
-
- first = stats.get(0);
- }
-
- private SequenceStatement(Statement head, Statement tail) {
-
- this(Arrays.asList(new Statement[] {head, tail}));
-
- List<StatEdge> lstSuccs = tail.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- if(!lstSuccs.isEmpty()) {
- StatEdge edge = lstSuccs.get(0);
-
- if(edge.getType() == StatEdge.TYPE_REGULAR && edge.getDestination() != head) {
- post = edge.getDestination();
- }
- }
- }
-
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public static Statement isHead2Block(Statement head) {
-
- if(head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) {
- return null;
- }
-
- // at most one outgoing edge
- StatEdge edge = null;
- List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- if(!lstSuccs.isEmpty()) {
- edge = lstSuccs.get(0);
- }
-
- if(edge != null && edge.getType() == StatEdge.TYPE_REGULAR) {
- Statement stat = edge.getDestination();
-
- if(stat != head && stat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() == 1
- && !stat.isMonitorEnter()) {
-
- if(stat.getLastBasicType() == Statement.LASTBASICTYPE_GENERAL) {
- if(DecHelper.checkStatementExceptions(Arrays.asList(new Statement[] {head, stat}))) {
- return new SequenceStatement(head, stat);
- }
- }
- }
- }
-
- return null;
- }
-
- public String toJava(int indent) {
-
- StringBuilder buf = new StringBuilder();
-
- String indstr = null;
- boolean islabeled = isLabeled();
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- buf.append(ExprProcessor.listToJava(varDefinitions, indent));
-
- if(islabeled) {
- indstr = InterpreterUtil.getIndentString(indent);
- indent++;
- buf.append(indstr+"label"+this.id+": {" + new_line_separator);
- }
-
- boolean notempty = false;
-
- for(int i=0;i<stats.size();i++) {
-
- Statement st = stats.get(i);
-
- if(i>0 && notempty) {
- buf.append(new_line_separator);
- }
-
- String str = ExprProcessor.jmpWrapper(st, indent, false);
- buf.append(str);
-
- notempty = (str.trim().length() > 0);
- }
-
- if(islabeled) {
- buf.append(indstr+"}" + new_line_separator);
- }
-
- return buf.toString();
- }
-
- public Statement getSimpleCopy() {
- return new SequenceStatement();
- }
-
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private SequenceStatement() {
+ type = Statement.TYPE_SEQUENCE;
+ }
+
+ public SequenceStatement(List<Statement> lst) {
+
+ this();
+
+ lastBasicType = lst.get(lst.size() - 1).getLastBasicType();
+
+ for (Statement st : lst) {
+ stats.addWithKey(st, st.id);
+ }
+
+ first = stats.get(0);
+ }
+
+ private SequenceStatement(Statement head, Statement tail) {
+
+ this(Arrays.asList(new Statement[]{head, tail}));
+
+ List<StatEdge> lstSuccs = tail.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstSuccs.isEmpty()) {
+ StatEdge edge = lstSuccs.get(0);
+
+ if (edge.getType() == StatEdge.TYPE_REGULAR && edge.getDestination() != head) {
+ post = edge.getDestination();
+ }
+ }
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead2Block(Statement head) {
+
+ if (head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) {
+ return null;
+ }
+
+ // at most one outgoing edge
+ StatEdge edge = null;
+ List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstSuccs.isEmpty()) {
+ edge = lstSuccs.get(0);
+ }
+
+ if (edge != null && edge.getType() == StatEdge.TYPE_REGULAR) {
+ Statement stat = edge.getDestination();
+
+ if (stat != head && stat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() == 1
+ && !stat.isMonitorEnter()) {
+
+ if (stat.getLastBasicType() == Statement.LASTBASICTYPE_GENERAL) {
+ if (DecHelper.checkStatementExceptions(Arrays.asList(new Statement[]{head, stat}))) {
+ return new SequenceStatement(head, stat);
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String toJava(int indent) {
+
+ StringBuilder buf = new StringBuilder();
+
+ String indstr = null;
+ boolean islabeled = isLabeled();
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+
+ if (islabeled) {
+ indstr = InterpreterUtil.getIndentString(indent);
+ indent++;
+ buf.append(indstr + "label" + this.id + ": {" + new_line_separator);
+ }
+
+ boolean notempty = false;
+
+ for (int i = 0; i < stats.size(); i++) {
+
+ Statement st = stats.get(i);
+
+ if (i > 0 && notempty) {
+ buf.append(new_line_separator);
+ }
+
+ String str = ExprProcessor.jmpWrapper(st, indent, false);
+ buf.append(str);
+
+ notempty = (str.trim().length() > 0);
+ }
+
+ if (islabeled) {
+ buf.append(indstr + "}" + new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public Statement getSimpleCopy() {
+ return new SequenceStatement();
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java
index 2f64035..aceb2b8 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java
@@ -1,27 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.code.InstructionSequence;
import org.jetbrains.java.decompiler.main.DecompilerContext;
@@ -32,840 +25,848 @@ import org.jetbrains.java.decompiler.modules.decompiler.StrongConnectivityHelper
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.util.*;
+
public class Statement {
-
- public static final int STATEDGE_ALL = 1 << 31;
- public static final int STATEDGE_DIRECT_ALL = 1 << 30;
-
- public static final int DIRECTION_BACKWARD = 0;
- public static final int DIRECTION_FORWARD = 1;
-
- public static final int TYPE_GENERAL = 0;
- public static final int TYPE_IF = 2;
- public static final int TYPE_DO = 5;
- public static final int TYPE_SWITCH = 6;
- public static final int TYPE_TRYCATCH = 7;
- public static final int TYPE_BASICBLOCK = 8;
- public static final int TYPE_FINALLY = 9;
- public static final int TYPE_SYNCRONIZED = 10;
- public static final int TYPE_PLACEHOLDER = 11;
- public static final int TYPE_CATCHALL = 12;
- public static final int TYPE_ROOT = 13;
- public static final int TYPE_DUMMYEXIT = 14;
- public static final int TYPE_SEQUENCE = 15;
-
-
- public static final int LASTBASICTYPE_IF = 0;
- public static final int LASTBASICTYPE_SWITCH = 1;
- public static final int LASTBASICTYPE_GENERAL = 2;
-
-
- // *****************************************************************************
- // public fields
- // *****************************************************************************
-
- public int type;
-
- public Integer id;
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private Map<Integer, List<StatEdge>> mapSuccEdges = new HashMap<Integer, List<StatEdge>>();
- private Map<Integer, List<StatEdge>> mapPredEdges = new HashMap<Integer, List<StatEdge>>();
-
- private Map<Integer, List<Statement>> mapSuccStates = new HashMap<Integer, List<Statement>>();
- private Map<Integer, List<Statement>> mapPredStates = new HashMap<Integer, List<Statement>>();
-
- // statement as graph
- protected VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<Statement, Integer>();
-
- protected Statement parent;
-
- protected Statement first;
-
- protected List<Exprent> exprents;
-
- protected HashSet<StatEdge> labelEdges = new HashSet<StatEdge>();
-
- protected List<Exprent> varDefinitions = new ArrayList<Exprent>();
-
- // copied statement, s. deobfuscating of irreducible CFGs
- private boolean copied = false;
-
- // relevant for the first stage of processing only
- // set to null after initializing of the statement structure
-
- protected Statement post;
-
- protected int lastBasicType = LASTBASICTYPE_GENERAL;
-
- protected boolean isMonitorEnter;
-
- protected boolean containsMonitorExit;
-
- protected HashSet<Statement> continueSet = new HashSet<Statement>();
-
- // *****************************************************************************
- // initializers
- // *****************************************************************************
-
- {
- // set statement id
- id = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER);
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public void clearTempInformation() {
-
- post = null;
- continueSet = null;
-
- copied = false;
- // FIXME: used in FlattenStatementsHelper.flattenStatement()! check and remove
- //lastBasicType = LASTBASICTYPE_GENERAL;
- isMonitorEnter = false;;
- containsMonitorExit = false;
-
- for(Map<Integer, List<StatEdge>> map : new Map[]{mapSuccEdges, mapPredEdges}) {
- map.remove(StatEdge.TYPE_EXCEPTION);
-
- List<StatEdge> lst = map.get(STATEDGE_DIRECT_ALL);
- if(lst != null) {
- map.put(STATEDGE_ALL, new ArrayList<StatEdge>(lst));
- } else {
- map.remove(STATEDGE_ALL);
- }
- }
-
- for(Map<Integer, List<Statement>> map : new Map[]{mapSuccStates, mapPredStates}) {
- map.remove(StatEdge.TYPE_EXCEPTION);
-
- List<Statement> lst = map.get(STATEDGE_DIRECT_ALL);
- if(lst != null) {
- map.put(STATEDGE_ALL, new ArrayList<Statement>(lst));
- } else {
- map.remove(STATEDGE_ALL);
- }
- }
-
- }
-
- public void collapseNodesToStatement(Statement stat) {
-
- Statement head = stat.getFirst();
- Statement post = stat.getPost();
-
- VBStyleCollection<Statement, Integer> setNodes = stat.getStats();
-
- // post edges
- if(post != null) {
- for(StatEdge edge : post.getEdges(STATEDGE_DIRECT_ALL, DIRECTION_BACKWARD)) {
- if(stat.containsStatementStrict(edge.getSource())) {
- edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK);
- stat.addLabeledEdge(edge);
- }
- }
- }
-
- // regular head edges
- for(StatEdge prededge : head.getAllPredecessorEdges()) {
-
- if(prededge.getType() != StatEdge.TYPE_EXCEPTION &&
- stat.containsStatementStrict(prededge.getSource())) {
- prededge.getSource().changeEdgeType(DIRECTION_FORWARD, prededge, StatEdge.TYPE_CONTINUE);
- stat.addLabeledEdge(prededge);
- }
-
- head.removePredecessor(prededge);
- prededge.getSource().changeEdgeNode(DIRECTION_FORWARD, prededge, stat);
- stat.addPredecessor(prededge);
- }
-
- if(setNodes.containsKey(first.id)) {
- first = stat;
- }
-
- // exception edges
- Set<Statement> setHandlers = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD));
- for(Statement node : setNodes) {
- setHandlers.retainAll(node.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD));
- }
-
- if(!setHandlers.isEmpty()) {
-
- for(StatEdge edge : head.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) {
- Statement handler = edge.getDestination();
-
- if(setHandlers.contains(handler)) {
- if(!setNodes.containsKey(handler.id)) {
- stat.addSuccessor(new StatEdge(stat, handler, edge.getExceptions()));
- }
- }
- }
-
- for(Statement node : setNodes) {
- for(StatEdge edge : node.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) {
- if(setHandlers.contains(edge.getDestination())) {
- node.removeSuccessor(edge);
- }
- }
- }
- }
-
- if(post!=null && !stat.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD).contains(post)) { // TODO: second condition redundant?
- stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, post));
- }
-
-
- // adjust statement collection
- for(Statement st: setNodes) {
- stats.removeWithKey(st.id);
- }
-
- stats.addWithKey(stat, stat.id);
-
- stat.setAllParent();
- stat.setParent(this);
-
- stat.buildContinueSet();
- // monitorenter and monitorexit
- stat.buildMonitorFlags();
-
- if(stat.type == Statement.TYPE_SWITCH) {
- // special case switch, sorting leaf nodes
- ((SwitchStatement)stat).sortEdgesAndNodes();
- }
-
- }
-
- public void setAllParent() {
- for(Statement st: stats) {
- st.setParent(this);
- }
- }
-
- public void addLabeledEdge(StatEdge edge) {
-
- if(edge.closure != null) {
- edge.closure.getLabelEdges().remove(edge);
- }
- edge.closure = this;
- this.getLabelEdges().add(edge);
- }
-
- private void addEdgeDirectInternal(int direction, StatEdge edge, int edgetype) {
-
- Map<Integer, List<StatEdge>> mapEdges = direction==DIRECTION_BACKWARD?mapPredEdges:mapSuccEdges;
- Map<Integer, List<Statement>> mapStates = direction==DIRECTION_BACKWARD?mapPredStates:mapSuccStates;
-
- List<StatEdge> lst = mapEdges.get(edgetype);
- if(lst == null) {
- mapEdges.put(edgetype, lst = new ArrayList<StatEdge>());
- }
- lst.add(edge);
-
- List<Statement> lstStates = mapStates.get(edgetype);
- if(lstStates == null) {
- mapStates.put(edgetype, lstStates = new ArrayList<Statement>());
- }
- lstStates.add(direction==DIRECTION_BACKWARD?edge.getSource():edge.getDestination());
- }
-
- private void addEdgeInternal(int direction, StatEdge edge) {
-
- int type = edge.getType();
-
- int[] arrtypes;
- if(type == StatEdge.TYPE_EXCEPTION) {
- arrtypes = new int[] {STATEDGE_ALL, StatEdge.TYPE_EXCEPTION};
- } else {
- arrtypes = new int[] {STATEDGE_ALL, STATEDGE_DIRECT_ALL, type};
- }
-
- for(int edgetype : arrtypes) {
- addEdgeDirectInternal(direction, edge, edgetype);
- }
-
- }
-
- private void removeEdgeDirectInternal(int direction, StatEdge edge, int edgetype) {
-
- Map<Integer, List<StatEdge>> mapEdges = direction==DIRECTION_BACKWARD?mapPredEdges:mapSuccEdges;
- Map<Integer, List<Statement>> mapStates = direction==DIRECTION_BACKWARD?mapPredStates:mapSuccStates;
-
- List<StatEdge> lst = mapEdges.get(edgetype);
- if(lst != null) {
- int index = lst.indexOf(edge);
- if(index >= 0) {
- lst.remove(index);
- mapStates.get(edgetype).remove(index);
- }
- }
-
- }
-
- private void removeEdgeInternal(int direction, StatEdge edge) {
-
- int type = edge.getType();
-
- int[] arrtypes;
- if(type == StatEdge.TYPE_EXCEPTION) {
- arrtypes = new int[] {STATEDGE_ALL, StatEdge.TYPE_EXCEPTION};
- } else {
- arrtypes = new int[] {STATEDGE_ALL, STATEDGE_DIRECT_ALL, type};
- }
-
- for(int edgetype : arrtypes) {
- removeEdgeDirectInternal(direction, edge, edgetype);
- }
-
- }
-
- public void addPredecessor(StatEdge edge) {
- addEdgeInternal(DIRECTION_BACKWARD, edge);
- }
-
- public void removePredecessor(StatEdge edge) {
-
- if(edge == null) { // FIXME: redundant?
- return;
- }
-
- removeEdgeInternal(DIRECTION_BACKWARD, edge);
- }
-
- public void addSuccessor(StatEdge edge) {
- addEdgeInternal(DIRECTION_FORWARD, edge);
-
- if(edge.closure != null) {
- edge.closure.getLabelEdges().add(edge);
- }
-
- edge.getDestination().addPredecessor(edge);
- }
-
- public void removeSuccessor(StatEdge edge) {
-
- if(edge == null) {
- return;
- }
-
- removeEdgeInternal(DIRECTION_FORWARD, edge);
-
- if(edge.closure != null) {
- edge.closure.getLabelEdges().remove(edge);
- }
-
- if(edge.getDestination() != null) { // TODO: redundant?
- edge.getDestination().removePredecessor(edge);
- }
- }
-
- // TODO: make obsolete and remove
- public void removeAllSuccessors(Statement stat) {
-
- if(stat == null) {
- return;
- }
-
- for(StatEdge edge : getAllSuccessorEdges()) {
- if(edge.getDestination() == stat) {
- removeSuccessor(edge);
- }
- }
- }
-
- public HashSet<Statement> buildContinueSet() {
- continueSet.clear();
-
- for(Statement st: stats) {
- continueSet.addAll(st.buildContinueSet());
- if(st != first) {
- continueSet.remove(st.getBasichead());
- }
- }
-
- for(StatEdge edge: getEdges(StatEdge.TYPE_CONTINUE, DIRECTION_FORWARD)) {
- continueSet.add(edge.getDestination().getBasichead());
- }
-
- if(type == Statement.TYPE_DO) {
- continueSet.remove(first.getBasichead());
- }
-
- return continueSet;
- }
-
- public void buildMonitorFlags() {
-
- for(Statement st: stats) {
- st.buildMonitorFlags();
- }
-
- switch(type) {
- case TYPE_BASICBLOCK:
- BasicBlockStatement bblock = (BasicBlockStatement)this;
- InstructionSequence seq = bblock.getBlock().getSeq();
-
- if(seq!=null && seq.length()>0) {
- for(int i=0;i<seq.length();i++) {
- if(seq.getInstr(i).opcode == CodeConstants.opc_monitorexit) {
- containsMonitorExit = true;
- break;
- }
- }
- isMonitorEnter = (seq.getLastInstr().opcode == CodeConstants.opc_monitorenter);
- }
- break;
- case TYPE_SEQUENCE:
- case TYPE_IF:
- containsMonitorExit = false;
- for(Statement st: stats) {
- containsMonitorExit |= st.isContainsMonitorExit();
- }
-
- break;
- case TYPE_SYNCRONIZED:
- case TYPE_ROOT:
- case TYPE_GENERAL:
- break;
- default:
- containsMonitorExit = false;
- for(Statement st: stats) {
- containsMonitorExit |= st.isContainsMonitorExit();
- }
- }
- }
-
-
- public List<Statement> getReversePostOrderList() {
- return getReversePostOrderList(first);
- }
-
- public List<Statement> getReversePostOrderList(Statement stat) {
- List<Statement> res = new ArrayList<Statement>();
-
- addToReversePostOrderListIterative(stat, res);
-
- return res;
- }
-
- public List<Statement> getPostReversePostOrderList() {
- return getPostReversePostOrderList(null);
- }
-
- public List<Statement> getPostReversePostOrderList(List<Statement> lstexits) {
-
- List<Statement> res = new ArrayList<Statement>();
-
- if(lstexits == null) {
- StrongConnectivityHelper schelper = new StrongConnectivityHelper(this);
- lstexits = StrongConnectivityHelper.getExitReps(schelper.getComponents());
- }
-
- HashSet<Statement> setVisited = new HashSet<Statement>();
-
- for(Statement exit : lstexits) {
- addToPostReversePostOrderList(exit, res, setVisited);
- }
-
- if(res.size() != stats.size()) {
- DecompilerContext.getLogger().writeMessage("computing post reverse post order failed!", IFernflowerLogger.ERROR);
-
- throw new RuntimeException("parsing failure!");
- }
-
- return res;
- }
-
- public boolean containsStatement(Statement stat) {
- return this == stat || containsStatementStrict(stat);
- }
-
- public boolean containsStatementStrict(Statement stat) {
-
- if(stats.contains(stat)) {
- return true;
- }
-
- for(int i=0;i<stats.size();i++) {
- if(stats.get(i).containsStatementStrict(stat)) {
- return true;
- }
- }
-
- return false;
- }
-
- // to be overwritten
- public String toJava() {
- return toJava(0);
- }
-
- public String toJava(int indent) {
- throw new RuntimeException("not implemented");
- }
-
- // TODO: make obsolete and remove
- public List<Object> getSequentialObjects() {
- return new ArrayList<Object>(stats);
- }
-
- public void initExprents() {
- ; // do nothing
- }
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- ; // do nothing
- }
-
- public Statement getSimpleCopy() {
- throw new RuntimeException("not implemented");
- }
-
- public void initSimpleCopy() {
- if(!stats.isEmpty()) {
- first = stats.get(0);
- }
- }
-
- public void replaceStatement(Statement oldstat, Statement newstat) {
-
- for(StatEdge edge : oldstat.getAllPredecessorEdges()) {
- oldstat.removePredecessor(edge);
- edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, newstat);
- newstat.addPredecessor(edge);
- }
-
- for(StatEdge edge : oldstat.getAllSuccessorEdges()) {
- oldstat.removeSuccessor(edge);
- edge.setSource(newstat);
- newstat.addSuccessor(edge);
- }
-
- int statindex = stats.getIndexByKey(oldstat.id);
- stats.removeWithKey(oldstat.id);
- stats.addWithKeyAndIndex(statindex, newstat, newstat.id);
-
- newstat.setParent(this);
- newstat.post = oldstat.post;
-
- if(first == oldstat) {
- first = newstat;
- }
-
- List<StatEdge> lst = new ArrayList<StatEdge>(oldstat.getLabelEdges());
-
- for(int i=lst.size()-1;i>=0;i--) {
- StatEdge edge = lst.get(i);
- if(edge.getSource() != newstat) {
- newstat.addLabeledEdge(edge);
- } else {
- if(this == edge.getDestination() || this.containsStatementStrict(edge.getDestination())) {
- edge.closure = null;
- } else {
- this.addLabeledEdge(edge);
- }
- }
- }
-
- oldstat.getLabelEdges().clear();
- }
-
-
- // *****************************************************************************
- // private methods
- // *****************************************************************************
-
- private void addToReversePostOrderListIterative(Statement root, List<Statement> lst) {
-
- LinkedList<Statement> stackNode = new LinkedList<Statement>();
- LinkedList<Integer> stackIndex = new LinkedList<Integer>();
- HashSet<Statement> setVisited = new HashSet<Statement>();
-
- stackNode.add(root);
- stackIndex.add(0);
-
- while(!stackNode.isEmpty()) {
-
- Statement node = stackNode.getLast();
- int index = stackIndex.removeLast();
-
- setVisited.add(node);
-
- List<StatEdge> lstEdges = node.getAllSuccessorEdges();
-
- for(;index<lstEdges.size();index++) {
- StatEdge edge = lstEdges.get(index);
- Statement succ = edge.getDestination();
-
- if(!setVisited.contains(succ) &&
- (edge.getType() == StatEdge.TYPE_REGULAR || edge.getType() == StatEdge.TYPE_EXCEPTION)) { // TODO: edge filter?
-
- stackIndex.add(index+1);
-
- stackNode.add(succ);
- stackIndex.add(0);
-
- break;
- }
- }
-
- if(index == lstEdges.size()) {
- lst.add(0, node);
-
- stackNode.removeLast();
- }
- }
-
- }
-
-
- private void addToPostReversePostOrderList(Statement stat, List<Statement> lst, HashSet<Statement> setVisited) {
-
- if(setVisited.contains(stat)) { // because of not considered exception edges, s. isExitComponent. Should be rewritten, if possible.
- return;
- }
- setVisited.add(stat);
-
- for(StatEdge prededge : stat.getEdges(StatEdge.TYPE_REGULAR | StatEdge.TYPE_EXCEPTION, DIRECTION_BACKWARD)) {
- Statement pred = prededge.getSource();
- if(!setVisited.contains(pred)) {
- addToPostReversePostOrderList(pred, lst, setVisited);
- }
- }
-
- lst.add(0, stat);
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public void changeEdgeNode(int direction, StatEdge edge, Statement value) {
-
- Map<Integer, List<StatEdge>> mapEdges = direction==DIRECTION_BACKWARD?mapPredEdges:mapSuccEdges;
- Map<Integer, List<Statement>> mapStates = direction==DIRECTION_BACKWARD?mapPredStates:mapSuccStates;
-
- int type = edge.getType();
-
- int[] arrtypes;
- if(type == StatEdge.TYPE_EXCEPTION) {
- arrtypes = new int[] {STATEDGE_ALL, StatEdge.TYPE_EXCEPTION};
- } else {
- arrtypes = new int[] {STATEDGE_ALL, STATEDGE_DIRECT_ALL, type};
- }
-
- for(int edgetype : arrtypes) {
- List<StatEdge> lst = mapEdges.get(edgetype);
- if(lst != null) {
- int index = lst.indexOf(edge);
- if(index >= 0) {
- mapStates.get(edgetype).set(index, value);
- }
- }
- }
-
- if(direction == DIRECTION_BACKWARD) {
- edge.setSource(value);
- } else {
- edge.setDestination(value);
- }
-
- }
-
- public void changeEdgeType(int direction, StatEdge edge, int newtype) {
-
- int oldtype = edge.getType();
- if(oldtype == newtype) {
- return;
- }
-
- if(oldtype == StatEdge.TYPE_EXCEPTION || newtype == StatEdge.TYPE_EXCEPTION) {
- throw new RuntimeException("Invalid edge type!");
- }
-
- removeEdgeDirectInternal(direction, edge, oldtype);
- addEdgeDirectInternal(direction, edge, newtype);
-
- if(direction == DIRECTION_FORWARD) {
- edge.getDestination().changeEdgeType(DIRECTION_BACKWARD, edge, newtype);
- }
-
- edge.setType(newtype);
- }
-
-
- private List<StatEdge> getEdges(int type, int direction) {
-
- Map<Integer, List<StatEdge>> map = direction==DIRECTION_BACKWARD?mapPredEdges:mapSuccEdges;
-
- List<StatEdge> res;
- if((type & (type -1)) == 0) {
- res = map.get(type);
- res = res==null?new ArrayList<StatEdge>():new ArrayList<StatEdge>(res);
- } else {
- res = new ArrayList<StatEdge>();
- for(int edgetype : StatEdge.TYPES) {
- if((type & edgetype) != 0) {
- List<StatEdge> lst = map.get(edgetype);
- if(lst != null) {
- res.addAll(lst);
- }
- }
- }
- }
-
- return res;
- }
-
- public List<Statement> getNeighbours(int type, int direction) {
-
- Map<Integer, List<Statement>> map = direction==DIRECTION_BACKWARD?mapPredStates:mapSuccStates;
-
- List<Statement> res;
- if((type & (type -1)) == 0) {
- res = map.get(type);
- res = res==null?new ArrayList<Statement>():new ArrayList<Statement>(res);
- } else {
- res = new ArrayList<Statement>();
- for(int edgetype : StatEdge.TYPES) {
- if((type & edgetype) != 0) {
- List<Statement> lst = map.get(edgetype);
- if(lst != null) {
- res.addAll(lst);
- }
- }
- }
- }
-
- return res;
- }
-
- public Set<Statement> getNeighboursSet(int type, int direction) {
- return new HashSet<Statement>(getNeighbours(type, direction));
- }
-
- public List<StatEdge> getSuccessorEdges(int type) {
- return getEdges(type, DIRECTION_FORWARD);
- }
-
- public List<StatEdge> getPredecessorEdges(int type) {
- return getEdges(type, DIRECTION_BACKWARD);
- }
-
- public List<StatEdge> getAllSuccessorEdges() {
- return getEdges(STATEDGE_ALL, DIRECTION_FORWARD);
- }
-
- public List<StatEdge> getAllPredecessorEdges() {
- return getEdges(STATEDGE_ALL, DIRECTION_BACKWARD);
- }
-
- public Statement getFirst() {
- return first;
- }
-
- public void setFirst(Statement first) {
- this.first = first;
- }
-
- public Statement getPost() {
- return post;
- }
-
- public void setPost(Statement post) {
- this.post = post;
- }
-
- public VBStyleCollection<Statement, Integer> getStats() {
- return stats;
- }
-
- public int getLastBasicType() {
- return lastBasicType;
- }
-
- public HashSet<Statement> getContinueSet() {
- return continueSet;
- }
-
- public boolean isContainsMonitorExit() {
- return containsMonitorExit;
- }
-
- public boolean isMonitorEnter() {
- return isMonitorEnter;
- }
-
- public BasicBlockStatement getBasichead() {
- if(type == Statement.TYPE_BASICBLOCK) {
- return (BasicBlockStatement)this;
- } else {
- return first.getBasichead();
- }
- }
-
- public boolean isLabeled() {
-
- for(StatEdge edge: labelEdges) {
- if(edge.labeled && edge.explicit) { // FIXME: consistent setting
- return true;
- }
- }
- return false;
- }
-
- public boolean hasBasicSuccEdge() {
- boolean res = type == Statement.TYPE_BASICBLOCK || (type == Statement.TYPE_IF &&
- ((IfStatement)this).iftype == IfStatement.IFTYPE_IF) ||
- (type == Statement.TYPE_DO && ((DoStatement)this).getLooptype() != DoStatement.LOOP_DO);
-
- // FIXME: default switch
-
- return res;
- }
-
-
- public Statement getParent() {
- return parent;
- }
-
- public void setParent(Statement parent) {
- this.parent = parent;
- }
-
- public HashSet<StatEdge> getLabelEdges() { // FIXME: why HashSet?
- return labelEdges;
- }
-
- public List<Exprent> getVarDefinitions() {
- return varDefinitions;
- }
-
- public List<Exprent> getExprents() {
- return exprents;
- }
-
- public void setExprents(List<Exprent> exprents) {
- this.exprents = exprents;
- }
-
- public boolean isCopied() {
- return copied;
- }
-
- public void setCopied(boolean copied) {
- this.copied = copied;
- }
-
- // helper methods
- public String toString() {
- return id.toString();
- }
+
+ public static final int STATEDGE_ALL = 1 << 31;
+ public static final int STATEDGE_DIRECT_ALL = 1 << 30;
+
+ public static final int DIRECTION_BACKWARD = 0;
+ public static final int DIRECTION_FORWARD = 1;
+
+ public static final int TYPE_GENERAL = 0;
+ public static final int TYPE_IF = 2;
+ public static final int TYPE_DO = 5;
+ public static final int TYPE_SWITCH = 6;
+ public static final int TYPE_TRYCATCH = 7;
+ public static final int TYPE_BASICBLOCK = 8;
+ public static final int TYPE_FINALLY = 9;
+ public static final int TYPE_SYNCRONIZED = 10;
+ public static final int TYPE_PLACEHOLDER = 11;
+ public static final int TYPE_CATCHALL = 12;
+ public static final int TYPE_ROOT = 13;
+ public static final int TYPE_DUMMYEXIT = 14;
+ public static final int TYPE_SEQUENCE = 15;
+
+
+ public static final int LASTBASICTYPE_IF = 0;
+ public static final int LASTBASICTYPE_SWITCH = 1;
+ public static final int LASTBASICTYPE_GENERAL = 2;
+
+
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int type;
+
+ public Integer id;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private Map<Integer, List<StatEdge>> mapSuccEdges = new HashMap<Integer, List<StatEdge>>();
+ private Map<Integer, List<StatEdge>> mapPredEdges = new HashMap<Integer, List<StatEdge>>();
+
+ private Map<Integer, List<Statement>> mapSuccStates = new HashMap<Integer, List<Statement>>();
+ private Map<Integer, List<Statement>> mapPredStates = new HashMap<Integer, List<Statement>>();
+
+ // statement as graph
+ protected VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<Statement, Integer>();
+
+ protected Statement parent;
+
+ protected Statement first;
+
+ protected List<Exprent> exprents;
+
+ protected HashSet<StatEdge> labelEdges = new HashSet<StatEdge>();
+
+ protected List<Exprent> varDefinitions = new ArrayList<Exprent>();
+
+ // copied statement, s. deobfuscating of irreducible CFGs
+ private boolean copied = false;
+
+ // relevant for the first stage of processing only
+ // set to null after initializing of the statement structure
+
+ protected Statement post;
+
+ protected int lastBasicType = LASTBASICTYPE_GENERAL;
+
+ protected boolean isMonitorEnter;
+
+ protected boolean containsMonitorExit;
+
+ protected HashSet<Statement> continueSet = new HashSet<Statement>();
+
+ // *****************************************************************************
+ // initializers
+ // *****************************************************************************
+
+ {
+ // set statement id
+ id = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER);
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void clearTempInformation() {
+
+ post = null;
+ continueSet = null;
+
+ copied = false;
+ // FIXME: used in FlattenStatementsHelper.flattenStatement()! check and remove
+ //lastBasicType = LASTBASICTYPE_GENERAL;
+ isMonitorEnter = false;
+ ;
+ containsMonitorExit = false;
+
+ for (Map<Integer, List<StatEdge>> map : new Map[]{mapSuccEdges, mapPredEdges}) {
+ map.remove(StatEdge.TYPE_EXCEPTION);
+
+ List<StatEdge> lst = map.get(STATEDGE_DIRECT_ALL);
+ if (lst != null) {
+ map.put(STATEDGE_ALL, new ArrayList<StatEdge>(lst));
+ }
+ else {
+ map.remove(STATEDGE_ALL);
+ }
+ }
+
+ for (Map<Integer, List<Statement>> map : new Map[]{mapSuccStates, mapPredStates}) {
+ map.remove(StatEdge.TYPE_EXCEPTION);
+
+ List<Statement> lst = map.get(STATEDGE_DIRECT_ALL);
+ if (lst != null) {
+ map.put(STATEDGE_ALL, new ArrayList<Statement>(lst));
+ }
+ else {
+ map.remove(STATEDGE_ALL);
+ }
+ }
+ }
+
+ public void collapseNodesToStatement(Statement stat) {
+
+ Statement head = stat.getFirst();
+ Statement post = stat.getPost();
+
+ VBStyleCollection<Statement, Integer> setNodes = stat.getStats();
+
+ // post edges
+ if (post != null) {
+ for (StatEdge edge : post.getEdges(STATEDGE_DIRECT_ALL, DIRECTION_BACKWARD)) {
+ if (stat.containsStatementStrict(edge.getSource())) {
+ edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK);
+ stat.addLabeledEdge(edge);
+ }
+ }
+ }
+
+ // regular head edges
+ for (StatEdge prededge : head.getAllPredecessorEdges()) {
+
+ if (prededge.getType() != StatEdge.TYPE_EXCEPTION &&
+ stat.containsStatementStrict(prededge.getSource())) {
+ prededge.getSource().changeEdgeType(DIRECTION_FORWARD, prededge, StatEdge.TYPE_CONTINUE);
+ stat.addLabeledEdge(prededge);
+ }
+
+ head.removePredecessor(prededge);
+ prededge.getSource().changeEdgeNode(DIRECTION_FORWARD, prededge, stat);
+ stat.addPredecessor(prededge);
+ }
+
+ if (setNodes.containsKey(first.id)) {
+ first = stat;
+ }
+
+ // exception edges
+ Set<Statement> setHandlers = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD));
+ for (Statement node : setNodes) {
+ setHandlers.retainAll(node.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD));
+ }
+
+ if (!setHandlers.isEmpty()) {
+
+ for (StatEdge edge : head.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) {
+ Statement handler = edge.getDestination();
+
+ if (setHandlers.contains(handler)) {
+ if (!setNodes.containsKey(handler.id)) {
+ stat.addSuccessor(new StatEdge(stat, handler, edge.getExceptions()));
+ }
+ }
+ }
+
+ for (Statement node : setNodes) {
+ for (StatEdge edge : node.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) {
+ if (setHandlers.contains(edge.getDestination())) {
+ node.removeSuccessor(edge);
+ }
+ }
+ }
+ }
+
+ if (post != null &&
+ !stat.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD).contains(post)) { // TODO: second condition redundant?
+ stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, post));
+ }
+
+
+ // adjust statement collection
+ for (Statement st : setNodes) {
+ stats.removeWithKey(st.id);
+ }
+
+ stats.addWithKey(stat, stat.id);
+
+ stat.setAllParent();
+ stat.setParent(this);
+
+ stat.buildContinueSet();
+ // monitorenter and monitorexit
+ stat.buildMonitorFlags();
+
+ if (stat.type == Statement.TYPE_SWITCH) {
+ // special case switch, sorting leaf nodes
+ ((SwitchStatement)stat).sortEdgesAndNodes();
+ }
+ }
+
+ public void setAllParent() {
+ for (Statement st : stats) {
+ st.setParent(this);
+ }
+ }
+
+ public void addLabeledEdge(StatEdge edge) {
+
+ if (edge.closure != null) {
+ edge.closure.getLabelEdges().remove(edge);
+ }
+ edge.closure = this;
+ this.getLabelEdges().add(edge);
+ }
+
+ private void addEdgeDirectInternal(int direction, StatEdge edge, int edgetype) {
+
+ Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges;
+ Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates;
+
+ List<StatEdge> lst = mapEdges.get(edgetype);
+ if (lst == null) {
+ mapEdges.put(edgetype, lst = new ArrayList<StatEdge>());
+ }
+ lst.add(edge);
+
+ List<Statement> lstStates = mapStates.get(edgetype);
+ if (lstStates == null) {
+ mapStates.put(edgetype, lstStates = new ArrayList<Statement>());
+ }
+ lstStates.add(direction == DIRECTION_BACKWARD ? edge.getSource() : edge.getDestination());
+ }
+
+ private void addEdgeInternal(int direction, StatEdge edge) {
+
+ int type = edge.getType();
+
+ int[] arrtypes;
+ if (type == StatEdge.TYPE_EXCEPTION) {
+ arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION};
+ }
+ else {
+ arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type};
+ }
+
+ for (int edgetype : arrtypes) {
+ addEdgeDirectInternal(direction, edge, edgetype);
+ }
+ }
+
+ private void removeEdgeDirectInternal(int direction, StatEdge edge, int edgetype) {
+
+ Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges;
+ Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates;
+
+ List<StatEdge> lst = mapEdges.get(edgetype);
+ if (lst != null) {
+ int index = lst.indexOf(edge);
+ if (index >= 0) {
+ lst.remove(index);
+ mapStates.get(edgetype).remove(index);
+ }
+ }
+ }
+
+ private void removeEdgeInternal(int direction, StatEdge edge) {
+
+ int type = edge.getType();
+
+ int[] arrtypes;
+ if (type == StatEdge.TYPE_EXCEPTION) {
+ arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION};
+ }
+ else {
+ arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type};
+ }
+
+ for (int edgetype : arrtypes) {
+ removeEdgeDirectInternal(direction, edge, edgetype);
+ }
+ }
+
+ public void addPredecessor(StatEdge edge) {
+ addEdgeInternal(DIRECTION_BACKWARD, edge);
+ }
+
+ public void removePredecessor(StatEdge edge) {
+
+ if (edge == null) { // FIXME: redundant?
+ return;
+ }
+
+ removeEdgeInternal(DIRECTION_BACKWARD, edge);
+ }
+
+ public void addSuccessor(StatEdge edge) {
+ addEdgeInternal(DIRECTION_FORWARD, edge);
+
+ if (edge.closure != null) {
+ edge.closure.getLabelEdges().add(edge);
+ }
+
+ edge.getDestination().addPredecessor(edge);
+ }
+
+ public void removeSuccessor(StatEdge edge) {
+
+ if (edge == null) {
+ return;
+ }
+
+ removeEdgeInternal(DIRECTION_FORWARD, edge);
+
+ if (edge.closure != null) {
+ edge.closure.getLabelEdges().remove(edge);
+ }
+
+ if (edge.getDestination() != null) { // TODO: redundant?
+ edge.getDestination().removePredecessor(edge);
+ }
+ }
+
+ // TODO: make obsolete and remove
+ public void removeAllSuccessors(Statement stat) {
+
+ if (stat == null) {
+ return;
+ }
+
+ for (StatEdge edge : getAllSuccessorEdges()) {
+ if (edge.getDestination() == stat) {
+ removeSuccessor(edge);
+ }
+ }
+ }
+
+ public HashSet<Statement> buildContinueSet() {
+ continueSet.clear();
+
+ for (Statement st : stats) {
+ continueSet.addAll(st.buildContinueSet());
+ if (st != first) {
+ continueSet.remove(st.getBasichead());
+ }
+ }
+
+ for (StatEdge edge : getEdges(StatEdge.TYPE_CONTINUE, DIRECTION_FORWARD)) {
+ continueSet.add(edge.getDestination().getBasichead());
+ }
+
+ if (type == Statement.TYPE_DO) {
+ continueSet.remove(first.getBasichead());
+ }
+
+ return continueSet;
+ }
+
+ public void buildMonitorFlags() {
+
+ for (Statement st : stats) {
+ st.buildMonitorFlags();
+ }
+
+ switch (type) {
+ case TYPE_BASICBLOCK:
+ BasicBlockStatement bblock = (BasicBlockStatement)this;
+ InstructionSequence seq = bblock.getBlock().getSeq();
+
+ if (seq != null && seq.length() > 0) {
+ for (int i = 0; i < seq.length(); i++) {
+ if (seq.getInstr(i).opcode == CodeConstants.opc_monitorexit) {
+ containsMonitorExit = true;
+ break;
+ }
+ }
+ isMonitorEnter = (seq.getLastInstr().opcode == CodeConstants.opc_monitorenter);
+ }
+ break;
+ case TYPE_SEQUENCE:
+ case TYPE_IF:
+ containsMonitorExit = false;
+ for (Statement st : stats) {
+ containsMonitorExit |= st.isContainsMonitorExit();
+ }
+
+ break;
+ case TYPE_SYNCRONIZED:
+ case TYPE_ROOT:
+ case TYPE_GENERAL:
+ break;
+ default:
+ containsMonitorExit = false;
+ for (Statement st : stats) {
+ containsMonitorExit |= st.isContainsMonitorExit();
+ }
+ }
+ }
+
+
+ public List<Statement> getReversePostOrderList() {
+ return getReversePostOrderList(first);
+ }
+
+ public List<Statement> getReversePostOrderList(Statement stat) {
+ List<Statement> res = new ArrayList<Statement>();
+
+ addToReversePostOrderListIterative(stat, res);
+
+ return res;
+ }
+
+ public List<Statement> getPostReversePostOrderList() {
+ return getPostReversePostOrderList(null);
+ }
+
+ public List<Statement> getPostReversePostOrderList(List<Statement> lstexits) {
+
+ List<Statement> res = new ArrayList<Statement>();
+
+ if (lstexits == null) {
+ StrongConnectivityHelper schelper = new StrongConnectivityHelper(this);
+ lstexits = StrongConnectivityHelper.getExitReps(schelper.getComponents());
+ }
+
+ HashSet<Statement> setVisited = new HashSet<Statement>();
+
+ for (Statement exit : lstexits) {
+ addToPostReversePostOrderList(exit, res, setVisited);
+ }
+
+ if (res.size() != stats.size()) {
+ DecompilerContext.getLogger().writeMessage("computing post reverse post order failed!", IFernflowerLogger.ERROR);
+
+ throw new RuntimeException("parsing failure!");
+ }
+
+ return res;
+ }
+
+ public boolean containsStatement(Statement stat) {
+ return this == stat || containsStatementStrict(stat);
+ }
+
+ public boolean containsStatementStrict(Statement stat) {
+
+ if (stats.contains(stat)) {
+ return true;
+ }
+
+ for (int i = 0; i < stats.size(); i++) {
+ if (stats.get(i).containsStatementStrict(stat)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // to be overwritten
+ public String toJava() {
+ return toJava(0);
+ }
+
+ public String toJava(int indent) {
+ throw new RuntimeException("not implemented");
+ }
+
+ // TODO: make obsolete and remove
+ public List<Object> getSequentialObjects() {
+ return new ArrayList<Object>(stats);
+ }
+
+ public void initExprents() {
+ ; // do nothing
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ ; // do nothing
+ }
+
+ public Statement getSimpleCopy() {
+ throw new RuntimeException("not implemented");
+ }
+
+ public void initSimpleCopy() {
+ if (!stats.isEmpty()) {
+ first = stats.get(0);
+ }
+ }
+
+ public void replaceStatement(Statement oldstat, Statement newstat) {
+
+ for (StatEdge edge : oldstat.getAllPredecessorEdges()) {
+ oldstat.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, newstat);
+ newstat.addPredecessor(edge);
+ }
+
+ for (StatEdge edge : oldstat.getAllSuccessorEdges()) {
+ oldstat.removeSuccessor(edge);
+ edge.setSource(newstat);
+ newstat.addSuccessor(edge);
+ }
+
+ int statindex = stats.getIndexByKey(oldstat.id);
+ stats.removeWithKey(oldstat.id);
+ stats.addWithKeyAndIndex(statindex, newstat, newstat.id);
+
+ newstat.setParent(this);
+ newstat.post = oldstat.post;
+
+ if (first == oldstat) {
+ first = newstat;
+ }
+
+ List<StatEdge> lst = new ArrayList<StatEdge>(oldstat.getLabelEdges());
+
+ for (int i = lst.size() - 1; i >= 0; i--) {
+ StatEdge edge = lst.get(i);
+ if (edge.getSource() != newstat) {
+ newstat.addLabeledEdge(edge);
+ }
+ else {
+ if (this == edge.getDestination() || this.containsStatementStrict(edge.getDestination())) {
+ edge.closure = null;
+ }
+ else {
+ this.addLabeledEdge(edge);
+ }
+ }
+ }
+
+ oldstat.getLabelEdges().clear();
+ }
+
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private void addToReversePostOrderListIterative(Statement root, List<Statement> lst) {
+
+ LinkedList<Statement> stackNode = new LinkedList<Statement>();
+ LinkedList<Integer> stackIndex = new LinkedList<Integer>();
+ HashSet<Statement> setVisited = new HashSet<Statement>();
+
+ stackNode.add(root);
+ stackIndex.add(0);
+
+ while (!stackNode.isEmpty()) {
+
+ Statement node = stackNode.getLast();
+ int index = stackIndex.removeLast();
+
+ setVisited.add(node);
+
+ List<StatEdge> lstEdges = node.getAllSuccessorEdges();
+
+ for (; index < lstEdges.size(); index++) {
+ StatEdge edge = lstEdges.get(index);
+ Statement succ = edge.getDestination();
+
+ if (!setVisited.contains(succ) &&
+ (edge.getType() == StatEdge.TYPE_REGULAR || edge.getType() == StatEdge.TYPE_EXCEPTION)) { // TODO: edge filter?
+
+ stackIndex.add(index + 1);
+
+ stackNode.add(succ);
+ stackIndex.add(0);
+
+ break;
+ }
+ }
+
+ if (index == lstEdges.size()) {
+ lst.add(0, node);
+
+ stackNode.removeLast();
+ }
+ }
+ }
+
+
+ private void addToPostReversePostOrderList(Statement stat, List<Statement> lst, HashSet<Statement> setVisited) {
+
+ if (setVisited.contains(stat)) { // because of not considered exception edges, s. isExitComponent. Should be rewritten, if possible.
+ return;
+ }
+ setVisited.add(stat);
+
+ for (StatEdge prededge : stat.getEdges(StatEdge.TYPE_REGULAR | StatEdge.TYPE_EXCEPTION, DIRECTION_BACKWARD)) {
+ Statement pred = prededge.getSource();
+ if (!setVisited.contains(pred)) {
+ addToPostReversePostOrderList(pred, lst, setVisited);
+ }
+ }
+
+ lst.add(0, stat);
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public void changeEdgeNode(int direction, StatEdge edge, Statement value) {
+
+ Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges;
+ Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates;
+
+ int type = edge.getType();
+
+ int[] arrtypes;
+ if (type == StatEdge.TYPE_EXCEPTION) {
+ arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION};
+ }
+ else {
+ arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type};
+ }
+
+ for (int edgetype : arrtypes) {
+ List<StatEdge> lst = mapEdges.get(edgetype);
+ if (lst != null) {
+ int index = lst.indexOf(edge);
+ if (index >= 0) {
+ mapStates.get(edgetype).set(index, value);
+ }
+ }
+ }
+
+ if (direction == DIRECTION_BACKWARD) {
+ edge.setSource(value);
+ }
+ else {
+ edge.setDestination(value);
+ }
+ }
+
+ public void changeEdgeType(int direction, StatEdge edge, int newtype) {
+
+ int oldtype = edge.getType();
+ if (oldtype == newtype) {
+ return;
+ }
+
+ if (oldtype == StatEdge.TYPE_EXCEPTION || newtype == StatEdge.TYPE_EXCEPTION) {
+ throw new RuntimeException("Invalid edge type!");
+ }
+
+ removeEdgeDirectInternal(direction, edge, oldtype);
+ addEdgeDirectInternal(direction, edge, newtype);
+
+ if (direction == DIRECTION_FORWARD) {
+ edge.getDestination().changeEdgeType(DIRECTION_BACKWARD, edge, newtype);
+ }
+
+ edge.setType(newtype);
+ }
+
+
+ private List<StatEdge> getEdges(int type, int direction) {
+
+ Map<Integer, List<StatEdge>> map = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges;
+
+ List<StatEdge> res;
+ if ((type & (type - 1)) == 0) {
+ res = map.get(type);
+ res = res == null ? new ArrayList<StatEdge>() : new ArrayList<StatEdge>(res);
+ }
+ else {
+ res = new ArrayList<StatEdge>();
+ for (int edgetype : StatEdge.TYPES) {
+ if ((type & edgetype) != 0) {
+ List<StatEdge> lst = map.get(edgetype);
+ if (lst != null) {
+ res.addAll(lst);
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public List<Statement> getNeighbours(int type, int direction) {
+
+ Map<Integer, List<Statement>> map = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates;
+
+ List<Statement> res;
+ if ((type & (type - 1)) == 0) {
+ res = map.get(type);
+ res = res == null ? new ArrayList<Statement>() : new ArrayList<Statement>(res);
+ }
+ else {
+ res = new ArrayList<Statement>();
+ for (int edgetype : StatEdge.TYPES) {
+ if ((type & edgetype) != 0) {
+ List<Statement> lst = map.get(edgetype);
+ if (lst != null) {
+ res.addAll(lst);
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public Set<Statement> getNeighboursSet(int type, int direction) {
+ return new HashSet<Statement>(getNeighbours(type, direction));
+ }
+
+ public List<StatEdge> getSuccessorEdges(int type) {
+ return getEdges(type, DIRECTION_FORWARD);
+ }
+
+ public List<StatEdge> getPredecessorEdges(int type) {
+ return getEdges(type, DIRECTION_BACKWARD);
+ }
+
+ public List<StatEdge> getAllSuccessorEdges() {
+ return getEdges(STATEDGE_ALL, DIRECTION_FORWARD);
+ }
+
+ public List<StatEdge> getAllPredecessorEdges() {
+ return getEdges(STATEDGE_ALL, DIRECTION_BACKWARD);
+ }
+
+ public Statement getFirst() {
+ return first;
+ }
+
+ public void setFirst(Statement first) {
+ this.first = first;
+ }
+
+ public Statement getPost() {
+ return post;
+ }
+
+ public void setPost(Statement post) {
+ this.post = post;
+ }
+
+ public VBStyleCollection<Statement, Integer> getStats() {
+ return stats;
+ }
+
+ public int getLastBasicType() {
+ return lastBasicType;
+ }
+
+ public HashSet<Statement> getContinueSet() {
+ return continueSet;
+ }
+
+ public boolean isContainsMonitorExit() {
+ return containsMonitorExit;
+ }
+
+ public boolean isMonitorEnter() {
+ return isMonitorEnter;
+ }
+
+ public BasicBlockStatement getBasichead() {
+ if (type == Statement.TYPE_BASICBLOCK) {
+ return (BasicBlockStatement)this;
+ }
+ else {
+ return first.getBasichead();
+ }
+ }
+
+ public boolean isLabeled() {
+
+ for (StatEdge edge : labelEdges) {
+ if (edge.labeled && edge.explicit) { // FIXME: consistent setting
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean hasBasicSuccEdge() {
+ boolean res = type == Statement.TYPE_BASICBLOCK || (type == Statement.TYPE_IF &&
+ ((IfStatement)this).iftype == IfStatement.IFTYPE_IF) ||
+ (type == Statement.TYPE_DO && ((DoStatement)this).getLooptype() != DoStatement.LOOP_DO);
+
+ // FIXME: default switch
+
+ return res;
+ }
+
+
+ public Statement getParent() {
+ return parent;
+ }
+
+ public void setParent(Statement parent) {
+ this.parent = parent;
+ }
+
+ public HashSet<StatEdge> getLabelEdges() { // FIXME: why HashSet?
+ return labelEdges;
+ }
+
+ public List<Exprent> getVarDefinitions() {
+ return varDefinitions;
+ }
+
+ public List<Exprent> getExprents() {
+ return exprents;
+ }
+
+ public void setExprents(List<Exprent> exprents) {
+ this.exprents = exprents;
+ }
+
+ public boolean isCopied() {
+ return copied;
+ }
+
+ public void setCopied(boolean copied) {
+ this.copied = copied;
+ }
+
+ // helper methods
+ public String toString() {
+ return id.toString();
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java
index ec03886..379d00d 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java
@@ -1,26 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.code.SwitchInstruction;
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
import org.jetbrains.java.decompiler.main.DecompilerContext;
@@ -34,337 +28,340 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.SwitchExprent;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.*;
+
public class SwitchStatement extends Statement {
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private List<Statement> caseStatements = new ArrayList<Statement>();
-
- private List<List<StatEdge>> caseEdges = new ArrayList<List<StatEdge>>();
-
- private List<List<ConstExprent>> caseValues = new ArrayList<List<ConstExprent>>();
-
- private StatEdge default_edge;
-
- private List<Exprent> headexprent = new ArrayList<Exprent>();
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- private SwitchStatement() {
- type = TYPE_SWITCH;
-
- headexprent.add(null);
- }
-
- private SwitchStatement(Statement head, Statement poststat) {
-
- this();
-
- first = head;
- stats.addWithKey(head, head.id);
-
- // find post node
- Set<Statement> lstNodes = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_REGULAR, DIRECTION_FORWARD));
-
- // cluster nodes
- if(poststat != null) {
- post = poststat;
- lstNodes.remove(post);
- }
-
- default_edge = head.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0);
-
- for(Statement st: lstNodes) {
- stats.addWithKey(st, st.id);
- }
-
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public static Statement isHead(Statement head) {
-
- if(head.type == Statement.TYPE_BASICBLOCK && head.getLastBasicType() == Statement.LASTBASICTYPE_SWITCH) {
-
- List<Statement> lst = new ArrayList<Statement>();
- if(DecHelper.isChoiceStatement(head, lst)) {
- Statement post = lst.remove(0);
-
- for(Statement st : lst) {
- if(st.isMonitorEnter()) {
- return null;
- }
- }
-
- if(DecHelper.checkStatementExceptions(lst)) {
- return new SwitchStatement(head, post);
- }
- }
- }
-
- return null;
- }
-
- public String toJava(int indent) {
-
- String indstr = InterpreterUtil.getIndentString(indent);
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- StringBuilder buf = new StringBuilder();
- buf.append(ExprProcessor.listToJava(varDefinitions, indent));
- buf.append(first.toJava(indent));
-
- if(isLabeled()) {
- buf.append(indstr+"label"+this.id+":" + new_line_separator);
- }
-
- buf.append(indstr+headexprent.get(0).toJava(indent)+" {" + new_line_separator);
-
- VarType switch_type = headexprent.get(0).getExprType();
-
- for(int i=0;i<caseStatements.size();i++) {
-
- Statement stat = caseStatements.get(i);
- List<StatEdge> edges = caseEdges.get(i);
- List<ConstExprent> values = caseValues.get(i);
-
- for(int j=0;j<edges.size();j++) {
- if(edges.get(j) == default_edge) {
- buf.append(indstr+"default:" + new_line_separator);
- } else {
- ConstExprent value = (ConstExprent)values.get(j).copy();
- value.setConsttype(switch_type);
-
- buf.append(indstr+"case "+ value.toJava(indent)+":" + new_line_separator);
- }
- }
-
- buf.append(ExprProcessor.jmpWrapper(stat, indent+1, false));
- }
-
- buf.append(indstr+"}" + new_line_separator);
-
- return buf.toString();
- }
-
- public void initExprents() {
- SwitchExprent swexpr = (SwitchExprent)first.getExprents().remove(first.getExprents().size()-1);
- swexpr.setCaseValues(caseValues);
-
- headexprent.set(0, swexpr);
- }
-
- public List<Object> getSequentialObjects() {
-
- List<Object> lst = new ArrayList<Object>(stats);
- lst.add(1, headexprent.get(0));
-
- return lst;
- }
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(headexprent.get(0) == oldexpr) {
- headexprent.set(0, newexpr);
- }
- }
-
- public void replaceStatement(Statement oldstat, Statement newstat) {
-
- for(int i=0;i<caseStatements.size();i++) {
- if(caseStatements.get(i) == oldstat) {
- caseStatements.set(i, newstat);
- }
- }
-
- super.replaceStatement(oldstat, newstat);
- }
-
- public Statement getSimpleCopy() {
- return new SwitchStatement();
- }
-
- public void initSimpleCopy() {
- first = stats.get(0);
- default_edge = first.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0);
-
- sortEdgesAndNodes();
- }
-
- // *****************************************************************************
- // private methods
- // *****************************************************************************
-
- public void sortEdgesAndNodes() {
-
- HashMap<StatEdge, Integer> mapEdgeIndex = new HashMap<StatEdge, Integer>();
-
- List<StatEdge> lstFirstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- for(int i=0;i<lstFirstSuccs.size();i++) {
- mapEdgeIndex.put(lstFirstSuccs.get(i), i==0?lstFirstSuccs.size():i);
- }
-
- // case values
- BasicBlockStatement bbstat = (BasicBlockStatement)first;
- int[] values = ((SwitchInstruction)bbstat.getBlock().getLastInstruction()).getValues();
-
- List<Statement> nodes = new ArrayList<Statement>();
- List<List<Integer>> edges = new ArrayList<List<Integer>>();
-
- // collect regular edges
- for(int i=1;i<stats.size();i++) {
-
- Statement stat = stats.get(i);
-
- List<Integer> lst = new ArrayList<Integer>();
- for(StatEdge edge: stat.getPredecessorEdges(StatEdge.TYPE_REGULAR)) {
- if(edge.getSource() == first) {
- lst.add(mapEdgeIndex.get(edge));
- }
- }
- Collections.sort(lst);
-
- nodes.add(stat);
- edges.add(lst);
- }
-
- // collect exit edges
- List<StatEdge> lstExitEdges = first.getSuccessorEdges(StatEdge.TYPE_BREAK | StatEdge.TYPE_CONTINUE);
- while(!lstExitEdges.isEmpty()) {
- StatEdge edge = lstExitEdges.get(0);
-
- List<Integer> lst = new ArrayList<Integer>();
- for(int i=lstExitEdges.size()-1;i>=0;i--) {
- StatEdge edgeTemp = lstExitEdges.get(i);
- if(edgeTemp.getDestination() == edge.getDestination() && edgeTemp.getType() == edge.getType()) {
- lst.add(mapEdgeIndex.get(edgeTemp));
- lstExitEdges.remove(i);
- }
- }
- Collections.sort(lst);
-
- nodes.add(null);
- edges.add(lst);
- }
-
- // sort edges (bubblesort)
- for(int i=0;i<edges.size()-1;i++) {
- for(int j=edges.size()-1;j>i;j--) {
- if(edges.get(j-1).get(0) > edges.get(j).get(0)) {
- edges.set(j, edges.set(j-1, edges.get(j)));
- nodes.set(j, nodes.set(j-1, nodes.get(j)));
- }
- }
- }
-
- // sort statement cliques
- for(int index = 0; index < nodes.size(); index++) {
- Statement stat = nodes.get(index);
-
- if(stat != null) {
- HashSet<Statement> setPreds = new HashSet<Statement>(stat.getNeighbours(StatEdge.TYPE_REGULAR, DIRECTION_BACKWARD));
- setPreds.remove(first);
-
- if(!setPreds.isEmpty()) {
- Statement pred = setPreds.iterator().next(); // assumption: at most one predecessor node besides the head. May not hold true for obfuscated code.
- for(int j=0;j<nodes.size();j++) {
- if(j != (index - 1) && nodes.get(j) == pred) {
- nodes.add(j+1, stat);
- edges.add(j+1, edges.get(index));
-
- if(j > index) {
- nodes.remove(index);
- edges.remove(index);
- index--;
- } else {
- nodes.remove(index + 1);
- edges.remove(index + 1);
- }
- break;
- }
- }
- }
- }
- }
-
- // translate indices back into edges
- List<List<StatEdge>> lstEdges = new ArrayList<List<StatEdge>>();
- List<List<ConstExprent>> lstValues = new ArrayList<List<ConstExprent>>();
-
- for(List<Integer> lst: edges) {
- List<StatEdge> lste = new ArrayList<StatEdge>();
- List<ConstExprent> lstv = new ArrayList<ConstExprent>();
-
- List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- for(Integer in: lst) {
- int index = in==lstSuccs.size()?0:in;
-
- lste.add(lstSuccs.get(index));
- lstv.add(index==0?null:new ConstExprent(values[index-1], false));
- }
- lstEdges.add(lste);
- lstValues.add(lstv);
- }
-
- // replace null statements with dummy basic blocks
- for(int i=0;i<nodes.size();i++) {
- if(nodes.get(i) == null) {
- BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
- DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
-
- StatEdge sample_edge = lstEdges.get(i).get(0);
-
- bstat.addSuccessor(new StatEdge(sample_edge.getType(), bstat, sample_edge.getDestination(), sample_edge.closure));
-
- for(StatEdge edge : lstEdges.get(i)) {
-
- edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_REGULAR);
- edge.closure.getLabelEdges().remove(edge);
-
- edge.getDestination().removePredecessor(edge);
- edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, bstat);
- bstat.addPredecessor(edge);
- }
-
- nodes.set(i, bstat);
- stats.addWithKey(bstat, bstat.id);
- bstat.setParent(this);
- }
- }
-
- caseStatements = nodes;
- caseEdges = lstEdges;
- caseValues = lstValues;
- }
-
- public List<Exprent> getHeadexprentList() {
- return headexprent;
- }
-
- public Exprent getHeadexprent() {
- return headexprent.get(0);
- }
-
- public List<List<StatEdge>> getCaseEdges() {
- return caseEdges;
- }
-
- public List<Statement> getCaseStatements() {
- return caseStatements;
- }
-
- public StatEdge getDefault_edge() {
- return default_edge;
- }
-
- public List<List<ConstExprent>> getCaseValues() {
- return caseValues;
- }
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private List<Statement> caseStatements = new ArrayList<Statement>();
+
+ private List<List<StatEdge>> caseEdges = new ArrayList<List<StatEdge>>();
+
+ private List<List<ConstExprent>> caseValues = new ArrayList<List<ConstExprent>>();
+
+ private StatEdge default_edge;
+
+ private List<Exprent> headexprent = new ArrayList<Exprent>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private SwitchStatement() {
+ type = TYPE_SWITCH;
+
+ headexprent.add(null);
+ }
+
+ private SwitchStatement(Statement head, Statement poststat) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(head, head.id);
+
+ // find post node
+ Set<Statement> lstNodes = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_REGULAR, DIRECTION_FORWARD));
+
+ // cluster nodes
+ if (poststat != null) {
+ post = poststat;
+ lstNodes.remove(post);
+ }
+
+ default_edge = head.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0);
+
+ for (Statement st : lstNodes) {
+ stats.addWithKey(st, st.id);
+ }
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead(Statement head) {
+
+ if (head.type == Statement.TYPE_BASICBLOCK && head.getLastBasicType() == Statement.LASTBASICTYPE_SWITCH) {
+
+ List<Statement> lst = new ArrayList<Statement>();
+ if (DecHelper.isChoiceStatement(head, lst)) {
+ Statement post = lst.remove(0);
+
+ for (Statement st : lst) {
+ if (st.isMonitorEnter()) {
+ return null;
+ }
+ }
+
+ if (DecHelper.checkStatementExceptions(lst)) {
+ return new SwitchStatement(head, post);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String toJava(int indent) {
+
+ String indstr = InterpreterUtil.getIndentString(indent);
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buf = new StringBuilder();
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+ buf.append(first.toJava(indent));
+
+ if (isLabeled()) {
+ buf.append(indstr + "label" + this.id + ":" + new_line_separator);
+ }
+
+ buf.append(indstr + headexprent.get(0).toJava(indent) + " {" + new_line_separator);
+
+ VarType switch_type = headexprent.get(0).getExprType();
+
+ for (int i = 0; i < caseStatements.size(); i++) {
+
+ Statement stat = caseStatements.get(i);
+ List<StatEdge> edges = caseEdges.get(i);
+ List<ConstExprent> values = caseValues.get(i);
+
+ for (int j = 0; j < edges.size(); j++) {
+ if (edges.get(j) == default_edge) {
+ buf.append(indstr + "default:" + new_line_separator);
+ }
+ else {
+ ConstExprent value = (ConstExprent)values.get(j).copy();
+ value.setConsttype(switch_type);
+
+ buf.append(indstr + "case " + value.toJava(indent) + ":" + new_line_separator);
+ }
+ }
+
+ buf.append(ExprProcessor.jmpWrapper(stat, indent + 1, false));
+ }
+
+ buf.append(indstr + "}" + new_line_separator);
+
+ return buf.toString();
+ }
+
+ public void initExprents() {
+ SwitchExprent swexpr = (SwitchExprent)first.getExprents().remove(first.getExprents().size() - 1);
+ swexpr.setCaseValues(caseValues);
+
+ headexprent.set(0, swexpr);
+ }
+
+ public List<Object> getSequentialObjects() {
+
+ List<Object> lst = new ArrayList<Object>(stats);
+ lst.add(1, headexprent.get(0));
+
+ return lst;
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (headexprent.get(0) == oldexpr) {
+ headexprent.set(0, newexpr);
+ }
+ }
+
+ public void replaceStatement(Statement oldstat, Statement newstat) {
+
+ for (int i = 0; i < caseStatements.size(); i++) {
+ if (caseStatements.get(i) == oldstat) {
+ caseStatements.set(i, newstat);
+ }
+ }
+
+ super.replaceStatement(oldstat, newstat);
+ }
+
+ public Statement getSimpleCopy() {
+ return new SwitchStatement();
+ }
+
+ public void initSimpleCopy() {
+ first = stats.get(0);
+ default_edge = first.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0);
+
+ sortEdgesAndNodes();
+ }
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ public void sortEdgesAndNodes() {
+
+ HashMap<StatEdge, Integer> mapEdgeIndex = new HashMap<StatEdge, Integer>();
+
+ List<StatEdge> lstFirstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ for (int i = 0; i < lstFirstSuccs.size(); i++) {
+ mapEdgeIndex.put(lstFirstSuccs.get(i), i == 0 ? lstFirstSuccs.size() : i);
+ }
+
+ // case values
+ BasicBlockStatement bbstat = (BasicBlockStatement)first;
+ int[] values = ((SwitchInstruction)bbstat.getBlock().getLastInstruction()).getValues();
+
+ List<Statement> nodes = new ArrayList<Statement>();
+ List<List<Integer>> edges = new ArrayList<List<Integer>>();
+
+ // collect regular edges
+ for (int i = 1; i < stats.size(); i++) {
+
+ Statement stat = stats.get(i);
+
+ List<Integer> lst = new ArrayList<Integer>();
+ for (StatEdge edge : stat.getPredecessorEdges(StatEdge.TYPE_REGULAR)) {
+ if (edge.getSource() == first) {
+ lst.add(mapEdgeIndex.get(edge));
+ }
+ }
+ Collections.sort(lst);
+
+ nodes.add(stat);
+ edges.add(lst);
+ }
+
+ // collect exit edges
+ List<StatEdge> lstExitEdges = first.getSuccessorEdges(StatEdge.TYPE_BREAK | StatEdge.TYPE_CONTINUE);
+ while (!lstExitEdges.isEmpty()) {
+ StatEdge edge = lstExitEdges.get(0);
+
+ List<Integer> lst = new ArrayList<Integer>();
+ for (int i = lstExitEdges.size() - 1; i >= 0; i--) {
+ StatEdge edgeTemp = lstExitEdges.get(i);
+ if (edgeTemp.getDestination() == edge.getDestination() && edgeTemp.getType() == edge.getType()) {
+ lst.add(mapEdgeIndex.get(edgeTemp));
+ lstExitEdges.remove(i);
+ }
+ }
+ Collections.sort(lst);
+
+ nodes.add(null);
+ edges.add(lst);
+ }
+
+ // sort edges (bubblesort)
+ for (int i = 0; i < edges.size() - 1; i++) {
+ for (int j = edges.size() - 1; j > i; j--) {
+ if (edges.get(j - 1).get(0) > edges.get(j).get(0)) {
+ edges.set(j, edges.set(j - 1, edges.get(j)));
+ nodes.set(j, nodes.set(j - 1, nodes.get(j)));
+ }
+ }
+ }
+
+ // sort statement cliques
+ for (int index = 0; index < nodes.size(); index++) {
+ Statement stat = nodes.get(index);
+
+ if (stat != null) {
+ HashSet<Statement> setPreds = new HashSet<Statement>(stat.getNeighbours(StatEdge.TYPE_REGULAR, DIRECTION_BACKWARD));
+ setPreds.remove(first);
+
+ if (!setPreds.isEmpty()) {
+ Statement pred =
+ setPreds.iterator().next(); // assumption: at most one predecessor node besides the head. May not hold true for obfuscated code.
+ for (int j = 0; j < nodes.size(); j++) {
+ if (j != (index - 1) && nodes.get(j) == pred) {
+ nodes.add(j + 1, stat);
+ edges.add(j + 1, edges.get(index));
+
+ if (j > index) {
+ nodes.remove(index);
+ edges.remove(index);
+ index--;
+ }
+ else {
+ nodes.remove(index + 1);
+ edges.remove(index + 1);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // translate indices back into edges
+ List<List<StatEdge>> lstEdges = new ArrayList<List<StatEdge>>();
+ List<List<ConstExprent>> lstValues = new ArrayList<List<ConstExprent>>();
+
+ for (List<Integer> lst : edges) {
+ List<StatEdge> lste = new ArrayList<StatEdge>();
+ List<ConstExprent> lstv = new ArrayList<ConstExprent>();
+
+ List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ for (Integer in : lst) {
+ int index = in == lstSuccs.size() ? 0 : in;
+
+ lste.add(lstSuccs.get(index));
+ lstv.add(index == 0 ? null : new ConstExprent(values[index - 1], false));
+ }
+ lstEdges.add(lste);
+ lstValues.add(lstv);
+ }
+
+ // replace null statements with dummy basic blocks
+ for (int i = 0; i < nodes.size(); i++) {
+ if (nodes.get(i) == null) {
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+
+ StatEdge sample_edge = lstEdges.get(i).get(0);
+
+ bstat.addSuccessor(new StatEdge(sample_edge.getType(), bstat, sample_edge.getDestination(), sample_edge.closure));
+
+ for (StatEdge edge : lstEdges.get(i)) {
+
+ edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_REGULAR);
+ edge.closure.getLabelEdges().remove(edge);
+
+ edge.getDestination().removePredecessor(edge);
+ edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, bstat);
+ bstat.addPredecessor(edge);
+ }
+
+ nodes.set(i, bstat);
+ stats.addWithKey(bstat, bstat.id);
+ bstat.setParent(this);
+ }
+ }
+
+ caseStatements = nodes;
+ caseEdges = lstEdges;
+ caseValues = lstValues;
+ }
+
+ public List<Exprent> getHeadexprentList() {
+ return headexprent;
+ }
+
+ public Exprent getHeadexprent() {
+ return headexprent.get(0);
+ }
+
+ public List<List<StatEdge>> getCaseEdges() {
+ return caseEdges;
+ }
+
+ public List<Statement> getCaseStatements() {
+ return caseStatements;
+ }
+
+ public StatEdge getDefault_edge() {
+ return default_edge;
+ }
+ public List<List<ConstExprent>> getCaseValues() {
+ return caseValues;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java
index 5336f12..3fcb042 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java
@@ -1,22 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.stats;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.SequenceHelper;
@@ -24,131 +22,132 @@ import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import java.util.ArrayList;
+import java.util.List;
+
public class SynchronizedStatement extends Statement {
- private Statement body;
-
- private List<Exprent> headexprent = new ArrayList<Exprent>();
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public SynchronizedStatement() {
- type = TYPE_SYNCRONIZED;
-
- headexprent.add(null);
- }
-
- public SynchronizedStatement(Statement head, Statement body, Statement exc) {
-
- this();
-
- first = head;
- stats.addWithKey(head, head.id);
-
- this.body = body;
- stats.addWithKey(body, body.id);
-
- stats.addWithKey(exc, exc.id);
-
- List<StatEdge> lstSuccs = body.getSuccessorEdges(STATEDGE_DIRECT_ALL);
- if(!lstSuccs.isEmpty()) {
- StatEdge edge = lstSuccs.get(0);
- if(edge.getType() == StatEdge.TYPE_REGULAR) {
- post = edge.getDestination();
- }
- }
-
- }
-
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public String toJava(int indent) {
- String indstr = InterpreterUtil.getIndentString(indent);
-
- String new_line_separator = DecompilerContext.getNewLineSeparator();
-
- StringBuffer buf = new StringBuffer();
- buf.append(ExprProcessor.listToJava(varDefinitions, indent));
- buf.append(first.toJava(indent));
-
- if(isLabeled()) {
- buf.append(indstr+"label"+this.id+":" + new_line_separator);
- }
-
- buf.append(indstr+headexprent.get(0).toJava(indent)+" {" + new_line_separator);
- buf.append(ExprProcessor.jmpWrapper(body, indent+1, true));
- buf.append(indstr+"}" + new_line_separator);
-
- return buf.toString();
- }
-
- public void initExprents() {
- headexprent.set(0, first.getExprents().remove(first.getExprents().size()-1));
- }
-
- public List<Object> getSequentialObjects() {
-
- List<Object> lst = new ArrayList<Object>(stats);
- lst.add(1, headexprent.get(0));
-
- return lst;
- }
-
- public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
- if(headexprent.get(0) == oldexpr) {
- headexprent.set(0, newexpr);
- }
- }
-
- public void replaceStatement(Statement oldstat, Statement newstat) {
-
- if(body == oldstat) {
- body = newstat;
- }
-
- super.replaceStatement(oldstat, newstat);
- }
-
- public void removeExc() {
- Statement exc = stats.get(2);
- SequenceHelper.destroyStatementContent(exc, true);
-
- stats.removeWithKey(exc.id);
- }
-
- public Statement getSimpleCopy() {
- return new SynchronizedStatement();
- }
-
- public void initSimpleCopy() {
- first = stats.get(0);
- body = stats.get(1);
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public Statement getBody() {
- return body;
- }
-
- public void setBody(Statement body) {
- this.body = body;
- }
-
- public List<Exprent> getHeadexprentList() {
- return headexprent;
- }
-
- public Exprent getHeadexprent() {
- return headexprent.get(0);
- }
-
+ private Statement body;
+
+ private List<Exprent> headexprent = new ArrayList<Exprent>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public SynchronizedStatement() {
+ type = TYPE_SYNCRONIZED;
+
+ headexprent.add(null);
+ }
+
+ public SynchronizedStatement(Statement head, Statement body, Statement exc) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(head, head.id);
+
+ this.body = body;
+ stats.addWithKey(body, body.id);
+
+ stats.addWithKey(exc, exc.id);
+
+ List<StatEdge> lstSuccs = body.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstSuccs.isEmpty()) {
+ StatEdge edge = lstSuccs.get(0);
+ if (edge.getType() == StatEdge.TYPE_REGULAR) {
+ post = edge.getDestination();
+ }
+ }
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuffer buf = new StringBuffer();
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+ buf.append(first.toJava(indent));
+
+ if (isLabeled()) {
+ buf.append(indstr + "label" + this.id + ":" + new_line_separator);
+ }
+
+ buf.append(indstr + headexprent.get(0).toJava(indent) + " {" + new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(body, indent + 1, true));
+ buf.append(indstr + "}" + new_line_separator);
+
+ return buf.toString();
+ }
+
+ public void initExprents() {
+ headexprent.set(0, first.getExprents().remove(first.getExprents().size() - 1));
+ }
+
+ public List<Object> getSequentialObjects() {
+
+ List<Object> lst = new ArrayList<Object>(stats);
+ lst.add(1, headexprent.get(0));
+
+ return lst;
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (headexprent.get(0) == oldexpr) {
+ headexprent.set(0, newexpr);
+ }
+ }
+
+ public void replaceStatement(Statement oldstat, Statement newstat) {
+
+ if (body == oldstat) {
+ body = newstat;
+ }
+
+ super.replaceStatement(oldstat, newstat);
+ }
+
+ public void removeExc() {
+ Statement exc = stats.get(2);
+ SequenceHelper.destroyStatementContent(exc, true);
+
+ stats.removeWithKey(exc.id);
+ }
+
+ public Statement getSimpleCopy() {
+ return new SynchronizedStatement();
+ }
+
+ public void initSimpleCopy() {
+ first = stats.get(0);
+ body = stats.get(1);
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public Statement getBody() {
+ return body;
+ }
+
+ public void setBody(Statement body) {
+ this.body = body;
+ }
+
+ public List<Exprent> getHeadexprentList() {
+ return headexprent;
+ }
+
+ public Exprent getHeadexprent() {
+ return headexprent.get(0);
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java
index 5519797..6e7c967 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java
@@ -1,57 +1,57 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.vars;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.struct.gen.VarType;
+import java.util.ArrayList;
+import java.util.List;
+
public class CheckTypesResult {
- private List<ExprentTypePair> lstMaxTypeExprents = new ArrayList<ExprentTypePair>();
-
- private List<ExprentTypePair> lstMinTypeExprents = new ArrayList<ExprentTypePair>();
-
- public void addMaxTypeExprent(Exprent exprent, VarType type) {
- lstMaxTypeExprents.add(new ExprentTypePair(exprent, type, null));
- }
-
- public void addMinTypeExprent(Exprent exprent, VarType type) {
- lstMinTypeExprents.add(new ExprentTypePair(exprent, type, null));
- }
-
- public List<ExprentTypePair> getLstMaxTypeExprents() {
- return lstMaxTypeExprents;
- }
-
- public List<ExprentTypePair> getLstMinTypeExprents() {
- return lstMinTypeExprents;
- }
-
- public class ExprentTypePair {
- public Exprent exprent;
- public VarType type;
- public VarType desttype;
-
- public ExprentTypePair(Exprent exprent, VarType type, VarType desttype) {
- this.exprent = exprent;
- this.type = type;
- this.desttype = desttype;
- }
- }
-
+ private List<ExprentTypePair> lstMaxTypeExprents = new ArrayList<ExprentTypePair>();
+
+ private List<ExprentTypePair> lstMinTypeExprents = new ArrayList<ExprentTypePair>();
+
+ public void addMaxTypeExprent(Exprent exprent, VarType type) {
+ lstMaxTypeExprents.add(new ExprentTypePair(exprent, type, null));
+ }
+
+ public void addMinTypeExprent(Exprent exprent, VarType type) {
+ lstMinTypeExprents.add(new ExprentTypePair(exprent, type, null));
+ }
+
+ public List<ExprentTypePair> getLstMaxTypeExprents() {
+ return lstMaxTypeExprents;
+ }
+
+ public List<ExprentTypePair> getLstMinTypeExprents() {
+ return lstMinTypeExprents;
+ }
+
+ public class ExprentTypePair {
+ public Exprent exprent;
+ public VarType type;
+ public VarType desttype;
+
+ public ExprentTypePair(Exprent exprent, VarType type, VarType desttype) {
+ this.exprent = exprent;
+ this.type = type;
+ this.desttype = desttype;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java
index 5c04ccd..7e5a56f 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java
@@ -1,29 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.vars;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
@@ -38,321 +29,332 @@ import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import java.util.*;
+import java.util.Map.Entry;
+
public class VarDefinitionHelper {
- private HashMap<Integer, Statement> mapVarDefStatements;
-
- // statement.id, defined vars
- private HashMap<Integer, HashSet<Integer>> mapStatementVars;
-
- private HashSet<Integer> implDefVars;
-
- private VarProcessor varproc;
-
- public VarDefinitionHelper(Statement root, StructMethod mt, VarProcessor varproc) {
-
- mapVarDefStatements = new HashMap<Integer, Statement>();
- mapStatementVars = new HashMap<Integer, HashSet<Integer>>();
- implDefVars = new HashSet<Integer>();
-
- this.varproc = varproc;
-
- VarNamesCollector vc = DecompilerContext.getVarncollector();
-
- boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
-
- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
-
- int paramcount = 0;
- if(thisvar) {
- paramcount = 1;
- }
- paramcount += md.params.length;
-
-
- // method parameters are implicitly defined
- int varindex = 0;
- for(int i=0;i<paramcount;i++) {
- implDefVars.add(varindex);
- varproc.setVarName(new VarVersionPaar(varindex, 0), vc.getFreeName(varindex));
-
- if(thisvar) {
- if(i==0) {
- varindex++;
- } else {
- varindex+=md.params[i-1].stack_size;
- }
- } else {
- varindex+=md.params[i].stack_size;
- }
- }
-
- if(thisvar) {
- StructClass current_class = (StructClass)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS);
-
- varproc.getThisvars().put(new VarVersionPaar(0, 0), current_class.qualifiedName);
- varproc.setVarName(new VarVersionPaar(0, 0), "this");
- vc.addName("this");
- }
-
- // catch variables are implicitly defined
- LinkedList<Statement> stack = new LinkedList<Statement>();
- stack.add(root);
-
- while(!stack.isEmpty()) {
- Statement st = stack.removeFirst();
-
- List<VarExprent> lstVars = null;
- if(st.type == Statement.TYPE_CATCHALL) {
- lstVars = ((CatchAllStatement)st).getVars();
- } else if(st.type == Statement.TYPE_TRYCATCH) {
- lstVars = ((CatchStatement)st).getVars();
- }
-
- if(lstVars != null) {
- for(VarExprent var: lstVars) {
- implDefVars.add(var.getIndex());
- varproc.setVarName(new VarVersionPaar(var), vc.getFreeName(var.getIndex()));
- var.setDefinition(true);
- }
- }
-
- stack.addAll(st.getStats());
- }
-
- initStatement(root);
- }
-
-
- public void setVarDefinitions() {
-
- VarNamesCollector vc = DecompilerContext.getVarncollector();
-
- Iterator<Entry<Integer, Statement>> it = mapVarDefStatements.entrySet().iterator();
- while(it.hasNext()) {
- Entry<Integer, Statement> en = it.next();
-
- Statement stat = en.getValue();
- Integer index = en.getKey();
-
- if(implDefVars.contains(index)) {
- // already implicitly defined
- continue;
- }
-
- varproc.setVarName(new VarVersionPaar(index.intValue(), 0), vc.getFreeName(index));
-
- // special case for
- if(stat.type == Statement.TYPE_DO) {
- DoStatement dstat = (DoStatement)stat;
- if(dstat.getLooptype() == DoStatement.LOOP_FOR) {
-
- if(dstat.getInitExprent() != null && setDefinition(dstat.getInitExprent(), index)) {
- continue;
- } else {
- List<Exprent> lstSpecial = Arrays.asList(new Exprent[]{dstat.getConditionExprent(), dstat.getIncExprent()});
- for(VarExprent var: getAllVars(lstSpecial)) {
- if(var.getIndex() == index.intValue()) {
- stat = stat.getParent();
- break;
- }
- }
- }
- }
- }
-
-
- Statement first = findFirstBlock(stat, index);
-
- List<Exprent> lst;
- if(first == null) {
- lst = stat.getVarDefinitions();
- } else if(first.getExprents() == null) {
- lst = first.getVarDefinitions();
- } else {
- lst = first.getExprents();
- }
-
-
- boolean defset = false;
-
- // search for the first assignement to var [index]
- int addindex = 0;
- for(Exprent expr: lst) {
- if(setDefinition(expr, index)) {
- defset = true;
- break;
- } else {
- boolean foundvar = false;
- for(Exprent exp: expr.getAllExprents(true)) {
- if(exp.type == Exprent.EXPRENT_VAR && ((VarExprent)exp).getIndex() == index) {
- foundvar = true;
- break;
- }
- }
- if(foundvar) {
- break;
- }
- }
- addindex++;
- }
-
- if(!defset) {
- VarExprent var = new VarExprent(index.intValue(), varproc.getVarType(new VarVersionPaar(index.intValue(), 0)), varproc);
- var.setDefinition(true);
-
- lst.add(addindex, var);
- }
-
- }
-
- }
-
-
- // *****************************************************************************
- // private methods
- // *****************************************************************************
-
- private Statement findFirstBlock(Statement stat, Integer varindex) {
-
- LinkedList<Statement> stack = new LinkedList<Statement>();
- stack.add(stat);
-
- while(!stack.isEmpty()) {
- Statement st = stack.remove(0);
-
- if(stack.isEmpty() || mapStatementVars.get(st.id).contains(varindex)) {
-
- if(st.isLabeled() && !stack.isEmpty()) {
- return st;
- }
-
- if(st.getExprents() != null) {
- return st;
- } else {
- stack.clear();
-
- switch(st.type) {
- case Statement.TYPE_SEQUENCE:
- stack.addAll(0, st.getStats());
- break;
- case Statement.TYPE_IF:
- case Statement.TYPE_ROOT:
- case Statement.TYPE_SWITCH:
- case Statement.TYPE_SYNCRONIZED:
- stack.add(st.getFirst());
- break;
- default:
- return st;
- }
- }
- }
- }
-
- return null;
- }
-
- private Set<Integer> initStatement(Statement stat) {
-
- HashMap<Integer, Integer> mapCount = new HashMap<Integer, Integer>();
-
- List<VarExprent> condlst;
-
- if(stat.getExprents() == null) {
-
- // recurse on children statements
- List<Integer> childVars = new ArrayList<Integer>();
- List<Exprent> currVars = new ArrayList<Exprent>();
-
- for(Object obj: stat.getSequentialObjects()) {
- if(obj instanceof Statement) {
- Statement st = (Statement)obj;
- childVars.addAll(initStatement(st));
-
- if(st.type == DoStatement.TYPE_DO) {
- DoStatement dost = (DoStatement)st;
- if(dost.getLooptype() != DoStatement.LOOP_FOR &&
- dost.getLooptype() != DoStatement.LOOP_DO) {
- currVars.add(dost.getConditionExprent());
- }
- } else if(st.type == DoStatement.TYPE_CATCHALL) {
- CatchAllStatement fin = (CatchAllStatement)st;
- if(fin.isFinally() && fin.getMonitor() != null) {
- currVars.add(fin.getMonitor());
- }
- }
- } else if(obj instanceof Exprent) {
- currVars.add((Exprent)obj);
- }
- }
-
- // children statements
- for(Integer index: childVars) {
- Integer count = mapCount.get(index);
- if(count == null) {
- count = new Integer(0);
- }
- mapCount.put(index, new Integer(count.intValue()+1));
- }
-
- condlst = getAllVars(currVars);
- } else {
- condlst = getAllVars(stat.getExprents());
- }
-
- // this statement
- for(VarExprent var: condlst) {
- mapCount.put(new Integer(var.getIndex()), new Integer(2));
- }
-
-
- HashSet<Integer> set = new HashSet<Integer>(mapCount.keySet());
-
- // put all variables defined in this statement into the set
- Iterator<Entry<Integer, Integer>> itMult = mapCount.entrySet().iterator();
- while(itMult.hasNext()) {
- Entry<Integer, Integer> en = itMult.next();
- if(en.getValue().intValue()>1) {
- mapVarDefStatements.put(en.getKey(), stat);
- }
- }
-
- mapStatementVars.put(stat.id, set);
-
- return set;
- }
-
- private List<VarExprent> getAllVars(List<Exprent> lst) {
-
- List<VarExprent> res = new ArrayList<VarExprent>();
- List<Exprent> listTemp = new ArrayList<Exprent>();
-
- for(Exprent expr: lst) {
- listTemp.addAll(expr.getAllExprents(true));
- listTemp.add(expr);
- }
-
- for(Exprent exprent: listTemp) {
- if(exprent.type == Exprent.EXPRENT_VAR) {
- res.add((VarExprent)exprent);
- }
- }
-
- return res;
- }
-
- private boolean setDefinition(Exprent expr, Integer index) {
- if(expr.type == Exprent.EXPRENT_ASSIGNMENT) {
- Exprent left = ((AssignmentExprent)expr).getLeft();
- if(left.type == Exprent.EXPRENT_VAR) {
- VarExprent var = (VarExprent)left;
- if(var.getIndex() == index.intValue()) {
- var.setDefinition(true);
- return true;
- }
- }
- }
- return false;
- }
+ private HashMap<Integer, Statement> mapVarDefStatements;
+
+ // statement.id, defined vars
+ private HashMap<Integer, HashSet<Integer>> mapStatementVars;
+
+ private HashSet<Integer> implDefVars;
+
+ private VarProcessor varproc;
+
+ public VarDefinitionHelper(Statement root, StructMethod mt, VarProcessor varproc) {
+
+ mapVarDefStatements = new HashMap<Integer, Statement>();
+ mapStatementVars = new HashMap<Integer, HashSet<Integer>>();
+ implDefVars = new HashSet<Integer>();
+
+ this.varproc = varproc;
+
+ VarNamesCollector vc = DecompilerContext.getVarncollector();
+
+ boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int paramcount = 0;
+ if (thisvar) {
+ paramcount = 1;
+ }
+ paramcount += md.params.length;
+
+
+ // method parameters are implicitly defined
+ int varindex = 0;
+ for (int i = 0; i < paramcount; i++) {
+ implDefVars.add(varindex);
+ varproc.setVarName(new VarVersionPaar(varindex, 0), vc.getFreeName(varindex));
+
+ if (thisvar) {
+ if (i == 0) {
+ varindex++;
+ }
+ else {
+ varindex += md.params[i - 1].stack_size;
+ }
+ }
+ else {
+ varindex += md.params[i].stack_size;
+ }
+ }
+
+ if (thisvar) {
+ StructClass current_class = (StructClass)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS);
+
+ varproc.getThisvars().put(new VarVersionPaar(0, 0), current_class.qualifiedName);
+ varproc.setVarName(new VarVersionPaar(0, 0), "this");
+ vc.addName("this");
+ }
+
+ // catch variables are implicitly defined
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+ Statement st = stack.removeFirst();
+
+ List<VarExprent> lstVars = null;
+ if (st.type == Statement.TYPE_CATCHALL) {
+ lstVars = ((CatchAllStatement)st).getVars();
+ }
+ else if (st.type == Statement.TYPE_TRYCATCH) {
+ lstVars = ((CatchStatement)st).getVars();
+ }
+
+ if (lstVars != null) {
+ for (VarExprent var : lstVars) {
+ implDefVars.add(var.getIndex());
+ varproc.setVarName(new VarVersionPaar(var), vc.getFreeName(var.getIndex()));
+ var.setDefinition(true);
+ }
+ }
+
+ stack.addAll(st.getStats());
+ }
+
+ initStatement(root);
+ }
+
+
+ public void setVarDefinitions() {
+
+ VarNamesCollector vc = DecompilerContext.getVarncollector();
+
+ Iterator<Entry<Integer, Statement>> it = mapVarDefStatements.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry<Integer, Statement> en = it.next();
+
+ Statement stat = en.getValue();
+ Integer index = en.getKey();
+
+ if (implDefVars.contains(index)) {
+ // already implicitly defined
+ continue;
+ }
+
+ varproc.setVarName(new VarVersionPaar(index.intValue(), 0), vc.getFreeName(index));
+
+ // special case for
+ if (stat.type == Statement.TYPE_DO) {
+ DoStatement dstat = (DoStatement)stat;
+ if (dstat.getLooptype() == DoStatement.LOOP_FOR) {
+
+ if (dstat.getInitExprent() != null && setDefinition(dstat.getInitExprent(), index)) {
+ continue;
+ }
+ else {
+ List<Exprent> lstSpecial = Arrays.asList(new Exprent[]{dstat.getConditionExprent(), dstat.getIncExprent()});
+ for (VarExprent var : getAllVars(lstSpecial)) {
+ if (var.getIndex() == index.intValue()) {
+ stat = stat.getParent();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+
+ Statement first = findFirstBlock(stat, index);
+
+ List<Exprent> lst;
+ if (first == null) {
+ lst = stat.getVarDefinitions();
+ }
+ else if (first.getExprents() == null) {
+ lst = first.getVarDefinitions();
+ }
+ else {
+ lst = first.getExprents();
+ }
+
+
+ boolean defset = false;
+
+ // search for the first assignement to var [index]
+ int addindex = 0;
+ for (Exprent expr : lst) {
+ if (setDefinition(expr, index)) {
+ defset = true;
+ break;
+ }
+ else {
+ boolean foundvar = false;
+ for (Exprent exp : expr.getAllExprents(true)) {
+ if (exp.type == Exprent.EXPRENT_VAR && ((VarExprent)exp).getIndex() == index) {
+ foundvar = true;
+ break;
+ }
+ }
+ if (foundvar) {
+ break;
+ }
+ }
+ addindex++;
+ }
+
+ if (!defset) {
+ VarExprent var = new VarExprent(index.intValue(), varproc.getVarType(new VarVersionPaar(index.intValue(), 0)), varproc);
+ var.setDefinition(true);
+
+ lst.add(addindex, var);
+ }
+ }
+ }
+
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private Statement findFirstBlock(Statement stat, Integer varindex) {
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(stat);
+
+ while (!stack.isEmpty()) {
+ Statement st = stack.remove(0);
+
+ if (stack.isEmpty() || mapStatementVars.get(st.id).contains(varindex)) {
+
+ if (st.isLabeled() && !stack.isEmpty()) {
+ return st;
+ }
+
+ if (st.getExprents() != null) {
+ return st;
+ }
+ else {
+ stack.clear();
+
+ switch (st.type) {
+ case Statement.TYPE_SEQUENCE:
+ stack.addAll(0, st.getStats());
+ break;
+ case Statement.TYPE_IF:
+ case Statement.TYPE_ROOT:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ stack.add(st.getFirst());
+ break;
+ default:
+ return st;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private Set<Integer> initStatement(Statement stat) {
+
+ HashMap<Integer, Integer> mapCount = new HashMap<Integer, Integer>();
+
+ List<VarExprent> condlst;
+
+ if (stat.getExprents() == null) {
+
+ // recurse on children statements
+ List<Integer> childVars = new ArrayList<Integer>();
+ List<Exprent> currVars = new ArrayList<Exprent>();
+
+ for (Object obj : stat.getSequentialObjects()) {
+ if (obj instanceof Statement) {
+ Statement st = (Statement)obj;
+ childVars.addAll(initStatement(st));
+
+ if (st.type == DoStatement.TYPE_DO) {
+ DoStatement dost = (DoStatement)st;
+ if (dost.getLooptype() != DoStatement.LOOP_FOR &&
+ dost.getLooptype() != DoStatement.LOOP_DO) {
+ currVars.add(dost.getConditionExprent());
+ }
+ }
+ else if (st.type == DoStatement.TYPE_CATCHALL) {
+ CatchAllStatement fin = (CatchAllStatement)st;
+ if (fin.isFinally() && fin.getMonitor() != null) {
+ currVars.add(fin.getMonitor());
+ }
+ }
+ }
+ else if (obj instanceof Exprent) {
+ currVars.add((Exprent)obj);
+ }
+ }
+
+ // children statements
+ for (Integer index : childVars) {
+ Integer count = mapCount.get(index);
+ if (count == null) {
+ count = new Integer(0);
+ }
+ mapCount.put(index, new Integer(count.intValue() + 1));
+ }
+
+ condlst = getAllVars(currVars);
+ }
+ else {
+ condlst = getAllVars(stat.getExprents());
+ }
+
+ // this statement
+ for (VarExprent var : condlst) {
+ mapCount.put(new Integer(var.getIndex()), new Integer(2));
+ }
+
+
+ HashSet<Integer> set = new HashSet<Integer>(mapCount.keySet());
+
+ // put all variables defined in this statement into the set
+ Iterator<Entry<Integer, Integer>> itMult = mapCount.entrySet().iterator();
+ while (itMult.hasNext()) {
+ Entry<Integer, Integer> en = itMult.next();
+ if (en.getValue().intValue() > 1) {
+ mapVarDefStatements.put(en.getKey(), stat);
+ }
+ }
+
+ mapStatementVars.put(stat.id, set);
+
+ return set;
+ }
+
+ private List<VarExprent> getAllVars(List<Exprent> lst) {
+
+ List<VarExprent> res = new ArrayList<VarExprent>();
+ List<Exprent> listTemp = new ArrayList<Exprent>();
+
+ for (Exprent expr : lst) {
+ listTemp.addAll(expr.getAllExprents(true));
+ listTemp.add(expr);
+ }
+
+ for (Exprent exprent : listTemp) {
+ if (exprent.type == Exprent.EXPRENT_VAR) {
+ res.add((VarExprent)exprent);
+ }
+ }
+
+ return res;
+ }
+ private boolean setDefinition(Exprent expr, Integer index) {
+ if (expr.type == Exprent.EXPRENT_ASSIGNMENT) {
+ Exprent left = ((AssignmentExprent)expr).getLeft();
+ if (left.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)left;
+ if (var.getIndex() == index.intValue()) {
+ var.setDefinition(true);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java
index 6af5720..5783ea7 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java
@@ -1,27 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.vars;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
@@ -29,107 +22,109 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.gen.VarType;
+import java.util.*;
+import java.util.Map.Entry;
+
public class VarProcessor {
- private HashMap<VarVersionPaar, String> mapVarNames = new HashMap<VarVersionPaar, String>();
-
- private VarVersionsProcessor varvers;
-
- private HashMap<VarVersionPaar, String> thisvars = new HashMap<VarVersionPaar, String>();
-
- private HashSet<VarVersionPaar> externvars = new HashSet<VarVersionPaar>();
-
- public void setVarVersions(RootStatement root) {
-
- varvers = new VarVersionsProcessor();
- varvers.setVarVersions(root);
- }
-
- public void setVarDefinitions(Statement root) {
- mapVarNames = new HashMap<VarVersionPaar, String>();
-
- VarDefinitionHelper defproc = new VarDefinitionHelper(root,
- (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD), this);
- defproc.setVarDefinitions();
- }
-
- public void setDebugVarNames(HashMap<Integer, String> mapDebugVarNames) {
-
- if(varvers == null) {
- return;
- }
-
- HashMap<Integer, Integer> mapOriginalVarIndices = varvers.getMapOriginalVarIndices();
-
- List<VarVersionPaar> listVars = new ArrayList<VarVersionPaar>(mapVarNames.keySet());
- Collections.sort(listVars, new Comparator<VarVersionPaar>() {
- public int compare(VarVersionPaar o1, VarVersionPaar o2) {
- return o1.var>o2.var?1:(o1.var==o2.var?0:-1);
- }
- });
-
- HashMap<String, Integer> mapNames = new HashMap<String, Integer>();
-
- for(VarVersionPaar varpaar : listVars) {
- String name = mapVarNames.get(varpaar);
-
- Integer orindex = mapOriginalVarIndices.get(varpaar.var);
- if(orindex != null && mapDebugVarNames.containsKey(orindex)) {
- name = mapDebugVarNames.get(orindex);
- }
-
- Integer counter = mapNames.get(name);
- mapNames.put(name, counter==null?counter = new Integer(0):++counter);
-
- if(counter > 0) {
- name+=String.valueOf(counter);
- }
-
- mapVarNames.put(varpaar, name);
- }
-
- }
-
- public void refreshVarNames(VarNamesCollector vc) {
-
- HashMap<VarVersionPaar, String> tempVarNames = new HashMap<VarVersionPaar, String>(mapVarNames);
- for(Entry<VarVersionPaar, String> ent: tempVarNames.entrySet()) {
- mapVarNames.put(ent.getKey(), vc.getFreeName(ent.getValue()));
- }
- }
-
-
- public VarType getVarType(VarVersionPaar varpaar) {
- return varvers==null?null:varvers.getVarType(varpaar);
- }
-
- public void setVarType(VarVersionPaar varpaar, VarType type) {
- varvers.setVarType(varpaar, type);
- }
-
- public String getVarName(VarVersionPaar varpaar) {
- return mapVarNames==null?null:mapVarNames.get(varpaar);
- }
-
- public void setVarName(VarVersionPaar varpaar, String name) {
- mapVarNames.put(varpaar, name);
- }
-
- public int getVarFinal(VarVersionPaar varpaar) {
- return varvers==null?VarTypeProcessor.VAR_FINAL:varvers.getVarFinal(varpaar);
- }
-
- public void setVarFinal(VarVersionPaar varpaar, int finaltype) {
- varvers.setVarFinal(varpaar, finaltype);
- }
-
- public HashMap<VarVersionPaar, String> getThisvars() {
- return thisvars;
- }
-
- public HashSet<VarVersionPaar> getExternvars() {
- return externvars;
- }
+ private HashMap<VarVersionPaar, String> mapVarNames = new HashMap<VarVersionPaar, String>();
+
+ private VarVersionsProcessor varvers;
+
+ private HashMap<VarVersionPaar, String> thisvars = new HashMap<VarVersionPaar, String>();
+
+ private HashSet<VarVersionPaar> externvars = new HashSet<VarVersionPaar>();
+
+ public void setVarVersions(RootStatement root) {
+
+ varvers = new VarVersionsProcessor();
+ varvers.setVarVersions(root);
+ }
+
+ public void setVarDefinitions(Statement root) {
+ mapVarNames = new HashMap<VarVersionPaar, String>();
+
+ VarDefinitionHelper defproc = new VarDefinitionHelper(root,
+ (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD),
+ this);
+ defproc.setVarDefinitions();
+ }
+
+ public void setDebugVarNames(HashMap<Integer, String> mapDebugVarNames) {
+
+ if (varvers == null) {
+ return;
+ }
+
+ HashMap<Integer, Integer> mapOriginalVarIndices = varvers.getMapOriginalVarIndices();
+
+ List<VarVersionPaar> listVars = new ArrayList<VarVersionPaar>(mapVarNames.keySet());
+ Collections.sort(listVars, new Comparator<VarVersionPaar>() {
+ public int compare(VarVersionPaar o1, VarVersionPaar o2) {
+ return o1.var > o2.var ? 1 : (o1.var == o2.var ? 0 : -1);
+ }
+ });
+
+ HashMap<String, Integer> mapNames = new HashMap<String, Integer>();
+
+ for (VarVersionPaar varpaar : listVars) {
+ String name = mapVarNames.get(varpaar);
+
+ Integer orindex = mapOriginalVarIndices.get(varpaar.var);
+ if (orindex != null && mapDebugVarNames.containsKey(orindex)) {
+ name = mapDebugVarNames.get(orindex);
+ }
+
+ Integer counter = mapNames.get(name);
+ mapNames.put(name, counter == null ? counter = new Integer(0) : ++counter);
+
+ if (counter > 0) {
+ name += String.valueOf(counter);
+ }
+
+ mapVarNames.put(varpaar, name);
+ }
+ }
+
+ public void refreshVarNames(VarNamesCollector vc) {
+
+ HashMap<VarVersionPaar, String> tempVarNames = new HashMap<VarVersionPaar, String>(mapVarNames);
+ for (Entry<VarVersionPaar, String> ent : tempVarNames.entrySet()) {
+ mapVarNames.put(ent.getKey(), vc.getFreeName(ent.getValue()));
+ }
+ }
+
+
+ public VarType getVarType(VarVersionPaar varpaar) {
+ return varvers == null ? null : varvers.getVarType(varpaar);
+ }
+
+ public void setVarType(VarVersionPaar varpaar, VarType type) {
+ varvers.setVarType(varpaar, type);
+ }
+
+ public String getVarName(VarVersionPaar varpaar) {
+ return mapVarNames == null ? null : mapVarNames.get(varpaar);
+ }
+
+ public void setVarName(VarVersionPaar varpaar, String name) {
+ mapVarNames.put(varpaar, name);
+ }
+
+ public int getVarFinal(VarVersionPaar varpaar) {
+ return varvers == null ? VarTypeProcessor.VAR_FINAL : varvers.getVarFinal(varpaar);
+ }
+
+ public void setVarFinal(VarVersionPaar varpaar, int finaltype) {
+ varvers.setVarFinal(varpaar, finaltype);
+ }
+
+ public HashMap<VarVersionPaar, String> getThisvars() {
+ return thisvars;
+ }
+ public HashSet<VarVersionPaar> getExternvars() {
+ return externvars;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java
index 3e2e2b3..8792f3e 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java
@@ -1,30 +1,23 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.vars;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
@@ -35,239 +28,251 @@ import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
public class VarTypeProcessor {
-
- public static final int VAR_NONFINAL = 1;
- public static final int VAR_FINALEXPLICIT = 2;
- public static final int VAR_FINAL = 3;
-
- private HashMap<VarVersionPaar, VarType> mapExprentMinTypes = new HashMap<VarVersionPaar, VarType>();
-
- private HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = new HashMap<VarVersionPaar, VarType>();
-
- private HashMap<VarVersionPaar, Integer> mapFinalVars = new HashMap<VarVersionPaar, Integer>();
-
- private void setInitVars(RootStatement root) {
-
- StructMethod mt = (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD);
-
- // method descriptor
- boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
-
- MethodDescriptor md = (MethodDescriptor)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR);
-
- if(thisvar) {
- VarType cltype = new VarType(CodeConstants.TYPE_OBJECT, 0,
- ((StructClass)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS)).qualifiedName);
- mapExprentMinTypes.put(new VarVersionPaar(0,1), cltype);
- mapExprentMaxTypes.put(new VarVersionPaar(0,1), cltype);
- }
-
- int varindex = 0;
- for(int i=0;i<md.params.length;i++) {
- mapExprentMinTypes.put(new VarVersionPaar(varindex+(thisvar?1:0), 1), md.params[i]);
- mapExprentMaxTypes.put(new VarVersionPaar(varindex+(thisvar?1:0), 1), md.params[i]);
- varindex+=md.params[i].stack_size;
- }
-
- // catch variables
- LinkedList<Statement> stack = new LinkedList<Statement>();
- stack.add(root);
-
- while(!stack.isEmpty()) {
- Statement stat = stack.removeFirst();
-
- List<VarExprent> lstVars = null;
- if(stat.type == Statement.TYPE_CATCHALL) {
- lstVars = ((CatchAllStatement)stat).getVars();
- } else if(stat.type == Statement.TYPE_TRYCATCH) {
- lstVars = ((CatchStatement)stat).getVars();
- }
-
- if(lstVars != null) {
- for(VarExprent var: lstVars) {
- mapExprentMinTypes.put(new VarVersionPaar(var.getIndex(), 1), var.getVartype());
- mapExprentMaxTypes.put(new VarVersionPaar(var.getIndex(), 1), var.getVartype());
- }
- }
-
- stack.addAll(stat.getStats());
- }
- }
-
- public void calculateVarTypes(RootStatement root, DirectGraph dgraph) {
-
- setInitVars(root);
-
- resetExprentTypes(dgraph);
-
- while(!processVarTypes(dgraph));
- }
-
- private void resetExprentTypes(DirectGraph dgraph) {
-
- dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
- public int processExprent(Exprent exprent) {
- List<Exprent> lst = exprent.getAllExprents(true);
- lst.add(exprent);
-
- for(Exprent expr: lst) {
- if(expr.type == Exprent.EXPRENT_VAR) {
- ((VarExprent)expr).setVartype(VarType.VARTYPE_UNKNOWN);
- } else if(expr.type == Exprent.EXPRENT_CONST) {
- ConstExprent cexpr = (ConstExprent)expr;
- if(cexpr.getConsttype().type_family == CodeConstants.TYPE_FAMILY_INTEGER) {
- cexpr.setConsttype(new ConstExprent(cexpr.getIntValue(), cexpr.isBoolPermitted()).getConsttype());
- }
- }
- }
- return 0;
- }
- });
- }
-
- private boolean processVarTypes(DirectGraph dgraph) {
-
- return dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
- public int processExprent(Exprent exprent) {
- return checkTypeExprent(exprent)?0:1;
- }
- });
- }
-
-
- private boolean checkTypeExprent(Exprent exprent) {
-
- for(Exprent expr: exprent.getAllExprents()) {
- if(!checkTypeExprent(expr)) {
- return false;
- }
- }
-
- if(exprent.type == Exprent.EXPRENT_CONST) {
- ConstExprent cexpr = (ConstExprent)exprent;
- if(cexpr.getConsttype().type_family <= CodeConstants.TYPE_FAMILY_INTEGER) { // boolean or integer
- VarVersionPaar cpaar = new VarVersionPaar(cexpr.id, -1);
- if(!mapExprentMinTypes.containsKey(cpaar)) {
- mapExprentMinTypes.put(cpaar, cexpr.getConsttype());
- }
- }
- }
-
- CheckTypesResult result = exprent.checkExprTypeBounds();
-
- for(CheckTypesResult.ExprentTypePair entry: result.getLstMaxTypeExprents()) {
- if(entry.type.type_family != CodeConstants.TYPE_FAMILY_OBJECT) {
- changeExprentType(entry.exprent, entry.type, 1);
- }
- }
-
- boolean res = true;
- for(CheckTypesResult.ExprentTypePair entry: result.getLstMinTypeExprents()) {
- res &= changeExprentType(entry.exprent, entry.type, 0);
- }
-
- return res;
- }
-
-
- private boolean changeExprentType(Exprent exprent, VarType newtype, int minmax) {
-
- boolean res = true;
-
- switch(exprent.type) {
- case Exprent.EXPRENT_CONST:
- ConstExprent cexpr = (ConstExprent)exprent;
- VarType consttype = cexpr.getConsttype();
-
- if(newtype.type_family > CodeConstants.TYPE_FAMILY_INTEGER || consttype.type_family > CodeConstants.TYPE_FAMILY_INTEGER) {
- return true;
- } else if(newtype.type_family == CodeConstants.TYPE_FAMILY_INTEGER) {
- VarType mininteger = new ConstExprent((Integer)((ConstExprent)exprent).getValue(), false).getConsttype();
- if(mininteger.isStrictSuperset(newtype)) {
- newtype = mininteger;
- }
- }
- case Exprent.EXPRENT_VAR:
- VarVersionPaar varpaar = null;
- if(exprent.type == Exprent.EXPRENT_CONST) {
- varpaar = new VarVersionPaar(((ConstExprent)exprent).id, -1);
- } else if(exprent.type == Exprent.EXPRENT_VAR) {
- varpaar = new VarVersionPaar((VarExprent)exprent);
- }
-
- if(minmax == 0) { // min
- VarType currentMinType = mapExprentMinTypes.get(varpaar);
- VarType newMinType;
- if(currentMinType==null || newtype.type_family > currentMinType.type_family) {
- newMinType = newtype;
- } else if(newtype.type_family < currentMinType.type_family) {
- return true;
- } else {
- newMinType = VarType.getCommonSupertype(currentMinType, newtype);
- }
-
- mapExprentMinTypes.put(varpaar, newMinType);
- if(exprent.type == Exprent.EXPRENT_CONST) {
- ((ConstExprent)exprent).setConsttype(newMinType);
- }
-
- if(currentMinType != null && (newMinType.type_family > currentMinType.type_family ||
- newMinType.isStrictSuperset(currentMinType))) {
- return false;
- }
- } else { // max
- VarType currentMaxType = mapExprentMaxTypes.get(varpaar);
- VarType newMaxType;
- if(currentMaxType==null || newtype.type_family < currentMaxType.type_family) {
- newMaxType = newtype;
- } else if(newtype.type_family > currentMaxType.type_family) {
- return true;
- } else {
- newMaxType = VarType.getCommonMinType(currentMaxType, newtype);
- }
-
- mapExprentMaxTypes.put(varpaar, newMaxType);
- }
- break;
- case Exprent.EXPRENT_ASSIGNMENT:
- return changeExprentType(((AssignmentExprent)exprent).getRight(), newtype, minmax);
- case Exprent.EXPRENT_FUNCTION:
- FunctionExprent func = (FunctionExprent)exprent;
- switch(func.getFunctype()){
- case FunctionExprent.FUNCTION_IIF: // FIXME:
- res &= changeExprentType(func.getLstOperands().get(1), newtype, minmax);
- res &= changeExprentType(func.getLstOperands().get(2), newtype, minmax);
- break;
- case FunctionExprent.FUNCTION_AND:
- case FunctionExprent.FUNCTION_OR:
- case FunctionExprent.FUNCTION_XOR:
- res &= changeExprentType(func.getLstOperands().get(0), newtype, minmax);
- res &= changeExprentType(func.getLstOperands().get(1), newtype, minmax);
- }
- }
-
- return res;
- }
-
- public HashMap<VarVersionPaar, VarType> getMapExprentMaxTypes() {
- return mapExprentMaxTypes;
- }
-
- public HashMap<VarVersionPaar, VarType> getMapExprentMinTypes() {
- return mapExprentMinTypes;
- }
-
- public HashMap<VarVersionPaar, Integer> getMapFinalVars() {
- return mapFinalVars;
- }
-
- public void setVarType(VarVersionPaar varpaar, VarType type) {
- mapExprentMinTypes.put(varpaar, type);
- }
-
- public VarType getVarType(VarVersionPaar varpaar) {
- return mapExprentMinTypes.get(varpaar);
- }
+ public static final int VAR_NONFINAL = 1;
+ public static final int VAR_FINALEXPLICIT = 2;
+ public static final int VAR_FINAL = 3;
+
+ private HashMap<VarVersionPaar, VarType> mapExprentMinTypes = new HashMap<VarVersionPaar, VarType>();
+
+ private HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = new HashMap<VarVersionPaar, VarType>();
+
+ private HashMap<VarVersionPaar, Integer> mapFinalVars = new HashMap<VarVersionPaar, Integer>();
+
+ private void setInitVars(RootStatement root) {
+
+ StructMethod mt = (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD);
+
+ // method descriptor
+ boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
+
+ MethodDescriptor md = (MethodDescriptor)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR);
+
+ if (thisvar) {
+ VarType cltype = new VarType(CodeConstants.TYPE_OBJECT, 0,
+ ((StructClass)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS)).qualifiedName);
+ mapExprentMinTypes.put(new VarVersionPaar(0, 1), cltype);
+ mapExprentMaxTypes.put(new VarVersionPaar(0, 1), cltype);
+ }
+
+ int varindex = 0;
+ for (int i = 0; i < md.params.length; i++) {
+ mapExprentMinTypes.put(new VarVersionPaar(varindex + (thisvar ? 1 : 0), 1), md.params[i]);
+ mapExprentMaxTypes.put(new VarVersionPaar(varindex + (thisvar ? 1 : 0), 1), md.params[i]);
+ varindex += md.params[i].stack_size;
+ }
+
+ // catch variables
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+ Statement stat = stack.removeFirst();
+
+ List<VarExprent> lstVars = null;
+ if (stat.type == Statement.TYPE_CATCHALL) {
+ lstVars = ((CatchAllStatement)stat).getVars();
+ }
+ else if (stat.type == Statement.TYPE_TRYCATCH) {
+ lstVars = ((CatchStatement)stat).getVars();
+ }
+
+ if (lstVars != null) {
+ for (VarExprent var : lstVars) {
+ mapExprentMinTypes.put(new VarVersionPaar(var.getIndex(), 1), var.getVartype());
+ mapExprentMaxTypes.put(new VarVersionPaar(var.getIndex(), 1), var.getVartype());
+ }
+ }
+
+ stack.addAll(stat.getStats());
+ }
+ }
+
+ public void calculateVarTypes(RootStatement root, DirectGraph dgraph) {
+
+ setInitVars(root);
+
+ resetExprentTypes(dgraph);
+
+ while (!processVarTypes(dgraph)) ;
+ }
+
+ private void resetExprentTypes(DirectGraph dgraph) {
+
+ dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ ((VarExprent)expr).setVartype(VarType.VARTYPE_UNKNOWN);
+ }
+ else if (expr.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cexpr = (ConstExprent)expr;
+ if (cexpr.getConsttype().type_family == CodeConstants.TYPE_FAMILY_INTEGER) {
+ cexpr.setConsttype(new ConstExprent(cexpr.getIntValue(), cexpr.isBoolPermitted()).getConsttype());
+ }
+ }
+ }
+ return 0;
+ }
+ });
+ }
+
+ private boolean processVarTypes(DirectGraph dgraph) {
+
+ return dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ return checkTypeExprent(exprent) ? 0 : 1;
+ }
+ });
+ }
+
+
+ private boolean checkTypeExprent(Exprent exprent) {
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ if (!checkTypeExprent(expr)) {
+ return false;
+ }
+ }
+
+ if (exprent.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cexpr = (ConstExprent)exprent;
+ if (cexpr.getConsttype().type_family <= CodeConstants.TYPE_FAMILY_INTEGER) { // boolean or integer
+ VarVersionPaar cpaar = new VarVersionPaar(cexpr.id, -1);
+ if (!mapExprentMinTypes.containsKey(cpaar)) {
+ mapExprentMinTypes.put(cpaar, cexpr.getConsttype());
+ }
+ }
+ }
+
+ CheckTypesResult result = exprent.checkExprTypeBounds();
+
+ for (CheckTypesResult.ExprentTypePair entry : result.getLstMaxTypeExprents()) {
+ if (entry.type.type_family != CodeConstants.TYPE_FAMILY_OBJECT) {
+ changeExprentType(entry.exprent, entry.type, 1);
+ }
+ }
+
+ boolean res = true;
+ for (CheckTypesResult.ExprentTypePair entry : result.getLstMinTypeExprents()) {
+ res &= changeExprentType(entry.exprent, entry.type, 0);
+ }
+
+ return res;
+ }
+
+
+ private boolean changeExprentType(Exprent exprent, VarType newtype, int minmax) {
+
+ boolean res = true;
+
+ switch (exprent.type) {
+ case Exprent.EXPRENT_CONST:
+ ConstExprent cexpr = (ConstExprent)exprent;
+ VarType consttype = cexpr.getConsttype();
+
+ if (newtype.type_family > CodeConstants.TYPE_FAMILY_INTEGER || consttype.type_family > CodeConstants.TYPE_FAMILY_INTEGER) {
+ return true;
+ }
+ else if (newtype.type_family == CodeConstants.TYPE_FAMILY_INTEGER) {
+ VarType mininteger = new ConstExprent((Integer)((ConstExprent)exprent).getValue(), false).getConsttype();
+ if (mininteger.isStrictSuperset(newtype)) {
+ newtype = mininteger;
+ }
+ }
+ case Exprent.EXPRENT_VAR:
+ VarVersionPaar varpaar = null;
+ if (exprent.type == Exprent.EXPRENT_CONST) {
+ varpaar = new VarVersionPaar(((ConstExprent)exprent).id, -1);
+ }
+ else if (exprent.type == Exprent.EXPRENT_VAR) {
+ varpaar = new VarVersionPaar((VarExprent)exprent);
+ }
+
+ if (minmax == 0) { // min
+ VarType currentMinType = mapExprentMinTypes.get(varpaar);
+ VarType newMinType;
+ if (currentMinType == null || newtype.type_family > currentMinType.type_family) {
+ newMinType = newtype;
+ }
+ else if (newtype.type_family < currentMinType.type_family) {
+ return true;
+ }
+ else {
+ newMinType = VarType.getCommonSupertype(currentMinType, newtype);
+ }
+
+ mapExprentMinTypes.put(varpaar, newMinType);
+ if (exprent.type == Exprent.EXPRENT_CONST) {
+ ((ConstExprent)exprent).setConsttype(newMinType);
+ }
+
+ if (currentMinType != null && (newMinType.type_family > currentMinType.type_family ||
+ newMinType.isStrictSuperset(currentMinType))) {
+ return false;
+ }
+ }
+ else { // max
+ VarType currentMaxType = mapExprentMaxTypes.get(varpaar);
+ VarType newMaxType;
+ if (currentMaxType == null || newtype.type_family < currentMaxType.type_family) {
+ newMaxType = newtype;
+ }
+ else if (newtype.type_family > currentMaxType.type_family) {
+ return true;
+ }
+ else {
+ newMaxType = VarType.getCommonMinType(currentMaxType, newtype);
+ }
+
+ mapExprentMaxTypes.put(varpaar, newMaxType);
+ }
+ break;
+ case Exprent.EXPRENT_ASSIGNMENT:
+ return changeExprentType(((AssignmentExprent)exprent).getRight(), newtype, minmax);
+ case Exprent.EXPRENT_FUNCTION:
+ FunctionExprent func = (FunctionExprent)exprent;
+ switch (func.getFunctype()) {
+ case FunctionExprent.FUNCTION_IIF: // FIXME:
+ res &= changeExprentType(func.getLstOperands().get(1), newtype, minmax);
+ res &= changeExprentType(func.getLstOperands().get(2), newtype, minmax);
+ break;
+ case FunctionExprent.FUNCTION_AND:
+ case FunctionExprent.FUNCTION_OR:
+ case FunctionExprent.FUNCTION_XOR:
+ res &= changeExprentType(func.getLstOperands().get(0), newtype, minmax);
+ res &= changeExprentType(func.getLstOperands().get(1), newtype, minmax);
+ }
+ }
+
+ return res;
+ }
+
+ public HashMap<VarVersionPaar, VarType> getMapExprentMaxTypes() {
+ return mapExprentMaxTypes;
+ }
+
+ public HashMap<VarVersionPaar, VarType> getMapExprentMinTypes() {
+ return mapExprentMinTypes;
+ }
+
+ public HashMap<VarVersionPaar, Integer> getMapFinalVars() {
+ return mapFinalVars;
+ }
+
+ public void setVarType(VarVersionPaar varpaar, VarType type) {
+ mapExprentMinTypes.put(varpaar, type);
+ }
+
+ public VarType getVarType(VarVersionPaar varpaar) {
+ return mapExprentMinTypes.get(varpaar);
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionEdge.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionEdge.java
index cac86ef..9d97982 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionEdge.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionEdge.java
@@ -1,56 +1,56 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.vars;
public class VarVersionEdge { // FIXME: can be removed?
- public static final int EDGE_GENERAL = 0;
- public static final int EDGE_PHANTOM = 1;
-
- public int type;
-
- public VarVersionNode source;
-
- public VarVersionNode dest;
-
- private int hashCode;
-
- public VarVersionEdge(int type, VarVersionNode source, VarVersionNode dest) {
- this.type = type;
- this.source = source;
- this.dest = dest;
- this.hashCode = source.hashCode() ^ dest.hashCode() + type;
- }
-
- @Override
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof VarVersionEdge)) return false;
-
- VarVersionEdge edge = (VarVersionEdge)o;
- return type == edge.type && source == edge.source && dest == edge.dest;
- }
-
- @Override
- public int hashCode() {
- return hashCode;
- }
-
- @Override
- public String toString() {
- return source.toString() + " ->" + type + "-> " + dest.toString();
- }
-
+ public static final int EDGE_GENERAL = 0;
+ public static final int EDGE_PHANTOM = 1;
+
+ public int type;
+
+ public VarVersionNode source;
+
+ public VarVersionNode dest;
+
+ private int hashCode;
+
+ public VarVersionEdge(int type, VarVersionNode source, VarVersionNode dest) {
+ this.type = type;
+ this.source = source;
+ this.dest = dest;
+ this.hashCode = source.hashCode() ^ dest.hashCode() + type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof VarVersionEdge)) return false;
+
+ VarVersionEdge edge = (VarVersionEdge)o;
+ return type == edge.type && source == edge.source && dest == edge.dest;
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ return source.toString() + " ->" + type + "-> " + dest.toString();
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionNode.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionNode.java
index 7e2b69b..587c653 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionNode.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionNode.java
@@ -1,80 +1,80 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.vars;
+import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
+import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
-import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
-
public class VarVersionNode implements IGraphNode {
-
- public static final int FLAG_PHANTOM_FINEXIT = 2;
-
- public int var;
-
- public int version;
-
- public Set<VarVersionEdge> succs = new HashSet<VarVersionEdge>();
-
- public Set<VarVersionEdge> preds = new HashSet<VarVersionEdge>();
-
- public int flags;
-
- public SFormsFastMapDirect live = new SFormsFastMapDirect();
-
-
- public VarVersionNode(int var, int version) {
- this.var = var;
- this.version = version;
- }
-
- public VarVersionPaar getVarPaar() {
- return new VarVersionPaar(var, version);
- }
-
- public List<IGraphNode> getPredecessors() {
- List<IGraphNode> lst = new ArrayList<IGraphNode>(preds.size());
- for(VarVersionEdge edge : preds) {
- lst.add(edge.source);
- }
- return lst;
- }
-
- public void removeSuccessor(VarVersionEdge edge) {
- succs.remove(edge);
- }
-
- public void removePredecessor(VarVersionEdge edge) {
- preds.remove(edge);
- }
-
- public void addSuccessor(VarVersionEdge edge) {
- succs.add(edge);
- }
-
- public void addPredecessor(VarVersionEdge edge) {
- preds.add(edge);
- }
-
- @Override
- public String toString() {
- return "("+var+"_"+version+")";
- }
-
+
+ public static final int FLAG_PHANTOM_FINEXIT = 2;
+
+ public int var;
+
+ public int version;
+
+ public Set<VarVersionEdge> succs = new HashSet<VarVersionEdge>();
+
+ public Set<VarVersionEdge> preds = new HashSet<VarVersionEdge>();
+
+ public int flags;
+
+ public SFormsFastMapDirect live = new SFormsFastMapDirect();
+
+
+ public VarVersionNode(int var, int version) {
+ this.var = var;
+ this.version = version;
+ }
+
+ public VarVersionPaar getVarPaar() {
+ return new VarVersionPaar(var, version);
+ }
+
+ public List<IGraphNode> getPredecessors() {
+ List<IGraphNode> lst = new ArrayList<IGraphNode>(preds.size());
+ for (VarVersionEdge edge : preds) {
+ lst.add(edge.source);
+ }
+ return lst;
+ }
+
+ public void removeSuccessor(VarVersionEdge edge) {
+ succs.remove(edge);
+ }
+
+ public void removePredecessor(VarVersionEdge edge) {
+ preds.remove(edge);
+ }
+
+ public void addSuccessor(VarVersionEdge edge) {
+ succs.add(edge);
+ }
+
+ public void addPredecessor(VarVersionEdge edge) {
+ preds.add(edge);
+ }
+
+ @Override
+ public String toString() {
+ return "(" + var + "_" + version + ")";
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionPaar.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionPaar.java
index b9a3cec..5f3e520 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionPaar.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionPaar.java
@@ -1,65 +1,63 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.vars;
import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
public class VarVersionPaar {
- public int var;
- public int version;
-
- private int hashCode = -1;
-
- public VarVersionPaar(int var, int version) {
- this.var = var;
- this.version = version;
- }
-
- public VarVersionPaar(Integer var, Integer version) {
- this.var = var.intValue();
- this.version = version.intValue();
- }
-
- public VarVersionPaar(VarExprent var) {
- this.var = var.getIndex();
- this.version = var.getVersion();
- }
-
- @Override
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof VarVersionPaar)) return false;
-
- VarVersionPaar paar = (VarVersionPaar)o;
- return var == paar.var && version == paar.version;
- }
-
- @Override
- public int hashCode() {
- if(hashCode == -1) {
- hashCode = this.var * 3 + this.version;
- }
- return hashCode;
- }
-
- @Override
- public String toString() {
- return "("+var+","+version+")";
- }
-
-
-
+ public int var;
+ public int version;
+
+ private int hashCode = -1;
+
+ public VarVersionPaar(int var, int version) {
+ this.var = var;
+ this.version = version;
+ }
+
+ public VarVersionPaar(Integer var, Integer version) {
+ this.var = var.intValue();
+ this.version = version.intValue();
+ }
+
+ public VarVersionPaar(VarExprent var) {
+ this.var = var.getIndex();
+ this.version = var.getVersion();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof VarVersionPaar)) return false;
+
+ VarVersionPaar paar = (VarVersionPaar)o;
+ return var == paar.var && version == paar.version;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode == -1) {
+ hashCode = this.var * 3 + this.version;
+ }
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + var + "," + version + ")";
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java
index 2ad672b..ce05071 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java
@@ -1,172 +1,167 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.vars;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.modules.decompiler.decompose.GenericDominatorEngine;
import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraph;
import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.util.*;
+
public class VarVersionsGraph {
- public int counter = 0;
-
- public VBStyleCollection<VarVersionNode, VarVersionPaar> nodes = new VBStyleCollection<VarVersionNode, VarVersionPaar>();
-
- private GenericDominatorEngine engine;
-
- public VarVersionNode createNode(VarVersionPaar ver) {
- VarVersionNode node;
- nodes.addWithKey(node = new VarVersionNode(ver.var, ver.version), ver);
- return node;
- }
-
- public void addNodes(Collection<VarVersionNode> colnodes, Collection<VarVersionPaar> colpaars) {
- nodes.addAllWithKey(colnodes, colpaars);
- }
-
- public boolean isDominatorSet(VarVersionNode node, HashSet<VarVersionNode> domnodes) {
-
- if(domnodes.size() == 1) {
- return engine.isDominator(node, domnodes.iterator().next());
- } else {
-
- HashSet<VarVersionNode> marked = new HashSet<VarVersionNode>();
-
- if(domnodes.contains(node)) {
- return true;
- }
-
- LinkedList<VarVersionNode> lstNodes = new LinkedList<VarVersionNode>();
- lstNodes.add(node);
-
- while(!lstNodes.isEmpty()) {
-
- VarVersionNode nd = lstNodes.remove(0);
- if(marked.contains(nd)) {
- continue;
- } else {
- marked.add(nd);
- }
-
- if(nd.preds.isEmpty()) {
- return false;
- }
-
- for(VarVersionEdge edge: nd.preds) {
- VarVersionNode pred = edge.source;
- if(!marked.contains(pred) && !domnodes.contains(pred)) {
- lstNodes.add(pred);
- }
- }
- }
- }
-
- return true;
- }
-
- public void initDominators() {
-
- final HashSet<VarVersionNode> roots = new HashSet<VarVersionNode>();
-
- for(VarVersionNode node: nodes) {
- if(node.preds.isEmpty()) {
- roots.add(node);
- }
- }
-
- engine = new GenericDominatorEngine(new IGraph() {
- public List<? extends IGraphNode> getReversePostOrderList() {
- return getReversedPostOrder(roots);
- }
-
- public Set<? extends IGraphNode> getRoots() {
- return new HashSet<IGraphNode>(roots);
- }
- });
-
- engine.initialize();
- }
-
- private LinkedList<VarVersionNode> getReversedPostOrder(Collection<VarVersionNode> roots) {
-
- LinkedList<VarVersionNode> lst = new LinkedList<VarVersionNode>();
- HashSet<VarVersionNode> setVisited = new HashSet<VarVersionNode>();
-
- for(VarVersionNode root: roots) {
-
- LinkedList<VarVersionNode> lstTemp = new LinkedList<VarVersionNode>();
- addToReversePostOrderListIterative(root, lstTemp, setVisited);
-
- lst.addAll(lstTemp);
- }
-
- return lst;
- }
-
- private void addToReversePostOrderListIterative(VarVersionNode root, List<VarVersionNode> lst, HashSet<VarVersionNode> setVisited) {
-
- HashMap<VarVersionNode, List<VarVersionEdge>> mapNodeSuccs = new HashMap<VarVersionNode, List<VarVersionEdge>>();
-
- LinkedList<VarVersionNode> stackNode = new LinkedList<VarVersionNode>();
- LinkedList<Integer> stackIndex = new LinkedList<Integer>();
-
- stackNode.add(root);
- stackIndex.add(0);
-
- while(!stackNode.isEmpty()) {
-
- VarVersionNode node = stackNode.getLast();
- int index = stackIndex.removeLast();
-
- setVisited.add(node);
-
- List<VarVersionEdge> lstSuccs = mapNodeSuccs.get(node);
- if(lstSuccs == null) {
- mapNodeSuccs.put(node, lstSuccs = new ArrayList<VarVersionEdge>(node.succs));
- }
-
- for(;index<lstSuccs.size();index++) {
- VarVersionNode succ = lstSuccs.get(index).dest;
-
- if(!setVisited.contains(succ)) {
- stackIndex.add(index+1);
-
- stackNode.add(succ);
- stackIndex.add(0);
-
- break;
- }
- }
-
- if(index == lstSuccs.size()) {
- lst.add(0, node);
-
- stackNode.removeLast();
- }
- }
-
- }
-
+ public int counter = 0;
+
+ public VBStyleCollection<VarVersionNode, VarVersionPaar> nodes = new VBStyleCollection<VarVersionNode, VarVersionPaar>();
+
+ private GenericDominatorEngine engine;
+
+ public VarVersionNode createNode(VarVersionPaar ver) {
+ VarVersionNode node;
+ nodes.addWithKey(node = new VarVersionNode(ver.var, ver.version), ver);
+ return node;
+ }
+
+ public void addNodes(Collection<VarVersionNode> colnodes, Collection<VarVersionPaar> colpaars) {
+ nodes.addAllWithKey(colnodes, colpaars);
+ }
+
+ public boolean isDominatorSet(VarVersionNode node, HashSet<VarVersionNode> domnodes) {
+
+ if (domnodes.size() == 1) {
+ return engine.isDominator(node, domnodes.iterator().next());
+ }
+ else {
+
+ HashSet<VarVersionNode> marked = new HashSet<VarVersionNode>();
+
+ if (domnodes.contains(node)) {
+ return true;
+ }
+
+ LinkedList<VarVersionNode> lstNodes = new LinkedList<VarVersionNode>();
+ lstNodes.add(node);
+
+ while (!lstNodes.isEmpty()) {
+
+ VarVersionNode nd = lstNodes.remove(0);
+ if (marked.contains(nd)) {
+ continue;
+ }
+ else {
+ marked.add(nd);
+ }
+
+ if (nd.preds.isEmpty()) {
+ return false;
+ }
+
+ for (VarVersionEdge edge : nd.preds) {
+ VarVersionNode pred = edge.source;
+ if (!marked.contains(pred) && !domnodes.contains(pred)) {
+ lstNodes.add(pred);
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public void initDominators() {
+
+ final HashSet<VarVersionNode> roots = new HashSet<VarVersionNode>();
+
+ for (VarVersionNode node : nodes) {
+ if (node.preds.isEmpty()) {
+ roots.add(node);
+ }
+ }
+
+ engine = new GenericDominatorEngine(new IGraph() {
+ public List<? extends IGraphNode> getReversePostOrderList() {
+ return getReversedPostOrder(roots);
+ }
+
+ public Set<? extends IGraphNode> getRoots() {
+ return new HashSet<IGraphNode>(roots);
+ }
+ });
+
+ engine.initialize();
+ }
+
+ private LinkedList<VarVersionNode> getReversedPostOrder(Collection<VarVersionNode> roots) {
+
+ LinkedList<VarVersionNode> lst = new LinkedList<VarVersionNode>();
+ HashSet<VarVersionNode> setVisited = new HashSet<VarVersionNode>();
+
+ for (VarVersionNode root : roots) {
+
+ LinkedList<VarVersionNode> lstTemp = new LinkedList<VarVersionNode>();
+ addToReversePostOrderListIterative(root, lstTemp, setVisited);
+
+ lst.addAll(lstTemp);
+ }
+
+ return lst;
+ }
+
+ private void addToReversePostOrderListIterative(VarVersionNode root, List<VarVersionNode> lst, HashSet<VarVersionNode> setVisited) {
+
+ HashMap<VarVersionNode, List<VarVersionEdge>> mapNodeSuccs = new HashMap<VarVersionNode, List<VarVersionEdge>>();
+
+ LinkedList<VarVersionNode> stackNode = new LinkedList<VarVersionNode>();
+ LinkedList<Integer> stackIndex = new LinkedList<Integer>();
+
+ stackNode.add(root);
+ stackIndex.add(0);
+
+ while (!stackNode.isEmpty()) {
+
+ VarVersionNode node = stackNode.getLast();
+ int index = stackIndex.removeLast();
+
+ setVisited.add(node);
+
+ List<VarVersionEdge> lstSuccs = mapNodeSuccs.get(node);
+ if (lstSuccs == null) {
+ mapNodeSuccs.put(node, lstSuccs = new ArrayList<VarVersionEdge>(node.succs));
+ }
+
+ for (; index < lstSuccs.size(); index++) {
+ VarVersionNode succ = lstSuccs.get(index).dest;
+
+ if (!setVisited.contains(succ)) {
+ stackIndex.add(index + 1);
+
+ stackNode.add(succ);
+ stackIndex.add(0);
+
+ break;
+ }
+ }
+
+ if (index == lstSuccs.size()) {
+ lst.add(0, node);
+
+ stackNode.removeLast();
+ }
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java
index 5e2adca..4093992 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java
@@ -1,26 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.modules.decompiler.vars;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
@@ -35,306 +29,306 @@ import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+import java.util.*;
+import java.util.Map.Entry;
+
public class VarVersionsProcessor {
-
- private HashMap<Integer, Integer> mapOriginalVarIndices = new HashMap<Integer, Integer>();
-
- private VarTypeProcessor typeproc;
-
- public void setVarVersions(RootStatement root) {
-
- StructMethod mt = (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD);
-
- SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
- ssa.splitVariables(root, mt);
-
- FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
- DirectGraph dgraph = flatthelper.buildDirectGraph(root);
-
-// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
-
- mergePhiVersions(ssa, dgraph);
-
-// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
-
- typeproc = new VarTypeProcessor();
- typeproc.calculateVarTypes(root, dgraph);
-
- simpleMerge(typeproc, dgraph, mt);
-
- // FIXME: advanced merging
-
- eliminateNonJavaTypes(typeproc);
-
- setNewVarIndices(typeproc, dgraph);
- }
-
- private void mergePhiVersions(SSAConstructorSparseEx ssa, DirectGraph dgraph) {
-
- // collect phi versions
- List<HashSet<VarVersionPaar>> lst = new ArrayList<HashSet<VarVersionPaar>>();
- for(Entry<VarVersionPaar, FastSparseSet<Integer>> ent: ssa.getPhi().entrySet()) {
- HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>();
- set.add(ent.getKey());
- for(Integer vers: ent.getValue()) {
- set.add(new VarVersionPaar(ent.getKey().var, vers.intValue()));
- }
-
- for(int i=lst.size()-1;i>=0;i--) {
- HashSet<VarVersionPaar> tset = lst.get(i);
- HashSet<VarVersionPaar> intersection = new HashSet<VarVersionPaar>(set);
- intersection.retainAll(tset);
-
- if(!intersection.isEmpty()) {
- set.addAll(tset);
- lst.remove(i);
- }
- }
-
- lst.add(set);
- }
-
- final HashMap<VarVersionPaar, Integer> phivers = new HashMap<VarVersionPaar, Integer>();
- for(HashSet<VarVersionPaar> set: lst) {
- int min = Integer.MAX_VALUE;
- for(VarVersionPaar paar: set) {
- if(paar.version<min) {
- min = paar.version;
- }
- }
-
- for(VarVersionPaar paar: set) {
- phivers.put(new VarVersionPaar(paar.var, paar.version), min);
- }
- }
-
-
- dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
- public int processExprent(Exprent exprent) {
- List<Exprent> lst = exprent.getAllExprents(true);
- lst.add(exprent);
-
- for(Exprent expr: lst) {
- if(expr.type == Exprent.EXPRENT_VAR) {
- VarExprent var = (VarExprent)expr;
- Integer vers = phivers.get(new VarVersionPaar(var));
- if(vers != null) {
- var.setVersion(vers);
- }
- }
- }
- return 0;
- }
- });
-
- }
-
- private void eliminateNonJavaTypes(VarTypeProcessor typeproc) {
-
- HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = typeproc.getMapExprentMaxTypes();
- HashMap<VarVersionPaar, VarType> mapExprentMinTypes = typeproc.getMapExprentMinTypes();
-
- HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>(mapExprentMinTypes.keySet());
- for(VarVersionPaar paar: set) {
- VarType type = mapExprentMinTypes.get(paar);
- VarType maxtype = mapExprentMaxTypes.get(paar);
-
- if(type.type == CodeConstants.TYPE_BYTECHAR || type.type == CodeConstants.TYPE_SHORTCHAR) {
- if(maxtype != null && maxtype.type == CodeConstants.TYPE_CHAR) {
- type = VarType.VARTYPE_CHAR;
- } else {
- type = type.type == CodeConstants.TYPE_BYTECHAR?VarType.VARTYPE_BYTE:VarType.VARTYPE_SHORT;
- }
- mapExprentMinTypes.put(paar, type);
- //} else if(type.type == CodeConstants.TYPE_CHAR && (maxtype == null || maxtype.type == CodeConstants.TYPE_INT)) { // when possible, lift char to int
- // mapExprentMinTypes.put(paar, VarType.VARTYPE_INT);
- } else if(type.type == CodeConstants.TYPE_NULL) {
- mapExprentMinTypes.put(paar, VarType.VARTYPE_OBJECT);
- }
- }
-
- }
-
- private void simpleMerge(VarTypeProcessor typeproc, DirectGraph dgraph, StructMethod mt) {
-
- HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = typeproc.getMapExprentMaxTypes();
- HashMap<VarVersionPaar, VarType> mapExprentMinTypes = typeproc.getMapExprentMinTypes();
-
- HashMap<Integer, HashSet<Integer>> mapVarVersions = new HashMap<Integer, HashSet<Integer>>();
-
- for(VarVersionPaar varpaar: mapExprentMinTypes.keySet()) {
- if(varpaar.version >= 0) { // don't merge constants
- HashSet<Integer> set = mapVarVersions.get(varpaar.var);
- if(set == null) {
- set = new HashSet<Integer>();
- mapVarVersions.put(varpaar.var, set);
- }
- set.add(varpaar.version);
- }
- }
-
- boolean is_method_static = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) != 0;
-
- final HashMap<VarVersionPaar, Integer> mapMergedVersions = new HashMap<VarVersionPaar, Integer>();
-
- for(Entry<Integer, HashSet<Integer>> ent: mapVarVersions.entrySet()) {
-
- if(ent.getValue().size() > 1) {
- List<Integer> lstVersions = new ArrayList<Integer>(ent.getValue());
- Collections.sort(lstVersions);
-
- for(int i=0;i<lstVersions.size();i++) {
- VarVersionPaar firstpaar = new VarVersionPaar(ent.getKey(), lstVersions.get(i));
- VarType firsttype = mapExprentMinTypes.get(firstpaar);
-
- if(firstpaar.var == 0 && firstpaar.version == 1 && !is_method_static) {
- continue; // don't merge 'this' variable
- }
-
- for(int j=i+1;j<lstVersions.size();j++) {
- VarVersionPaar secpaar = new VarVersionPaar(ent.getKey(), lstVersions.get(j));
- VarType sectype = mapExprentMinTypes.get(secpaar);
-
- if(firsttype.equals(sectype) || (firsttype.equals(VarType.VARTYPE_NULL) && sectype.type == CodeConstants.TYPE_OBJECT)
- || (sectype.equals(VarType.VARTYPE_NULL) && firsttype.type == CodeConstants.TYPE_OBJECT)) {
-
- VarType firstMaxType = mapExprentMaxTypes.get(firstpaar);
- VarType secMaxType = mapExprentMaxTypes.get(secpaar);
- mapExprentMaxTypes.put(firstpaar, firstMaxType==null?secMaxType:
- (secMaxType==null?firstMaxType:VarType.getCommonMinType(firstMaxType, secMaxType)));
-
-
- mapMergedVersions.put(secpaar, firstpaar.version);
- mapExprentMaxTypes.remove(secpaar);
- mapExprentMinTypes.remove(secpaar);
-
- if(firsttype.equals(VarType.VARTYPE_NULL)) {
- mapExprentMinTypes.put(firstpaar, sectype);
- firsttype = sectype;
- }
-
- typeproc.getMapFinalVars().put(firstpaar, VarTypeProcessor.VAR_NONFINAL);
-
- lstVersions.remove(j);
- j--;
- }
-
- }
- }
- }
- }
-
- if(!mapMergedVersions.isEmpty()) {
- dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
- public int processExprent(Exprent exprent) {
- List<Exprent> lst = exprent.getAllExprents(true);
- lst.add(exprent);
-
- for(Exprent expr: lst) {
- if(expr.type == Exprent.EXPRENT_VAR) {
- VarExprent varex = (VarExprent)expr;
- Integer newversion = mapMergedVersions.get(new VarVersionPaar(varex));
- if(newversion != null) {
- varex.setVersion(newversion);
- }
- }
- }
-
- return 0;
- }
- });
- }
-
- }
-
- private void setNewVarIndices(VarTypeProcessor typeproc, DirectGraph dgraph) {
-
- final HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = typeproc.getMapExprentMaxTypes();
- HashMap<VarVersionPaar, VarType> mapExprentMinTypes = typeproc.getMapExprentMinTypes();
- HashMap<VarVersionPaar, Integer> mapFinalVars = typeproc.getMapFinalVars();
-
- CounterContainer ccon = DecompilerContext.getCountercontainer();
-
- final HashMap<VarVersionPaar, Integer> mapVarPaar = new HashMap<VarVersionPaar, Integer>();
- HashMap<Integer, Integer> mapOriginalVarIndices = new HashMap<Integer, Integer>();
-
- // map var-version paars on new var indexes
- HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>(mapExprentMinTypes.keySet());
- for(VarVersionPaar vpaar: set) {
-
- if(vpaar.version >= 0) {
- int newindex = vpaar.version == 1?vpaar.var:
- ccon.getCounterAndIncrement(CounterContainer.VAR_COUNTER);
-
- VarVersionPaar newvar = new VarVersionPaar(newindex, 0);
-
- mapExprentMinTypes.put(newvar, mapExprentMinTypes.get(vpaar));
- mapExprentMaxTypes.put(newvar, mapExprentMaxTypes.get(vpaar));
-
- if(mapFinalVars.containsKey(vpaar)) {
- mapFinalVars.put(newvar, mapFinalVars.remove(vpaar));
- }
-
- mapVarPaar.put(vpaar, newindex);
- mapOriginalVarIndices.put(newindex, vpaar.var);
- }
- }
-
- // set new vars
- dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
- public int processExprent(Exprent exprent) {
- List<Exprent> lst = exprent.getAllExprents(true);
- lst.add(exprent);
-
- for(Exprent expr: lst) {
- if(expr.type == Exprent.EXPRENT_VAR) {
- VarExprent varex = (VarExprent)expr;
- Integer newvarindex = mapVarPaar.get(new VarVersionPaar(varex));
- if(newvarindex != null) {
- varex.setIndex(newvarindex);
- varex.setVersion(0);
- }
- } else if(expr.type == Exprent.EXPRENT_CONST) {
- VarType maxType = mapExprentMaxTypes.get(new VarVersionPaar(expr.id, -1));
- if(maxType != null && maxType.equals(VarType.VARTYPE_CHAR)) {
- ((ConstExprent)expr).setConsttype(maxType);
- }
- }
- }
-
- return 0;
- }
- });
-
- this.mapOriginalVarIndices = mapOriginalVarIndices;
- }
-
- public VarType getVarType(VarVersionPaar varpaar) {
- return typeproc==null?null:typeproc.getVarType(varpaar);
- }
-
- public void setVarType(VarVersionPaar varpaar, VarType type) {
- typeproc.setVarType(varpaar, type);
- }
-
- public int getVarFinal(VarVersionPaar varpaar) {
-
- int ret = VarTypeProcessor.VAR_FINAL;
- if(typeproc!=null) {
- Integer fin = typeproc.getMapFinalVars().get(varpaar);
- ret = fin==null?VarTypeProcessor.VAR_FINAL:fin.intValue();
- }
-
- return ret;
- }
-
- public void setVarFinal(VarVersionPaar varpaar, int finaltype) {
- typeproc.getMapFinalVars().put(varpaar, finaltype);
- }
-
- public HashMap<Integer, Integer> getMapOriginalVarIndices() {
- return mapOriginalVarIndices;
- }
-
-
+
+ private HashMap<Integer, Integer> mapOriginalVarIndices = new HashMap<Integer, Integer>();
+
+ private VarTypeProcessor typeproc;
+
+ public void setVarVersions(RootStatement root) {
+
+ StructMethod mt = (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD);
+
+ SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
+ ssa.splitVariables(root, mt);
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ mergePhiVersions(ssa, dgraph);
+
+ // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ typeproc = new VarTypeProcessor();
+ typeproc.calculateVarTypes(root, dgraph);
+
+ simpleMerge(typeproc, dgraph, mt);
+
+ // FIXME: advanced merging
+
+ eliminateNonJavaTypes(typeproc);
+
+ setNewVarIndices(typeproc, dgraph);
+ }
+
+ private void mergePhiVersions(SSAConstructorSparseEx ssa, DirectGraph dgraph) {
+
+ // collect phi versions
+ List<HashSet<VarVersionPaar>> lst = new ArrayList<HashSet<VarVersionPaar>>();
+ for (Entry<VarVersionPaar, FastSparseSet<Integer>> ent : ssa.getPhi().entrySet()) {
+ HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>();
+ set.add(ent.getKey());
+ for (Integer vers : ent.getValue()) {
+ set.add(new VarVersionPaar(ent.getKey().var, vers.intValue()));
+ }
+
+ for (int i = lst.size() - 1; i >= 0; i--) {
+ HashSet<VarVersionPaar> tset = lst.get(i);
+ HashSet<VarVersionPaar> intersection = new HashSet<VarVersionPaar>(set);
+ intersection.retainAll(tset);
+
+ if (!intersection.isEmpty()) {
+ set.addAll(tset);
+ lst.remove(i);
+ }
+ }
+
+ lst.add(set);
+ }
+
+ final HashMap<VarVersionPaar, Integer> phivers = new HashMap<VarVersionPaar, Integer>();
+ for (HashSet<VarVersionPaar> set : lst) {
+ int min = Integer.MAX_VALUE;
+ for (VarVersionPaar paar : set) {
+ if (paar.version < min) {
+ min = paar.version;
+ }
+ }
+
+ for (VarVersionPaar paar : set) {
+ phivers.put(new VarVersionPaar(paar.var, paar.version), min);
+ }
+ }
+
+
+ dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)expr;
+ Integer vers = phivers.get(new VarVersionPaar(var));
+ if (vers != null) {
+ var.setVersion(vers);
+ }
+ }
+ }
+ return 0;
+ }
+ });
+ }
+
+ private void eliminateNonJavaTypes(VarTypeProcessor typeproc) {
+
+ HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = typeproc.getMapExprentMaxTypes();
+ HashMap<VarVersionPaar, VarType> mapExprentMinTypes = typeproc.getMapExprentMinTypes();
+
+ HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>(mapExprentMinTypes.keySet());
+ for (VarVersionPaar paar : set) {
+ VarType type = mapExprentMinTypes.get(paar);
+ VarType maxtype = mapExprentMaxTypes.get(paar);
+
+ if (type.type == CodeConstants.TYPE_BYTECHAR || type.type == CodeConstants.TYPE_SHORTCHAR) {
+ if (maxtype != null && maxtype.type == CodeConstants.TYPE_CHAR) {
+ type = VarType.VARTYPE_CHAR;
+ }
+ else {
+ type = type.type == CodeConstants.TYPE_BYTECHAR ? VarType.VARTYPE_BYTE : VarType.VARTYPE_SHORT;
+ }
+ mapExprentMinTypes.put(paar, type);
+ //} else if(type.type == CodeConstants.TYPE_CHAR && (maxtype == null || maxtype.type == CodeConstants.TYPE_INT)) { // when possible, lift char to int
+ // mapExprentMinTypes.put(paar, VarType.VARTYPE_INT);
+ }
+ else if (type.type == CodeConstants.TYPE_NULL) {
+ mapExprentMinTypes.put(paar, VarType.VARTYPE_OBJECT);
+ }
+ }
+ }
+
+ private void simpleMerge(VarTypeProcessor typeproc, DirectGraph dgraph, StructMethod mt) {
+
+ HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = typeproc.getMapExprentMaxTypes();
+ HashMap<VarVersionPaar, VarType> mapExprentMinTypes = typeproc.getMapExprentMinTypes();
+
+ HashMap<Integer, HashSet<Integer>> mapVarVersions = new HashMap<Integer, HashSet<Integer>>();
+
+ for (VarVersionPaar varpaar : mapExprentMinTypes.keySet()) {
+ if (varpaar.version >= 0) { // don't merge constants
+ HashSet<Integer> set = mapVarVersions.get(varpaar.var);
+ if (set == null) {
+ set = new HashSet<Integer>();
+ mapVarVersions.put(varpaar.var, set);
+ }
+ set.add(varpaar.version);
+ }
+ }
+
+ boolean is_method_static = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) != 0;
+
+ final HashMap<VarVersionPaar, Integer> mapMergedVersions = new HashMap<VarVersionPaar, Integer>();
+
+ for (Entry<Integer, HashSet<Integer>> ent : mapVarVersions.entrySet()) {
+
+ if (ent.getValue().size() > 1) {
+ List<Integer> lstVersions = new ArrayList<Integer>(ent.getValue());
+ Collections.sort(lstVersions);
+
+ for (int i = 0; i < lstVersions.size(); i++) {
+ VarVersionPaar firstpaar = new VarVersionPaar(ent.getKey(), lstVersions.get(i));
+ VarType firsttype = mapExprentMinTypes.get(firstpaar);
+
+ if (firstpaar.var == 0 && firstpaar.version == 1 && !is_method_static) {
+ continue; // don't merge 'this' variable
+ }
+
+ for (int j = i + 1; j < lstVersions.size(); j++) {
+ VarVersionPaar secpaar = new VarVersionPaar(ent.getKey(), lstVersions.get(j));
+ VarType sectype = mapExprentMinTypes.get(secpaar);
+
+ if (firsttype.equals(sectype) || (firsttype.equals(VarType.VARTYPE_NULL) && sectype.type == CodeConstants.TYPE_OBJECT)
+ || (sectype.equals(VarType.VARTYPE_NULL) && firsttype.type == CodeConstants.TYPE_OBJECT)) {
+
+ VarType firstMaxType = mapExprentMaxTypes.get(firstpaar);
+ VarType secMaxType = mapExprentMaxTypes.get(secpaar);
+ mapExprentMaxTypes.put(firstpaar, firstMaxType == null ? secMaxType :
+ (secMaxType == null ? firstMaxType : VarType.getCommonMinType(firstMaxType, secMaxType)));
+
+
+ mapMergedVersions.put(secpaar, firstpaar.version);
+ mapExprentMaxTypes.remove(secpaar);
+ mapExprentMinTypes.remove(secpaar);
+
+ if (firsttype.equals(VarType.VARTYPE_NULL)) {
+ mapExprentMinTypes.put(firstpaar, sectype);
+ firsttype = sectype;
+ }
+
+ typeproc.getMapFinalVars().put(firstpaar, VarTypeProcessor.VAR_NONFINAL);
+
+ lstVersions.remove(j);
+ j--;
+ }
+ }
+ }
+ }
+ }
+
+ if (!mapMergedVersions.isEmpty()) {
+ dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ VarExprent varex = (VarExprent)expr;
+ Integer newversion = mapMergedVersions.get(new VarVersionPaar(varex));
+ if (newversion != null) {
+ varex.setVersion(newversion);
+ }
+ }
+ }
+
+ return 0;
+ }
+ });
+ }
+ }
+
+ private void setNewVarIndices(VarTypeProcessor typeproc, DirectGraph dgraph) {
+
+ final HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = typeproc.getMapExprentMaxTypes();
+ HashMap<VarVersionPaar, VarType> mapExprentMinTypes = typeproc.getMapExprentMinTypes();
+ HashMap<VarVersionPaar, Integer> mapFinalVars = typeproc.getMapFinalVars();
+
+ CounterContainer ccon = DecompilerContext.getCountercontainer();
+
+ final HashMap<VarVersionPaar, Integer> mapVarPaar = new HashMap<VarVersionPaar, Integer>();
+ HashMap<Integer, Integer> mapOriginalVarIndices = new HashMap<Integer, Integer>();
+
+ // map var-version paars on new var indexes
+ HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>(mapExprentMinTypes.keySet());
+ for (VarVersionPaar vpaar : set) {
+
+ if (vpaar.version >= 0) {
+ int newindex = vpaar.version == 1 ? vpaar.var :
+ ccon.getCounterAndIncrement(CounterContainer.VAR_COUNTER);
+
+ VarVersionPaar newvar = new VarVersionPaar(newindex, 0);
+
+ mapExprentMinTypes.put(newvar, mapExprentMinTypes.get(vpaar));
+ mapExprentMaxTypes.put(newvar, mapExprentMaxTypes.get(vpaar));
+
+ if (mapFinalVars.containsKey(vpaar)) {
+ mapFinalVars.put(newvar, mapFinalVars.remove(vpaar));
+ }
+
+ mapVarPaar.put(vpaar, newindex);
+ mapOriginalVarIndices.put(newindex, vpaar.var);
+ }
+ }
+
+ // set new vars
+ dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ VarExprent varex = (VarExprent)expr;
+ Integer newvarindex = mapVarPaar.get(new VarVersionPaar(varex));
+ if (newvarindex != null) {
+ varex.setIndex(newvarindex);
+ varex.setVersion(0);
+ }
+ }
+ else if (expr.type == Exprent.EXPRENT_CONST) {
+ VarType maxType = mapExprentMaxTypes.get(new VarVersionPaar(expr.id, -1));
+ if (maxType != null && maxType.equals(VarType.VARTYPE_CHAR)) {
+ ((ConstExprent)expr).setConsttype(maxType);
+ }
+ }
+ }
+
+ return 0;
+ }
+ });
+
+ this.mapOriginalVarIndices = mapOriginalVarIndices;
+ }
+
+ public VarType getVarType(VarVersionPaar varpaar) {
+ return typeproc == null ? null : typeproc.getVarType(varpaar);
+ }
+
+ public void setVarType(VarVersionPaar varpaar, VarType type) {
+ typeproc.setVarType(varpaar, type);
+ }
+
+ public int getVarFinal(VarVersionPaar varpaar) {
+
+ int ret = VarTypeProcessor.VAR_FINAL;
+ if (typeproc != null) {
+ Integer fin = typeproc.getMapFinalVars().get(varpaar);
+ ret = fin == null ? VarTypeProcessor.VAR_FINAL : fin.intValue();
+ }
+
+ return ret;
+ }
+
+ public void setVarFinal(VarVersionPaar varpaar, int finaltype) {
+ typeproc.getMapFinalVars().put(varpaar, finaltype);
+ }
+
+ public HashMap<Integer, Integer> getMapOriginalVarIndices() {
+ return mapOriginalVarIndices;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/renamer/ClassWrapperNode.java b/src/org/jetbrains/java/decompiler/modules/renamer/ClassWrapperNode.java
index a3015a8..273579a 100644
--- a/src/org/jetbrains/java/decompiler/modules/renamer/ClassWrapperNode.java
+++ b/src/org/jetbrains/java/decompiler/modules/renamer/ClassWrapperNode.java
@@ -1,41 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.modules.renamer;
+import org.jetbrains.java.decompiler.struct.StructClass;
+
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.struct.StructClass;
-
public class ClassWrapperNode {
- private StructClass classStruct;
-
- private ClassWrapperNode superclass;
-
- private List<ClassWrapperNode> subclasses = new ArrayList<ClassWrapperNode>();
-
- public ClassWrapperNode(StructClass cl) {
- this.classStruct = cl;
- }
-
- public void addSubclass(ClassWrapperNode node) {
- node.setSuperclass(this);
- subclasses.add(node);
- }
-
- public StructClass getClassStruct() {
- return classStruct;
- }
-
- public List<ClassWrapperNode> getSubclasses() {
- return subclasses;
- }
-
- public ClassWrapperNode getSuperclass() {
- return superclass;
- }
-
- public void setSuperclass(ClassWrapperNode superclass) {
- this.superclass = superclass;
- }
+ private StructClass classStruct;
+
+ private ClassWrapperNode superclass;
+
+ private List<ClassWrapperNode> subclasses = new ArrayList<ClassWrapperNode>();
+
+ public ClassWrapperNode(StructClass cl) {
+ this.classStruct = cl;
+ }
+
+ public void addSubclass(ClassWrapperNode node) {
+ node.setSuperclass(this);
+ subclasses.add(node);
+ }
+
+ public StructClass getClassStruct() {
+ return classStruct;
+ }
+
+ public List<ClassWrapperNode> getSubclasses() {
+ return subclasses;
+ }
+
+ public ClassWrapperNode getSuperclass() {
+ return superclass;
+ }
+ public void setSuperclass(ClassWrapperNode superclass) {
+ this.superclass = superclass;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/renamer/ConverterHelper.java b/src/org/jetbrains/java/decompiler/modules/renamer/ConverterHelper.java
index d85d51f..f2cb1ec 100644
--- a/src/org/jetbrains/java/decompiler/modules/renamer/ConverterHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/renamer/ConverterHelper.java
@@ -1,127 +1,143 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.modules.renamer;
-import java.util.HashSet;
-
import org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer;
+import java.util.HashSet;
+
public class ConverterHelper implements IIdentifierRenamer {
- private static HashSet<String> setReserved = new HashSet<String>();
-
- static {
- setReserved.add("abstract");
- setReserved.add("do");
- setReserved.add("if");
- setReserved.add("package");
- setReserved.add("synchronized");
- setReserved.add("boolean");
- setReserved.add("double");
- setReserved.add("implements");
- setReserved.add("private");
- setReserved.add("this");
- setReserved.add("break");
- setReserved.add("else");
- setReserved.add("import");
- setReserved.add("protected");
- setReserved.add("throw");
- setReserved.add("byte");
- setReserved.add("extends");
- setReserved.add("instanceof");
- setReserved.add("public");
- setReserved.add("throws");
- setReserved.add("case");
- setReserved.add("false");
- setReserved.add("int");
- setReserved.add("return");
- setReserved.add("transient");
- setReserved.add("catch");
- setReserved.add("final");
- setReserved.add("interface");
- setReserved.add("short");
- setReserved.add("true");
- setReserved.add("char");
- setReserved.add("finally");
- setReserved.add("long");
- setReserved.add("static");
- setReserved.add("try");
- setReserved.add("class");
- setReserved.add("float");
- setReserved.add("native");
- setReserved.add("strictfp");
- setReserved.add("void");
- setReserved.add("const");
- setReserved.add("for");
- setReserved.add("new");
- setReserved.add("super");
- setReserved.add("volatile");
- setReserved.add("continue");
- setReserved.add("goto");
- setReserved.add("null");
- setReserved.add("switch");
- setReserved.add("while");
- setReserved.add("default");
- setReserved.add("assert");
- setReserved.add("enum");
- }
-
- private int class_counter = 0;
-
- private int field_counter = 0;
-
- private int method_counter = 0;
-
- private HashSet<String> setNonStandardClassNames = new HashSet<String>();
-
- public boolean toBeRenamed(int element_type, String classname, String element, String descriptor) {
- String value = (element_type == IIdentifierRenamer.ELEMENT_CLASS)?classname:element;
- return value == null || value.length() == 0 || value.length()<=2 || setReserved.contains(value) || Character.isDigit(value.charAt(0));
- }
-
- // TODO: consider possible conflicts with not renamed classes, fields and methods!
- // We should get all relevant information here.
- public String getNextClassname(String fullname, String shortname) {
-
- if(shortname == null) {
- return "class_"+(class_counter++);
- }
-
- int index = 0;
- while(Character.isDigit(shortname.charAt(index))) {
- index++;
- }
-
- if(index == 0 || index == shortname.length()) {
- return "class_"+(class_counter++);
- } else {
- String name = shortname.substring(index);
-
- if(setNonStandardClassNames.contains(name)) {
- return "Inner"+name+"_"+(class_counter++);
- } else {
- setNonStandardClassNames.add(name);
- return "Inner"+name;
- }
- }
- }
-
- public String getNextFieldname(String classname, String field, String descriptor) {
- return "field_"+(field_counter++);
- }
-
- public String getNextMethodname(String classname, String method, String descriptor) {
- return "method_"+(method_counter++);
- }
-
- // *****************************************************************************
- // static methods
- // *****************************************************************************
-
- public static String getSimpleClassName(String fullname) {
- return fullname.substring(fullname.lastIndexOf('/')+1);
- }
-
- public static String replaceSimpleClassName(String fullname, String newname) {
- return fullname.substring(0, fullname.lastIndexOf('/')+1)+newname;
- }
-
+ private static HashSet<String> setReserved = new HashSet<String>();
+
+ static {
+ setReserved.add("abstract");
+ setReserved.add("do");
+ setReserved.add("if");
+ setReserved.add("package");
+ setReserved.add("synchronized");
+ setReserved.add("boolean");
+ setReserved.add("double");
+ setReserved.add("implements");
+ setReserved.add("private");
+ setReserved.add("this");
+ setReserved.add("break");
+ setReserved.add("else");
+ setReserved.add("import");
+ setReserved.add("protected");
+ setReserved.add("throw");
+ setReserved.add("byte");
+ setReserved.add("extends");
+ setReserved.add("instanceof");
+ setReserved.add("public");
+ setReserved.add("throws");
+ setReserved.add("case");
+ setReserved.add("false");
+ setReserved.add("int");
+ setReserved.add("return");
+ setReserved.add("transient");
+ setReserved.add("catch");
+ setReserved.add("final");
+ setReserved.add("interface");
+ setReserved.add("short");
+ setReserved.add("true");
+ setReserved.add("char");
+ setReserved.add("finally");
+ setReserved.add("long");
+ setReserved.add("static");
+ setReserved.add("try");
+ setReserved.add("class");
+ setReserved.add("float");
+ setReserved.add("native");
+ setReserved.add("strictfp");
+ setReserved.add("void");
+ setReserved.add("const");
+ setReserved.add("for");
+ setReserved.add("new");
+ setReserved.add("super");
+ setReserved.add("volatile");
+ setReserved.add("continue");
+ setReserved.add("goto");
+ setReserved.add("null");
+ setReserved.add("switch");
+ setReserved.add("while");
+ setReserved.add("default");
+ setReserved.add("assert");
+ setReserved.add("enum");
+ }
+
+ private int class_counter = 0;
+
+ private int field_counter = 0;
+
+ private int method_counter = 0;
+
+ private HashSet<String> setNonStandardClassNames = new HashSet<String>();
+
+ public boolean toBeRenamed(int element_type, String classname, String element, String descriptor) {
+ String value = (element_type == IIdentifierRenamer.ELEMENT_CLASS) ? classname : element;
+ return value == null || value.length() == 0 || value.length() <= 2 || setReserved.contains(value) || Character.isDigit(value.charAt(0));
+ }
+
+ // TODO: consider possible conflicts with not renamed classes, fields and methods!
+ // We should get all relevant information here.
+ public String getNextClassname(String fullname, String shortname) {
+
+ if (shortname == null) {
+ return "class_" + (class_counter++);
+ }
+
+ int index = 0;
+ while (Character.isDigit(shortname.charAt(index))) {
+ index++;
+ }
+
+ if (index == 0 || index == shortname.length()) {
+ return "class_" + (class_counter++);
+ }
+ else {
+ String name = shortname.substring(index);
+
+ if (setNonStandardClassNames.contains(name)) {
+ return "Inner" + name + "_" + (class_counter++);
+ }
+ else {
+ setNonStandardClassNames.add(name);
+ return "Inner" + name;
+ }
+ }
+ }
+
+ public String getNextFieldname(String classname, String field, String descriptor) {
+ return "field_" + (field_counter++);
+ }
+
+ public String getNextMethodname(String classname, String method, String descriptor) {
+ return "method_" + (method_counter++);
+ }
+
+ // *****************************************************************************
+ // static methods
+ // *****************************************************************************
+
+ public static String getSimpleClassName(String fullname) {
+ return fullname.substring(fullname.lastIndexOf('/') + 1);
+ }
+
+ public static String replaceSimpleClassName(String fullname, String newname) {
+ return fullname.substring(0, fullname.lastIndexOf('/') + 1) + newname;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java b/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java
index 634dc59..a665de8 100644
--- a/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java
+++ b/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java
@@ -1,12 +1,20 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.modules.renamer;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
@@ -20,428 +28,437 @@ import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.io.IOException;
+import java.util.*;
+
public class IdentifierConverter {
- private StructContext context;
-
- private IIdentifierRenamer helper;
-
- private PoolInterceptor interceptor;
-
- private List<ClassWrapperNode> rootClasses = new ArrayList<ClassWrapperNode>();
-
- private List<ClassWrapperNode> rootInterfaces = new ArrayList<ClassWrapperNode>();
-
- private HashMap<String, HashMap<String, String>> interfaceNameMaps = new HashMap<String, HashMap<String, String>>();
-
- public void rename(StructContext context) {
-
- try {
- this.context = context;
-
- String user_class = (String)DecompilerContext.getProperty(IFernflowerPreferences.USER_RENAMER_CLASS);
- if(user_class != null) {
- try {
- helper = (IIdentifierRenamer)IdentifierConverter.class.getClassLoader().loadClass(user_class).newInstance();
- } catch(Exception ex) {
- ; // ignore errors
- }
- }
-
- if(helper == null) {
- helper = new ConverterHelper();
- }
-
- interceptor = new PoolInterceptor(helper);
-
- buildInheritanceTree();
-
- renameAllClasses();
-
- renameInterfaces();
-
- renameClasses();
-
- DecompilerContext.setPoolInterceptor(interceptor);
- context.reloadContext();
-
- } catch(IOException ex){
- throw new RuntimeException("Renaming failed!");
- }
-
- }
-
- private void renameClasses() {
-
- List<ClassWrapperNode> lstClasses = getReversePostOrderListIterative(rootClasses);
-
- HashMap<String, HashMap<String, String>> classNameMaps = new HashMap<String, HashMap<String, String>>();
-
- for(ClassWrapperNode node : lstClasses) {
-
- StructClass cl = node.getClassStruct();
- HashMap<String, String> names = new HashMap<String, String>();
-
- // merge informations on super class
- if(cl.superClass != null) {
- HashMap<String, String> mapClass = classNameMaps.get(cl.superClass.getString());
- if(mapClass != null) {
- names.putAll(mapClass);
- }
- }
-
- // merge informations on interfaces
- for(String intrName : cl.getInterfaceNames()) {
- HashMap<String, String> mapInt = interfaceNameMaps.get(intrName);
- if(mapInt != null) {
- names.putAll(mapInt);
- } else {
- StructClass clintr = context.getClass(intrName);
- if(clintr!=null) {
- names.putAll(processExternalInterface(clintr));
- }
- }
- }
-
- renameClassIdentifiers(cl, names);
-
- if(!node.getSubclasses().isEmpty()) {
- classNameMaps.put(cl.qualifiedName, names);
- }
- }
-
- }
-
- private HashMap<String, String> processExternalInterface(StructClass cl) {
-
- HashMap<String, String> names = new HashMap<String, String>();
-
- for(String intrName : cl.getInterfaceNames()) {
-
- HashMap<String, String> mapInt = interfaceNameMaps.get(intrName);
- if(mapInt != null) {
- names.putAll(mapInt);
- } else {
- StructClass clintr = context.getClass(intrName);
- if(clintr!=null) {
- names.putAll(processExternalInterface(clintr));
- }
- }
- }
-
- renameClassIdentifiers(cl, names);
-
- return names;
- }
-
- private void renameInterfaces() {
-
- List<ClassWrapperNode> lstInterfaces = getReversePostOrderListIterative(rootInterfaces);
-
- HashMap<String, HashMap<String, String>> interfaceNameMaps = new HashMap<String, HashMap<String, String>>();
-
- // rename methods and fields
- for(ClassWrapperNode node : lstInterfaces) {
-
- StructClass cl = node.getClassStruct();
- HashMap<String, String> names = new HashMap<String, String>();
-
- // merge informations on super interfaces
- for(String intrName : cl.getInterfaceNames()) {
- HashMap<String, String> mapInt = interfaceNameMaps.get(intrName);
- if(mapInt != null) {
- names.putAll(mapInt);
- }
- }
-
- renameClassIdentifiers(cl, names);
-
- interfaceNameMaps.put(cl.qualifiedName, names);
- }
-
- this.interfaceNameMaps = interfaceNameMaps;
- }
-
- private void renameAllClasses() {
-
- // order not important
- List<ClassWrapperNode> lstAllClasses = new ArrayList<ClassWrapperNode>(getReversePostOrderListIterative(rootInterfaces));
- lstAllClasses.addAll(getReversePostOrderListIterative(rootClasses));
-
- // rename all interfaces and classes
- for(ClassWrapperNode node : lstAllClasses) {
- renameClass(node.getClassStruct());
- }
- }
-
- private void renameClass(StructClass cl) {
-
- if(!cl.isOwn()) {
- return;
- }
-
- String classOldFullName = cl.qualifiedName;
- String classNewFullName = classOldFullName;
-
- // TODO: rename packages
- String clsimplename = ConverterHelper.getSimpleClassName(classOldFullName);
- if(helper.toBeRenamed(IIdentifierRenamer.ELEMENT_CLASS, clsimplename, null, null)) {
- do {
- classNewFullName = ConverterHelper.replaceSimpleClassName(classOldFullName,
- helper.getNextClassname(classOldFullName, ConverterHelper.getSimpleClassName(classOldFullName)));
- } while(context.getClasses().containsKey(classNewFullName));
-
- interceptor.addName(classOldFullName, classNewFullName);
- }
-
- }
-
- private void renameClassIdentifiers(StructClass cl, HashMap<String, String> names) {
-
- // all classes are already renamed
- String classOldFullName = cl.qualifiedName;
- String classNewFullName = interceptor.getName(classOldFullName);
-
- if(classNewFullName == null) {
- classNewFullName = classOldFullName;
- }
-
- // methods
- HashSet<String> setMethodNames = new HashSet<String>();
- for(StructMethod md : cl.getMethods()) {
- setMethodNames.add(md.getName());
- }
-
- VBStyleCollection<StructMethod, String> methods = cl.getMethods();
- for(int i=0;i<methods.size();i++) {
-
- StructMethod mt = methods.get(i);
- String key = methods.getKey(i);
-
- int access_flags = mt.getAccessFlags();
- boolean isPrivate = ((access_flags & CodeConstants.ACC_PRIVATE) != 0);
-
- String name = mt.getName();
- if(!cl.isOwn() || (access_flags & CodeConstants.ACC_NATIVE) != 0) {
- // external and native methods must not be renamed
- if(!isPrivate) {
- names.put(key, name);
- }
- } else if(helper.toBeRenamed(IIdentifierRenamer.ELEMENT_METHOD, classOldFullName, name, mt.getDescriptor())) {
- if(isPrivate || !names.containsKey(key)) {
- do {
- name = helper.getNextMethodname(classOldFullName, name, mt.getDescriptor());
- } while(setMethodNames.contains(name));
-
- if(!isPrivate) {
- names.put(key, name);
- }
- } else {
- name = names.get(key);
- }
-
- interceptor.addName(classOldFullName+" "+mt.getName()+" "+mt.getDescriptor(),
- classNewFullName+" "+name+" "+buildNewDescriptor(false, mt.getDescriptor()));
- }
- }
-
- // external fields are not being renamed
- if(!cl.isOwn()) {
- return;
- }
-
- // fields
- // FIXME: should overloaded fields become the same name?
- HashSet<String> setFieldNames = new HashSet<String>();
- for(StructField fd : cl.getFields()) {
- setFieldNames.add(fd.getName());
- }
-
- for(StructField fd : cl.getFields()) {
- if(helper.toBeRenamed(IIdentifierRenamer.ELEMENT_FIELD, classOldFullName, fd.getName(), fd.getDescriptor())) {
- String newname;
-
- do {
- newname = helper.getNextFieldname(classOldFullName, fd.getName(), fd.getDescriptor());
- } while(setFieldNames.contains(newname));
-
- interceptor.addName(classOldFullName+" "+fd.getName()+" "+fd.getDescriptor(),
- classNewFullName+" "+newname+" "+buildNewDescriptor(true, fd.getDescriptor()));
- }
- }
-
- }
-
- private String buildNewDescriptor(boolean isField, String descriptor) {
-
- boolean updated = false;
-
- if(isField) {
- FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor);
-
- VarType ftype = fd.type;
- if(ftype.type == CodeConstants.TYPE_OBJECT) {
- String newclname = interceptor.getName(ftype.value);
- if(newclname != null) {
- ftype.value = newclname;
- updated = true;
- }
- }
-
- if(updated) {
- return fd.getDescriptor();
- }
-
- } else {
-
- MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
- // params
- for(VarType partype : md.params) {
- if(partype.type == CodeConstants.TYPE_OBJECT) {
- String newclname = interceptor.getName(partype.value);
- if(newclname != null) {
- partype.value = newclname;
- updated = true;
- }
- }
- }
-
- // return value
- if(md.ret.type == CodeConstants.TYPE_OBJECT) {
- String newclname = interceptor.getName(md.ret.value);
- if(newclname!=null) {
- md.ret.value = newclname;
- updated = true;
- }
- }
-
- if(updated) {
- return md.getDescriptor();
- }
- }
-
- return descriptor;
- }
-
- private List<ClassWrapperNode> getReversePostOrderListIterative(List<ClassWrapperNode> roots) {
-
- List<ClassWrapperNode> res = new ArrayList<ClassWrapperNode>();
-
- LinkedList<ClassWrapperNode> stackNode = new LinkedList<ClassWrapperNode>();
- LinkedList<Integer> stackIndex = new LinkedList<Integer>();
-
- HashSet<ClassWrapperNode> setVisited = new HashSet<ClassWrapperNode>();
-
- for(ClassWrapperNode root : roots) {
- stackNode.add(root);
- stackIndex.add(0);
- }
-
- while(!stackNode.isEmpty()) {
-
- ClassWrapperNode node = stackNode.getLast();
- int index = stackIndex.removeLast();
-
- setVisited.add(node);
-
- List<ClassWrapperNode> lstSubs = node.getSubclasses();
-
- for(; index < lstSubs.size(); index++) {
- ClassWrapperNode sub = lstSubs.get(index);
- if(!setVisited.contains(sub)) {
- stackIndex.add(index+1);
-
- stackNode.add(sub);
- stackIndex.add(0);
-
- break;
- }
- }
-
- if(index == lstSubs.size()) {
- res.add(0, node);
-
- stackNode.removeLast();
- }
- }
-
- return res;
- }
-
-
- private void buildInheritanceTree() {
-
- HashMap<String, ClassWrapperNode> nodes = new HashMap<String, ClassWrapperNode>();
- HashMap<String, StructClass> classes = context.getClasses();
-
- List<ClassWrapperNode> rootClasses = new ArrayList<ClassWrapperNode>();
- List<ClassWrapperNode> rootInterfaces = new ArrayList<ClassWrapperNode>();
-
- for(StructClass cl : classes.values()) {
-
- if(!cl.isOwn()) {
- continue;
- }
-
- LinkedList<StructClass> stack = new LinkedList<StructClass>();
- LinkedList<ClassWrapperNode> stackSubnodes = new LinkedList<ClassWrapperNode>();
-
- stack.add(cl);
- stackSubnodes.add(null);
-
- while(!stack.isEmpty()) {
-
- StructClass clstr = stack.removeFirst();
- ClassWrapperNode child = stackSubnodes.removeFirst();
-
- ClassWrapperNode node = nodes.get(clstr.qualifiedName);
- boolean isNewNode = (node == null);
-
- if(isNewNode) {
- nodes.put(clstr.qualifiedName, node = new ClassWrapperNode(clstr));
- }
-
- if(child!=null) {
- node.addSubclass(child);
- }
-
- if(!isNewNode) {
- break;
- } else {
-
- boolean isInterface = ((clstr.access_flags & CodeConstants.ACC_INTERFACE) != 0);
- boolean found_parent = false;
-
- if(isInterface) {
- for(String intrName : clstr.getInterfaceNames()) {
- StructClass clparent = classes.get(intrName);
- if(clparent != null) {
- stack.add(clparent);
- stackSubnodes.add(node);
- found_parent = true;
- }
- }
- } else {
- if(clstr.superClass != null) { // null iff java/lang/Object
- StructClass clparent = classes.get(clstr.superClass.getString());
-
- if(clparent != null) {
- stack.add(clparent);
- stackSubnodes.add(node);
- found_parent = true;
- }
- }
- }
-
- if(!found_parent) { // no super class or interface
- (isInterface?rootInterfaces:rootClasses).add(node);
- }
- }
- }
- }
-
- this.rootClasses = rootClasses;
- this.rootInterfaces = rootInterfaces;
- }
-
+ private StructContext context;
+
+ private IIdentifierRenamer helper;
+
+ private PoolInterceptor interceptor;
+
+ private List<ClassWrapperNode> rootClasses = new ArrayList<ClassWrapperNode>();
+
+ private List<ClassWrapperNode> rootInterfaces = new ArrayList<ClassWrapperNode>();
+
+ private HashMap<String, HashMap<String, String>> interfaceNameMaps = new HashMap<String, HashMap<String, String>>();
+
+ public void rename(StructContext context) {
+
+ try {
+ this.context = context;
+
+ String user_class = (String)DecompilerContext.getProperty(IFernflowerPreferences.USER_RENAMER_CLASS);
+ if (user_class != null) {
+ try {
+ helper = (IIdentifierRenamer)IdentifierConverter.class.getClassLoader().loadClass(user_class).newInstance();
+ }
+ catch (Exception ex) {
+ ; // ignore errors
+ }
+ }
+
+ if (helper == null) {
+ helper = new ConverterHelper();
+ }
+
+ interceptor = new PoolInterceptor(helper);
+
+ buildInheritanceTree();
+
+ renameAllClasses();
+
+ renameInterfaces();
+
+ renameClasses();
+
+ DecompilerContext.setPoolInterceptor(interceptor);
+ context.reloadContext();
+ }
+ catch (IOException ex) {
+ throw new RuntimeException("Renaming failed!");
+ }
+ }
+
+ private void renameClasses() {
+
+ List<ClassWrapperNode> lstClasses = getReversePostOrderListIterative(rootClasses);
+
+ HashMap<String, HashMap<String, String>> classNameMaps = new HashMap<String, HashMap<String, String>>();
+
+ for (ClassWrapperNode node : lstClasses) {
+
+ StructClass cl = node.getClassStruct();
+ HashMap<String, String> names = new HashMap<String, String>();
+
+ // merge informations on super class
+ if (cl.superClass != null) {
+ HashMap<String, String> mapClass = classNameMaps.get(cl.superClass.getString());
+ if (mapClass != null) {
+ names.putAll(mapClass);
+ }
+ }
+
+ // merge informations on interfaces
+ for (String intrName : cl.getInterfaceNames()) {
+ HashMap<String, String> mapInt = interfaceNameMaps.get(intrName);
+ if (mapInt != null) {
+ names.putAll(mapInt);
+ }
+ else {
+ StructClass clintr = context.getClass(intrName);
+ if (clintr != null) {
+ names.putAll(processExternalInterface(clintr));
+ }
+ }
+ }
+
+ renameClassIdentifiers(cl, names);
+
+ if (!node.getSubclasses().isEmpty()) {
+ classNameMaps.put(cl.qualifiedName, names);
+ }
+ }
+ }
+
+ private HashMap<String, String> processExternalInterface(StructClass cl) {
+
+ HashMap<String, String> names = new HashMap<String, String>();
+
+ for (String intrName : cl.getInterfaceNames()) {
+
+ HashMap<String, String> mapInt = interfaceNameMaps.get(intrName);
+ if (mapInt != null) {
+ names.putAll(mapInt);
+ }
+ else {
+ StructClass clintr = context.getClass(intrName);
+ if (clintr != null) {
+ names.putAll(processExternalInterface(clintr));
+ }
+ }
+ }
+
+ renameClassIdentifiers(cl, names);
+
+ return names;
+ }
+
+ private void renameInterfaces() {
+
+ List<ClassWrapperNode> lstInterfaces = getReversePostOrderListIterative(rootInterfaces);
+
+ HashMap<String, HashMap<String, String>> interfaceNameMaps = new HashMap<String, HashMap<String, String>>();
+
+ // rename methods and fields
+ for (ClassWrapperNode node : lstInterfaces) {
+
+ StructClass cl = node.getClassStruct();
+ HashMap<String, String> names = new HashMap<String, String>();
+
+ // merge informations on super interfaces
+ for (String intrName : cl.getInterfaceNames()) {
+ HashMap<String, String> mapInt = interfaceNameMaps.get(intrName);
+ if (mapInt != null) {
+ names.putAll(mapInt);
+ }
+ }
+
+ renameClassIdentifiers(cl, names);
+
+ interfaceNameMaps.put(cl.qualifiedName, names);
+ }
+
+ this.interfaceNameMaps = interfaceNameMaps;
+ }
+
+ private void renameAllClasses() {
+
+ // order not important
+ List<ClassWrapperNode> lstAllClasses = new ArrayList<ClassWrapperNode>(getReversePostOrderListIterative(rootInterfaces));
+ lstAllClasses.addAll(getReversePostOrderListIterative(rootClasses));
+
+ // rename all interfaces and classes
+ for (ClassWrapperNode node : lstAllClasses) {
+ renameClass(node.getClassStruct());
+ }
+ }
+
+ private void renameClass(StructClass cl) {
+
+ if (!cl.isOwn()) {
+ return;
+ }
+
+ String classOldFullName = cl.qualifiedName;
+ String classNewFullName = classOldFullName;
+
+ // TODO: rename packages
+ String clsimplename = ConverterHelper.getSimpleClassName(classOldFullName);
+ if (helper.toBeRenamed(IIdentifierRenamer.ELEMENT_CLASS, clsimplename, null, null)) {
+ do {
+ classNewFullName = ConverterHelper.replaceSimpleClassName(classOldFullName,
+ helper.getNextClassname(classOldFullName, ConverterHelper
+ .getSimpleClassName(classOldFullName)));
+ }
+ while (context.getClasses().containsKey(classNewFullName));
+
+ interceptor.addName(classOldFullName, classNewFullName);
+ }
+ }
+
+ private void renameClassIdentifiers(StructClass cl, HashMap<String, String> names) {
+
+ // all classes are already renamed
+ String classOldFullName = cl.qualifiedName;
+ String classNewFullName = interceptor.getName(classOldFullName);
+
+ if (classNewFullName == null) {
+ classNewFullName = classOldFullName;
+ }
+
+ // methods
+ HashSet<String> setMethodNames = new HashSet<String>();
+ for (StructMethod md : cl.getMethods()) {
+ setMethodNames.add(md.getName());
+ }
+
+ VBStyleCollection<StructMethod, String> methods = cl.getMethods();
+ for (int i = 0; i < methods.size(); i++) {
+
+ StructMethod mt = methods.get(i);
+ String key = methods.getKey(i);
+
+ int access_flags = mt.getAccessFlags();
+ boolean isPrivate = ((access_flags & CodeConstants.ACC_PRIVATE) != 0);
+
+ String name = mt.getName();
+ if (!cl.isOwn() || (access_flags & CodeConstants.ACC_NATIVE) != 0) {
+ // external and native methods must not be renamed
+ if (!isPrivate) {
+ names.put(key, name);
+ }
+ }
+ else if (helper.toBeRenamed(IIdentifierRenamer.ELEMENT_METHOD, classOldFullName, name, mt.getDescriptor())) {
+ if (isPrivate || !names.containsKey(key)) {
+ do {
+ name = helper.getNextMethodname(classOldFullName, name, mt.getDescriptor());
+ }
+ while (setMethodNames.contains(name));
+
+ if (!isPrivate) {
+ names.put(key, name);
+ }
+ }
+ else {
+ name = names.get(key);
+ }
+
+ interceptor.addName(classOldFullName + " " + mt.getName() + " " + mt.getDescriptor(),
+ classNewFullName + " " + name + " " + buildNewDescriptor(false, mt.getDescriptor()));
+ }
+ }
+
+ // external fields are not being renamed
+ if (!cl.isOwn()) {
+ return;
+ }
+
+ // fields
+ // FIXME: should overloaded fields become the same name?
+ HashSet<String> setFieldNames = new HashSet<String>();
+ for (StructField fd : cl.getFields()) {
+ setFieldNames.add(fd.getName());
+ }
+
+ for (StructField fd : cl.getFields()) {
+ if (helper.toBeRenamed(IIdentifierRenamer.ELEMENT_FIELD, classOldFullName, fd.getName(), fd.getDescriptor())) {
+ String newname;
+
+ do {
+ newname = helper.getNextFieldname(classOldFullName, fd.getName(), fd.getDescriptor());
+ }
+ while (setFieldNames.contains(newname));
+
+ interceptor.addName(classOldFullName + " " + fd.getName() + " " + fd.getDescriptor(),
+ classNewFullName + " " + newname + " " + buildNewDescriptor(true, fd.getDescriptor()));
+ }
+ }
+ }
+
+ private String buildNewDescriptor(boolean isField, String descriptor) {
+
+ boolean updated = false;
+
+ if (isField) {
+ FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor);
+
+ VarType ftype = fd.type;
+ if (ftype.type == CodeConstants.TYPE_OBJECT) {
+ String newclname = interceptor.getName(ftype.value);
+ if (newclname != null) {
+ ftype.value = newclname;
+ updated = true;
+ }
+ }
+
+ if (updated) {
+ return fd.getDescriptor();
+ }
+ }
+ else {
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
+ // params
+ for (VarType partype : md.params) {
+ if (partype.type == CodeConstants.TYPE_OBJECT) {
+ String newclname = interceptor.getName(partype.value);
+ if (newclname != null) {
+ partype.value = newclname;
+ updated = true;
+ }
+ }
+ }
+
+ // return value
+ if (md.ret.type == CodeConstants.TYPE_OBJECT) {
+ String newclname = interceptor.getName(md.ret.value);
+ if (newclname != null) {
+ md.ret.value = newclname;
+ updated = true;
+ }
+ }
+
+ if (updated) {
+ return md.getDescriptor();
+ }
+ }
+
+ return descriptor;
+ }
+
+ private List<ClassWrapperNode> getReversePostOrderListIterative(List<ClassWrapperNode> roots) {
+
+ List<ClassWrapperNode> res = new ArrayList<ClassWrapperNode>();
+
+ LinkedList<ClassWrapperNode> stackNode = new LinkedList<ClassWrapperNode>();
+ LinkedList<Integer> stackIndex = new LinkedList<Integer>();
+
+ HashSet<ClassWrapperNode> setVisited = new HashSet<ClassWrapperNode>();
+
+ for (ClassWrapperNode root : roots) {
+ stackNode.add(root);
+ stackIndex.add(0);
+ }
+
+ while (!stackNode.isEmpty()) {
+
+ ClassWrapperNode node = stackNode.getLast();
+ int index = stackIndex.removeLast();
+
+ setVisited.add(node);
+
+ List<ClassWrapperNode> lstSubs = node.getSubclasses();
+
+ for (; index < lstSubs.size(); index++) {
+ ClassWrapperNode sub = lstSubs.get(index);
+ if (!setVisited.contains(sub)) {
+ stackIndex.add(index + 1);
+
+ stackNode.add(sub);
+ stackIndex.add(0);
+
+ break;
+ }
+ }
+
+ if (index == lstSubs.size()) {
+ res.add(0, node);
+
+ stackNode.removeLast();
+ }
+ }
+
+ return res;
+ }
+
+
+ private void buildInheritanceTree() {
+
+ HashMap<String, ClassWrapperNode> nodes = new HashMap<String, ClassWrapperNode>();
+ HashMap<String, StructClass> classes = context.getClasses();
+
+ List<ClassWrapperNode> rootClasses = new ArrayList<ClassWrapperNode>();
+ List<ClassWrapperNode> rootInterfaces = new ArrayList<ClassWrapperNode>();
+
+ for (StructClass cl : classes.values()) {
+
+ if (!cl.isOwn()) {
+ continue;
+ }
+
+ LinkedList<StructClass> stack = new LinkedList<StructClass>();
+ LinkedList<ClassWrapperNode> stackSubnodes = new LinkedList<ClassWrapperNode>();
+
+ stack.add(cl);
+ stackSubnodes.add(null);
+
+ while (!stack.isEmpty()) {
+
+ StructClass clstr = stack.removeFirst();
+ ClassWrapperNode child = stackSubnodes.removeFirst();
+
+ ClassWrapperNode node = nodes.get(clstr.qualifiedName);
+ boolean isNewNode = (node == null);
+
+ if (isNewNode) {
+ nodes.put(clstr.qualifiedName, node = new ClassWrapperNode(clstr));
+ }
+
+ if (child != null) {
+ node.addSubclass(child);
+ }
+
+ if (!isNewNode) {
+ break;
+ }
+ else {
+
+ boolean isInterface = ((clstr.access_flags & CodeConstants.ACC_INTERFACE) != 0);
+ boolean found_parent = false;
+
+ if (isInterface) {
+ for (String intrName : clstr.getInterfaceNames()) {
+ StructClass clparent = classes.get(intrName);
+ if (clparent != null) {
+ stack.add(clparent);
+ stackSubnodes.add(node);
+ found_parent = true;
+ }
+ }
+ }
+ else {
+ if (clstr.superClass != null) { // null iff java/lang/Object
+ StructClass clparent = classes.get(clstr.superClass.getString());
+
+ if (clparent != null) {
+ stack.add(clparent);
+ stackSubnodes.add(node);
+ found_parent = true;
+ }
+ }
+ }
+
+ if (!found_parent) { // no super class or interface
+ (isInterface ? rootInterfaces : rootClasses).add(node);
+ }
+ }
+ }
+ }
+
+ this.rootClasses = rootClasses;
+ this.rootInterfaces = rootInterfaces;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/modules/renamer/PoolInterceptor.java b/src/org/jetbrains/java/decompiler/modules/renamer/PoolInterceptor.java
index 73260f4..74e2ed8 100644
--- a/src/org/jetbrains/java/decompiler/modules/renamer/PoolInterceptor.java
+++ b/src/org/jetbrains/java/decompiler/modules/renamer/PoolInterceptor.java
@@ -1,36 +1,50 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.modules.renamer;
-import java.util.HashMap;
-
import org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer;
+import java.util.HashMap;
+
public class PoolInterceptor {
- private IIdentifierRenamer helper;
-
- private HashMap<String, String> mapOldToNewNames = new HashMap<String, String>();
-
- private HashMap<String, String> mapNewToOldNames = new HashMap<String, String>();
-
- public PoolInterceptor(IIdentifierRenamer helper) {
- this.helper = helper;
- }
-
- public void addName(String oldName, String newName) {
- mapOldToNewNames.put(oldName, newName);
- mapNewToOldNames.put(newName, oldName);
- }
-
- public String getName(String oldName) {
- return mapOldToNewNames.get(oldName);
- }
-
- public String getOldName(String newName) {
- return mapNewToOldNames.get(newName);
- }
-
- public IIdentifierRenamer getHelper() {
- return helper;
- }
-
+ private IIdentifierRenamer helper;
+
+ private HashMap<String, String> mapOldToNewNames = new HashMap<String, String>();
+
+ private HashMap<String, String> mapNewToOldNames = new HashMap<String, String>();
+
+ public PoolInterceptor(IIdentifierRenamer helper) {
+ this.helper = helper;
+ }
+
+ public void addName(String oldName, String newName) {
+ mapOldToNewNames.put(oldName, newName);
+ mapNewToOldNames.put(newName, oldName);
+ }
+
+ public String getName(String oldName) {
+ return mapOldToNewNames.get(oldName);
+ }
+
+ public String getOldName(String newName) {
+ return mapNewToOldNames.get(newName);
+ }
+
+ public IIdentifierRenamer getHelper() {
+ return helper;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/ContextUnit.java b/src/org/jetbrains/java/decompiler/struct/ContextUnit.java
index d859b29..c942e76 100644
--- a/src/org/jetbrains/java/decompiler/struct/ContextUnit.java
+++ b/src/org/jetbrains/java/decompiler/struct/ContextUnit.java
@@ -1,210 +1,210 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct;
+import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver;
+import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
+import org.jetbrains.java.decompiler.struct.lazy.LazyLoader.Link;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.Manifest;
-import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver;
-import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
-import org.jetbrains.java.decompiler.struct.lazy.LazyLoader.Link;
-
public class ContextUnit {
-
- public static final int TYPE_FOLDER = 0;
- public static final int TYPE_JAR = 1;
- public static final int TYPE_ZIP = 2;
-
- private static final String MANIFEST_ENTRY = "META-INF/MANIFEST.MF";
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private int type;
-
- // relative path to jar/zip
- private String archivepath;
-
- // folder: relative path
- // archive: file name
- private String filename;
-
- private List<StructClass> classes = new ArrayList<StructClass>();
-
- // class file or jar/zip entry. Should, but doesn't have to be the same as qualifiedName of the class
- private List<String> classentries = new ArrayList<String>();
-
- private List<String> direntries = new ArrayList<String>();
-
- private List<String[]> otherentries = new ArrayList<String[]>();
-
- private Manifest manifest;
-
- private IDecompilatSaver decompilatSaver;
-
- private IDecompiledData decompiledData;
-
- private boolean own = true;
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public ContextUnit(int type, String archivepath, String filename, boolean own,
- IDecompilatSaver decompilatSaver, IDecompiledData decompiledData) {
- this.type = type;
- this.own = own;
- this.archivepath = archivepath;
- this.filename = filename;
- this.decompilatSaver = decompilatSaver;
- this.decompiledData = decompiledData;
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public void addClass(StructClass cl, String entryname) {
- classes.add(cl);
- classentries.add(entryname);
- }
-
- public void addDirEntry(String entry) {
- direntries.add(entry);
- }
-
- public void addOtherEntry(String fullpath, String entry) {
- otherentries.add(new String[]{fullpath, entry});
- }
-
- public void reload(LazyLoader loader) throws IOException {
-
- List<StructClass> lstClasses = new ArrayList<StructClass>();
- for(StructClass cl : classes) {
- String oldname = cl.qualifiedName;
- StructClass newcl = new StructClass(loader.getClassStream(oldname), cl.isOwn(), loader);
-
- lstClasses.add(newcl);
-
- Link lnk = loader.getClassLink(oldname);
- loader.removeClassLink(oldname);
- loader.addClassLink(newcl.qualifiedName, lnk);
- }
-
- classes = lstClasses;
- }
-
- public void save() {
-
- switch(type) {
- case TYPE_FOLDER:
-
- // create folder
- decompilatSaver.saveFolder(filename);
-
- // non-class files
- for(String[] arr: otherentries) {
- decompilatSaver.copyFile(arr[0], filename, arr[0]);
- }
-
- // classes
- for(int i=0;i<classes.size();i++) {
-
- StructClass cl = classes.get(i);
- String entryname = classentries.get(i);
-
- entryname = decompiledData.getClassEntryName(cl, entryname);
- if(entryname != null) {
- String content = decompiledData.getClassContent(cl);
- if(content != null) {
- decompilatSaver.saveClassFile(filename, cl.qualifiedName, entryname, content);
- }
- }
- }
-
- break;
- case TYPE_JAR:
- case TYPE_ZIP:
-
- // create archive file
- decompilatSaver.saveFolder(archivepath);
- decompilatSaver.createArchive(archivepath, filename, manifest);
-
- // directory entries
- for(String direntry: direntries) {
- decompilatSaver.saveEntry(archivepath, filename, direntry, null);
- }
-
- // non-class entries
- for(String[] arr: otherentries) {
- // manifest was defined by constructor invocation
- if(type != TYPE_JAR || !MANIFEST_ENTRY.equalsIgnoreCase(arr[1])) {
- decompilatSaver.copyEntry(arr[0], archivepath, filename, arr[1]);
- }
- }
-
- // classes
- for(int i=0;i<classes.size();i++) {
-
- StructClass cl = classes.get(i);
- String entryname = classentries.get(i);
-
- entryname = decompiledData.getClassEntryName(cl, entryname);
- if(entryname != null) {
- String content = decompiledData.getClassContent(cl);
- decompilatSaver.saveClassEntry(archivepath, filename, cl.qualifiedName, entryname, content);
- }
- }
-
- decompilatSaver.closeArchive(archivepath, filename);
- }
- }
-
- // *****************************************************************************
- // private methods
- // *****************************************************************************
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public void setManifest(Manifest manifest) {
- this.manifest = manifest;
- }
-
- public boolean isOwn() {
- return own;
- }
-
- public List<StructClass> getClasses() {
- return classes;
- }
-
- public int getType() {
- return type;
- }
-
- public void setDecompilatSaver(IDecompilatSaver decompilatSaver) {
- this.decompilatSaver = decompilatSaver;
- }
-
- public void setDecompiledData(IDecompiledData decompiledData) {
- this.decompiledData = decompiledData;
- }
+ public static final int TYPE_FOLDER = 0;
+ public static final int TYPE_JAR = 1;
+ public static final int TYPE_ZIP = 2;
+
+ private static final String MANIFEST_ENTRY = "META-INF/MANIFEST.MF";
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private int type;
+
+ // relative path to jar/zip
+ private String archivepath;
+
+ // folder: relative path
+ // archive: file name
+ private String filename;
+
+ private List<StructClass> classes = new ArrayList<StructClass>();
+
+ // class file or jar/zip entry. Should, but doesn't have to be the same as qualifiedName of the class
+ private List<String> classentries = new ArrayList<String>();
+
+ private List<String> direntries = new ArrayList<String>();
+
+ private List<String[]> otherentries = new ArrayList<String[]>();
+
+ private Manifest manifest;
+
+ private IDecompilatSaver decompilatSaver;
+
+ private IDecompiledData decompiledData;
+
+ private boolean own = true;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public ContextUnit(int type, String archivepath, String filename, boolean own,
+ IDecompilatSaver decompilatSaver, IDecompiledData decompiledData) {
+ this.type = type;
+ this.own = own;
+ this.archivepath = archivepath;
+ this.filename = filename;
+ this.decompilatSaver = decompilatSaver;
+ this.decompiledData = decompiledData;
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void addClass(StructClass cl, String entryname) {
+ classes.add(cl);
+ classentries.add(entryname);
+ }
+
+ public void addDirEntry(String entry) {
+ direntries.add(entry);
+ }
+
+ public void addOtherEntry(String fullpath, String entry) {
+ otherentries.add(new String[]{fullpath, entry});
+ }
+
+ public void reload(LazyLoader loader) throws IOException {
+
+ List<StructClass> lstClasses = new ArrayList<StructClass>();
+ for (StructClass cl : classes) {
+ String oldname = cl.qualifiedName;
+ StructClass newcl = new StructClass(loader.getClassStream(oldname), cl.isOwn(), loader);
+
+ lstClasses.add(newcl);
+
+ Link lnk = loader.getClassLink(oldname);
+ loader.removeClassLink(oldname);
+ loader.addClassLink(newcl.qualifiedName, lnk);
+ }
+
+ classes = lstClasses;
+ }
+
+ public void save() {
+
+ switch (type) {
+ case TYPE_FOLDER:
+
+ // create folder
+ decompilatSaver.saveFolder(filename);
+
+ // non-class files
+ for (String[] arr : otherentries) {
+ decompilatSaver.copyFile(arr[0], filename, arr[0]);
+ }
+
+ // classes
+ for (int i = 0; i < classes.size(); i++) {
+
+ StructClass cl = classes.get(i);
+ String entryname = classentries.get(i);
+
+ entryname = decompiledData.getClassEntryName(cl, entryname);
+ if (entryname != null) {
+ String content = decompiledData.getClassContent(cl);
+ if (content != null) {
+ decompilatSaver.saveClassFile(filename, cl.qualifiedName, entryname, content);
+ }
+ }
+ }
+
+ break;
+ case TYPE_JAR:
+ case TYPE_ZIP:
+
+ // create archive file
+ decompilatSaver.saveFolder(archivepath);
+ decompilatSaver.createArchive(archivepath, filename, manifest);
+
+ // directory entries
+ for (String direntry : direntries) {
+ decompilatSaver.saveEntry(archivepath, filename, direntry, null);
+ }
+
+ // non-class entries
+ for (String[] arr : otherentries) {
+ // manifest was defined by constructor invocation
+ if (type != TYPE_JAR || !MANIFEST_ENTRY.equalsIgnoreCase(arr[1])) {
+ decompilatSaver.copyEntry(arr[0], archivepath, filename, arr[1]);
+ }
+ }
+
+ // classes
+ for (int i = 0; i < classes.size(); i++) {
+
+ StructClass cl = classes.get(i);
+ String entryname = classentries.get(i);
+
+ entryname = decompiledData.getClassEntryName(cl, entryname);
+ if (entryname != null) {
+ String content = decompiledData.getClassContent(cl);
+ decompilatSaver.saveClassEntry(archivepath, filename, cl.qualifiedName, entryname, content);
+ }
+ }
+
+ decompilatSaver.closeArchive(archivepath, filename);
+ }
+ }
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public void setManifest(Manifest manifest) {
+ this.manifest = manifest;
+ }
+
+ public boolean isOwn() {
+ return own;
+ }
+
+ public List<StructClass> getClasses() {
+ return classes;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setDecompilatSaver(IDecompilatSaver decompilatSaver) {
+ this.decompilatSaver = decompilatSaver;
+ }
+
+ public void setDecompiledData(IDecompiledData decompiledData) {
+ this.decompiledData = decompiledData;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/IDecompiledData.java b/src/org/jetbrains/java/decompiler/struct/IDecompiledData.java
index 9c8bc14..1976216 100644
--- a/src/org/jetbrains/java/decompiler/struct/IDecompiledData.java
+++ b/src/org/jetbrains/java/decompiler/struct/IDecompiledData.java
@@ -1,23 +1,23 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct;
public interface IDecompiledData {
- public String getClassEntryName(StructClass cl, String entryname);
+ public String getClassEntryName(StructClass cl, String entryname);
- public String getClassContent(StructClass cl);
-
+ public String getClassContent(StructClass cl);
}
diff --git a/src/org/jetbrains/java/decompiler/struct/ISaveClass.java b/src/org/jetbrains/java/decompiler/struct/ISaveClass.java
index 6fbfb9c..69a90f9 100644
--- a/src/org/jetbrains/java/decompiler/struct/ISaveClass.java
+++ b/src/org/jetbrains/java/decompiler/struct/ISaveClass.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct;
import java.io.DataOutputStream;
@@ -21,10 +22,9 @@ import java.io.IOException;
public interface ISaveClass {
- public String getClassEntryName(StructClass cl, String entryname);
-
- public void saveClassToFile(StructClass cl, File file) throws FileNotFoundException, IOException;
+ public String getClassEntryName(StructClass cl, String entryname);
+
+ public void saveClassToFile(StructClass cl, File file) throws FileNotFoundException, IOException;
- public void saveClassToStream(StructClass cl, DataOutputStream out);
-
+ public void saveClassToStream(StructClass cl, DataOutputStream out);
}
diff --git a/src/org/jetbrains/java/decompiler/struct/StructClass.java b/src/org/jetbrains/java/decompiler/struct/StructClass.java
index 456cc70..19946a0 100644
--- a/src/org/jetbrains/java/decompiler/struct/StructClass.java
+++ b/src/org/jetbrains/java/decompiler/struct/StructClass.java
@@ -1,27 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
@@ -31,6 +24,8 @@ import org.jetbrains.java.decompiler.util.DataInputFullStream;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.io.*;
+
/*
ClassFile {
u4 magic;
@@ -54,299 +49,298 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection;
public class StructClass {
- // *****************************************************************************
- // public fields
- // *****************************************************************************
-
- public int minor_version;
-
- public int major_version;
-
- public int access_flags;
-
- public int this_class;
-
- public int super_class;
-
- public PrimitiveConstant thisClass;
-
- public PrimitiveConstant superClass;
-
- public String qualifiedName;
-
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private ConstantPool pool;
-
- private int[] interfaces;
-
- private String[] interfaceNames;
-
- private VBStyleCollection<StructField, String> fields = new VBStyleCollection<StructField, String>();
-
- private VBStyleCollection<StructMethod, String> methods = new VBStyleCollection<StructMethod, String>();
-
- private VBStyleCollection<StructGeneralAttribute, String> attributes = new VBStyleCollection<StructGeneralAttribute, String>();
-
- private boolean own = true;
-
- private LazyLoader loader;
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public StructClass(String filename, boolean own, LazyLoader loader) throws FileNotFoundException, IOException {
- this(new FileInputStream(filename), own, loader);
- }
-
- public StructClass(InputStream inStream, boolean own, LazyLoader loader) throws FileNotFoundException, IOException {
- this(new DataInputFullStream(inStream), own, loader);
- }
-
- public StructClass(DataInputFullStream inStream, boolean own, LazyLoader loader) throws FileNotFoundException, IOException {
- this.own = own;
- this.loader = loader;
-
- initStruct(inStream);
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public boolean hasField(String name, String descriptor) {
- return getField(name, descriptor) != null;
- }
-
- public StructField getField(String name, String descriptor) {
- return fields.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
- }
-
- public StructMethod getMethod(String key) {
- return methods.getWithKey(key);
- }
-
- public StructMethod getMethod(String name, String descriptor) {
- return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
- }
-
- public void writeToFile(File file) throws IOException {
- DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
- writeToOutputStream(out);
- out.close();
- }
-
- public void writeToOutputStream(DataOutputStream out) throws IOException {
-
- out.writeInt(0xCAFEBABE);
- out.writeShort(minor_version);
- out.writeShort(major_version);
-
- getPool().writeToOutputStream(out);
-
- out.writeShort(access_flags);
- out.writeShort(this_class);
- out.writeShort(super_class);
-
- out.writeShort(interfaces.length);
- for(int i=0;i<interfaces.length;i++) {
- out.writeShort(interfaces[i]);
- }
-
- out.writeShort(fields.size());
- for(int i=0;i<fields.size();i++) {
- fields.get(i).writeToStream(out);
- }
-
- out.writeShort(methods.size());
- for(int i=0;i<methods.size();i++) {
- methods.get(i).writeToStream(out);
- }
-
- out.writeShort(attributes.size());
- for(StructGeneralAttribute attr: attributes) {
- attr.writeToStream(out);
- }
-
- }
-
- public String getInterface(int i) {
- return interfaceNames[i];
- }
-
- public void releaseResources() {
- if(loader != null) {
- pool = null;
- }
- }
-
- // *****************************************************************************
- // private methods
- // *****************************************************************************
-
- private void initStruct(DataInputFullStream in) throws IOException {
-
- in.skip(4);
-
- this.minor_version = in.readUnsignedShort();
- this.major_version = in.readUnsignedShort();
-
- pool = new ConstantPool(in);
-
- this.access_flags = in.readUnsignedShort();
-
- this_class = in.readUnsignedShort();
- thisClass = pool.getPrimitiveConstant(this_class);
- qualifiedName = thisClass.getString();
-
- super_class = in.readUnsignedShort();
- superClass = pool.getPrimitiveConstant(super_class);
-
- // interfaces
- int length = in.readUnsignedShort();
- int[] arrInterfaces = new int[length];
- String[] arrInterfaceNames = new String[length];
-
- for (int i = 0; i < length; i++) {
- arrInterfaces[i] = in.readUnsignedShort();
- arrInterfaceNames[i] = pool.getPrimitiveConstant(arrInterfaces[i]).getString();
- }
- this.interfaces = arrInterfaces;
- this.interfaceNames = arrInterfaceNames;
-
- // fields
- VBStyleCollection<StructField, String> lstFields = new VBStyleCollection<StructField, String>();
- length = in.readUnsignedShort();
- for (int i = 0; i < length; i++) {
- StructField field = new StructField();
- field.access_flags = in.readUnsignedShort();
- field.name_index = in.readUnsignedShort();
- field.descriptor_index = in.readUnsignedShort();
-
- field.initStrings(pool, this_class);
-
- field.setAttributes(readAttributes(in));
-
- lstFields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor()));
- }
- this.fields = lstFields;
-
- // methods
- length = in.readUnsignedShort();
- for (int i = 0; i < length; i++) {
- StructMethod meth = new StructMethod(in, own, this);
-
- //if(qualifiedName.endsWith("JUnitStatusLine") && !meth.getName().equals("onProcessStarted") && !meth.getName().startsWith("access")) {
- //if(!meth.getName().equals("run")) {
- // continue;
- //}
-
- methods.addWithKey(meth, InterpreterUtil.makeUniqueKey(meth.getName(), meth.getDescriptor()));
- }
-
- // attributes
- this.attributes = readAttributes(in);
-
-
- // release memory
- if(loader != null) {
- pool = null;
- }
- }
-
- private VBStyleCollection<StructGeneralAttribute, String> readAttributes(DataInputFullStream in) throws IOException {
-
- VBStyleCollection<StructGeneralAttribute, String> lstAttribute = new VBStyleCollection<StructGeneralAttribute, String>();
-
- int length = in.readUnsignedShort();
- for (int i = 0; i < length; i++) {
- int attr_nameindex = in.readUnsignedShort();
- String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
-
- StructGeneralAttribute attr = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname);
-
- if(attr != null) {
- byte[] arr = new byte[in.readInt()];
- in.readFull(arr);
- attr.setInfo(arr);
-
- attr.initContent(pool);
- lstAttribute.addWithKey(attr, attr.getName());
- } else {
- in.skip(in.readInt());
- }
- }
-
- return lstAttribute;
- }
-
-
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public ConstantPool getPool() {
-
- if(pool == null && loader != null) {
- pool = loader.loadPool(qualifiedName);
- }
-
- return pool;
- }
-
- public int[] getInterfaces() {
- return interfaces;
- }
-
- public String[] getInterfaceNames() {
- return interfaceNames;
- }
-
- public VBStyleCollection<StructMethod, String> getMethods() {
- return methods;
- }
-
- public VBStyleCollection<StructField, String> getFields() {
- return fields;
- }
-
- public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
- return attributes;
- }
-
- public boolean isOwn() {
- return own;
- }
-
- public LazyLoader getLoader() {
- return loader;
- }
-
- public boolean isVersionGE_1_5() {
- return (major_version > 48 || (major_version == 48 && minor_version > 0)); // FIXME: check second condition
- }
-
- public boolean isVersionGE_1_7() {
- return (major_version >= 51);
- }
-
- public int getBytecodeVersion() {
- switch(major_version) {
- case 52:
- return CodeConstants.BYTECODE_JAVA_8;
- case 51:
- return CodeConstants.BYTECODE_JAVA_7;
- case 50:
- return CodeConstants.BYTECODE_JAVA_6;
- case 49:
- return CodeConstants.BYTECODE_JAVA_5;
- }
-
- return CodeConstants.BYTECODE_JAVA_LE_4;
- }
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int minor_version;
+
+ public int major_version;
+
+ public int access_flags;
+
+ public int this_class;
+
+ public int super_class;
+
+ public PrimitiveConstant thisClass;
+
+ public PrimitiveConstant superClass;
+
+ public String qualifiedName;
+
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private ConstantPool pool;
+
+ private int[] interfaces;
+
+ private String[] interfaceNames;
+
+ private VBStyleCollection<StructField, String> fields = new VBStyleCollection<StructField, String>();
+
+ private VBStyleCollection<StructMethod, String> methods = new VBStyleCollection<StructMethod, String>();
+
+ private VBStyleCollection<StructGeneralAttribute, String> attributes = new VBStyleCollection<StructGeneralAttribute, String>();
+
+ private boolean own = true;
+
+ private LazyLoader loader;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public StructClass(String filename, boolean own, LazyLoader loader) throws FileNotFoundException, IOException {
+ this(new FileInputStream(filename), own, loader);
+ }
+
+ public StructClass(InputStream inStream, boolean own, LazyLoader loader) throws FileNotFoundException, IOException {
+ this(new DataInputFullStream(inStream), own, loader);
+ }
+
+ public StructClass(DataInputFullStream inStream, boolean own, LazyLoader loader) throws FileNotFoundException, IOException {
+ this.own = own;
+ this.loader = loader;
+
+ initStruct(inStream);
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public boolean hasField(String name, String descriptor) {
+ return getField(name, descriptor) != null;
+ }
+
+ public StructField getField(String name, String descriptor) {
+ return fields.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
+ }
+
+ public StructMethod getMethod(String key) {
+ return methods.getWithKey(key);
+ }
+
+ public StructMethod getMethod(String name, String descriptor) {
+ return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
+ }
+
+ public void writeToFile(File file) throws IOException {
+ DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
+ writeToOutputStream(out);
+ out.close();
+ }
+
+ public void writeToOutputStream(DataOutputStream out) throws IOException {
+
+ out.writeInt(0xCAFEBABE);
+ out.writeShort(minor_version);
+ out.writeShort(major_version);
+
+ getPool().writeToOutputStream(out);
+
+ out.writeShort(access_flags);
+ out.writeShort(this_class);
+ out.writeShort(super_class);
+
+ out.writeShort(interfaces.length);
+ for (int i = 0; i < interfaces.length; i++) {
+ out.writeShort(interfaces[i]);
+ }
+
+ out.writeShort(fields.size());
+ for (int i = 0; i < fields.size(); i++) {
+ fields.get(i).writeToStream(out);
+ }
+
+ out.writeShort(methods.size());
+ for (int i = 0; i < methods.size(); i++) {
+ methods.get(i).writeToStream(out);
+ }
+
+ out.writeShort(attributes.size());
+ for (StructGeneralAttribute attr : attributes) {
+ attr.writeToStream(out);
+ }
+ }
+
+ public String getInterface(int i) {
+ return interfaceNames[i];
+ }
+
+ public void releaseResources() {
+ if (loader != null) {
+ pool = null;
+ }
+ }
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private void initStruct(DataInputFullStream in) throws IOException {
+
+ in.skip(4);
+
+ this.minor_version = in.readUnsignedShort();
+ this.major_version = in.readUnsignedShort();
+
+ pool = new ConstantPool(in);
+
+ this.access_flags = in.readUnsignedShort();
+
+ this_class = in.readUnsignedShort();
+ thisClass = pool.getPrimitiveConstant(this_class);
+ qualifiedName = thisClass.getString();
+
+ super_class = in.readUnsignedShort();
+ superClass = pool.getPrimitiveConstant(super_class);
+
+ // interfaces
+ int length = in.readUnsignedShort();
+ int[] arrInterfaces = new int[length];
+ String[] arrInterfaceNames = new String[length];
+
+ for (int i = 0; i < length; i++) {
+ arrInterfaces[i] = in.readUnsignedShort();
+ arrInterfaceNames[i] = pool.getPrimitiveConstant(arrInterfaces[i]).getString();
+ }
+ this.interfaces = arrInterfaces;
+ this.interfaceNames = arrInterfaceNames;
+
+ // fields
+ VBStyleCollection<StructField, String> lstFields = new VBStyleCollection<StructField, String>();
+ length = in.readUnsignedShort();
+ for (int i = 0; i < length; i++) {
+ StructField field = new StructField();
+ field.access_flags = in.readUnsignedShort();
+ field.name_index = in.readUnsignedShort();
+ field.descriptor_index = in.readUnsignedShort();
+
+ field.initStrings(pool, this_class);
+
+ field.setAttributes(readAttributes(in));
+
+ lstFields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor()));
+ }
+ this.fields = lstFields;
+
+ // methods
+ length = in.readUnsignedShort();
+ for (int i = 0; i < length; i++) {
+ StructMethod meth = new StructMethod(in, own, this);
+
+ //if(qualifiedName.endsWith("JUnitStatusLine") && !meth.getName().equals("onProcessStarted") && !meth.getName().startsWith("access")) {
+ //if(!meth.getName().equals("run")) {
+ // continue;
+ //}
+
+ methods.addWithKey(meth, InterpreterUtil.makeUniqueKey(meth.getName(), meth.getDescriptor()));
+ }
+
+ // attributes
+ this.attributes = readAttributes(in);
+
+
+ // release memory
+ if (loader != null) {
+ pool = null;
+ }
+ }
+
+ private VBStyleCollection<StructGeneralAttribute, String> readAttributes(DataInputFullStream in) throws IOException {
+
+ VBStyleCollection<StructGeneralAttribute, String> lstAttribute = new VBStyleCollection<StructGeneralAttribute, String>();
+
+ int length = in.readUnsignedShort();
+ for (int i = 0; i < length; i++) {
+ int attr_nameindex = in.readUnsignedShort();
+ String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
+
+ StructGeneralAttribute attr = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname);
+
+ if (attr != null) {
+ byte[] arr = new byte[in.readInt()];
+ in.readFull(arr);
+ attr.setInfo(arr);
+
+ attr.initContent(pool);
+ lstAttribute.addWithKey(attr, attr.getName());
+ }
+ else {
+ in.skip(in.readInt());
+ }
+ }
+
+ return lstAttribute;
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public ConstantPool getPool() {
+
+ if (pool == null && loader != null) {
+ pool = loader.loadPool(qualifiedName);
+ }
+
+ return pool;
+ }
+
+ public int[] getInterfaces() {
+ return interfaces;
+ }
+
+ public String[] getInterfaceNames() {
+ return interfaceNames;
+ }
+
+ public VBStyleCollection<StructMethod, String> getMethods() {
+ return methods;
+ }
+
+ public VBStyleCollection<StructField, String> getFields() {
+ return fields;
+ }
+
+ public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
+ return attributes;
+ }
+
+ public boolean isOwn() {
+ return own;
+ }
+
+ public LazyLoader getLoader() {
+ return loader;
+ }
+
+ public boolean isVersionGE_1_5() {
+ return (major_version > 48 || (major_version == 48 && minor_version > 0)); // FIXME: check second condition
+ }
+
+ public boolean isVersionGE_1_7() {
+ return (major_version >= 51);
+ }
+
+ public int getBytecodeVersion() {
+ switch (major_version) {
+ case 52:
+ return CodeConstants.BYTECODE_JAVA_8;
+ case 51:
+ return CodeConstants.BYTECODE_JAVA_7;
+ case 50:
+ return CodeConstants.BYTECODE_JAVA_6;
+ case 49:
+ return CodeConstants.BYTECODE_JAVA_5;
+ }
+
+ return CodeConstants.BYTECODE_JAVA_LE_4;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/StructContext.java b/src/org/jetbrains/java/decompiler/struct/StructContext.java
index c253a10..3728a2a 100644
--- a/src/org/jetbrains/java/decompiler/struct/StructContext.java
+++ b/src/org/jetbrains/java/decompiler/struct/StructContext.java
@@ -1,19 +1,25 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
+
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
@@ -22,190 +28,189 @@ import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
-import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver;
-import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
-import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
-
public class StructContext {
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private LazyLoader loader;
-
- private HashMap<String, StructClass> classes = new HashMap<String, StructClass>();
-
- private HashMap<String, ContextUnit> units = new HashMap<String, ContextUnit>();
-
- private ContextUnit defaultUnit;
-
- private IDecompilatSaver saver;
-
- private IDecompiledData decdata;
-
- public StructContext(IDecompilatSaver saver, IDecompiledData decdata, LazyLoader loader) {
-
- this.saver = saver;
- this.decdata = decdata;
- this.loader = loader;
-
- defaultUnit = new ContextUnit(ContextUnit.TYPE_FOLDER, null, "", true, saver, decdata);
- units.put("", defaultUnit);
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public StructClass getClass(String name) {
- return classes.get(name);
- }
-
- public void reloadContext() throws IOException {
-
- for(ContextUnit unit: units.values()) {
-
- for(StructClass cl : unit.getClasses()) {
- classes.remove(cl.qualifiedName);
- }
-
- unit.reload(loader);
-
- // adjust lobal class collection
- for(StructClass cl : unit.getClasses()) {
- classes.put(cl.qualifiedName, cl);
- }
- }
- }
-
- public void saveContext() {
-
- for(ContextUnit unit: units.values()) {
- if(unit.isOwn()) {
- unit.save();
- }
- }
- }
-
- public void addSpace(File file, boolean isOwn) throws IOException {
- addSpace("", file, isOwn);
- }
-
- private void addSpace(String path, File file, boolean isOwn) throws IOException {
-
- if(file.isDirectory()) {
-
- File[] files = file.listFiles();
- path += "/" + (path.length()==0?"":file.getName());
-
- for(int i=files.length-1;i>=0;i--) {
- addSpace(path, files[i], isOwn);
- }
-
- } else {
-
- String filename = file.getName();
-
- boolean isArchive = false;
-
- try {
- if(filename.endsWith(".jar")) {
- addArchive(path, file, ContextUnit.TYPE_JAR, isOwn);
- isArchive = true;
- } else if(filename.endsWith(".zip")) {
- addArchive(path, file, ContextUnit.TYPE_ZIP, isOwn);
- isArchive = true;
- }
- } catch(IOException ex) {
- DecompilerContext.getLogger()
- .writeMessage("Invalid archive file: "+(path.length()>0?path+"/":"")+filename, IFernflowerLogger.ERROR);
- }
-
- if(!isArchive) {
- ContextUnit unit = units.get(path);
- if(unit == null) {
- unit = new ContextUnit(ContextUnit.TYPE_FOLDER, null, path, isOwn, saver, decdata);
- units.put(path, unit);
- }
-
- boolean isClass = false;
-
- if(filename.endsWith(".class")) {
- try {
- StructClass cl = new StructClass(loader.getClassStream(file.getAbsolutePath(), null), isOwn, loader);
-
- classes.put(cl.qualifiedName, cl);
- unit.addClass(cl, filename);
- loader.addClassLink(cl.qualifiedName, new LazyLoader.Link(LazyLoader.Link.CLASS, file.getAbsolutePath(), null));
-
- isClass = true;
- } catch(IOException ex) {
- DecompilerContext.getLogger()
- .writeMessage("Invalid class file: "+(path.length()>0?path+"/":"")+filename, IFernflowerLogger.ERROR);
- }
- }
-
- if(!isClass) {
- unit.addOtherEntry(file.getAbsolutePath(), filename);
- }
- }
- }
- }
-
-
- private void addArchive(String path, File file, int type, boolean isOwn) throws IOException {
-
- ZipFile archive;
-
- if(type == ContextUnit.TYPE_JAR) { // jar
- archive = new JarFile(file);
- } else { // zip
- archive = new ZipFile(file);
- }
-
- Enumeration<? extends ZipEntry> en = archive.entries();
- while(en.hasMoreElements()) {
- ZipEntry entr = en.nextElement();
-
- ContextUnit unit = units.get(path+"/"+file.getName());
- if(unit == null) {
- unit = new ContextUnit(type, path, file.getName(), isOwn, saver, decdata);
- if(type == ContextUnit.TYPE_JAR) {
- unit.setManifest(((JarFile)archive).getManifest());
- }
- units.put(path+"/"+file.getName(), unit);
- }
-
- String name = entr.getName();
- if(!entr.isDirectory()) {
- if(name.endsWith(".class")) {
- StructClass cl = new StructClass(archive.getInputStream(entr), isOwn, loader);
- classes.put(cl.qualifiedName, cl);
-
- unit.addClass(cl, name);
-
- if(loader != null) {
- loader.addClassLink(cl.qualifiedName, new LazyLoader.Link(LazyLoader.Link.ENTRY, file.getAbsolutePath(), name));
- }
-
- } else {
- unit.addOtherEntry(file.getAbsolutePath(), name);
- }
- } else if(entr.isDirectory()) {
- unit.addDirEntry(name);
- }
- }
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public HashMap<String, StructClass> getClasses() {
- return classes;
- }
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private LazyLoader loader;
+
+ private HashMap<String, StructClass> classes = new HashMap<String, StructClass>();
+
+ private HashMap<String, ContextUnit> units = new HashMap<String, ContextUnit>();
+
+ private ContextUnit defaultUnit;
+
+ private IDecompilatSaver saver;
+
+ private IDecompiledData decdata;
+
+ public StructContext(IDecompilatSaver saver, IDecompiledData decdata, LazyLoader loader) {
+
+ this.saver = saver;
+ this.decdata = decdata;
+ this.loader = loader;
+
+ defaultUnit = new ContextUnit(ContextUnit.TYPE_FOLDER, null, "", true, saver, decdata);
+ units.put("", defaultUnit);
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public StructClass getClass(String name) {
+ return classes.get(name);
+ }
+
+ public void reloadContext() throws IOException {
+
+ for (ContextUnit unit : units.values()) {
+
+ for (StructClass cl : unit.getClasses()) {
+ classes.remove(cl.qualifiedName);
+ }
+
+ unit.reload(loader);
+
+ // adjust lobal class collection
+ for (StructClass cl : unit.getClasses()) {
+ classes.put(cl.qualifiedName, cl);
+ }
+ }
+ }
+
+ public void saveContext() {
+
+ for (ContextUnit unit : units.values()) {
+ if (unit.isOwn()) {
+ unit.save();
+ }
+ }
+ }
+
+ public void addSpace(File file, boolean isOwn) throws IOException {
+ addSpace("", file, isOwn);
+ }
+
+ private void addSpace(String path, File file, boolean isOwn) throws IOException {
+
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ path += "/" + (path.length() == 0 ? "" : file.getName());
+
+ for (int i = files.length - 1; i >= 0; i--) {
+ addSpace(path, files[i], isOwn);
+ }
+ }
+ else {
+
+ String filename = file.getName();
+
+ boolean isArchive = false;
+
+ try {
+ if (filename.endsWith(".jar")) {
+ addArchive(path, file, ContextUnit.TYPE_JAR, isOwn);
+ isArchive = true;
+ }
+ else if (filename.endsWith(".zip")) {
+ addArchive(path, file, ContextUnit.TYPE_ZIP, isOwn);
+ isArchive = true;
+ }
+ }
+ catch (IOException ex) {
+ DecompilerContext.getLogger()
+ .writeMessage("Invalid archive file: " + (path.length() > 0 ? path + "/" : "") + filename, IFernflowerLogger.ERROR);
+ }
+
+ if (!isArchive) {
+ ContextUnit unit = units.get(path);
+ if (unit == null) {
+ unit = new ContextUnit(ContextUnit.TYPE_FOLDER, null, path, isOwn, saver, decdata);
+ units.put(path, unit);
+ }
+
+ boolean isClass = false;
+
+ if (filename.endsWith(".class")) {
+ try {
+ StructClass cl = new StructClass(loader.getClassStream(file.getAbsolutePath(), null), isOwn, loader);
+
+ classes.put(cl.qualifiedName, cl);
+ unit.addClass(cl, filename);
+ loader.addClassLink(cl.qualifiedName, new LazyLoader.Link(LazyLoader.Link.CLASS, file.getAbsolutePath(), null));
+
+ isClass = true;
+ }
+ catch (IOException ex) {
+ DecompilerContext.getLogger()
+ .writeMessage("Invalid class file: " + (path.length() > 0 ? path + "/" : "") + filename, IFernflowerLogger.ERROR);
+ }
+ }
+
+ if (!isClass) {
+ unit.addOtherEntry(file.getAbsolutePath(), filename);
+ }
+ }
+ }
+ }
+
+
+ private void addArchive(String path, File file, int type, boolean isOwn) throws IOException {
+
+ ZipFile archive;
+
+ if (type == ContextUnit.TYPE_JAR) { // jar
+ archive = new JarFile(file);
+ }
+ else { // zip
+ archive = new ZipFile(file);
+ }
+
+ Enumeration<? extends ZipEntry> en = archive.entries();
+ while (en.hasMoreElements()) {
+ ZipEntry entr = en.nextElement();
+
+ ContextUnit unit = units.get(path + "/" + file.getName());
+ if (unit == null) {
+ unit = new ContextUnit(type, path, file.getName(), isOwn, saver, decdata);
+ if (type == ContextUnit.TYPE_JAR) {
+ unit.setManifest(((JarFile)archive).getManifest());
+ }
+ units.put(path + "/" + file.getName(), unit);
+ }
+
+ String name = entr.getName();
+ if (!entr.isDirectory()) {
+ if (name.endsWith(".class")) {
+ StructClass cl = new StructClass(archive.getInputStream(entr), isOwn, loader);
+ classes.put(cl.qualifiedName, cl);
+
+ unit.addClass(cl, name);
+
+ if (loader != null) {
+ loader.addClassLink(cl.qualifiedName, new LazyLoader.Link(LazyLoader.Link.ENTRY, file.getAbsolutePath(), name));
+ }
+ }
+ else {
+ unit.addOtherEntry(file.getAbsolutePath(), name);
+ }
+ }
+ else if (entr.isDirectory()) {
+ unit.addDirEntry(name);
+ }
+ }
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public HashMap<String, StructClass> getClasses() {
+ return classes;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/StructField.java b/src/org/jetbrains/java/decompiler/struct/StructField.java
index 2537e7b..4c0f25d 100644
--- a/src/org/jetbrains/java/decompiler/struct/StructField.java
+++ b/src/org/jetbrains/java/decompiler/struct/StructField.java
@@ -1,28 +1,29 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
/*
- field_info {
+ field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
@@ -33,77 +34,77 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection;
public class StructField {
- // *****************************************************************************
- // public fields
- // *****************************************************************************
-
- public int access_flags;
- public int name_index;
- public int descriptor_index;
-
- private String name;
- private String descriptor;
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private VBStyleCollection<StructGeneralAttribute, String> attributes;
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public StructField() {}
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public void writeToStream(DataOutputStream out) throws IOException {
-
- out.writeShort(access_flags);
- out.writeShort(name_index);
- out.writeShort(descriptor_index);
-
- out.writeShort(attributes.size());
- for(StructGeneralAttribute attr: attributes) {
- attr.writeToStream(out);
- }
- }
-
- public void initStrings(ConstantPool pool, int class_index) {
- String[] values = pool.getClassElement(ConstantPool.FIELD, class_index, name_index, descriptor_index);
- name = values[0];
- descriptor = values[1];
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
- return attributes;
- }
-
- public void setAttributes(VBStyleCollection<StructGeneralAttribute, String> attributes) {
- this.attributes = attributes;
- }
-
- public String getDescriptor() {
- return descriptor;
- }
-
- public void setDescriptor(String descriptor) {
- this.descriptor = descriptor;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int access_flags;
+ public int name_index;
+ public int descriptor_index;
+
+ private String name;
+ private String descriptor;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private VBStyleCollection<StructGeneralAttribute, String> attributes;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public StructField() {
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+
+ out.writeShort(access_flags);
+ out.writeShort(name_index);
+ out.writeShort(descriptor_index);
+
+ out.writeShort(attributes.size());
+ for (StructGeneralAttribute attr : attributes) {
+ attr.writeToStream(out);
+ }
+ }
+
+ public void initStrings(ConstantPool pool, int class_index) {
+ String[] values = pool.getClassElement(ConstantPool.FIELD, class_index, name_index, descriptor_index);
+ name = values[0];
+ descriptor = values[1];
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
+ return attributes;
+ }
+
+ public void setAttributes(VBStyleCollection<StructGeneralAttribute, String> attributes) {
+ this.attributes = attributes;
+ }
+
+ public String getDescriptor() {
+ return descriptor;
+ }
+
+ public void setDescriptor(String descriptor) {
+ this.descriptor = descriptor;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/StructMethod.java b/src/org/jetbrains/java/decompiler/struct/StructMethod.java
index 20fdae9..baaf633 100644
--- a/src/org/jetbrains/java/decompiler/struct/StructMethod.java
+++ b/src/org/jetbrains/java/decompiler/struct/StructMethod.java
@@ -1,19 +1,27 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct;
+import org.jetbrains.java.decompiler.code.*;
+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
@@ -21,19 +29,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.code.ConstantsUtil;
-import org.jetbrains.java.decompiler.code.ExceptionHandler;
-import org.jetbrains.java.decompiler.code.ExceptionTable;
-import org.jetbrains.java.decompiler.code.FullInstructionSequence;
-import org.jetbrains.java.decompiler.code.Instruction;
-import org.jetbrains.java.decompiler.code.InstructionSequence;
-import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
-import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
-import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
-import org.jetbrains.java.decompiler.util.DataInputFullStream;
-import org.jetbrains.java.decompiler.util.VBStyleCollection;
-
/*
method_info {
u2 access_flags;
@@ -45,516 +40,525 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection;
*/
public class StructMethod implements CodeConstants {
-
- // *****************************************************************************
- // public fields
- // *****************************************************************************
-
- public int name_index;
-
- public int descriptor_index;
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private static final int[] opr_iconst = new int[] {-1,0,1,2,3,4,5};
-
- private static final int[] opr_loadstore = new int[] {0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3};
-
- private static final int[] opcs_load = new int[] {opc_iload,opc_lload,opc_fload,opc_dload,opc_aload};
-
- private static final int[] opcs_store = new int[] {opc_istore,opc_lstore,opc_fstore,opc_dstore,opc_astore};
-
-
- private int accessFlags;
-
- private VBStyleCollection<StructGeneralAttribute, String> attributes;
-
- private int localVariables;
-
- private int maxStack;
-
- private String name;
-
- private String descriptor;
-
- private InstructionSequence seq;
-
- private boolean containsCode = false;
-
- private boolean own;
-
- private StructClass classStruct;
-
-
- // lazy properties
- private boolean lazy;
-
- private boolean expanded;
-
- private byte[] code_content;
-
- private int code_length = 0;
-
- private int code_fulllength = 0;
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public StructMethod(DataInputFullStream in, boolean own, StructClass clstruct) throws IOException {
- this(in, true, own, clstruct);
- }
-
- public StructMethod(DataInputFullStream in, boolean lazy, boolean own, StructClass clstruct) throws IOException {
-
- this.own = own;
- this.lazy = lazy;
- this.expanded = !lazy;
- this.classStruct = clstruct;
-
- accessFlags = in.readUnsignedShort();
- name_index = in.readUnsignedShort();
- descriptor_index = in.readUnsignedShort();
-
- ConstantPool pool = clstruct.getPool();
-
- initStrings(pool, clstruct.this_class);
-
- VBStyleCollection<StructGeneralAttribute, String> lstAttribute = new VBStyleCollection<StructGeneralAttribute, String>();
- int len = in.readUnsignedShort();
- for(int i=0;i<len;i++) {
-
- int attr_nameindex = in.readUnsignedShort();
- String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
-
- if(StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) {
- if(!this.own) {
- // skip code in foreign classes
- in.skip(8);
- in.skip(in.readInt());
- in.skip(8*in.readUnsignedShort());
- } else {
- containsCode = true;
-
- in.skip(4);
-
- maxStack = in.readUnsignedShort();
- localVariables = in.readUnsignedShort();
-
- if(lazy) {
- code_length = in.readInt();
-
- in.skip(code_length);
-
- int exc_length = in.readUnsignedShort();
- code_fulllength = code_length + exc_length*8+2;
-
- in.skip(exc_length*8);
-
- } else {
- seq = parseBytecode(in, in.readInt(), pool);
- }
- }
-
- // code attributes
- int length = in.readUnsignedShort();
- for (int j = 0; j < length; j++) {
- int codeattr_nameindex = in.readUnsignedShort();
- String codeattrname = pool.getPrimitiveConstant(codeattr_nameindex).getString();
-
- readAttribute(in, pool, lstAttribute, codeattr_nameindex, codeattrname);
- }
- } else {
- readAttribute(in, pool, lstAttribute, attr_nameindex, attrname);
- }
- }
-
- attributes = lstAttribute;
- }
-
-
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public void writeToStream(DataOutputStream out) throws IOException {
-
- out.writeShort(accessFlags);
- out.writeShort(name_index);
- out.writeShort(descriptor_index);
-
- out.writeShort(attributes.size());
-
- for(StructGeneralAttribute attr: attributes) {
- if(StructGeneralAttribute.ATTRIBUTE_CODE.equals(attr.getName())){
- out.writeShort(attr.getAttribute_name_index());
-
- if(lazy && !expanded) {
- out.writeInt(10+code_content.length);
- out.writeShort(maxStack);
- out.writeShort(localVariables);
- out.writeInt(code_length);
- out.write(code_content);
- } else {
- ByteArrayOutputStream codeout = new ByteArrayOutputStream();
- seq.writeCodeToStream(new DataOutputStream(codeout));
-
- ByteArrayOutputStream excout = new ByteArrayOutputStream();
- seq.writeExceptionsToStream(new DataOutputStream(excout));
-
- out.writeInt(10+codeout.size()+excout.size());
-
- out.writeShort(maxStack);
- out.writeShort(localVariables);
- out.writeInt(codeout.size());
- codeout.writeTo(out);
- excout.writeTo(out);
- }
- // no attributes
- out.writeShort(0);
- } else {
- attr.writeToStream(out);
- }
- }
-
- }
-
- private void readAttribute(DataInputFullStream in, ConstantPool pool, VBStyleCollection<StructGeneralAttribute, String> lstAttribute,
- int attr_nameindex, String attrname) throws IOException {
-
- StructGeneralAttribute attribute = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname);
-
- if(attribute != null) {
- attrname = attribute.getName();
-
- byte[] arr = new byte[in.readInt()];
- in.readFull(arr);
- attribute.setInfo(arr);
-
- attribute.initContent(pool);
-
- if(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname) &&
- lstAttribute.containsKey(attrname)) {
- // merge all variable tables
- StructLocalVariableTableAttribute oldattr = (StructLocalVariableTableAttribute)lstAttribute.getWithKey(attrname);
- oldattr.addLocalVariableTable((StructLocalVariableTableAttribute)attribute);
- } else {
- lstAttribute.addWithKey(attribute, attribute.getName());
- }
- } else {
- in.skip(in.readInt());
- }
- }
-
- private void initStrings(ConstantPool pool, int class_index) {
- String[] values = pool.getClassElement(ConstantPool.METHOD, class_index, name_index, descriptor_index);
- name = values[0];
- descriptor = values[1];
- }
-
- public void expandData() throws IOException {
- if(containsCode && lazy && !expanded) {
-
- byte[] codearr = classStruct.getLoader().loadBytecode(this, code_fulllength);
-
- seq = parseBytecode(new DataInputFullStream(new ByteArrayInputStream(codearr)), code_length, classStruct.getPool());
- expanded = true;
- }
- }
-
- public void releaseResources() throws IOException {
- if(containsCode && lazy && expanded) {
- seq = null;
- expanded = false;
- }
- }
-
- // *****************************************************************************
- // private methods
- // *****************************************************************************
-
- private InstructionSequence parseBytecode(DataInputFullStream in, int length, ConstantPool pool) throws IOException {
-
- VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
-
- int bytecode_version = classStruct.getBytecodeVersion();
-
- for(int i=0;i<length;) {
-
- int offset = i;
-
- int opcode = in.readUnsignedByte();
- int group = GROUP_GENERAL;
-
- boolean wide = (opcode == opc_wide);
-
- if(wide) {
- i++;
- opcode = in.readUnsignedByte();
- }
-
- List<Integer> operands = new ArrayList<Integer>();
-
- if(opcode>=opc_iconst_m1 && opcode<=opc_iconst_5) {
- operands.add(new Integer(opr_iconst[opcode-opc_iconst_m1]));
- opcode = opc_bipush;
- }else if(opcode>=opc_iload_0 && opcode<=opc_aload_3) {
- operands.add(new Integer(opr_loadstore[opcode-opc_iload_0]));
- opcode = opcs_load[(opcode-opc_iload_0)/4];
- }else if(opcode>=opc_istore_0 && opcode<=opc_astore_3) {
- operands.add(new Integer(opr_loadstore[opcode-opc_istore_0]));
- opcode = opcs_store[(opcode-opc_istore_0)/4];
- } else {
- switch (opcode) {
- case opc_bipush:
- operands.add(new Integer(in.readByte()));
- i++;
- break;
- case opc_ldc:
- case opc_newarray:
- operands.add(new Integer(in.readUnsignedByte()));
- i++;
- break;
- case opc_sipush:
- case opc_ifeq:
- case opc_ifne:
- case opc_iflt:
- case opc_ifge:
- case opc_ifgt:
- case opc_ifle:
- case opc_if_icmpeq:
- case opc_if_icmpne:
- case opc_if_icmplt:
- case opc_if_icmpge:
- case opc_if_icmpgt:
- case opc_if_icmple:
- case opc_if_acmpeq:
- case opc_if_acmpne:
- case opc_goto:
- case opc_jsr:
- case opc_ifnull:
- case opc_ifnonnull:
- if(opcode!=opc_sipush) {
- group = GROUP_JUMP;
- }
- operands.add(new Integer(in.readShort()));
- i+=2;
- break;
- case opc_ldc_w:
- case opc_ldc2_w:
- case opc_getstatic:
- case opc_putstatic:
- case opc_getfield:
- case opc_putfield:
- case opc_invokevirtual:
- case opc_invokespecial:
- case opc_invokestatic:
- case opc_new:
- case opc_anewarray:
- case opc_checkcast:
- case opc_instanceof:
- operands.add(new Integer(in.readUnsignedShort()));
- i+=2;
- if(opcode>=opc_getstatic && opcode<=opc_putfield) {
- group = GROUP_FIELDACCESS;
- } else if(opcode>=opc_invokevirtual && opcode<=opc_invokestatic) {
- group = GROUP_INVOCATION;
- }
- break;
- case opc_invokedynamic:
- if(classStruct.isVersionGE_1_7()) { // instruction unused in Java 6 and before
- operands.add(new Integer(in.readUnsignedShort()));
- in.skip(2);
- group = GROUP_INVOCATION;
- i+=4;
- }
- break;
- case opc_iload:
- case opc_lload:
- case opc_fload:
- case opc_dload:
- case opc_aload:
- case opc_istore:
- case opc_lstore:
- case opc_fstore:
- case opc_dstore:
- case opc_astore:
- case opc_ret:
- if(wide) {
- operands.add(new Integer(in.readUnsignedShort()));
- i+=2;
- } else {
- operands.add(new Integer(in.readUnsignedByte()));
- i++;
- }
- if(opcode == opc_ret) {
- group = GROUP_RETURN;
- }
- break;
- case opc_iinc:
- if (wide) {
- operands.add(new Integer(in.readUnsignedShort()));
- operands.add(new Integer(in.readShort()));
- i+=4;
- } else {
- operands.add(new Integer(in.readUnsignedByte()));
- operands.add(new Integer(in.readByte()));
- i+=2;
- }
- break;
- case opc_goto_w:
- case opc_jsr_w:
- opcode = opcode == opc_jsr_w?opc_jsr:opc_goto;
- operands.add(new Integer(in.readInt()));
- group = GROUP_JUMP;
- i+=4;
- break;
- case opc_invokeinterface:
- operands.add(new Integer(in.readUnsignedShort()));
- operands.add(new Integer(in.readUnsignedByte()));
- in.skip(1);
- group = GROUP_INVOCATION;
- i+=4;
- break;
- case opc_multianewarray:
- operands.add(new Integer(in.readUnsignedShort()));
- operands.add(new Integer(in.readUnsignedByte()));
- i+=3;
- break;
- case opc_tableswitch:
- in.skip((4-(i+1)%4)%4);
- i+=((4-(i+1)%4)%4); // padding
- operands.add(new Integer(in.readInt()));
- i+=4;
- int low = in.readInt();
- operands.add(new Integer(low));
- i+=4;
- int high = in.readInt();
- operands.add(new Integer(high));
- i+=4;
-
- for(int j=0;j<high-low+1;j++) {
- operands.add(new Integer(in.readInt()));
- i+=4;
- }
- group = GROUP_SWITCH;
-
- break;
- case opc_lookupswitch:
- in.skip((4-(i+1)%4)%4);
- i+=((4-(i+1)%4)%4); // padding
- operands.add(new Integer(in.readInt()));
- i+=4;
- int npairs = in.readInt();
- operands.add(new Integer(npairs));
- i+=4;
-
- for(int j=0;j<npairs;j++) {
- operands.add(new Integer(in.readInt()));
- i+=4;
- operands.add(new Integer(in.readInt()));
- i+=4;
- }
- group = GROUP_SWITCH;
- break;
- case opc_ireturn:
- case opc_lreturn:
- case opc_freturn:
- case opc_dreturn:
- case opc_areturn:
- case opc_return:
- case opc_athrow:
- group = GROUP_RETURN;
- }
- }
-
- int[] ops = new int[operands.size()];
- for(int j=0;j<operands.size();j++) {
- ops[j] = ((Integer)operands.get(j)).intValue();
- }
-
- Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, ops);
-
- collinstr.addWithKey(instr, new Integer(offset));
-
- i++;
- }
-
- // initialize exception table
- List<ExceptionHandler> lstHandlers = new ArrayList<ExceptionHandler>();
-
- int exception_count = in.readUnsignedShort();
- for(int i=0;i<exception_count;i++) {
- ExceptionHandler handler = new ExceptionHandler();
- handler.from = in.readUnsignedShort();
- handler.to = in.readUnsignedShort();
- handler.handler = in.readUnsignedShort();
-
- int excclass = in.readUnsignedShort();
- handler.class_index = excclass;
- if(excclass!=0) {
- handler.exceptionClass = pool.getPrimitiveConstant(excclass).getString();
- }
-
- lstHandlers.add(handler);
- }
-
- InstructionSequence seq = new FullInstructionSequence(collinstr, new ExceptionTable(lstHandlers));
-
- // initialize instructions
- int i = seq.length()-1;
- seq.setPointer(i);
-
- while(i>=0) {
- Instruction instr = seq.getInstr(i--);
- if(instr.group!=GROUP_GENERAL) {
- instr.initInstruction(seq);
- }
- seq.addToPointer(-1);
- }
-
- return seq;
-
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public InstructionSequence getInstructionSequence() {
- return seq;
- }
-
- public String getDescriptor() {
- return descriptor;
- }
-
- public String getName() {
- return name;
- }
-
- public int getAccessFlags() {
- return accessFlags;
- }
-
- public int getLocalVariables() {
- return localVariables;
- }
-
- public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
- return attributes;
- }
-
- public StructClass getClassStruct() {
- return classStruct;
- }
-
- public boolean containsCode() {
- return containsCode;
- }
+
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int name_index;
+
+ public int descriptor_index;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private static final int[] opr_iconst = new int[]{-1, 0, 1, 2, 3, 4, 5};
+
+ private static final int[] opr_loadstore = new int[]{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3};
+
+ private static final int[] opcs_load = new int[]{opc_iload, opc_lload, opc_fload, opc_dload, opc_aload};
+
+ private static final int[] opcs_store = new int[]{opc_istore, opc_lstore, opc_fstore, opc_dstore, opc_astore};
+
+
+ private int accessFlags;
+
+ private VBStyleCollection<StructGeneralAttribute, String> attributes;
+
+ private int localVariables;
+
+ private int maxStack;
+
+ private String name;
+
+ private String descriptor;
+
+ private InstructionSequence seq;
+
+ private boolean containsCode = false;
+
+ private boolean own;
+
+ private StructClass classStruct;
+
+
+ // lazy properties
+ private boolean lazy;
+
+ private boolean expanded;
+
+ private byte[] code_content;
+
+ private int code_length = 0;
+
+ private int code_fulllength = 0;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public StructMethod(DataInputFullStream in, boolean own, StructClass clstruct) throws IOException {
+ this(in, true, own, clstruct);
+ }
+
+ public StructMethod(DataInputFullStream in, boolean lazy, boolean own, StructClass clstruct) throws IOException {
+
+ this.own = own;
+ this.lazy = lazy;
+ this.expanded = !lazy;
+ this.classStruct = clstruct;
+
+ accessFlags = in.readUnsignedShort();
+ name_index = in.readUnsignedShort();
+ descriptor_index = in.readUnsignedShort();
+
+ ConstantPool pool = clstruct.getPool();
+
+ initStrings(pool, clstruct.this_class);
+
+ VBStyleCollection<StructGeneralAttribute, String> lstAttribute = new VBStyleCollection<StructGeneralAttribute, String>();
+ int len = in.readUnsignedShort();
+ for (int i = 0; i < len; i++) {
+
+ int attr_nameindex = in.readUnsignedShort();
+ String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
+
+ if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) {
+ if (!this.own) {
+ // skip code in foreign classes
+ in.skip(8);
+ in.skip(in.readInt());
+ in.skip(8 * in.readUnsignedShort());
+ }
+ else {
+ containsCode = true;
+
+ in.skip(4);
+
+ maxStack = in.readUnsignedShort();
+ localVariables = in.readUnsignedShort();
+
+ if (lazy) {
+ code_length = in.readInt();
+
+ in.skip(code_length);
+
+ int exc_length = in.readUnsignedShort();
+ code_fulllength = code_length + exc_length * 8 + 2;
+
+ in.skip(exc_length * 8);
+ }
+ else {
+ seq = parseBytecode(in, in.readInt(), pool);
+ }
+ }
+
+ // code attributes
+ int length = in.readUnsignedShort();
+ for (int j = 0; j < length; j++) {
+ int codeattr_nameindex = in.readUnsignedShort();
+ String codeattrname = pool.getPrimitiveConstant(codeattr_nameindex).getString();
+
+ readAttribute(in, pool, lstAttribute, codeattr_nameindex, codeattrname);
+ }
+ }
+ else {
+ readAttribute(in, pool, lstAttribute, attr_nameindex, attrname);
+ }
+ }
+
+ attributes = lstAttribute;
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+
+ out.writeShort(accessFlags);
+ out.writeShort(name_index);
+ out.writeShort(descriptor_index);
+
+ out.writeShort(attributes.size());
+
+ for (StructGeneralAttribute attr : attributes) {
+ if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attr.getName())) {
+ out.writeShort(attr.getAttribute_name_index());
+
+ if (lazy && !expanded) {
+ out.writeInt(10 + code_content.length);
+ out.writeShort(maxStack);
+ out.writeShort(localVariables);
+ out.writeInt(code_length);
+ out.write(code_content);
+ }
+ else {
+ ByteArrayOutputStream codeout = new ByteArrayOutputStream();
+ seq.writeCodeToStream(new DataOutputStream(codeout));
+
+ ByteArrayOutputStream excout = new ByteArrayOutputStream();
+ seq.writeExceptionsToStream(new DataOutputStream(excout));
+
+ out.writeInt(10 + codeout.size() + excout.size());
+
+ out.writeShort(maxStack);
+ out.writeShort(localVariables);
+ out.writeInt(codeout.size());
+ codeout.writeTo(out);
+ excout.writeTo(out);
+ }
+ // no attributes
+ out.writeShort(0);
+ }
+ else {
+ attr.writeToStream(out);
+ }
+ }
+ }
+
+ private void readAttribute(DataInputFullStream in, ConstantPool pool, VBStyleCollection<StructGeneralAttribute, String> lstAttribute,
+ int attr_nameindex, String attrname) throws IOException {
+
+ StructGeneralAttribute attribute = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname);
+
+ if (attribute != null) {
+ attrname = attribute.getName();
+
+ byte[] arr = new byte[in.readInt()];
+ in.readFull(arr);
+ attribute.setInfo(arr);
+
+ attribute.initContent(pool);
+
+ if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname) &&
+ lstAttribute.containsKey(attrname)) {
+ // merge all variable tables
+ StructLocalVariableTableAttribute oldattr = (StructLocalVariableTableAttribute)lstAttribute.getWithKey(attrname);
+ oldattr.addLocalVariableTable((StructLocalVariableTableAttribute)attribute);
+ }
+ else {
+ lstAttribute.addWithKey(attribute, attribute.getName());
+ }
+ }
+ else {
+ in.skip(in.readInt());
+ }
+ }
+
+ private void initStrings(ConstantPool pool, int class_index) {
+ String[] values = pool.getClassElement(ConstantPool.METHOD, class_index, name_index, descriptor_index);
+ name = values[0];
+ descriptor = values[1];
+ }
+
+ public void expandData() throws IOException {
+ if (containsCode && lazy && !expanded) {
+
+ byte[] codearr = classStruct.getLoader().loadBytecode(this, code_fulllength);
+
+ seq = parseBytecode(new DataInputFullStream(new ByteArrayInputStream(codearr)), code_length, classStruct.getPool());
+ expanded = true;
+ }
+ }
+
+ public void releaseResources() throws IOException {
+ if (containsCode && lazy && expanded) {
+ seq = null;
+ expanded = false;
+ }
+ }
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private InstructionSequence parseBytecode(DataInputFullStream in, int length, ConstantPool pool) throws IOException {
+
+ VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
+
+ int bytecode_version = classStruct.getBytecodeVersion();
+
+ for (int i = 0; i < length; ) {
+
+ int offset = i;
+
+ int opcode = in.readUnsignedByte();
+ int group = GROUP_GENERAL;
+
+ boolean wide = (opcode == opc_wide);
+
+ if (wide) {
+ i++;
+ opcode = in.readUnsignedByte();
+ }
+
+ List<Integer> operands = new ArrayList<Integer>();
+
+ if (opcode >= opc_iconst_m1 && opcode <= opc_iconst_5) {
+ operands.add(new Integer(opr_iconst[opcode - opc_iconst_m1]));
+ opcode = opc_bipush;
+ }
+ else if (opcode >= opc_iload_0 && opcode <= opc_aload_3) {
+ operands.add(new Integer(opr_loadstore[opcode - opc_iload_0]));
+ opcode = opcs_load[(opcode - opc_iload_0) / 4];
+ }
+ else if (opcode >= opc_istore_0 && opcode <= opc_astore_3) {
+ operands.add(new Integer(opr_loadstore[opcode - opc_istore_0]));
+ opcode = opcs_store[(opcode - opc_istore_0) / 4];
+ }
+ else {
+ switch (opcode) {
+ case opc_bipush:
+ operands.add(new Integer(in.readByte()));
+ i++;
+ break;
+ case opc_ldc:
+ case opc_newarray:
+ operands.add(new Integer(in.readUnsignedByte()));
+ i++;
+ break;
+ case opc_sipush:
+ case opc_ifeq:
+ case opc_ifne:
+ case opc_iflt:
+ case opc_ifge:
+ case opc_ifgt:
+ case opc_ifle:
+ case opc_if_icmpeq:
+ case opc_if_icmpne:
+ case opc_if_icmplt:
+ case opc_if_icmpge:
+ case opc_if_icmpgt:
+ case opc_if_icmple:
+ case opc_if_acmpeq:
+ case opc_if_acmpne:
+ case opc_goto:
+ case opc_jsr:
+ case opc_ifnull:
+ case opc_ifnonnull:
+ if (opcode != opc_sipush) {
+ group = GROUP_JUMP;
+ }
+ operands.add(new Integer(in.readShort()));
+ i += 2;
+ break;
+ case opc_ldc_w:
+ case opc_ldc2_w:
+ case opc_getstatic:
+ case opc_putstatic:
+ case opc_getfield:
+ case opc_putfield:
+ case opc_invokevirtual:
+ case opc_invokespecial:
+ case opc_invokestatic:
+ case opc_new:
+ case opc_anewarray:
+ case opc_checkcast:
+ case opc_instanceof:
+ operands.add(new Integer(in.readUnsignedShort()));
+ i += 2;
+ if (opcode >= opc_getstatic && opcode <= opc_putfield) {
+ group = GROUP_FIELDACCESS;
+ }
+ else if (opcode >= opc_invokevirtual && opcode <= opc_invokestatic) {
+ group = GROUP_INVOCATION;
+ }
+ break;
+ case opc_invokedynamic:
+ if (classStruct.isVersionGE_1_7()) { // instruction unused in Java 6 and before
+ operands.add(new Integer(in.readUnsignedShort()));
+ in.skip(2);
+ group = GROUP_INVOCATION;
+ i += 4;
+ }
+ break;
+ case opc_iload:
+ case opc_lload:
+ case opc_fload:
+ case opc_dload:
+ case opc_aload:
+ case opc_istore:
+ case opc_lstore:
+ case opc_fstore:
+ case opc_dstore:
+ case opc_astore:
+ case opc_ret:
+ if (wide) {
+ operands.add(new Integer(in.readUnsignedShort()));
+ i += 2;
+ }
+ else {
+ operands.add(new Integer(in.readUnsignedByte()));
+ i++;
+ }
+ if (opcode == opc_ret) {
+ group = GROUP_RETURN;
+ }
+ break;
+ case opc_iinc:
+ if (wide) {
+ operands.add(new Integer(in.readUnsignedShort()));
+ operands.add(new Integer(in.readShort()));
+ i += 4;
+ }
+ else {
+ operands.add(new Integer(in.readUnsignedByte()));
+ operands.add(new Integer(in.readByte()));
+ i += 2;
+ }
+ break;
+ case opc_goto_w:
+ case opc_jsr_w:
+ opcode = opcode == opc_jsr_w ? opc_jsr : opc_goto;
+ operands.add(new Integer(in.readInt()));
+ group = GROUP_JUMP;
+ i += 4;
+ break;
+ case opc_invokeinterface:
+ operands.add(new Integer(in.readUnsignedShort()));
+ operands.add(new Integer(in.readUnsignedByte()));
+ in.skip(1);
+ group = GROUP_INVOCATION;
+ i += 4;
+ break;
+ case opc_multianewarray:
+ operands.add(new Integer(in.readUnsignedShort()));
+ operands.add(new Integer(in.readUnsignedByte()));
+ i += 3;
+ break;
+ case opc_tableswitch:
+ in.skip((4 - (i + 1) % 4) % 4);
+ i += ((4 - (i + 1) % 4) % 4); // padding
+ operands.add(new Integer(in.readInt()));
+ i += 4;
+ int low = in.readInt();
+ operands.add(new Integer(low));
+ i += 4;
+ int high = in.readInt();
+ operands.add(new Integer(high));
+ i += 4;
+
+ for (int j = 0; j < high - low + 1; j++) {
+ operands.add(new Integer(in.readInt()));
+ i += 4;
+ }
+ group = GROUP_SWITCH;
+
+ break;
+ case opc_lookupswitch:
+ in.skip((4 - (i + 1) % 4) % 4);
+ i += ((4 - (i + 1) % 4) % 4); // padding
+ operands.add(new Integer(in.readInt()));
+ i += 4;
+ int npairs = in.readInt();
+ operands.add(new Integer(npairs));
+ i += 4;
+
+ for (int j = 0; j < npairs; j++) {
+ operands.add(new Integer(in.readInt()));
+ i += 4;
+ operands.add(new Integer(in.readInt()));
+ i += 4;
+ }
+ group = GROUP_SWITCH;
+ break;
+ case opc_ireturn:
+ case opc_lreturn:
+ case opc_freturn:
+ case opc_dreturn:
+ case opc_areturn:
+ case opc_return:
+ case opc_athrow:
+ group = GROUP_RETURN;
+ }
+ }
+
+ int[] ops = new int[operands.size()];
+ for (int j = 0; j < operands.size(); j++) {
+ ops[j] = ((Integer)operands.get(j)).intValue();
+ }
+
+ Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, ops);
+
+ collinstr.addWithKey(instr, new Integer(offset));
+
+ i++;
+ }
+
+ // initialize exception table
+ List<ExceptionHandler> lstHandlers = new ArrayList<ExceptionHandler>();
+
+ int exception_count = in.readUnsignedShort();
+ for (int i = 0; i < exception_count; i++) {
+ ExceptionHandler handler = new ExceptionHandler();
+ handler.from = in.readUnsignedShort();
+ handler.to = in.readUnsignedShort();
+ handler.handler = in.readUnsignedShort();
+
+ int excclass = in.readUnsignedShort();
+ handler.class_index = excclass;
+ if (excclass != 0) {
+ handler.exceptionClass = pool.getPrimitiveConstant(excclass).getString();
+ }
+
+ lstHandlers.add(handler);
+ }
+
+ InstructionSequence seq = new FullInstructionSequence(collinstr, new ExceptionTable(lstHandlers));
+
+ // initialize instructions
+ int i = seq.length() - 1;
+ seq.setPointer(i);
+
+ while (i >= 0) {
+ Instruction instr = seq.getInstr(i--);
+ if (instr.group != GROUP_GENERAL) {
+ instr.initInstruction(seq);
+ }
+ seq.addToPointer(-1);
+ }
+
+ return seq;
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public InstructionSequence getInstructionSequence() {
+ return seq;
+ }
+
+ public String getDescriptor() {
+ return descriptor;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAccessFlags() {
+ return accessFlags;
+ }
+
+ public int getLocalVariables() {
+ return localVariables;
+ }
+
+ public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
+ return attributes;
+ }
+
+ public StructClass getClassStruct() {
+ return classStruct;
+ }
+
+ public boolean containsCode() {
+ return containsCode;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java
index d171349..f36df6d 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java
@@ -1,40 +1,40 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.attr;
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+
public class StructAnnDefaultAttribute extends StructGeneralAttribute {
- private Exprent defaultValue;
-
- public void initContent(ConstantPool pool) {
-
- name = ATTRIBUTE_ANNOTATION_DEFAULT;
-
- DataInputStream data = new DataInputStream(new ByteArrayInputStream(info));
- defaultValue = StructAnnotationAttribute.parseAnnotationElement(data, pool);
- }
-
- public Exprent getDefaultValue() {
- return defaultValue;
- }
-
+ private Exprent defaultValue;
+
+ public void initContent(ConstantPool pool) {
+
+ name = ATTRIBUTE_ANNOTATION_DEFAULT;
+
+ DataInputStream data = new DataInputStream(new ByteArrayInputStream(info));
+ defaultValue = StructAnnotationAttribute.parseAnnotationElement(data, pool);
+ }
+
+ public Exprent getDefaultValue() {
+ return defaultValue;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java
index 8958299..2a2c74c 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java
@@ -1,187 +1,182 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.attr;
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
public class StructAnnotationAttribute extends StructGeneralAttribute {
- private List<AnnotationExprent> annotations;
-
- public void initContent(ConstantPool pool) {
-
- super.initContent(pool);
-
- annotations = new ArrayList<AnnotationExprent>();
- DataInputStream data = new DataInputStream(new ByteArrayInputStream(info, 2, info.length));
-
- int len = (((info[0] & 0xFF)<<8) | (info[1] & 0xFF));
- for(int i=0;i<len;i++) {
- annotations.add(parseAnnotation(data, pool));
- }
-
- }
-
- public static AnnotationExprent parseAnnotation(DataInputStream data, ConstantPool pool) {
-
- try {
-
- String classname = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
- VarType cltype = new VarType(classname);
-
- int len = data.readUnsignedShort();
-
- List<String> parnames = new ArrayList<String>();
- List<Exprent> parvalues = new ArrayList<Exprent>();
-
- for(int i=0;i<len;i++) {
- parnames.add(pool.getPrimitiveConstant(data.readUnsignedShort()).getString());
- parvalues.add(parseAnnotationElement(data, pool));
- }
-
- return new AnnotationExprent(cltype.value, parnames, parvalues);
-
- } catch(IOException ex) {
- throw new RuntimeException(ex);
- }
-
- }
-
- public static Exprent parseAnnotationElement(DataInputStream data, ConstantPool pool) {
-
- try {
- int tag = data.readUnsignedByte();
-
- switch(tag) {
- case 'e': // enum constant
- String classname = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
- String constname = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
-
- FieldDescriptor descr = FieldDescriptor.parseDescriptor(classname);
- return new FieldExprent(constname, descr.type.value, true, null, descr);
- case 'c': // class
- String descriptor = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
- VarType type = FieldDescriptor.parseDescriptor(descriptor).type;
-
- String value;
- switch(type.type) {
- case CodeConstants.TYPE_OBJECT:
- value = type.value;
- break;
- case CodeConstants.TYPE_BYTE:
- value = byte.class.getName();
- break;
- case CodeConstants.TYPE_CHAR:
- value = char.class.getName();
- break;
- case CodeConstants.TYPE_DOUBLE:
- value = double.class.getName();
- break;
- case CodeConstants.TYPE_FLOAT:
- value = float.class.getName();
- break;
- case CodeConstants.TYPE_INT:
- value = int.class.getName();
- break;
- case CodeConstants.TYPE_LONG:
- value = long.class.getName();
- break;
- case CodeConstants.TYPE_SHORT:
- value = short.class.getName();
- break;
- case CodeConstants.TYPE_BOOLEAN:
- value = boolean.class.getName();
- break;
- case CodeConstants.TYPE_VOID:
- value = void.class.getName();
- break;
- default:
- throw new RuntimeException("invalid class type: " + type.type);
- }
- return new ConstExprent(VarType.VARTYPE_CLASS, value);
- case '[': // array
- int len = data.readUnsignedShort();
- List<Exprent> lst = new ArrayList<Exprent>();
-
- for(int i=0;i<len;i++) {
- lst.add(parseAnnotationElement(data, pool));
- }
-
- VarType newtype;
- if(lst.isEmpty()) {
- newtype = new VarType(CodeConstants.TYPE_OBJECT, 1, "java/lang/Object");
- } else {
- VarType eltype = lst.get(0).getExprType();
- newtype = new VarType(eltype.type, 1, eltype.value);
- }
-
- NewExprent newexpr = new NewExprent(newtype, new ArrayList<Exprent>());
- newexpr.setDirectArrayInit(true);
- newexpr.setLstArrayElements(lst);
- return newexpr;
- case '@': // annotation
- return parseAnnotation(data, pool);
- default:
- PrimitiveConstant cn = pool.getPrimitiveConstant(data.readUnsignedShort());
- switch(tag) {
- case 'B':
- return new ConstExprent(VarType.VARTYPE_BYTE, cn.value);
- case 'C':
- return new ConstExprent(VarType.VARTYPE_CHAR, cn.value);
- case 'D':
- return new ConstExprent(VarType.VARTYPE_DOUBLE, cn.value);
- case 'F':
- return new ConstExprent(VarType.VARTYPE_FLOAT, cn.value);
- case 'I':
- return new ConstExprent(VarType.VARTYPE_INT, cn.value);
- case 'J':
- return new ConstExprent(VarType.VARTYPE_LONG, cn.value);
- case 'S':
- return new ConstExprent(VarType.VARTYPE_SHORT, cn.value);
- case 'Z':
- return new ConstExprent(VarType.VARTYPE_BOOLEAN, cn.value);
- case 's':
- return new ConstExprent(VarType.VARTYPE_STRING, cn.value);
- default:
- throw new RuntimeException("invalid element type!");
- }
- }
- } catch(IOException ex) {
- throw new RuntimeException(ex);
- }
-
- }
-
-
- public List<AnnotationExprent> getAnnotations() {
- return annotations;
- }
-
+ private List<AnnotationExprent> annotations;
+
+ public void initContent(ConstantPool pool) {
+
+ super.initContent(pool);
+
+ annotations = new ArrayList<AnnotationExprent>();
+ DataInputStream data = new DataInputStream(new ByteArrayInputStream(info, 2, info.length));
+
+ int len = (((info[0] & 0xFF) << 8) | (info[1] & 0xFF));
+ for (int i = 0; i < len; i++) {
+ annotations.add(parseAnnotation(data, pool));
+ }
+ }
+
+ public static AnnotationExprent parseAnnotation(DataInputStream data, ConstantPool pool) {
+
+ try {
+
+ String classname = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
+ VarType cltype = new VarType(classname);
+
+ int len = data.readUnsignedShort();
+
+ List<String> parnames = new ArrayList<String>();
+ List<Exprent> parvalues = new ArrayList<Exprent>();
+
+ for (int i = 0; i < len; i++) {
+ parnames.add(pool.getPrimitiveConstant(data.readUnsignedShort()).getString());
+ parvalues.add(parseAnnotationElement(data, pool));
+ }
+
+ return new AnnotationExprent(cltype.value, parnames, parvalues);
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public static Exprent parseAnnotationElement(DataInputStream data, ConstantPool pool) {
+
+ try {
+ int tag = data.readUnsignedByte();
+
+ switch (tag) {
+ case 'e': // enum constant
+ String classname = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
+ String constname = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
+
+ FieldDescriptor descr = FieldDescriptor.parseDescriptor(classname);
+ return new FieldExprent(constname, descr.type.value, true, null, descr);
+ case 'c': // class
+ String descriptor = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
+ VarType type = FieldDescriptor.parseDescriptor(descriptor).type;
+
+ String value;
+ switch (type.type) {
+ case CodeConstants.TYPE_OBJECT:
+ value = type.value;
+ break;
+ case CodeConstants.TYPE_BYTE:
+ value = byte.class.getName();
+ break;
+ case CodeConstants.TYPE_CHAR:
+ value = char.class.getName();
+ break;
+ case CodeConstants.TYPE_DOUBLE:
+ value = double.class.getName();
+ break;
+ case CodeConstants.TYPE_FLOAT:
+ value = float.class.getName();
+ break;
+ case CodeConstants.TYPE_INT:
+ value = int.class.getName();
+ break;
+ case CodeConstants.TYPE_LONG:
+ value = long.class.getName();
+ break;
+ case CodeConstants.TYPE_SHORT:
+ value = short.class.getName();
+ break;
+ case CodeConstants.TYPE_BOOLEAN:
+ value = boolean.class.getName();
+ break;
+ case CodeConstants.TYPE_VOID:
+ value = void.class.getName();
+ break;
+ default:
+ throw new RuntimeException("invalid class type: " + type.type);
+ }
+ return new ConstExprent(VarType.VARTYPE_CLASS, value);
+ case '[': // array
+ int len = data.readUnsignedShort();
+ List<Exprent> lst = new ArrayList<Exprent>();
+
+ for (int i = 0; i < len; i++) {
+ lst.add(parseAnnotationElement(data, pool));
+ }
+
+ VarType newtype;
+ if (lst.isEmpty()) {
+ newtype = new VarType(CodeConstants.TYPE_OBJECT, 1, "java/lang/Object");
+ }
+ else {
+ VarType eltype = lst.get(0).getExprType();
+ newtype = new VarType(eltype.type, 1, eltype.value);
+ }
+
+ NewExprent newexpr = new NewExprent(newtype, new ArrayList<Exprent>());
+ newexpr.setDirectArrayInit(true);
+ newexpr.setLstArrayElements(lst);
+ return newexpr;
+ case '@': // annotation
+ return parseAnnotation(data, pool);
+ default:
+ PrimitiveConstant cn = pool.getPrimitiveConstant(data.readUnsignedShort());
+ switch (tag) {
+ case 'B':
+ return new ConstExprent(VarType.VARTYPE_BYTE, cn.value);
+ case 'C':
+ return new ConstExprent(VarType.VARTYPE_CHAR, cn.value);
+ case 'D':
+ return new ConstExprent(VarType.VARTYPE_DOUBLE, cn.value);
+ case 'F':
+ return new ConstExprent(VarType.VARTYPE_FLOAT, cn.value);
+ case 'I':
+ return new ConstExprent(VarType.VARTYPE_INT, cn.value);
+ case 'J':
+ return new ConstExprent(VarType.VARTYPE_LONG, cn.value);
+ case 'S':
+ return new ConstExprent(VarType.VARTYPE_SHORT, cn.value);
+ case 'Z':
+ return new ConstExprent(VarType.VARTYPE_BOOLEAN, cn.value);
+ case 's':
+ return new ConstExprent(VarType.VARTYPE_STRING, cn.value);
+ default:
+ throw new RuntimeException("invalid element type!");
+ }
+ }
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+
+ public List<AnnotationExprent> getAnnotations() {
+ return annotations;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java
index dd28aa7..432d3b6 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java
@@ -1,57 +1,58 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.attr;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
-import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
-
public class StructAnnotationParameterAttribute extends StructGeneralAttribute {
- private List<List<AnnotationExprent>> paramAnnotations;
-
- public void initContent(ConstantPool pool) {
-
- super.initContent(pool);
-
- paramAnnotations = new ArrayList<List<AnnotationExprent>>();
- DataInputStream data = new DataInputStream(new ByteArrayInputStream(info));
-
- try {
- int len = data.readUnsignedByte();
- for(int i=0;i<len;i++) {
- List<AnnotationExprent> lst = new ArrayList<AnnotationExprent>();
- int annsize = data.readUnsignedShort();
-
- for(int j=0;j<annsize;j++) {
- lst.add(StructAnnotationAttribute.parseAnnotation(data, pool));
- }
- paramAnnotations.add(lst);
- }
- } catch(IOException ex) {
- throw new RuntimeException(ex);
- }
-
- }
-
- public List<List<AnnotationExprent>> getParamAnnotations() {
- return paramAnnotations;
- }
+ private List<List<AnnotationExprent>> paramAnnotations;
+
+ public void initContent(ConstantPool pool) {
+
+ super.initContent(pool);
+
+ paramAnnotations = new ArrayList<List<AnnotationExprent>>();
+ DataInputStream data = new DataInputStream(new ByteArrayInputStream(info));
+
+ try {
+ int len = data.readUnsignedByte();
+ for (int i = 0; i < len; i++) {
+ List<AnnotationExprent> lst = new ArrayList<AnnotationExprent>();
+ int annsize = data.readUnsignedShort();
+
+ for (int j = 0; j < annsize; j++) {
+ lst.add(StructAnnotationAttribute.parseAnnotation(data, pool));
+ }
+ paramAnnotations.add(lst);
+ }
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public List<List<AnnotationExprent>> getParamAnnotations() {
+ return paramAnnotations;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationTypeAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationTypeAttribute.java
index 9677ddd..f228ed5 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationTypeAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationTypeAttribute.java
@@ -1,188 +1,203 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.struct.attr;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
-import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
-
public class StructAnnotationTypeAttribute extends StructGeneralAttribute {
-
- public static final int ANNOTATION_TARGET_TYPE_GENERIC_CLASS = 0x00;
- public static final int ANNOTATION_TARGET_TYPE_GENERIC_METHOD = 0x01;
- public static final int ANNOTATION_TARGET_TYPE_EXTENDS_IMPLEMENTS = 0x10;
- public static final int ANNOTATION_TARGET_TYPE_GENERIC_CLASS_BOUND = 0x11;
- public static final int ANNOTATION_TARGET_TYPE_GENERIC_METHOD_BOUND = 0x12;
- public static final int ANNOTATION_TARGET_TYPE_FIELD = 0x13;
- public static final int ANNOTATION_TARGET_TYPE_RETURN = 0x14;
- public static final int ANNOTATION_TARGET_TYPE_RECEIVER = 0x15;
- public static final int ANNOTATION_TARGET_TYPE_FORMAL = 0x16;
- public static final int ANNOTATION_TARGET_TYPE_THROWS = 0x17;
- public static final int ANNOTATION_TARGET_TYPE_LOCAL_VARIABLE = 0x40;
- public static final int ANNOTATION_TARGET_TYPE_RESOURCE_VARIABLE = 0x41;
- public static final int ANNOTATION_TARGET_TYPE_EXCEPTION = 0x42;
- public static final int ANNOTATION_TARGET_TYPE_INSTANCEOF = 0x43;
- public static final int ANNOTATION_TARGET_TYPE_NEW = 0x44;
- public static final int ANNOTATION_TARGET_TYPE_DOUBLECOLON_NEW = 0x45;
- public static final int ANNOTATION_TARGET_TYPE_DOUBLECOLON_ID = 0x46;
- public static final int ANNOTATION_TARGET_TYPE_CAST = 0x47;
- public static final int ANNOTATION_TARGET_TYPE_INVOKATION_CONSTRUCTOR = 0x48;
- public static final int ANNOTATION_TARGET_TYPE_INVOKATION_METHOD = 0x49;
- public static final int ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_NEW = 0x4A;
- public static final int ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_ID = 0x4B;
-
- public static final int ANNOTATION_TARGET_UNION_TYPE_PARAMETER = 1;
- public static final int ANNOTATION_TARGET_UNION_SUPERTYPE = 2;
- public static final int ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND = 3;
- public static final int ANNOTATION_TARGET_UNION_EMPTY = 4;
- public static final int ANNOTATION_TARGET_UNION_FORMAL_PARAMETER = 5;
- public static final int ANNOTATION_TARGET_UNION_THROWS = 6;
- public static final int ANNOTATION_TARGET_UNION_LOCALVAR = 7;
- public static final int ANNOTATION_TARGET_UNION_CATCH = 8;
- public static final int ANNOTATION_TARGET_UNION_OFFSET = 9;
- public static final int ANNOTATION_TARGET_UNION_TYPE_ARGUMENT = 10;
-
-
- List<AnnotationLocation> locations = new ArrayList<AnnotationLocation>();
- List<AnnotationExprent> annotations = new ArrayList<AnnotationExprent>();
-
- public void initContent(ConstantPool pool) {
-
- super.initContent(pool);
-
- DataInputStream data = new DataInputStream(new ByteArrayInputStream(info));
-
- try {
-
- int ann_number = data.readUnsignedByte();
- for(int i = 0; i < ann_number; i++) {
- locations.add(parseAnnotationLocation(data));
- annotations.add(StructAnnotationAttribute.parseAnnotation(data, pool));
- }
-
- } catch(IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- public AnnotationLocation parseAnnotationLocation(DataInputStream data) throws IOException {
-
- AnnotationLocation ann_location = new AnnotationLocation();
-
- // target type
-
- ann_location.target_type = data.readUnsignedByte();
-
- // target union
-
- switch(ann_location.target_type) {
- case ANNOTATION_TARGET_TYPE_GENERIC_CLASS:
- case ANNOTATION_TARGET_TYPE_GENERIC_METHOD:
- ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_PARAMETER;
- break;
- case ANNOTATION_TARGET_TYPE_EXTENDS_IMPLEMENTS:
- ann_location.target_union = ANNOTATION_TARGET_UNION_SUPERTYPE;
- break;
- case ANNOTATION_TARGET_TYPE_GENERIC_CLASS_BOUND:
- case ANNOTATION_TARGET_TYPE_GENERIC_METHOD_BOUND:
- ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND;
- break;
- case ANNOTATION_TARGET_TYPE_FIELD:
- case ANNOTATION_TARGET_TYPE_RETURN:
- case ANNOTATION_TARGET_TYPE_RECEIVER:
- ann_location.target_union = ANNOTATION_TARGET_UNION_EMPTY;
- break;
- case ANNOTATION_TARGET_TYPE_FORMAL:
- ann_location.target_union = ANNOTATION_TARGET_UNION_FORMAL_PARAMETER;
- break;
- case ANNOTATION_TARGET_TYPE_THROWS:
- ann_location.target_union = ANNOTATION_TARGET_UNION_THROWS;
- break;
- case ANNOTATION_TARGET_TYPE_LOCAL_VARIABLE:
- case ANNOTATION_TARGET_TYPE_RESOURCE_VARIABLE:
- ann_location.target_union = ANNOTATION_TARGET_UNION_LOCALVAR;
- break;
- case ANNOTATION_TARGET_TYPE_EXCEPTION:
- ann_location.target_union = ANNOTATION_TARGET_UNION_CATCH;
- break;
- case ANNOTATION_TARGET_TYPE_INSTANCEOF:
- case ANNOTATION_TARGET_TYPE_NEW:
- case ANNOTATION_TARGET_TYPE_DOUBLECOLON_NEW:
- case ANNOTATION_TARGET_TYPE_DOUBLECOLON_ID:
- ann_location.target_union = ANNOTATION_TARGET_UNION_OFFSET;
- break;
- case ANNOTATION_TARGET_TYPE_CAST:
- case ANNOTATION_TARGET_TYPE_INVOKATION_CONSTRUCTOR:
- case ANNOTATION_TARGET_TYPE_INVOKATION_METHOD:
- case ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_NEW:
- case ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_ID:
- ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_ARGUMENT;
- break;
- default:
- throw new RuntimeException("Unknown target type in a type annotation!");
- }
-
- // target union data
-
- switch(ann_location.target_union) {
- case ANNOTATION_TARGET_UNION_TYPE_PARAMETER:
- case ANNOTATION_TARGET_UNION_FORMAL_PARAMETER:
- ann_location.data = new int[] {data.readUnsignedByte()};
- break;
- case ANNOTATION_TARGET_UNION_SUPERTYPE:
- case ANNOTATION_TARGET_UNION_THROWS:
- case ANNOTATION_TARGET_UNION_CATCH:
- case ANNOTATION_TARGET_UNION_OFFSET:
- ann_location.data = new int[] {data.readUnsignedShort()};
- break;
- case ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND:
- ann_location.data = new int[] {data.readUnsignedByte(), data.readUnsignedByte()};
- break;
- case ANNOTATION_TARGET_UNION_EMPTY:
- break;
- case ANNOTATION_TARGET_UNION_LOCALVAR:
- int table_length = data.readUnsignedShort();
-
- ann_location.data = new int[table_length * 3 + 1];
- ann_location.data[0] = table_length;
-
- for(int i = 0; i < table_length; ++i) {
- ann_location.data[3 * i + 1] = data.readUnsignedShort();
- ann_location.data[3 * i + 2] = data.readUnsignedShort();
- ann_location.data[3 * i + 3] = data.readUnsignedShort();
- }
- break;
- case ANNOTATION_TARGET_UNION_TYPE_ARGUMENT:
- ann_location.data = new int[] {data.readUnsignedShort(), data.readUnsignedByte()};
- }
-
- // target path
-
- int path_length = data.readUnsignedByte();
-
- ann_location.target_path_kind = new int[path_length];
- ann_location.target_argument_index = new int[path_length];
-
- for(int i = 0; i < path_length; ++i) {
- ann_location.target_path_kind[i] = data.readUnsignedByte();
- ann_location.target_argument_index[i] = data.readUnsignedByte();
- }
-
- return ann_location;
- }
-
- private static class AnnotationLocation {
-
- public int target_type;
- public int target_union;
-
- public int[] data;
-
- public int[] target_path_kind;
- public int[] target_argument_index;
- }
+
+ public static final int ANNOTATION_TARGET_TYPE_GENERIC_CLASS = 0x00;
+ public static final int ANNOTATION_TARGET_TYPE_GENERIC_METHOD = 0x01;
+ public static final int ANNOTATION_TARGET_TYPE_EXTENDS_IMPLEMENTS = 0x10;
+ public static final int ANNOTATION_TARGET_TYPE_GENERIC_CLASS_BOUND = 0x11;
+ public static final int ANNOTATION_TARGET_TYPE_GENERIC_METHOD_BOUND = 0x12;
+ public static final int ANNOTATION_TARGET_TYPE_FIELD = 0x13;
+ public static final int ANNOTATION_TARGET_TYPE_RETURN = 0x14;
+ public static final int ANNOTATION_TARGET_TYPE_RECEIVER = 0x15;
+ public static final int ANNOTATION_TARGET_TYPE_FORMAL = 0x16;
+ public static final int ANNOTATION_TARGET_TYPE_THROWS = 0x17;
+ public static final int ANNOTATION_TARGET_TYPE_LOCAL_VARIABLE = 0x40;
+ public static final int ANNOTATION_TARGET_TYPE_RESOURCE_VARIABLE = 0x41;
+ public static final int ANNOTATION_TARGET_TYPE_EXCEPTION = 0x42;
+ public static final int ANNOTATION_TARGET_TYPE_INSTANCEOF = 0x43;
+ public static final int ANNOTATION_TARGET_TYPE_NEW = 0x44;
+ public static final int ANNOTATION_TARGET_TYPE_DOUBLECOLON_NEW = 0x45;
+ public static final int ANNOTATION_TARGET_TYPE_DOUBLECOLON_ID = 0x46;
+ public static final int ANNOTATION_TARGET_TYPE_CAST = 0x47;
+ public static final int ANNOTATION_TARGET_TYPE_INVOKATION_CONSTRUCTOR = 0x48;
+ public static final int ANNOTATION_TARGET_TYPE_INVOKATION_METHOD = 0x49;
+ public static final int ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_NEW = 0x4A;
+ public static final int ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_ID = 0x4B;
+
+ public static final int ANNOTATION_TARGET_UNION_TYPE_PARAMETER = 1;
+ public static final int ANNOTATION_TARGET_UNION_SUPERTYPE = 2;
+ public static final int ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND = 3;
+ public static final int ANNOTATION_TARGET_UNION_EMPTY = 4;
+ public static final int ANNOTATION_TARGET_UNION_FORMAL_PARAMETER = 5;
+ public static final int ANNOTATION_TARGET_UNION_THROWS = 6;
+ public static final int ANNOTATION_TARGET_UNION_LOCALVAR = 7;
+ public static final int ANNOTATION_TARGET_UNION_CATCH = 8;
+ public static final int ANNOTATION_TARGET_UNION_OFFSET = 9;
+ public static final int ANNOTATION_TARGET_UNION_TYPE_ARGUMENT = 10;
+
+
+ List<AnnotationLocation> locations = new ArrayList<AnnotationLocation>();
+ List<AnnotationExprent> annotations = new ArrayList<AnnotationExprent>();
+
+ public void initContent(ConstantPool pool) {
+
+ super.initContent(pool);
+
+ DataInputStream data = new DataInputStream(new ByteArrayInputStream(info));
+
+ try {
+
+ int ann_number = data.readUnsignedByte();
+ for (int i = 0; i < ann_number; i++) {
+ locations.add(parseAnnotationLocation(data));
+ annotations.add(StructAnnotationAttribute.parseAnnotation(data, pool));
+ }
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public AnnotationLocation parseAnnotationLocation(DataInputStream data) throws IOException {
+
+ AnnotationLocation ann_location = new AnnotationLocation();
+
+ // target type
+
+ ann_location.target_type = data.readUnsignedByte();
+
+ // target union
+
+ switch (ann_location.target_type) {
+ case ANNOTATION_TARGET_TYPE_GENERIC_CLASS:
+ case ANNOTATION_TARGET_TYPE_GENERIC_METHOD:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_PARAMETER;
+ break;
+ case ANNOTATION_TARGET_TYPE_EXTENDS_IMPLEMENTS:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_SUPERTYPE;
+ break;
+ case ANNOTATION_TARGET_TYPE_GENERIC_CLASS_BOUND:
+ case ANNOTATION_TARGET_TYPE_GENERIC_METHOD_BOUND:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND;
+ break;
+ case ANNOTATION_TARGET_TYPE_FIELD:
+ case ANNOTATION_TARGET_TYPE_RETURN:
+ case ANNOTATION_TARGET_TYPE_RECEIVER:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_EMPTY;
+ break;
+ case ANNOTATION_TARGET_TYPE_FORMAL:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_FORMAL_PARAMETER;
+ break;
+ case ANNOTATION_TARGET_TYPE_THROWS:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_THROWS;
+ break;
+ case ANNOTATION_TARGET_TYPE_LOCAL_VARIABLE:
+ case ANNOTATION_TARGET_TYPE_RESOURCE_VARIABLE:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_LOCALVAR;
+ break;
+ case ANNOTATION_TARGET_TYPE_EXCEPTION:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_CATCH;
+ break;
+ case ANNOTATION_TARGET_TYPE_INSTANCEOF:
+ case ANNOTATION_TARGET_TYPE_NEW:
+ case ANNOTATION_TARGET_TYPE_DOUBLECOLON_NEW:
+ case ANNOTATION_TARGET_TYPE_DOUBLECOLON_ID:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_OFFSET;
+ break;
+ case ANNOTATION_TARGET_TYPE_CAST:
+ case ANNOTATION_TARGET_TYPE_INVOKATION_CONSTRUCTOR:
+ case ANNOTATION_TARGET_TYPE_INVOKATION_METHOD:
+ case ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_NEW:
+ case ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_ID:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_ARGUMENT;
+ break;
+ default:
+ throw new RuntimeException("Unknown target type in a type annotation!");
+ }
+
+ // target union data
+
+ switch (ann_location.target_union) {
+ case ANNOTATION_TARGET_UNION_TYPE_PARAMETER:
+ case ANNOTATION_TARGET_UNION_FORMAL_PARAMETER:
+ ann_location.data = new int[]{data.readUnsignedByte()};
+ break;
+ case ANNOTATION_TARGET_UNION_SUPERTYPE:
+ case ANNOTATION_TARGET_UNION_THROWS:
+ case ANNOTATION_TARGET_UNION_CATCH:
+ case ANNOTATION_TARGET_UNION_OFFSET:
+ ann_location.data = new int[]{data.readUnsignedShort()};
+ break;
+ case ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND:
+ ann_location.data = new int[]{data.readUnsignedByte(), data.readUnsignedByte()};
+ break;
+ case ANNOTATION_TARGET_UNION_EMPTY:
+ break;
+ case ANNOTATION_TARGET_UNION_LOCALVAR:
+ int table_length = data.readUnsignedShort();
+
+ ann_location.data = new int[table_length * 3 + 1];
+ ann_location.data[0] = table_length;
+
+ for (int i = 0; i < table_length; ++i) {
+ ann_location.data[3 * i + 1] = data.readUnsignedShort();
+ ann_location.data[3 * i + 2] = data.readUnsignedShort();
+ ann_location.data[3 * i + 3] = data.readUnsignedShort();
+ }
+ break;
+ case ANNOTATION_TARGET_UNION_TYPE_ARGUMENT:
+ ann_location.data = new int[]{data.readUnsignedShort(), data.readUnsignedByte()};
+ }
+
+ // target path
+
+ int path_length = data.readUnsignedByte();
+
+ ann_location.target_path_kind = new int[path_length];
+ ann_location.target_argument_index = new int[path_length];
+
+ for (int i = 0; i < path_length; ++i) {
+ ann_location.target_path_kind[i] = data.readUnsignedByte();
+ ann_location.target_argument_index[i] = data.readUnsignedByte();
+ }
+
+ return ann_location;
+ }
+
+ private static class AnnotationLocation {
+
+ public int target_type;
+ public int target_union;
+
+ public int[] data;
+
+ public int[] target_path_kind;
+ public int[] target_argument_index;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java
index ac51027..717bad9 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java
@@ -1,62 +1,75 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.struct.attr;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
+import org.jetbrains.java.decompiler.struct.consts.PooledConstant;
+
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
-import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
-import org.jetbrains.java.decompiler.struct.consts.PooledConstant;
-
public class StructBootstrapMethodsAttribute extends StructGeneralAttribute {
-
- private List<LinkConstant> method_refs = new ArrayList<LinkConstant>();
- private List<List<PooledConstant>> method_arguments = new ArrayList<List<PooledConstant>>();
-
- public void initContent(ConstantPool pool) {
-
- name = ATTRIBUTE_BOOTSTRAP_METHODS;
-
- try {
-
- DataInputStream data = new DataInputStream(new ByteArrayInputStream(info, 0, info.length));
-
- int method_number = data.readUnsignedShort();
-
- for(int i = 0; i < method_number; ++i) {
- int bootstrap_method_ref = data.readUnsignedShort();
- int num_bootstrap_arguments = data.readUnsignedShort();
-
- List<PooledConstant> list_arguments = new ArrayList<PooledConstant>();
-
- for(int j = 0; j < num_bootstrap_arguments; ++j) {
- int bootstrap_argument_ref = data.readUnsignedShort();
-
- list_arguments.add(pool.getConstant(bootstrap_argument_ref));
- }
-
- method_refs.add(pool.getLinkConstant(bootstrap_method_ref));
- method_arguments.add(list_arguments);
- }
-
- } catch(IOException ex) {
- throw new RuntimeException(ex);
- }
-
- }
-
- public int getMethodsNumber() {
- return method_refs.size();
- }
-
- public LinkConstant getMethodReference(int index) {
- return method_refs.get(index);
- }
-
- public List<PooledConstant> getMethodArguments(int index) {
- return method_arguments.get(index);
- }
-
+
+ private List<LinkConstant> method_refs = new ArrayList<LinkConstant>();
+ private List<List<PooledConstant>> method_arguments = new ArrayList<List<PooledConstant>>();
+
+ public void initContent(ConstantPool pool) {
+
+ name = ATTRIBUTE_BOOTSTRAP_METHODS;
+
+ try {
+
+ DataInputStream data = new DataInputStream(new ByteArrayInputStream(info, 0, info.length));
+
+ int method_number = data.readUnsignedShort();
+
+ for (int i = 0; i < method_number; ++i) {
+ int bootstrap_method_ref = data.readUnsignedShort();
+ int num_bootstrap_arguments = data.readUnsignedShort();
+
+ List<PooledConstant> list_arguments = new ArrayList<PooledConstant>();
+
+ for (int j = 0; j < num_bootstrap_arguments; ++j) {
+ int bootstrap_argument_ref = data.readUnsignedShort();
+
+ list_arguments.add(pool.getConstant(bootstrap_argument_ref));
+ }
+
+ method_refs.add(pool.getLinkConstant(bootstrap_method_ref));
+ method_arguments.add(list_arguments);
+ }
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public int getMethodsNumber() {
+ return method_refs.size();
+ }
+
+ public LinkConstant getMethodReference(int index) {
+ return method_refs.get(index);
+ }
+
+ public List<PooledConstant> getMethodArguments(int index) {
+ return method_arguments.get(index);
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java
index f186767..ae3bd1d 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java
@@ -1,34 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.attr;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
public class StructConstantValueAttribute extends StructGeneralAttribute {
- private int index;
+ private int index;
+
+ public void initContent(ConstantPool pool) {
- public void initContent(ConstantPool pool) {
+ name = ATTRIBUTE_CONSTANT_VALUE;
+ index = ((info[0] & 0xFF) << 8) | (info[1] & 0xFF);
+ }
- name = ATTRIBUTE_CONSTANT_VALUE;
- index = ((info[0] & 0xFF)<<8) | (info[1] & 0xFF);
- }
-
- public int getIndex() {
- return index;
- }
-
-
+ public int getIndex() {
+ return index;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java
index 61bb886..ebf9407 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.attr;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
@@ -19,39 +20,37 @@ import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
public class StructEnclosingMethodAttribute extends StructGeneralAttribute {
- private String classname;
-
- private String mtname;
-
- private String methodDescriptor;
-
- public void initContent(ConstantPool pool) {
-
- name = ATTRIBUTE_ENCLOSING_METHOD;
-
- int clindex = (((info[0] & 0xFF)<<8) | (info[1] & 0xFF));
- int mtindex = (((info[2] & 0xFF)<<8) | (info[3] & 0xFF));
-
- classname = pool.getPrimitiveConstant(clindex).getString();
- if(mtindex != 0) {
- LinkConstant lk = pool.getLinkConstant(mtindex);
-
- mtname = lk.elementname;
- methodDescriptor = lk.descriptor;
- }
- }
-
- public String getClassname() {
- return classname;
- }
-
- public String getMethodDescriptor() {
- return methodDescriptor;
- }
-
- public String getMethodName() {
- return mtname;
- }
-
-
+ private String classname;
+
+ private String mtname;
+
+ private String methodDescriptor;
+
+ public void initContent(ConstantPool pool) {
+
+ name = ATTRIBUTE_ENCLOSING_METHOD;
+
+ int clindex = (((info[0] & 0xFF) << 8) | (info[1] & 0xFF));
+ int mtindex = (((info[2] & 0xFF) << 8) | (info[3] & 0xFF));
+
+ classname = pool.getPrimitiveConstant(clindex).getString();
+ if (mtindex != 0) {
+ LinkConstant lk = pool.getLinkConstant(mtindex);
+
+ mtname = lk.elementname;
+ methodDescriptor = lk.descriptor;
+ }
+ }
+
+ public String getClassname() {
+ return classname;
+ }
+
+ public String getMethodDescriptor() {
+ return methodDescriptor;
+ }
+
+ public String getMethodName() {
+ return mtname;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java
index 4d6bd4c..930db78 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java
@@ -1,78 +1,76 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.attr;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
-
public class StructExceptionsAttribute extends StructGeneralAttribute {
- private List<Integer> throwsExceptions = new ArrayList<Integer>();
-
- public void initContent(ConstantPool pool) {
-
- name = ATTRIBUTE_EXCEPTIONS;
-
- int length = 2+(((info[0] & 0xFF)<<8) | (info[1] & 0xFF))*2;
- for(int i=2;i<length;i+=2) {
- int index = ((info[i] & 0xFF)<<8) | (info[i+1] & 0xFF);
- throwsExceptions.add(index);
- }
-
- }
-
- public void writeToStream(DataOutputStream out) throws IOException {
-
- out.writeShort(attribute_name_index);
-
- ByteArrayOutputStream codeout = new ByteArrayOutputStream();
- DataOutputStream dataout = new DataOutputStream(codeout);
-
- int len = throwsExceptions.size();
- dataout.writeShort(len);
-
- if(len>0) {
- info = new byte[len*2];
- for(int i=0,j=0;i<len;i++,j+=2) {
- int index = ((Integer)throwsExceptions.get(i)).intValue();
- info[j] = (byte)(index >> 8);
- info[j+1] = (byte)(index & 0xFF);
- }
- dataout.write(info);
- }
-
- out.writeInt(codeout.size());
- out.write(codeout.toByteArray());
- }
-
- public String getExcClassname(int index, ConstantPool pool) {
- return pool.getPrimitiveConstant(((Integer)throwsExceptions.get(index)).intValue()).getString();
- }
-
- public List<Integer> getThrowsExceptions() {
- return throwsExceptions;
- }
-
- public void setThrowsExceptions(List<Integer> throwsExceptions) {
- this.throwsExceptions = throwsExceptions;
- }
-
-
+ private List<Integer> throwsExceptions = new ArrayList<Integer>();
+
+ public void initContent(ConstantPool pool) {
+
+ name = ATTRIBUTE_EXCEPTIONS;
+
+ int length = 2 + (((info[0] & 0xFF) << 8) | (info[1] & 0xFF)) * 2;
+ for (int i = 2; i < length; i += 2) {
+ int index = ((info[i] & 0xFF) << 8) | (info[i + 1] & 0xFF);
+ throwsExceptions.add(index);
+ }
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+
+ out.writeShort(attribute_name_index);
+
+ ByteArrayOutputStream codeout = new ByteArrayOutputStream();
+ DataOutputStream dataout = new DataOutputStream(codeout);
+
+ int len = throwsExceptions.size();
+ dataout.writeShort(len);
+
+ if (len > 0) {
+ info = new byte[len * 2];
+ for (int i = 0, j = 0; i < len; i++, j += 2) {
+ int index = ((Integer)throwsExceptions.get(i)).intValue();
+ info[j] = (byte)(index >> 8);
+ info[j + 1] = (byte)(index & 0xFF);
+ }
+ dataout.write(info);
+ }
+
+ out.writeInt(codeout.size());
+ out.write(codeout.toByteArray());
+ }
+
+ public String getExcClassname(int index, ConstantPool pool) {
+ return pool.getPrimitiveConstant(((Integer)throwsExceptions.get(index)).intValue()).getString();
+ }
+
+ public List<Integer> getThrowsExceptions() {
+ return throwsExceptions;
+ }
+
+ public void setThrowsExceptions(List<Integer> throwsExceptions) {
+ this.throwsExceptions = throwsExceptions;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java
index 2648b3c..bd0596a 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java
@@ -1,24 +1,25 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.attr;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
-
/*
attribute_info {
u2 attribute_name_index;
@@ -29,117 +30,128 @@ import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
public class StructGeneralAttribute {
- public static final String ATTRIBUTE_CODE = "Code";
- public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses";
- public static final String ATTRIBUTE_SIGNATURE = "Signature";
- public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault";
- public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions";
- public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod";
- public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
- public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
- public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations";
- public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations";
- public static final String ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations";
- public static final String ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations";
- public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable";
- public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue";
- public static final String ATTRIBUTE_BOOTSTRAP_METHODS = "BootstrapMethods";
+ public static final String ATTRIBUTE_CODE = "Code";
+ public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses";
+ public static final String ATTRIBUTE_SIGNATURE = "Signature";
+ public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault";
+ public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions";
+ public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod";
+ public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
+ public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
+ public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations";
+ public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations";
+ public static final String ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations";
+ public static final String ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations";
+ public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable";
+ public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue";
+ public static final String ATTRIBUTE_BOOTSTRAP_METHODS = "BootstrapMethods";
public static final String ATTRIBUTE_SYNTHETIC = "Synthetic";
public static final String ATTRIBUTE_DEPRECATED = "Deprecated";
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- protected int attribute_name_index;
-
- protected byte[] info;
-
- protected String name;
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public void writeToStream(DataOutputStream out) throws IOException {
- out.writeShort(attribute_name_index);
- out.writeInt(info.length);
- if(info.length>0) {
- out.write(info);
- }
- }
-
- public void initContent(ConstantPool pool) {
- name = pool.getPrimitiveConstant(attribute_name_index).getString();
- }
-
- public static StructGeneralAttribute getMatchingAttributeInstance(int nameindex, String attrname) {
-
- StructGeneralAttribute attr;
-
- if(ATTRIBUTE_INNER_CLASSES.equals(attrname)) {
- attr = new StructInnerClassesAttribute();
- } else if(ATTRIBUTE_CONSTANT_VALUE.equals(attrname)) {
- attr = new StructConstantValueAttribute();
- } else if(ATTRIBUTE_SIGNATURE.equals(attrname)) {
- attr = new StructGenericSignatureAttribute();
- } else if(ATTRIBUTE_ANNOTATION_DEFAULT.equals(attrname)) {
- attr = new StructAnnDefaultAttribute();
- } else if(ATTRIBUTE_EXCEPTIONS.equals(attrname)) {
- attr = new StructExceptionsAttribute();
- } else if(ATTRIBUTE_ENCLOSING_METHOD.equals(attrname)) {
- attr = new StructEnclosingMethodAttribute();
- } else if(ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.equals(attrname) ||
- ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.equals(attrname)) {
- attr = new StructAnnotationAttribute();
- } else if(ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attrname) ||
- ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attrname)) {
- attr = new StructAnnotationParameterAttribute();
- } else if(ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attrname) ||
- ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attrname)) {
- attr = new StructAnnotationTypeAttribute();
- } else if(ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname)) {
- attr = new StructLocalVariableTableAttribute();
- } else if(ATTRIBUTE_BOOTSTRAP_METHODS.equals(attrname)) {
- attr = new StructBootstrapMethodsAttribute();
- } else if(ATTRIBUTE_SYNTHETIC.equals(attrname) || ATTRIBUTE_DEPRECATED.equals(attrname)) {
- attr = new StructGeneralAttribute();
- } else {
- // unsupported attribute
- return null;
- }
-
- attr.setAttribute_name_index(nameindex);
- return attr;
- }
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public byte[] getInfo() {
- return info;
- }
-
- public void setInfo(byte[] info) {
- this.info = info;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getAttribute_name_index() {
- return attribute_name_index;
- }
-
- public void setAttribute_name_index(int attribute_name_index) {
- this.attribute_name_index = attribute_name_index;
- }
-
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ protected int attribute_name_index;
+
+ protected byte[] info;
+
+ protected String name;
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+ out.writeShort(attribute_name_index);
+ out.writeInt(info.length);
+ if (info.length > 0) {
+ out.write(info);
+ }
+ }
+
+ public void initContent(ConstantPool pool) {
+ name = pool.getPrimitiveConstant(attribute_name_index).getString();
+ }
+
+ public static StructGeneralAttribute getMatchingAttributeInstance(int nameindex, String attrname) {
+
+ StructGeneralAttribute attr;
+
+ if (ATTRIBUTE_INNER_CLASSES.equals(attrname)) {
+ attr = new StructInnerClassesAttribute();
+ }
+ else if (ATTRIBUTE_CONSTANT_VALUE.equals(attrname)) {
+ attr = new StructConstantValueAttribute();
+ }
+ else if (ATTRIBUTE_SIGNATURE.equals(attrname)) {
+ attr = new StructGenericSignatureAttribute();
+ }
+ else if (ATTRIBUTE_ANNOTATION_DEFAULT.equals(attrname)) {
+ attr = new StructAnnDefaultAttribute();
+ }
+ else if (ATTRIBUTE_EXCEPTIONS.equals(attrname)) {
+ attr = new StructExceptionsAttribute();
+ }
+ else if (ATTRIBUTE_ENCLOSING_METHOD.equals(attrname)) {
+ attr = new StructEnclosingMethodAttribute();
+ }
+ else if (ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.equals(attrname) ||
+ ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.equals(attrname)) {
+ attr = new StructAnnotationAttribute();
+ }
+ else if (ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attrname) ||
+ ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attrname)) {
+ attr = new StructAnnotationParameterAttribute();
+ }
+ else if (ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attrname) ||
+ ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attrname)) {
+ attr = new StructAnnotationTypeAttribute();
+ }
+ else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname)) {
+ attr = new StructLocalVariableTableAttribute();
+ }
+ else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(attrname)) {
+ attr = new StructBootstrapMethodsAttribute();
+ }
+ else if (ATTRIBUTE_SYNTHETIC.equals(attrname) || ATTRIBUTE_DEPRECATED.equals(attrname)) {
+ attr = new StructGeneralAttribute();
+ }
+ else {
+ // unsupported attribute
+ return null;
+ }
+
+ attr.setAttribute_name_index(nameindex);
+ return attr;
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public byte[] getInfo() {
+ return info;
+ }
+
+ public void setInfo(byte[] info) {
+ this.info = info;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAttribute_name_index() {
+ return attribute_name_index;
+ }
+
+ public void setAttribute_name_index(int attribute_name_index) {
+ this.attribute_name_index = attribute_name_index;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java
index 11206e0..6f2224c 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java
@@ -1,34 +1,33 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.attr;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
public class StructGenericSignatureAttribute extends StructGeneralAttribute {
- private String signature;
+ private String signature;
+
+ public void initContent(ConstantPool pool) {
- public void initContent(ConstantPool pool) {
+ name = ATTRIBUTE_SIGNATURE;
+ signature = pool.getPrimitiveConstant(((info[0] & 0xFF) << 8) | (info[1] & 0xFF)).getString();
+ }
- name = ATTRIBUTE_SIGNATURE;
- signature = pool.getPrimitiveConstant(((info[0] & 0xFF)<<8) | (info[1] & 0xFF)).getString();
- }
-
- public String getSignature() {
- return signature;
- }
-
-
+ public String getSignature() {
+ return signature;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java
index 794da15..14ecd36 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java
@@ -1,73 +1,72 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.attr;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
-
public class StructInnerClassesAttribute extends StructGeneralAttribute {
- private List<int[]> classentries = new ArrayList<int[]>();
-
- private List<String[]> stringentries = new ArrayList<String[]>();
-
- public void initContent(ConstantPool pool) {
-
- name = ATTRIBUTE_INNER_CLASSES;
-
- int length = 2+(((info[0] & 0xFF)<<8) | (info[1] & 0xFF))*8;
- int i=2;
-
- while(i<length) {
-
- int[] arr = new int[4];
- for(int j=0;j<4;j++) {
- arr[j] = ((info[i] & 0xFF)<<8) | (info[i+1] & 0xFF);
- i+=2;
- }
-
- classentries.add(arr);
- }
-
- for(int[] entry: classentries) {
-
- String[] arr = new String[3];
- // inner name
- arr[0] = pool.getPrimitiveConstant(entry[0]).getString();
- //enclosing class
- if(entry[1] != 0) {
- arr[1] = pool.getPrimitiveConstant(entry[1]).getString();
- }
- // original simple name
- if(entry[2]!=0) {
- arr[2] = pool.getPrimitiveConstant(entry[2]).getString();
- }
-
- stringentries.add(arr);
- }
-
- }
-
- public List<int[]> getClassentries() {
- return classentries;
- }
-
- public List<String[]> getStringentries() {
- return stringentries;
- }
+ private List<int[]> classentries = new ArrayList<int[]>();
+
+ private List<String[]> stringentries = new ArrayList<String[]>();
+
+ public void initContent(ConstantPool pool) {
+
+ name = ATTRIBUTE_INNER_CLASSES;
+
+ int length = 2 + (((info[0] & 0xFF) << 8) | (info[1] & 0xFF)) * 8;
+ int i = 2;
+
+ while (i < length) {
+
+ int[] arr = new int[4];
+ for (int j = 0; j < 4; j++) {
+ arr[j] = ((info[i] & 0xFF) << 8) | (info[i + 1] & 0xFF);
+ i += 2;
+ }
+
+ classentries.add(arr);
+ }
+
+ for (int[] entry : classentries) {
+
+ String[] arr = new String[3];
+ // inner name
+ arr[0] = pool.getPrimitiveConstant(entry[0]).getString();
+ //enclosing class
+ if (entry[1] != 0) {
+ arr[1] = pool.getPrimitiveConstant(entry[1]).getString();
+ }
+ // original simple name
+ if (entry[2] != 0) {
+ arr[2] = pool.getPrimitiveConstant(entry[2]).getString();
+ }
+
+ stringentries.add(arr);
+ }
+ }
+
+ public List<int[]> getClassentries() {
+ return classentries;
+ }
+ public List<String[]> getStringentries() {
+ return stringentries;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java
index 119d1ff..0cf2a89 100644
--- a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java
+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java
@@ -1,47 +1,48 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.attr;
-import java.util.HashMap;
-
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import java.util.HashMap;
+
public class StructLocalVariableTableAttribute extends StructGeneralAttribute {
- private HashMap<Integer, String> mapVarNames = new HashMap<Integer, String>();
-
- public void initContent(ConstantPool pool) {
-
- name = ATTRIBUTE_LOCAL_VARIABLE_TABLE;
-
- int len = ((info[0] & 0xFF)<<8) | (info[1] & 0xFF);
-
- int ind = 6;
- for(int i=0;i<len;i++, ind+=10) {
- int nindex = ((info[ind] & 0xFF)<<8) | (info[ind+1] & 0xFF);
- int vindex = ((info[ind+4] & 0xFF)<<8) | (info[ind+5] & 0xFF);
-
- mapVarNames.put(vindex, pool.getPrimitiveConstant(nindex).getString());
- }
- }
-
- public void addLocalVariableTable(StructLocalVariableTableAttribute attr) {
- mapVarNames.putAll(attr.getMapVarNames());
- }
-
- public HashMap<Integer, String> getMapVarNames() {
- return mapVarNames;
- }
+ private HashMap<Integer, String> mapVarNames = new HashMap<Integer, String>();
+
+ public void initContent(ConstantPool pool) {
+
+ name = ATTRIBUTE_LOCAL_VARIABLE_TABLE;
+
+ int len = ((info[0] & 0xFF) << 8) | (info[1] & 0xFF);
+
+ int ind = 6;
+ for (int i = 0; i < len; i++, ind += 10) {
+ int nindex = ((info[ind] & 0xFF) << 8) | (info[ind + 1] & 0xFF);
+ int vindex = ((info[ind + 4] & 0xFF) << 8) | (info[ind + 5] & 0xFF);
+
+ mapVarNames.put(vindex, pool.getPrimitiveConstant(nindex).getString());
+ }
+ }
+
+ public void addLocalVariableTable(StructLocalVariableTableAttribute attr) {
+ mapVarNames.putAll(attr.getMapVarNames());
+ }
+
+ public HashMap<Integer, String> getMapVarNames() {
+ return mapVarNames;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java b/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java
index 8951cd1..5a593af 100644
--- a/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java
+++ b/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java
@@ -1,26 +1,20 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.consts;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
@@ -28,289 +22,297 @@ import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
public class ConstantPool {
-
- public static final int FIELD = 1;
-
- public static final int METHOD = 2;
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private List<PooledConstant> pool = new ArrayList<PooledConstant>();
-
- private PoolInterceptor interceptor;
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public ConstantPool(DataInputStream in) throws IOException {
-
- int size = in.readUnsignedShort();
-
- int[] pass = new int[size];
-
- // first dummy constant
- pool.add(null);
-
- // first pass: read the elements
- for (int i = 1; i < size; i++) {
-
- byte tag = (byte)in.readUnsignedByte();
-
- switch (tag) {
- case CodeConstants.CONSTANT_Utf8:
- pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Utf8, in.readUTF()));
- break;
- case CodeConstants.CONSTANT_Integer:
- pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Integer, new Integer(in.readInt())));
- break;
- case CodeConstants.CONSTANT_Float:
- pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Float, new Float(in.readFloat())));
- break;
- case CodeConstants.CONSTANT_Long:
- pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Long, new Long(in.readLong())));
- pool.add(null);
- i++;
- break;
- case CodeConstants.CONSTANT_Double:
- pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Double, new Double(in.readDouble())));
- pool.add(null);
- i++;
- break;
- case CodeConstants.CONSTANT_Class:
- case CodeConstants.CONSTANT_String:
- case CodeConstants.CONSTANT_MethodType:
- pool.add(new PrimitiveConstant(tag, in.readUnsignedShort()));
- pass[i] = 1;
- break;
- case CodeConstants.CONSTANT_Fieldref:
- case CodeConstants.CONSTANT_Methodref:
- case CodeConstants.CONSTANT_InterfaceMethodref:
- case CodeConstants.CONSTANT_NameAndType:
- case CodeConstants.CONSTANT_InvokeDynamic:
- pool.add(new LinkConstant(tag, in.readUnsignedShort(), in.readUnsignedShort()));
- if(tag == CodeConstants.CONSTANT_NameAndType) {
- pass[i] = 1;
- } else {
- pass[i] = 2;
- }
- break;
- case CodeConstants.CONSTANT_MethodHandle:
- pool.add(new LinkConstant(tag, in.readUnsignedByte(), in.readUnsignedShort()));
- pass[i] = 3;
- break;
- }
- }
-
-
- // resolving complex pool elements
- for(int pass_index = 1; pass_index <= 3; pass_index++) {
- for(int i = 1; i < size; i++) {
- if(pass[i] == pass_index) {
- pool.get(i).resolveConstant(this);
- }
- }
- }
-
- // get global constant pool interceptor instance, if any available
- interceptor = DecompilerContext.getPoolInterceptor();
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public void writeToOutputStream(DataOutputStream out) throws FileNotFoundException, IOException {
-
- out.writeShort(pool.size());
- for(int i=1;i<pool.size();i++) {
- PooledConstant cnst = (PooledConstant)pool.get(i);
- if(cnst!=null) {
- cnst.writeToStream(out);
- }
- }
- }
-
- public static void skipPool(DataInputStream in) throws IOException {
-
- int size = in.readUnsignedShort();
-
- for (int i = 1; i < size; i++) {
- switch (in.readUnsignedByte()) {
- case CodeConstants.CONSTANT_Utf8:
- in.readUTF();
- break;
- case CodeConstants.CONSTANT_Integer:
- case CodeConstants.CONSTANT_Float:
- case CodeConstants.CONSTANT_Fieldref:
- case CodeConstants.CONSTANT_Methodref:
- case CodeConstants.CONSTANT_InterfaceMethodref:
- case CodeConstants.CONSTANT_NameAndType:
- case CodeConstants.CONSTANT_InvokeDynamic:
- in.skip(4);
- break;
- case CodeConstants.CONSTANT_Long:
- case CodeConstants.CONSTANT_Double:
- in.skip(8);
- i++;
- break;
- case CodeConstants.CONSTANT_Class:
- case CodeConstants.CONSTANT_String:
- case CodeConstants.CONSTANT_MethodType:
- in.skip(2);
- break;
- case CodeConstants.CONSTANT_MethodHandle:
- in.skip(3);
- }
- }
- }
-
- public int size() {
- return pool.size();
- }
-
- public String[] getClassElement(int element_type, int class_index, int name_index, int descriptor_index) {
-
- String classname = ((PrimitiveConstant)getConstant(class_index)).getString();
- String elementname = ((PrimitiveConstant)getConstant(name_index)).getString();
- String descriptor = ((PrimitiveConstant)getConstant(descriptor_index)).getString();
-
- if(interceptor != null) {
- String new_element = interceptor.getName(classname+" "+elementname+" "+descriptor);
-
- if(new_element != null) {
- elementname = new_element.split(" ")[1];
- }
-
- String new_descriptor = buildNewDescriptor(element_type == FIELD?CodeConstants.CONSTANT_Fieldref:CodeConstants.CONSTANT_Methodref,
- descriptor);
- if(new_descriptor != null) {
- descriptor = new_descriptor;
- }
- }
-
- return new String[] {elementname, descriptor};
- }
-
- public PooledConstant getConstant(int index) {
- return pool.get(index);
- }
-
- public PrimitiveConstant getPrimitiveConstant(int index) {
- PrimitiveConstant cn = (PrimitiveConstant)getConstant(index);
-
- if(cn != null && interceptor != null) {
- if(cn.type == CodeConstants.CONSTANT_Class) {
- String newname = buildNewClassname(cn.getString());
- if(newname != null) {
- cn = new PrimitiveConstant(CodeConstants.CONSTANT_Class, newname);
- }
- }
- }
-
- return cn;
- }
-
- public LinkConstant getLinkConstant(int index) {
- LinkConstant ln = (LinkConstant)getConstant(index);
-
- if(ln != null && interceptor != null) {
- if(ln.type == CodeConstants.CONSTANT_Fieldref ||
- ln.type == CodeConstants.CONSTANT_Methodref ||
- ln.type == CodeConstants.CONSTANT_InterfaceMethodref) {
-
- String new_classname = buildNewClassname(ln.classname);
- String new_element = interceptor.getName(ln.classname+" "+ln.elementname+" "+ln.descriptor);
- String new_descriptor = buildNewDescriptor(ln.type, ln.descriptor);
-
- if(new_classname != null || new_element != null || new_descriptor != null) {
-
- ln = new LinkConstant(ln.type, new_classname==null?ln.classname:new_classname,
- new_element==null?ln.elementname:new_element.split(" ")[1],
- new_descriptor==null?ln.descriptor:new_descriptor);
- }
- }
- }
-
- return ln;
- }
-
- private String buildNewClassname(String classname) {
-
- VarType vt = new VarType(classname, true);
-
- String newname = interceptor.getName(vt.value);
- if(newname != null) {
- StringBuilder buffer = new StringBuilder();
-
- if(vt.arraydim > 0) {
- for(int i=0;i<vt.arraydim;i++) {
- buffer.append("[");
- }
-
- buffer.append("L"+newname+";");
- } else {
- buffer.append(newname);
- }
-
- return buffer.toString();
- }
-
- return null;
- }
-
- private String buildNewDescriptor(int type, String descriptor) {
-
- boolean updated = false;
-
- if(type == CodeConstants.CONSTANT_Fieldref) {
- FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor);
-
- VarType ftype = fd.type;
- if(ftype.type == CodeConstants.TYPE_OBJECT) {
- String newclname = buildNewClassname(ftype.value);
- if(newclname != null) {
- ftype.value = newclname;
- updated = true;
- }
- }
-
- if(updated) {
- return fd.getDescriptor();
- }
-
- } else {
-
- MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
- // params
- for(VarType partype : md.params) {
- if(partype.type == CodeConstants.TYPE_OBJECT) {
- String newclname = buildNewClassname(partype.value);
- if(newclname != null) {
- partype.value = newclname;
- updated = true;
- }
- }
- }
-
- // return value
- if(md.ret.type == CodeConstants.TYPE_OBJECT) {
- String newclname = buildNewClassname(md.ret.value);
- if(newclname!=null) {
- md.ret.value = newclname;
- updated = true;
- }
- }
-
- if(updated) {
- return md.getDescriptor();
- }
- }
-
- return null;
- }
-
+
+ public static final int FIELD = 1;
+
+ public static final int METHOD = 2;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private List<PooledConstant> pool = new ArrayList<PooledConstant>();
+
+ private PoolInterceptor interceptor;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public ConstantPool(DataInputStream in) throws IOException {
+
+ int size = in.readUnsignedShort();
+
+ int[] pass = new int[size];
+
+ // first dummy constant
+ pool.add(null);
+
+ // first pass: read the elements
+ for (int i = 1; i < size; i++) {
+
+ byte tag = (byte)in.readUnsignedByte();
+
+ switch (tag) {
+ case CodeConstants.CONSTANT_Utf8:
+ pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Utf8, in.readUTF()));
+ break;
+ case CodeConstants.CONSTANT_Integer:
+ pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Integer, new Integer(in.readInt())));
+ break;
+ case CodeConstants.CONSTANT_Float:
+ pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Float, new Float(in.readFloat())));
+ break;
+ case CodeConstants.CONSTANT_Long:
+ pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Long, new Long(in.readLong())));
+ pool.add(null);
+ i++;
+ break;
+ case CodeConstants.CONSTANT_Double:
+ pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Double, new Double(in.readDouble())));
+ pool.add(null);
+ i++;
+ break;
+ case CodeConstants.CONSTANT_Class:
+ case CodeConstants.CONSTANT_String:
+ case CodeConstants.CONSTANT_MethodType:
+ pool.add(new PrimitiveConstant(tag, in.readUnsignedShort()));
+ pass[i] = 1;
+ break;
+ case CodeConstants.CONSTANT_Fieldref:
+ case CodeConstants.CONSTANT_Methodref:
+ case CodeConstants.CONSTANT_InterfaceMethodref:
+ case CodeConstants.CONSTANT_NameAndType:
+ case CodeConstants.CONSTANT_InvokeDynamic:
+ pool.add(new LinkConstant(tag, in.readUnsignedShort(), in.readUnsignedShort()));
+ if (tag == CodeConstants.CONSTANT_NameAndType) {
+ pass[i] = 1;
+ }
+ else {
+ pass[i] = 2;
+ }
+ break;
+ case CodeConstants.CONSTANT_MethodHandle:
+ pool.add(new LinkConstant(tag, in.readUnsignedByte(), in.readUnsignedShort()));
+ pass[i] = 3;
+ break;
+ }
+ }
+
+
+ // resolving complex pool elements
+ for (int pass_index = 1; pass_index <= 3; pass_index++) {
+ for (int i = 1; i < size; i++) {
+ if (pass[i] == pass_index) {
+ pool.get(i).resolveConstant(this);
+ }
+ }
+ }
+
+ // get global constant pool interceptor instance, if any available
+ interceptor = DecompilerContext.getPoolInterceptor();
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void writeToOutputStream(DataOutputStream out) throws FileNotFoundException, IOException {
+
+ out.writeShort(pool.size());
+ for (int i = 1; i < pool.size(); i++) {
+ PooledConstant cnst = (PooledConstant)pool.get(i);
+ if (cnst != null) {
+ cnst.writeToStream(out);
+ }
+ }
+ }
+
+ public static void skipPool(DataInputStream in) throws IOException {
+
+ int size = in.readUnsignedShort();
+
+ for (int i = 1; i < size; i++) {
+ switch (in.readUnsignedByte()) {
+ case CodeConstants.CONSTANT_Utf8:
+ in.readUTF();
+ break;
+ case CodeConstants.CONSTANT_Integer:
+ case CodeConstants.CONSTANT_Float:
+ case CodeConstants.CONSTANT_Fieldref:
+ case CodeConstants.CONSTANT_Methodref:
+ case CodeConstants.CONSTANT_InterfaceMethodref:
+ case CodeConstants.CONSTANT_NameAndType:
+ case CodeConstants.CONSTANT_InvokeDynamic:
+ in.skip(4);
+ break;
+ case CodeConstants.CONSTANT_Long:
+ case CodeConstants.CONSTANT_Double:
+ in.skip(8);
+ i++;
+ break;
+ case CodeConstants.CONSTANT_Class:
+ case CodeConstants.CONSTANT_String:
+ case CodeConstants.CONSTANT_MethodType:
+ in.skip(2);
+ break;
+ case CodeConstants.CONSTANT_MethodHandle:
+ in.skip(3);
+ }
+ }
+ }
+
+ public int size() {
+ return pool.size();
+ }
+
+ public String[] getClassElement(int element_type, int class_index, int name_index, int descriptor_index) {
+
+ String classname = ((PrimitiveConstant)getConstant(class_index)).getString();
+ String elementname = ((PrimitiveConstant)getConstant(name_index)).getString();
+ String descriptor = ((PrimitiveConstant)getConstant(descriptor_index)).getString();
+
+ if (interceptor != null) {
+ String new_element = interceptor.getName(classname + " " + elementname + " " + descriptor);
+
+ if (new_element != null) {
+ elementname = new_element.split(" ")[1];
+ }
+
+ String new_descriptor = buildNewDescriptor(element_type == FIELD ? CodeConstants.CONSTANT_Fieldref : CodeConstants.CONSTANT_Methodref,
+ descriptor);
+ if (new_descriptor != null) {
+ descriptor = new_descriptor;
+ }
+ }
+
+ return new String[]{elementname, descriptor};
+ }
+
+ public PooledConstant getConstant(int index) {
+ return pool.get(index);
+ }
+
+ public PrimitiveConstant getPrimitiveConstant(int index) {
+ PrimitiveConstant cn = (PrimitiveConstant)getConstant(index);
+
+ if (cn != null && interceptor != null) {
+ if (cn.type == CodeConstants.CONSTANT_Class) {
+ String newname = buildNewClassname(cn.getString());
+ if (newname != null) {
+ cn = new PrimitiveConstant(CodeConstants.CONSTANT_Class, newname);
+ }
+ }
+ }
+
+ return cn;
+ }
+
+ public LinkConstant getLinkConstant(int index) {
+ LinkConstant ln = (LinkConstant)getConstant(index);
+
+ if (ln != null && interceptor != null) {
+ if (ln.type == CodeConstants.CONSTANT_Fieldref ||
+ ln.type == CodeConstants.CONSTANT_Methodref ||
+ ln.type == CodeConstants.CONSTANT_InterfaceMethodref) {
+
+ String new_classname = buildNewClassname(ln.classname);
+ String new_element = interceptor.getName(ln.classname + " " + ln.elementname + " " + ln.descriptor);
+ String new_descriptor = buildNewDescriptor(ln.type, ln.descriptor);
+
+ if (new_classname != null || new_element != null || new_descriptor != null) {
+
+ ln = new LinkConstant(ln.type, new_classname == null ? ln.classname : new_classname,
+ new_element == null ? ln.elementname : new_element.split(" ")[1],
+ new_descriptor == null ? ln.descriptor : new_descriptor);
+ }
+ }
+ }
+
+ return ln;
+ }
+
+ private String buildNewClassname(String classname) {
+
+ VarType vt = new VarType(classname, true);
+
+ String newname = interceptor.getName(vt.value);
+ if (newname != null) {
+ StringBuilder buffer = new StringBuilder();
+
+ if (vt.arraydim > 0) {
+ for (int i = 0; i < vt.arraydim; i++) {
+ buffer.append("[");
+ }
+
+ buffer.append("L" + newname + ";");
+ }
+ else {
+ buffer.append(newname);
+ }
+
+ return buffer.toString();
+ }
+
+ return null;
+ }
+
+ private String buildNewDescriptor(int type, String descriptor) {
+
+ boolean updated = false;
+
+ if (type == CodeConstants.CONSTANT_Fieldref) {
+ FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor);
+
+ VarType ftype = fd.type;
+ if (ftype.type == CodeConstants.TYPE_OBJECT) {
+ String newclname = buildNewClassname(ftype.value);
+ if (newclname != null) {
+ ftype.value = newclname;
+ updated = true;
+ }
+ }
+
+ if (updated) {
+ return fd.getDescriptor();
+ }
+ }
+ else {
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
+ // params
+ for (VarType partype : md.params) {
+ if (partype.type == CodeConstants.TYPE_OBJECT) {
+ String newclname = buildNewClassname(partype.value);
+ if (newclname != null) {
+ partype.value = newclname;
+ updated = true;
+ }
+ }
+ }
+
+ // return value
+ if (md.ret.type == CodeConstants.TYPE_OBJECT) {
+ String newclname = buildNewClassname(md.ret.value);
+ if (newclname != null) {
+ md.ret.value = newclname;
+ updated = true;
+ }
+ }
+
+ if (updated) {
+ return md.getDescriptor();
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/consts/LinkConstant.java b/src/org/jetbrains/java/decompiler/struct/consts/LinkConstant.java
index 770a5e3..c20b5af 100644
--- a/src/org/jetbrains/java/decompiler/struct/consts/LinkConstant.java
+++ b/src/org/jetbrains/java/decompiler/struct/consts/LinkConstant.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.consts;
import java.io.DataOutputStream;
@@ -24,136 +25,142 @@ import java.io.IOException;
public class LinkConstant extends PooledConstant {
- // *****************************************************************************
- // public fields
- // *****************************************************************************
-
- public int index1, index2;
-
- public String classname;
-
- public String elementname;
-
- public String descriptor;
-
- public int paramCount = 0;
-
- public boolean isVoid = false;;
-
- public boolean returnCategory2 = false;
-
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public LinkConstant(int type, String classname, String elementname, String descriptor) {
- this.type = type;
- this.classname = classname;
- this.elementname = elementname;
- this.descriptor = descriptor;
-
- initConstant();
- }
-
- public LinkConstant(int type, int index1, int index2) {
- this.type = type;
- this.index1 = index1;
- this.index2 = index2;
- }
-
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public void resolveConstant(ConstantPool pool) {
-
- if(type == CONSTANT_NameAndType) {
- elementname = pool.getPrimitiveConstant(index1).getString();
- descriptor = pool.getPrimitiveConstant(index2).getString();
- } else if(type == CONSTANT_MethodHandle) {
- LinkConstant ref_info = pool.getLinkConstant(index2);
-
- classname = ref_info.classname;
- elementname = ref_info.elementname;
- descriptor = ref_info.descriptor;
-
- } else {
- if(type != CONSTANT_InvokeDynamic) {
- classname = pool.getPrimitiveConstant(index1).getString();
- }
-
- LinkConstant nametype = pool.getLinkConstant(index2);
- elementname = nametype.elementname;
- descriptor = nametype.descriptor;
- }
-
- initConstant();
- }
-
- public void writeToStream(DataOutputStream out) throws IOException {
- out.writeByte(type);
- if(type == CONSTANT_MethodHandle) {
- out.writeByte(index1);
- } else {
- out.writeShort(index1);
- }
- out.writeShort(index2);
- }
-
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof LinkConstant)) return false;
-
- LinkConstant cn = (LinkConstant)o;
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int index1, index2;
+
+ public String classname;
+
+ public String elementname;
+
+ public String descriptor;
+
+ public int paramCount = 0;
+
+ public boolean isVoid = false;
+ ;
+
+ public boolean returnCategory2 = false;
+
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public LinkConstant(int type, String classname, String elementname, String descriptor) {
+ this.type = type;
+ this.classname = classname;
+ this.elementname = elementname;
+ this.descriptor = descriptor;
+
+ initConstant();
+ }
+
+ public LinkConstant(int type, int index1, int index2) {
+ this.type = type;
+ this.index1 = index1;
+ this.index2 = index2;
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void resolveConstant(ConstantPool pool) {
+
+ if (type == CONSTANT_NameAndType) {
+ elementname = pool.getPrimitiveConstant(index1).getString();
+ descriptor = pool.getPrimitiveConstant(index2).getString();
+ }
+ else if (type == CONSTANT_MethodHandle) {
+ LinkConstant ref_info = pool.getLinkConstant(index2);
+
+ classname = ref_info.classname;
+ elementname = ref_info.elementname;
+ descriptor = ref_info.descriptor;
+ }
+ else {
+ if (type != CONSTANT_InvokeDynamic) {
+ classname = pool.getPrimitiveConstant(index1).getString();
+ }
+
+ LinkConstant nametype = pool.getLinkConstant(index2);
+ elementname = nametype.elementname;
+ descriptor = nametype.descriptor;
+ }
+
+ initConstant();
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+ out.writeByte(type);
+ if (type == CONSTANT_MethodHandle) {
+ out.writeByte(index1);
+ }
+ else {
+ out.writeShort(index1);
+ }
+ out.writeShort(index2);
+ }
+
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof LinkConstant)) return false;
+
+ LinkConstant cn = (LinkConstant)o;
return this.type == cn.type &&
- this.elementname.equals(cn.elementname) &&
- this.descriptor.equals(cn.descriptor) &&
- (this.type != CONSTANT_NameAndType || this.classname.equals(cn.classname));
+ this.elementname.equals(cn.elementname) &&
+ this.descriptor.equals(cn.descriptor) &&
+ (this.type != CONSTANT_NameAndType || this.classname.equals(cn.classname));
+ }
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private void initConstant() {
+
+ if (type == CONSTANT_Methodref ||
+ type == CONSTANT_InterfaceMethodref ||
+ type == CONSTANT_InvokeDynamic ||
+ type == CONSTANT_MethodHandle) {
+ resolveDescriptor(descriptor);
+ }
+ else if (type == CONSTANT_Fieldref) {
+ returnCategory2 = ("D".equals(descriptor) || "J".equals(descriptor));
+ }
+ }
+
+ private void resolveDescriptor(String descr) {
+
+ String[] arr = descr.split("[()]");
+ String par = arr[1];
+
+ int index = 0, counter = 0;
+ int len = par.length();
+
+ while (index < len) {
+
+ char c = par.charAt(index);
+ if (c == 'L') {
+ index = par.indexOf(";", index);
+ }
+ else if (c == '[') {
+ index++;
+ continue;
+ }
+
+ counter++;
+ index++;
+ }
+
+ paramCount = counter;
+ isVoid = "V".equals(arr[2]);
+ returnCategory2 = ("D".equals(arr[2]) || "J".equals(arr[2]));
}
-
- // *****************************************************************************
- // private methods
- // *****************************************************************************
-
- private void initConstant() {
-
- if(type == CONSTANT_Methodref || type == CONSTANT_InterfaceMethodref || type == CONSTANT_InvokeDynamic || type == CONSTANT_MethodHandle) {
- resolveDescriptor(descriptor);
- } else if(type == CONSTANT_Fieldref) {
- returnCategory2 = ("D".equals(descriptor) || "J".equals(descriptor));
- }
-
- }
-
- private void resolveDescriptor(String descr){
-
- String[] arr = descr.split("[()]");
- String par = arr[1];
-
- int index = 0, counter = 0;
- int len = par.length();
-
- while(index<len) {
-
- char c = par.charAt(index);
- if(c == 'L') {
- index = par.indexOf(";", index);
- } else if (c == '[') {
- index++;
- continue;
- }
-
- counter++;
- index++;
- }
-
- paramCount = counter;
- isVoid = "V".equals(arr[2]);
- returnCategory2 = ("D".equals(arr[2]) || "J".equals(arr[2]));
- }
-
}
diff --git a/src/org/jetbrains/java/decompiler/struct/consts/PooledConstant.java b/src/org/jetbrains/java/decompiler/struct/consts/PooledConstant.java
index ae46604..d3d30c0 100644
--- a/src/org/jetbrains/java/decompiler/struct/consts/PooledConstant.java
+++ b/src/org/jetbrains/java/decompiler/struct/consts/PooledConstant.java
@@ -1,24 +1,25 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.consts;
+import org.jetbrains.java.decompiler.code.CodeConstants;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jetbrains.java.decompiler.code.CodeConstants;
-
/*
cp_info {
u1 tag;
@@ -29,88 +30,88 @@ import org.jetbrains.java.decompiler.code.CodeConstants;
public class PooledConstant implements CodeConstants, VariableTypeEnum {
- // *****************************************************************************
- // public fields
- // *****************************************************************************
-
- public int type;
-
- public boolean own = false;
-
- public int returnType;
-
-
- // *****************************************************************************
- // private fields
- // *****************************************************************************
-
- private Object[] values;
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public PooledConstant() {}
-
- public PooledConstant(int type, Object[] values) {
- this.type = type;
- this.values = values;
- this.returnType = poolTypeToIntern(type);
- }
-
- public PooledConstant(int type, boolean own, Object[] values) {
- this.type = type;
- this.own = own;
- this.values = values;
- this.returnType = poolTypeToIntern(type);
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public void resolveConstant(ConstantPool pool) {
- // to be overwritten
- }
-
- public void writeToStream(DataOutputStream out) throws IOException {
- // to be overwritten
- }
-
- public int poolTypeToIntern(int type) {
-
- switch(type){
- case CONSTANT_Integer:
- return INT;
- case CONSTANT_Float:
- return FLOAT;
- case CONSTANT_Long:
- return LONG;
- case CONSTANT_Double:
- return DOUBLE;
- case CONSTANT_String:
- case CONSTANT_Class: // 1.5 -> ldc class
- return REFERENCE;
- default:
- throw new RuntimeException("Huh?? What are you trying to load?");
- }
- }
-
- public Object getValue(int index){
- return values[index];
- }
-
-
- // *****************************************************************************
- // getter and setter methods
- // *****************************************************************************
-
- public Object[] getValues() {
- return values;
- }
-
- public void setValues(Object[] values) {
- this.values = values;
- }
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int type;
+
+ public boolean own = false;
+
+ public int returnType;
+
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private Object[] values;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public PooledConstant() {
+ }
+
+ public PooledConstant(int type, Object[] values) {
+ this.type = type;
+ this.values = values;
+ this.returnType = poolTypeToIntern(type);
+ }
+
+ public PooledConstant(int type, boolean own, Object[] values) {
+ this.type = type;
+ this.own = own;
+ this.values = values;
+ this.returnType = poolTypeToIntern(type);
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void resolveConstant(ConstantPool pool) {
+ // to be overwritten
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+ // to be overwritten
+ }
+
+ public int poolTypeToIntern(int type) {
+
+ switch (type) {
+ case CONSTANT_Integer:
+ return INT;
+ case CONSTANT_Float:
+ return FLOAT;
+ case CONSTANT_Long:
+ return LONG;
+ case CONSTANT_Double:
+ return DOUBLE;
+ case CONSTANT_String:
+ case CONSTANT_Class: // 1.5 -> ldc class
+ return REFERENCE;
+ default:
+ throw new RuntimeException("Huh?? What are you trying to load?");
+ }
+ }
+
+ public Object getValue(int index) {
+ return values[index];
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public Object[] getValues() {
+ return values;
+ }
+ public void setValues(Object[] values) {
+ this.values = values;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/consts/PrimitiveConstant.java b/src/org/jetbrains/java/decompiler/struct/consts/PrimitiveConstant.java
index f01a695..4cd4dd8 100644
--- a/src/org/jetbrains/java/decompiler/struct/consts/PrimitiveConstant.java
+++ b/src/org/jetbrains/java/decompiler/struct/consts/PrimitiveConstant.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.consts;
import java.io.DataOutputStream;
@@ -23,104 +24,103 @@ import java.io.IOException;
public class PrimitiveConstant extends PooledConstant {
- // *****************************************************************************
- // public fields
- // *****************************************************************************
-
- public int index;
-
- public Object value;
-
- public boolean isArray;
-
- // *****************************************************************************
- // constructors
- // *****************************************************************************
-
- public PrimitiveConstant(int type, Object value) {
- this.type = type;
- this.value = value;
-
- initConstant();
- }
-
- public PrimitiveConstant(int type, int index) {
- this.type = type;
- this.index = index;
- }
-
- // *****************************************************************************
- // public methods
- // *****************************************************************************
-
- public int getInt() {
- return ((Integer)value).intValue();
- }
-
- public long getLong() {
- return ((Long)value).longValue();
- }
-
- public float getFloat() {
- return ((Float)value).floatValue();
- }
-
- public double getDouble() {
- return ((Double)value).doubleValue();
- }
-
- public String getString() {
- return (String)value;
- }
-
- public void resolveConstant(ConstantPool pool) {
-
- if(type == CONSTANT_Class || type == CONSTANT_String || type == CONSTANT_MethodType) {
- value = pool.getPrimitiveConstant(index).getString();
- initConstant();
- }
- }
-
- public void writeToStream(DataOutputStream out) throws IOException {
-
- out.writeByte(type);
- switch(type) {
- case CONSTANT_Integer:
- out.writeInt(getInt());
- break;
- case CONSTANT_Float:
- out.writeFloat(getFloat());
- break;
- case CONSTANT_Long:
- out.writeLong(getLong());
- break;
- case CONSTANT_Double:
- out.writeDouble(getDouble());
- break;
- case CONSTANT_Utf8:
- out.writeUTF(getString());
- break;
- default: // CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType
- out.writeShort(index);
- }
- }
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof PrimitiveConstant)) return false;
-
- PrimitiveConstant cn = (PrimitiveConstant)o;
- return this.type == cn.type &&
- this.isArray == cn.isArray &&
- this.value.equals(cn.value);
-
- }
-
- private void initConstant() {
- if(type == CONSTANT_Class) {
- String className = getString();
- isArray = (className.length() > 0 && className.charAt(0)=='['); // empty string for a class name seems to be possible in some android files
- }
- }
-
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int index;
+
+ public Object value;
+
+ public boolean isArray;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public PrimitiveConstant(int type, Object value) {
+ this.type = type;
+ this.value = value;
+
+ initConstant();
+ }
+
+ public PrimitiveConstant(int type, int index) {
+ this.type = type;
+ this.index = index;
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public int getInt() {
+ return ((Integer)value).intValue();
+ }
+
+ public long getLong() {
+ return ((Long)value).longValue();
+ }
+
+ public float getFloat() {
+ return ((Float)value).floatValue();
+ }
+
+ public double getDouble() {
+ return ((Double)value).doubleValue();
+ }
+
+ public String getString() {
+ return (String)value;
+ }
+
+ public void resolveConstant(ConstantPool pool) {
+
+ if (type == CONSTANT_Class || type == CONSTANT_String || type == CONSTANT_MethodType) {
+ value = pool.getPrimitiveConstant(index).getString();
+ initConstant();
+ }
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+
+ out.writeByte(type);
+ switch (type) {
+ case CONSTANT_Integer:
+ out.writeInt(getInt());
+ break;
+ case CONSTANT_Float:
+ out.writeFloat(getFloat());
+ break;
+ case CONSTANT_Long:
+ out.writeLong(getLong());
+ break;
+ case CONSTANT_Double:
+ out.writeDouble(getDouble());
+ break;
+ case CONSTANT_Utf8:
+ out.writeUTF(getString());
+ break;
+ default: // CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType
+ out.writeShort(index);
+ }
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof PrimitiveConstant)) return false;
+
+ PrimitiveConstant cn = (PrimitiveConstant)o;
+ return this.type == cn.type &&
+ this.isArray == cn.isArray &&
+ this.value.equals(cn.value);
+ }
+
+ private void initConstant() {
+ if (type == CONSTANT_Class) {
+ String className = getString();
+ isArray =
+ (className.length() > 0 && className.charAt(0) == '['); // empty string for a class name seems to be possible in some android files
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/consts/VariableTypeEnum.java b/src/org/jetbrains/java/decompiler/struct/consts/VariableTypeEnum.java
index fc58c7e..ef949aa 100644
--- a/src/org/jetbrains/java/decompiler/struct/consts/VariableTypeEnum.java
+++ b/src/org/jetbrains/java/decompiler/struct/consts/VariableTypeEnum.java
@@ -1,47 +1,47 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.consts;
public interface VariableTypeEnum {
- public final static int BOOLEAN = 1;
- public final static int BYTE = 2;
- public final static int CHAR = 3;
- public final static int SHORT = 4;
- public final static int INT = 5;
- public final static int FLOAT = 6;
- public final static int LONG = 7;
- public final static int DOUBLE = 8;
- public final static int RETURN_ADDRESS = 9;
- public final static int REFERENCE = 10;
- public final static int INSTANCE_UNINITIALIZED = 11;
- public final static int VALUE_UNKNOWN = 12;
- public final static int VOID = 13;
-
- public final static Integer BOOLEAN_OBJ = new Integer(BOOLEAN);
- public final static Integer BYTE_OBJ = new Integer(BYTE);
- public final static Integer CHAR_OBJ = new Integer(CHAR);
- public final static Integer SHORT_OBJ = new Integer(SHORT);
- public final static Integer INT_OBJ = new Integer(INT);
- public final static Integer FLOAT_OBJ = new Integer(FLOAT);
- public final static Integer LONG_OBJ = new Integer(LONG);
- public final static Integer DOUBLE_OBJ = new Integer(DOUBLE);
- public final static Integer RETURN_ADDRESS_OBJ = new Integer(RETURN_ADDRESS);
- public final static Integer REFERENCE_OBJ = new Integer(REFERENCE);
- public final static Integer INSTANCE_UNINITIALIZED_OBJ = new Integer(INSTANCE_UNINITIALIZED);
- public final static Integer VALUE_UNKNOWN_OBJ = new Integer(VALUE_UNKNOWN);
- public final static Integer VOID_OBJ = new Integer(VOID);
-
+ public final static int BOOLEAN = 1;
+ public final static int BYTE = 2;
+ public final static int CHAR = 3;
+ public final static int SHORT = 4;
+ public final static int INT = 5;
+ public final static int FLOAT = 6;
+ public final static int LONG = 7;
+ public final static int DOUBLE = 8;
+ public final static int RETURN_ADDRESS = 9;
+ public final static int REFERENCE = 10;
+ public final static int INSTANCE_UNINITIALIZED = 11;
+ public final static int VALUE_UNKNOWN = 12;
+ public final static int VOID = 13;
+
+ public final static Integer BOOLEAN_OBJ = new Integer(BOOLEAN);
+ public final static Integer BYTE_OBJ = new Integer(BYTE);
+ public final static Integer CHAR_OBJ = new Integer(CHAR);
+ public final static Integer SHORT_OBJ = new Integer(SHORT);
+ public final static Integer INT_OBJ = new Integer(INT);
+ public final static Integer FLOAT_OBJ = new Integer(FLOAT);
+ public final static Integer LONG_OBJ = new Integer(LONG);
+ public final static Integer DOUBLE_OBJ = new Integer(DOUBLE);
+ public final static Integer RETURN_ADDRESS_OBJ = new Integer(RETURN_ADDRESS);
+ public final static Integer REFERENCE_OBJ = new Integer(REFERENCE);
+ public final static Integer INSTANCE_UNINITIALIZED_OBJ = new Integer(INSTANCE_UNINITIALIZED);
+ public final static Integer VALUE_UNKNOWN_OBJ = new Integer(VALUE_UNKNOWN);
+ public final static Integer VOID_OBJ = new Integer(VOID);
}
diff --git a/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java b/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java
index db6ecd1..53269da 100644
--- a/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java
+++ b/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java
@@ -1,98 +1,100 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.gen;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.util.ListStack;
+import java.util.ArrayList;
+import java.util.List;
+
public class DataPoint {
- private List<VarType> localVariables = new ArrayList<VarType>();
-
- private ListStack<VarType> stack = new ListStack<VarType>();
-
-
- public void setVariable(int index, VarType value) {
- if(index>=localVariables.size()) {
- for(int i=localVariables.size();i<=index;i++) {
- localVariables.add(new VarType(CodeConstants.TYPE_NOTINITIALIZED));
- }
- }
-
- localVariables.set(index, value);
- }
-
- public VarType getVariable(int index) {
- if(index<localVariables.size()) {
- return localVariables.get(index);
- } else if(index<0) {
- throw new IndexOutOfBoundsException();
- } else {
- return new VarType(CodeConstants.TYPE_NOTINITIALIZED);
- }
- }
-
- public DataPoint copy() {
- DataPoint point = new DataPoint();
- point.setLocalVariables(new ArrayList<VarType>(localVariables));
- point.setStack(stack.clone());
- return point;
- }
-
- public static DataPoint getInitialDataPoint(StructMethod mt) {
-
- DataPoint point = new DataPoint();
-
- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
-
- int k = 0;
- if((mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0) {
- point.setVariable(k++, new VarType(CodeConstants.TYPE_OBJECT, 0, null));
- }
-
- for(int i=0;i<md.params.length;i++) {
- VarType var = md.params[i];
-
- point.setVariable(k++, var);
- if(var.stack_size == 2) {
- point.setVariable(k++, new VarType(CodeConstants.TYPE_GROUP2EMPTY));
- }
- }
-
- return point;
- }
-
-
- public List<VarType> getLocalVariables() {
- return localVariables;
- }
-
- public void setLocalVariables(List<VarType> localVariables) {
- this.localVariables = localVariables;
- }
-
- public ListStack<VarType> getStack() {
- return stack;
- }
-
- public void setStack(ListStack<VarType> stack) {
- this.stack = stack;
- }
-
+ private List<VarType> localVariables = new ArrayList<VarType>();
+
+ private ListStack<VarType> stack = new ListStack<VarType>();
+
+
+ public void setVariable(int index, VarType value) {
+ if (index >= localVariables.size()) {
+ for (int i = localVariables.size(); i <= index; i++) {
+ localVariables.add(new VarType(CodeConstants.TYPE_NOTINITIALIZED));
+ }
+ }
+
+ localVariables.set(index, value);
+ }
+
+ public VarType getVariable(int index) {
+ if (index < localVariables.size()) {
+ return localVariables.get(index);
+ }
+ else if (index < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ else {
+ return new VarType(CodeConstants.TYPE_NOTINITIALIZED);
+ }
+ }
+
+ public DataPoint copy() {
+ DataPoint point = new DataPoint();
+ point.setLocalVariables(new ArrayList<VarType>(localVariables));
+ point.setStack(stack.clone());
+ return point;
+ }
+
+ public static DataPoint getInitialDataPoint(StructMethod mt) {
+
+ DataPoint point = new DataPoint();
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int k = 0;
+ if ((mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0) {
+ point.setVariable(k++, new VarType(CodeConstants.TYPE_OBJECT, 0, null));
+ }
+
+ for (int i = 0; i < md.params.length; i++) {
+ VarType var = md.params[i];
+
+ point.setVariable(k++, var);
+ if (var.stack_size == 2) {
+ point.setVariable(k++, new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ }
+ }
+
+ return point;
+ }
+
+
+ public List<VarType> getLocalVariables() {
+ return localVariables;
+ }
+
+ public void setLocalVariables(List<VarType> localVariables) {
+ this.localVariables = localVariables;
+ }
+
+ public ListStack<VarType> getStack() {
+ return stack;
+ }
+
+ public void setStack(ListStack<VarType> stack) {
+ this.stack = stack;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/gen/FieldDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/FieldDescriptor.java
index a475937..ff731ae 100644
--- a/src/org/jetbrains/java/decompiler/struct/gen/FieldDescriptor.java
+++ b/src/org/jetbrains/java/decompiler/struct/gen/FieldDescriptor.java
@@ -1,58 +1,59 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.gen;
public class FieldDescriptor {
-
- public static final FieldDescriptor INTEGER_DESCRIPTOR = FieldDescriptor.parseDescriptor("Ljava/lang/Integer;");
- public static final FieldDescriptor LONG_DESCRIPTOR = FieldDescriptor.parseDescriptor("Ljava/lang/Long;");
- public static final FieldDescriptor FLOAT_DESCRIPTOR = FieldDescriptor.parseDescriptor("Ljava/lang/Float;");
- public static final FieldDescriptor DOUBLE_DESCRIPTOR = FieldDescriptor.parseDescriptor("Ljava/lang/Double;");
-
- public VarType type;
-
- public String descriptorString;
-
- private FieldDescriptor() {}
-
- public static FieldDescriptor parseDescriptor(String descr) {
-
- FieldDescriptor fd = new FieldDescriptor();
-
- fd.type = new VarType(descr);
- fd.descriptorString = descr;
-
- return fd;
- }
-
- public String getDescriptor() {
- return type.toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof FieldDescriptor)) return false;
+
+ public static final FieldDescriptor INTEGER_DESCRIPTOR = FieldDescriptor.parseDescriptor("Ljava/lang/Integer;");
+ public static final FieldDescriptor LONG_DESCRIPTOR = FieldDescriptor.parseDescriptor("Ljava/lang/Long;");
+ public static final FieldDescriptor FLOAT_DESCRIPTOR = FieldDescriptor.parseDescriptor("Ljava/lang/Float;");
+ public static final FieldDescriptor DOUBLE_DESCRIPTOR = FieldDescriptor.parseDescriptor("Ljava/lang/Double;");
+
+ public VarType type;
+
+ public String descriptorString;
+
+ private FieldDescriptor() {
+ }
+
+ public static FieldDescriptor parseDescriptor(String descr) {
+
+ FieldDescriptor fd = new FieldDescriptor();
+
+ fd.type = new VarType(descr);
+ fd.descriptorString = descr;
+
+ return fd;
+ }
+
+ public String getDescriptor() {
+ return type.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FieldDescriptor)) return false;
FieldDescriptor fd = (FieldDescriptor)o;
return type.equals(fd.type);
}
- @Override
- public int hashCode() {
- return type.hashCode();
- }
-
+ @Override
+ public int hashCode() {
+ return type.hashCode();
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java
index 77a8394..7dbc16c 100644
--- a/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java
+++ b/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.gen;
import java.util.ArrayList;
@@ -20,83 +21,82 @@ import java.util.List;
public class MethodDescriptor {
- public VarType[] params;
-
- public VarType ret;
-
-
- public static MethodDescriptor parseDescriptor(String mdescr) {
-
- MethodDescriptor md = new MethodDescriptor();
-
- List<String> lst = new ArrayList<String>();
- String[] pars = mdescr.split("[()]");
-
- String par = pars[1];
-
- int indexFrom = -1, ind,index = 0;
- int len = par.length();
-
- for(;index<len;index++) {
-
- switch(par.charAt(index)){
- case '[':
- if(indexFrom<0){
- indexFrom = index;
- }
- break;
- case 'L':
- ind = par.indexOf(";", index);
- lst.add(par.substring(indexFrom<0?index:indexFrom, ind+1));
- index = ind;
- indexFrom = -1;
- break;
- default:
- lst.add(par.substring(indexFrom<0?index:indexFrom, index+1));
- indexFrom = -1;
- }
- }
-
- lst.add(pars[2]);
-
-
- md.params = new VarType[lst.size()-1];
-
- int i = 0;
- for(;i<lst.size()-1;i++) {
- md.params[i] = new VarType(lst.get(i));
- }
- md.ret = new VarType(lst.get(i));
-
- return md;
- }
-
- public String getDescriptor() {
- String res = "(";
-
- for(int j = 0;j<params.length;j++) {
- res+=params[j].toString();
- }
-
- res+=")"+ret.toString();
-
- return res;
- }
-
- @Override
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof MethodDescriptor)) return false;
+ public VarType[] params;
+
+ public VarType ret;
+
+
+ public static MethodDescriptor parseDescriptor(String mdescr) {
+
+ MethodDescriptor md = new MethodDescriptor();
+
+ List<String> lst = new ArrayList<String>();
+ String[] pars = mdescr.split("[()]");
+
+ String par = pars[1];
+
+ int indexFrom = -1, ind, index = 0;
+ int len = par.length();
+
+ for (; index < len; index++) {
+
+ switch (par.charAt(index)) {
+ case '[':
+ if (indexFrom < 0) {
+ indexFrom = index;
+ }
+ break;
+ case 'L':
+ ind = par.indexOf(";", index);
+ lst.add(par.substring(indexFrom < 0 ? index : indexFrom, ind + 1));
+ index = ind;
+ indexFrom = -1;
+ break;
+ default:
+ lst.add(par.substring(indexFrom < 0 ? index : indexFrom, index + 1));
+ indexFrom = -1;
+ }
+ }
+
+ lst.add(pars[2]);
+
+
+ md.params = new VarType[lst.size() - 1];
+
+ int i = 0;
+ for (; i < lst.size() - 1; i++) {
+ md.params[i] = new VarType(lst.get(i));
+ }
+ md.ret = new VarType(lst.get(i));
+
+ return md;
+ }
+
+ public String getDescriptor() {
+ String res = "(";
+
+ for (int j = 0; j < params.length; j++) {
+ res += params[j].toString();
+ }
+
+ res += ")" + ret.toString();
+
+ return res;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof MethodDescriptor)) return false;
MethodDescriptor md = (MethodDescriptor)o;
return ret.equals(md.ret) && Arrays.equals(params, md.params);
}
- @Override
- public int hashCode() {
+ @Override
+ public int hashCode() {
int result = ret.hashCode();
result = 31 * result + params.length;
return result;
- }
-
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java
index 5ee0c4b..79e2cbf 100644
--- a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java
+++ b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java
@@ -1,410 +1,422 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.gen;
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
public class VarType { // TODO: optimize switch
-
- public static final int FALSEBOOLEAN = 1;
-
- public static final VarType VARTYPE_UNKNOWN = new VarType(CodeConstants.TYPE_UNKNOWN);
- public static final VarType VARTYPE_INT = new VarType(CodeConstants.TYPE_INT);
- public static final VarType VARTYPE_FLOAT = new VarType(CodeConstants.TYPE_FLOAT);
- public static final VarType VARTYPE_LONG = new VarType(CodeConstants.TYPE_LONG);
- public static final VarType VARTYPE_DOUBLE = new VarType(CodeConstants.TYPE_DOUBLE);
- public static final VarType VARTYPE_BYTE = new VarType(CodeConstants.TYPE_BYTE);
- public static final VarType VARTYPE_CHAR = new VarType(CodeConstants.TYPE_CHAR);
- public static final VarType VARTYPE_SHORT = new VarType(CodeConstants.TYPE_SHORT);
- public static final VarType VARTYPE_BOOLEAN = new VarType(CodeConstants.TYPE_BOOLEAN);
- public static final VarType VARTYPE_BYTECHAR = new VarType(CodeConstants.TYPE_BYTECHAR);
- public static final VarType VARTYPE_SHORTCHAR = new VarType(CodeConstants.TYPE_SHORTCHAR);
-
- public static final VarType VARTYPE_NULL = new VarType(CodeConstants.TYPE_NULL,0,null);
- public static final VarType VARTYPE_GROUP2EMPTY = new VarType(CodeConstants.TYPE_GROUP2EMPTY);
- public static final VarType VARTYPE_STRING = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/String");
- public static final VarType VARTYPE_CLASS = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Class");
- public static final VarType VARTYPE_OBJECT = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Object");
- public static final VarType VARTYPE_VOID = new VarType(CodeConstants.TYPE_VOID);
-
- public int type;
-
- public int type_family;
-
- public int arraydim;
-
- public String value;
-
- public int stack_size;
-
- public int convinfo;
-
- public VarType(int type) {
- this.type = type;
- this.arraydim = 0;
-
- value = getChar(type);
- setStackSize(type);
- setFamily();
- }
-
- public VarType(int type, int arraydim) {
- this(type);
- this.arraydim = arraydim;
- setFamily();
- }
-
- public VarType(int type, int arraydim, String value) {
- this(type);
- this.arraydim = arraydim;
- this.value = value;
- setFamily();
- }
-
- public VarType(String strtype) {
- this(strtype, false);
- }
-
- public VarType(String strtype, boolean cltype) {
- parseTypeString(strtype, cltype);
- setStackSize(type);
- setFamily();
- }
-
- public void decArrayDim() {
- if(arraydim > 0) {
- arraydim--;
- setFamily();
- } else {
- // throw new RuntimeException("array dimension equals 0!"); FIXME: investigate this case
- }
- }
-
- public String toString() {
- String res = "";
-
- for(int i=0;i<arraydim;i++) {
- res+="[";
- }
-
- if(type == CodeConstants.TYPE_OBJECT) {
- res+="L"+value+";";
- } else {
- res+=value;
- }
-
- return res;
- }
-
- public VarType copy() {
- VarType v = new VarType(type, arraydim, value);
- v.convinfo = convinfo;
- return v;
- }
-
- public boolean isFalseBoolean() {
- return (convinfo & VarType.FALSEBOOLEAN) != 0;
- }
-
- public boolean isSuperset(VarType val) {
-
- return this.equals(val) || this.isStrictSuperset(val);
- }
-
- public boolean isStrictSuperset(VarType val) {
-
- int valtype = val.type;
-
- if(valtype == CodeConstants.TYPE_UNKNOWN && type != CodeConstants.TYPE_UNKNOWN) {
- return true;
- }
-
- if(val.arraydim > 0) {
- return this.equals(VARTYPE_OBJECT);
- } else if(arraydim > 0) {
- return (valtype == CodeConstants.TYPE_NULL);
- }
-
- boolean res = false;
-
- switch(type) {
- case CodeConstants.TYPE_INT:
- res |= (valtype == CodeConstants.TYPE_SHORT ||
- valtype == CodeConstants.TYPE_CHAR);
- case CodeConstants.TYPE_SHORT:
- res |= (valtype == CodeConstants.TYPE_BYTE);
- case CodeConstants.TYPE_CHAR:
- res |= (valtype == CodeConstants.TYPE_SHORTCHAR);
- case CodeConstants.TYPE_BYTE:
- case CodeConstants.TYPE_SHORTCHAR:
- res |= (valtype == CodeConstants.TYPE_BYTECHAR);
- case CodeConstants.TYPE_BYTECHAR:
- res |= (valtype == CodeConstants.TYPE_BOOLEAN);
- break;
- case CodeConstants.TYPE_OBJECT:
- if(valtype == CodeConstants.TYPE_NULL) {
- return true;
- } else if(this.equals(VARTYPE_OBJECT)) {
- return valtype == CodeConstants.TYPE_OBJECT &&
- !val.equals(VARTYPE_OBJECT);
- }
- }
-
- return res;
- }
-
- // type1 and type2 must not be null
- public static VarType getCommonMinType(VarType type1, VarType type2) {
-
- if(type1.type == CodeConstants.TYPE_BOOLEAN && type2.type == CodeConstants.TYPE_BOOLEAN) { // special case booleans
- return type1.isFalseBoolean() ? type2 : type1;
- }
-
- if(type1.isSuperset(type2)) {
- return type2;
- } else if(type2.isSuperset(type1)) {
- return type1;
- } else if(type1.type_family == type2.type_family) {
- switch(type1.type_family) {
- case CodeConstants.TYPE_FAMILY_INTEGER:
- if((type1.type == CodeConstants.TYPE_CHAR && type2.type == CodeConstants.TYPE_SHORT)
- || (type1.type == CodeConstants.TYPE_SHORT && type2.type == CodeConstants.TYPE_CHAR)) {
- return VarType.VARTYPE_SHORTCHAR;
- } else {
- return VarType.VARTYPE_BYTECHAR;
- }
- case CodeConstants.TYPE_FAMILY_OBJECT:
- return VarType.VARTYPE_NULL;
- }
- }
-
- return null;
- }
-
- // type1 and type2 must not be null
- public static VarType getCommonSupertype(VarType type1, VarType type2) {
-
- if(type1.type == CodeConstants.TYPE_BOOLEAN && type2.type == CodeConstants.TYPE_BOOLEAN) { // special case booleans
- return type1.isFalseBoolean() ? type1 : type2;
- }
-
- if(type1.isSuperset(type2)) {
- return type1;
- } else if(type2.isSuperset(type1)) {
- return type2;
- } else if(type1.type_family == type2.type_family) {
- switch(type1.type_family) {
- case CodeConstants.TYPE_FAMILY_INTEGER:
- if((type1.type == CodeConstants.TYPE_SHORTCHAR && type2.type == CodeConstants.TYPE_BYTE)
- || (type1.type == CodeConstants.TYPE_BYTE && type2.type == CodeConstants.TYPE_SHORTCHAR)) {
- return VarType.VARTYPE_SHORT;
- } else {
- return VarType.VARTYPE_INT;
- }
- case CodeConstants.TYPE_FAMILY_OBJECT:
- return VarType.VARTYPE_OBJECT;
- }
- }
-
- return null;
- }
-
- public static VarType getMinTypeInFamily(int family) {
- switch(family) {
- case CodeConstants.TYPE_FAMILY_BOOLEAN:
- return VarType.VARTYPE_BOOLEAN;
- case CodeConstants.TYPE_FAMILY_INTEGER:
- return VarType.VARTYPE_BYTECHAR;
- case CodeConstants.TYPE_FAMILY_OBJECT:
- return VarType.VARTYPE_NULL;
- case CodeConstants.TYPE_FAMILY_FLOAT:
- return VarType.VARTYPE_FLOAT;
- case CodeConstants.TYPE_FAMILY_LONG:
- return VarType.VARTYPE_LONG;
- case CodeConstants.TYPE_FAMILY_DOUBLE:
- return VarType.VARTYPE_DOUBLE;
- case CodeConstants.TYPE_FAMILY_UNKNOWN:
- return VarType.VARTYPE_UNKNOWN;
- default:
- throw new RuntimeException("invalid type family!");
- }
- }
-
- public boolean equals(Object o) {
-
- if(o == this) {
- return true;
- }
-
- if(o == null || !(o instanceof VarType)) {
- return false;
- }
-
- VarType vt = (VarType) o;
- return type == vt.type && arraydim == vt.arraydim && InterpreterUtil.equalObjects(value, vt.value);
- }
-
- private void parseTypeString(String strtype, boolean cltype) {
-
- for(int i=0;i<strtype.length();i++) {
- switch(strtype.charAt(i)){
- case '[':
- arraydim++;
- break;
- case 'L':
- if(strtype.charAt(strtype.length()-1) == ';') {
- type = CodeConstants.TYPE_OBJECT;
- value = strtype.substring(i+1, strtype.length()-1);
- return;
- }
- default:
- value = strtype.substring(i, strtype.length());
- if((cltype && i == 0) || value.length()>1) {
- type = CodeConstants.TYPE_OBJECT;
- } else {
- type = getType(value.charAt(0));
- }
- return;
- }
- }
- }
-
- private void setStackSize(int type) {
- if(arraydim > 0) {
- stack_size = 1;
- } else {
- stack_size = (type == CodeConstants.TYPE_DOUBLE ||
- type == CodeConstants.TYPE_LONG)?2:
- ((type == CodeConstants.TYPE_VOID ||
- type == CodeConstants.TYPE_GROUP2EMPTY)?0:1);
- }
- }
-
- private int getType(char c) {
- switch(c) {
- case 'B':
- return CodeConstants.TYPE_BYTE;
- case 'C':
- return CodeConstants.TYPE_CHAR;
- case 'D':
- return CodeConstants.TYPE_DOUBLE;
- case 'F':
- return CodeConstants.TYPE_FLOAT;
- case 'I':
- return CodeConstants.TYPE_INT;
- case 'J':
- return CodeConstants.TYPE_LONG;
- case 'S':
- return CodeConstants.TYPE_SHORT;
- case 'Z':
- return CodeConstants.TYPE_BOOLEAN;
- case 'V':
- return CodeConstants.TYPE_VOID;
- case 'G':
- return CodeConstants.TYPE_GROUP2EMPTY;
- case 'N':
- return CodeConstants.TYPE_NOTINITIALIZED;
- case 'A':
- return CodeConstants.TYPE_ADDRESS;
- case 'X':
- return CodeConstants.TYPE_BYTECHAR;
- case 'Y':
- return CodeConstants.TYPE_SHORTCHAR;
- case 'U':
- return CodeConstants.TYPE_UNKNOWN;
- default:
- throw new RuntimeException("Invalid type");
- }
- }
-
- private String getChar(int type) {
- switch(type) {
- case CodeConstants.TYPE_BYTE:
- return "B";
- case CodeConstants.TYPE_CHAR:
- return "C";
- case CodeConstants.TYPE_DOUBLE:
- return "D";
- case CodeConstants.TYPE_FLOAT:
- return "F";
- case CodeConstants.TYPE_INT:
- return "I";
- case CodeConstants.TYPE_LONG:
- return "J";
- case CodeConstants.TYPE_SHORT:
- return "S";
- case CodeConstants.TYPE_BOOLEAN:
- return "Z";
- case CodeConstants.TYPE_VOID:
- return "V";
- case CodeConstants.TYPE_GROUP2EMPTY:
- return "G";
- case CodeConstants.TYPE_NOTINITIALIZED:
- return "N";
- case CodeConstants.TYPE_ADDRESS:
- return "A";
- case CodeConstants.TYPE_BYTECHAR:
- return "X";
- case CodeConstants.TYPE_SHORTCHAR:
- return "Y";
- case CodeConstants.TYPE_UNKNOWN:
- return "U";
- case CodeConstants.TYPE_NULL:
- case CodeConstants.TYPE_OBJECT:
- return null;
- default:
- throw new RuntimeException("Invalid type");
- }
- }
-
- public void setFamily() {
-
- if(arraydim > 0) {
- this.type_family = CodeConstants.TYPE_FAMILY_OBJECT;
- return;
- }
-
- switch(type) {
- case CodeConstants.TYPE_BYTE:
- case CodeConstants.TYPE_BYTECHAR:
- case CodeConstants.TYPE_SHORTCHAR:
- case CodeConstants.TYPE_CHAR:
- case CodeConstants.TYPE_SHORT:
- case CodeConstants.TYPE_INT:
- this.type_family = CodeConstants.TYPE_FAMILY_INTEGER;
- break;
- case CodeConstants.TYPE_DOUBLE:
- this.type_family = CodeConstants.TYPE_FAMILY_DOUBLE;
- break;
- case CodeConstants.TYPE_FLOAT:
- this.type_family = CodeConstants.TYPE_FAMILY_FLOAT;
- break;
- case CodeConstants.TYPE_LONG:
- this.type_family = CodeConstants.TYPE_FAMILY_LONG;
- break;
- case CodeConstants.TYPE_BOOLEAN:
- this.type_family = CodeConstants.TYPE_FAMILY_BOOLEAN;
- break;
- case CodeConstants.TYPE_NULL:
- case CodeConstants.TYPE_OBJECT:
- this.type_family = CodeConstants.TYPE_FAMILY_OBJECT;
- break;
- default:
- this.type_family = CodeConstants.TYPE_FAMILY_UNKNOWN;
- }
- }
-
+
+ public static final int FALSEBOOLEAN = 1;
+
+ public static final VarType VARTYPE_UNKNOWN = new VarType(CodeConstants.TYPE_UNKNOWN);
+ public static final VarType VARTYPE_INT = new VarType(CodeConstants.TYPE_INT);
+ public static final VarType VARTYPE_FLOAT = new VarType(CodeConstants.TYPE_FLOAT);
+ public static final VarType VARTYPE_LONG = new VarType(CodeConstants.TYPE_LONG);
+ public static final VarType VARTYPE_DOUBLE = new VarType(CodeConstants.TYPE_DOUBLE);
+ public static final VarType VARTYPE_BYTE = new VarType(CodeConstants.TYPE_BYTE);
+ public static final VarType VARTYPE_CHAR = new VarType(CodeConstants.TYPE_CHAR);
+ public static final VarType VARTYPE_SHORT = new VarType(CodeConstants.TYPE_SHORT);
+ public static final VarType VARTYPE_BOOLEAN = new VarType(CodeConstants.TYPE_BOOLEAN);
+ public static final VarType VARTYPE_BYTECHAR = new VarType(CodeConstants.TYPE_BYTECHAR);
+ public static final VarType VARTYPE_SHORTCHAR = new VarType(CodeConstants.TYPE_SHORTCHAR);
+
+ public static final VarType VARTYPE_NULL = new VarType(CodeConstants.TYPE_NULL, 0, null);
+ public static final VarType VARTYPE_GROUP2EMPTY = new VarType(CodeConstants.TYPE_GROUP2EMPTY);
+ public static final VarType VARTYPE_STRING = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/String");
+ public static final VarType VARTYPE_CLASS = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Class");
+ public static final VarType VARTYPE_OBJECT = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Object");
+ public static final VarType VARTYPE_VOID = new VarType(CodeConstants.TYPE_VOID);
+
+ public int type;
+
+ public int type_family;
+
+ public int arraydim;
+
+ public String value;
+
+ public int stack_size;
+
+ public int convinfo;
+
+ public VarType(int type) {
+ this.type = type;
+ this.arraydim = 0;
+
+ value = getChar(type);
+ setStackSize(type);
+ setFamily();
+ }
+
+ public VarType(int type, int arraydim) {
+ this(type);
+ this.arraydim = arraydim;
+ setFamily();
+ }
+
+ public VarType(int type, int arraydim, String value) {
+ this(type);
+ this.arraydim = arraydim;
+ this.value = value;
+ setFamily();
+ }
+
+ public VarType(String strtype) {
+ this(strtype, false);
+ }
+
+ public VarType(String strtype, boolean cltype) {
+ parseTypeString(strtype, cltype);
+ setStackSize(type);
+ setFamily();
+ }
+
+ public void decArrayDim() {
+ if (arraydim > 0) {
+ arraydim--;
+ setFamily();
+ }
+ else {
+ // throw new RuntimeException("array dimension equals 0!"); FIXME: investigate this case
+ }
+ }
+
+ public String toString() {
+ String res = "";
+
+ for (int i = 0; i < arraydim; i++) {
+ res += "[";
+ }
+
+ if (type == CodeConstants.TYPE_OBJECT) {
+ res += "L" + value + ";";
+ }
+ else {
+ res += value;
+ }
+
+ return res;
+ }
+
+ public VarType copy() {
+ VarType v = new VarType(type, arraydim, value);
+ v.convinfo = convinfo;
+ return v;
+ }
+
+ public boolean isFalseBoolean() {
+ return (convinfo & VarType.FALSEBOOLEAN) != 0;
+ }
+
+ public boolean isSuperset(VarType val) {
+
+ return this.equals(val) || this.isStrictSuperset(val);
+ }
+
+ public boolean isStrictSuperset(VarType val) {
+
+ int valtype = val.type;
+
+ if (valtype == CodeConstants.TYPE_UNKNOWN && type != CodeConstants.TYPE_UNKNOWN) {
+ return true;
+ }
+
+ if (val.arraydim > 0) {
+ return this.equals(VARTYPE_OBJECT);
+ }
+ else if (arraydim > 0) {
+ return (valtype == CodeConstants.TYPE_NULL);
+ }
+
+ boolean res = false;
+
+ switch (type) {
+ case CodeConstants.TYPE_INT:
+ res |= (valtype == CodeConstants.TYPE_SHORT ||
+ valtype == CodeConstants.TYPE_CHAR);
+ case CodeConstants.TYPE_SHORT:
+ res |= (valtype == CodeConstants.TYPE_BYTE);
+ case CodeConstants.TYPE_CHAR:
+ res |= (valtype == CodeConstants.TYPE_SHORTCHAR);
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_SHORTCHAR:
+ res |= (valtype == CodeConstants.TYPE_BYTECHAR);
+ case CodeConstants.TYPE_BYTECHAR:
+ res |= (valtype == CodeConstants.TYPE_BOOLEAN);
+ break;
+ case CodeConstants.TYPE_OBJECT:
+ if (valtype == CodeConstants.TYPE_NULL) {
+ return true;
+ }
+ else if (this.equals(VARTYPE_OBJECT)) {
+ return valtype == CodeConstants.TYPE_OBJECT &&
+ !val.equals(VARTYPE_OBJECT);
+ }
+ }
+
+ return res;
+ }
+
+ // type1 and type2 must not be null
+ public static VarType getCommonMinType(VarType type1, VarType type2) {
+
+ if (type1.type == CodeConstants.TYPE_BOOLEAN && type2.type == CodeConstants.TYPE_BOOLEAN) { // special case booleans
+ return type1.isFalseBoolean() ? type2 : type1;
+ }
+
+ if (type1.isSuperset(type2)) {
+ return type2;
+ }
+ else if (type2.isSuperset(type1)) {
+ return type1;
+ }
+ else if (type1.type_family == type2.type_family) {
+ switch (type1.type_family) {
+ case CodeConstants.TYPE_FAMILY_INTEGER:
+ if ((type1.type == CodeConstants.TYPE_CHAR && type2.type == CodeConstants.TYPE_SHORT)
+ || (type1.type == CodeConstants.TYPE_SHORT && type2.type == CodeConstants.TYPE_CHAR)) {
+ return VarType.VARTYPE_SHORTCHAR;
+ }
+ else {
+ return VarType.VARTYPE_BYTECHAR;
+ }
+ case CodeConstants.TYPE_FAMILY_OBJECT:
+ return VarType.VARTYPE_NULL;
+ }
+ }
+
+ return null;
+ }
+
+ // type1 and type2 must not be null
+ public static VarType getCommonSupertype(VarType type1, VarType type2) {
+
+ if (type1.type == CodeConstants.TYPE_BOOLEAN && type2.type == CodeConstants.TYPE_BOOLEAN) { // special case booleans
+ return type1.isFalseBoolean() ? type1 : type2;
+ }
+
+ if (type1.isSuperset(type2)) {
+ return type1;
+ }
+ else if (type2.isSuperset(type1)) {
+ return type2;
+ }
+ else if (type1.type_family == type2.type_family) {
+ switch (type1.type_family) {
+ case CodeConstants.TYPE_FAMILY_INTEGER:
+ if ((type1.type == CodeConstants.TYPE_SHORTCHAR && type2.type == CodeConstants.TYPE_BYTE)
+ || (type1.type == CodeConstants.TYPE_BYTE && type2.type == CodeConstants.TYPE_SHORTCHAR)) {
+ return VarType.VARTYPE_SHORT;
+ }
+ else {
+ return VarType.VARTYPE_INT;
+ }
+ case CodeConstants.TYPE_FAMILY_OBJECT:
+ return VarType.VARTYPE_OBJECT;
+ }
+ }
+
+ return null;
+ }
+
+ public static VarType getMinTypeInFamily(int family) {
+ switch (family) {
+ case CodeConstants.TYPE_FAMILY_BOOLEAN:
+ return VarType.VARTYPE_BOOLEAN;
+ case CodeConstants.TYPE_FAMILY_INTEGER:
+ return VarType.VARTYPE_BYTECHAR;
+ case CodeConstants.TYPE_FAMILY_OBJECT:
+ return VarType.VARTYPE_NULL;
+ case CodeConstants.TYPE_FAMILY_FLOAT:
+ return VarType.VARTYPE_FLOAT;
+ case CodeConstants.TYPE_FAMILY_LONG:
+ return VarType.VARTYPE_LONG;
+ case CodeConstants.TYPE_FAMILY_DOUBLE:
+ return VarType.VARTYPE_DOUBLE;
+ case CodeConstants.TYPE_FAMILY_UNKNOWN:
+ return VarType.VARTYPE_UNKNOWN;
+ default:
+ throw new RuntimeException("invalid type family!");
+ }
+ }
+
+ public boolean equals(Object o) {
+
+ if (o == this) {
+ return true;
+ }
+
+ if (o == null || !(o instanceof VarType)) {
+ return false;
+ }
+
+ VarType vt = (VarType)o;
+ return type == vt.type && arraydim == vt.arraydim && InterpreterUtil.equalObjects(value, vt.value);
+ }
+
+ private void parseTypeString(String strtype, boolean cltype) {
+
+ for (int i = 0; i < strtype.length(); i++) {
+ switch (strtype.charAt(i)) {
+ case '[':
+ arraydim++;
+ break;
+ case 'L':
+ if (strtype.charAt(strtype.length() - 1) == ';') {
+ type = CodeConstants.TYPE_OBJECT;
+ value = strtype.substring(i + 1, strtype.length() - 1);
+ return;
+ }
+ default:
+ value = strtype.substring(i, strtype.length());
+ if ((cltype && i == 0) || value.length() > 1) {
+ type = CodeConstants.TYPE_OBJECT;
+ }
+ else {
+ type = getType(value.charAt(0));
+ }
+ return;
+ }
+ }
+ }
+
+ private void setStackSize(int type) {
+ if (arraydim > 0) {
+ stack_size = 1;
+ }
+ else {
+ stack_size = (type == CodeConstants.TYPE_DOUBLE ||
+ type == CodeConstants.TYPE_LONG) ? 2 :
+ ((type == CodeConstants.TYPE_VOID ||
+ type == CodeConstants.TYPE_GROUP2EMPTY) ? 0 : 1);
+ }
+ }
+
+ private int getType(char c) {
+ switch (c) {
+ case 'B':
+ return CodeConstants.TYPE_BYTE;
+ case 'C':
+ return CodeConstants.TYPE_CHAR;
+ case 'D':
+ return CodeConstants.TYPE_DOUBLE;
+ case 'F':
+ return CodeConstants.TYPE_FLOAT;
+ case 'I':
+ return CodeConstants.TYPE_INT;
+ case 'J':
+ return CodeConstants.TYPE_LONG;
+ case 'S':
+ return CodeConstants.TYPE_SHORT;
+ case 'Z':
+ return CodeConstants.TYPE_BOOLEAN;
+ case 'V':
+ return CodeConstants.TYPE_VOID;
+ case 'G':
+ return CodeConstants.TYPE_GROUP2EMPTY;
+ case 'N':
+ return CodeConstants.TYPE_NOTINITIALIZED;
+ case 'A':
+ return CodeConstants.TYPE_ADDRESS;
+ case 'X':
+ return CodeConstants.TYPE_BYTECHAR;
+ case 'Y':
+ return CodeConstants.TYPE_SHORTCHAR;
+ case 'U':
+ return CodeConstants.TYPE_UNKNOWN;
+ default:
+ throw new RuntimeException("Invalid type");
+ }
+ }
+
+ private String getChar(int type) {
+ switch (type) {
+ case CodeConstants.TYPE_BYTE:
+ return "B";
+ case CodeConstants.TYPE_CHAR:
+ return "C";
+ case CodeConstants.TYPE_DOUBLE:
+ return "D";
+ case CodeConstants.TYPE_FLOAT:
+ return "F";
+ case CodeConstants.TYPE_INT:
+ return "I";
+ case CodeConstants.TYPE_LONG:
+ return "J";
+ case CodeConstants.TYPE_SHORT:
+ return "S";
+ case CodeConstants.TYPE_BOOLEAN:
+ return "Z";
+ case CodeConstants.TYPE_VOID:
+ return "V";
+ case CodeConstants.TYPE_GROUP2EMPTY:
+ return "G";
+ case CodeConstants.TYPE_NOTINITIALIZED:
+ return "N";
+ case CodeConstants.TYPE_ADDRESS:
+ return "A";
+ case CodeConstants.TYPE_BYTECHAR:
+ return "X";
+ case CodeConstants.TYPE_SHORTCHAR:
+ return "Y";
+ case CodeConstants.TYPE_UNKNOWN:
+ return "U";
+ case CodeConstants.TYPE_NULL:
+ case CodeConstants.TYPE_OBJECT:
+ return null;
+ default:
+ throw new RuntimeException("Invalid type");
+ }
+ }
+
+ public void setFamily() {
+
+ if (arraydim > 0) {
+ this.type_family = CodeConstants.TYPE_FAMILY_OBJECT;
+ return;
+ }
+
+ switch (type) {
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_BYTECHAR:
+ case CodeConstants.TYPE_SHORTCHAR:
+ case CodeConstants.TYPE_CHAR:
+ case CodeConstants.TYPE_SHORT:
+ case CodeConstants.TYPE_INT:
+ this.type_family = CodeConstants.TYPE_FAMILY_INTEGER;
+ break;
+ case CodeConstants.TYPE_DOUBLE:
+ this.type_family = CodeConstants.TYPE_FAMILY_DOUBLE;
+ break;
+ case CodeConstants.TYPE_FLOAT:
+ this.type_family = CodeConstants.TYPE_FAMILY_FLOAT;
+ break;
+ case CodeConstants.TYPE_LONG:
+ this.type_family = CodeConstants.TYPE_FAMILY_LONG;
+ break;
+ case CodeConstants.TYPE_BOOLEAN:
+ this.type_family = CodeConstants.TYPE_FAMILY_BOOLEAN;
+ break;
+ case CodeConstants.TYPE_NULL:
+ case CodeConstants.TYPE_OBJECT:
+ this.type_family = CodeConstants.TYPE_FAMILY_OBJECT;
+ break;
+ default:
+ this.type_family = CodeConstants.TYPE_FAMILY_UNKNOWN;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java
index d4551ac..66fab96 100644
--- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java
+++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.gen.generics;
import java.util.ArrayList;
@@ -19,12 +20,11 @@ import java.util.List;
public class GenericClassDescriptor {
- public GenericType superclass;
-
- public List<GenericType> superinterfaces = new ArrayList<GenericType>();
-
- public List<String> fparameters = new ArrayList<String>();
+ public GenericType superclass;
+
+ public List<GenericType> superinterfaces = new ArrayList<GenericType>();
+
+ public List<String> fparameters = new ArrayList<String>();
- public List<List<GenericType>> fbounds = new ArrayList<List<GenericType>>();
-
+ public List<List<GenericType>> fbounds = new ArrayList<List<GenericType>>();
}
diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java
index 4b4114d..598d17b 100644
--- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java
+++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java
@@ -1,21 +1,21 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.gen.generics;
public class GenericFieldDescriptor {
- public GenericType type;
-
+ public GenericType type;
}
diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java
index 50433a9..db7d84b 100644
--- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java
+++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java
@@ -1,229 +1,233 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.gen.generics;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.struct.StructClass;
+import java.util.ArrayList;
+import java.util.List;
+
public class GenericMain {
-
- private static final String[] typeNames = new String[] {
- "byte",
- "char",
- "double",
- "float",
- "int",
- "long",
- "short",
- "boolean",
- };
-
- public static GenericClassDescriptor parseClassSignature(String signature) {
-
- GenericClassDescriptor descriptor = new GenericClassDescriptor();
-
- signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds);
-
- String supercl = GenericType.getNextType(signature);
- descriptor.superclass = new GenericType(supercl);
-
- signature = signature.substring(supercl.length());
- while(signature.length() > 0) {
- String superintr = GenericType.getNextType(signature);
- descriptor.superinterfaces.add(new GenericType(superintr));
- signature = signature.substring(superintr.length());
- }
-
- return descriptor;
- }
-
- public static GenericFieldDescriptor parseFieldSignature(String signature) {
- GenericFieldDescriptor descriptor = new GenericFieldDescriptor();
- descriptor.type = new GenericType(signature);
- return descriptor;
- }
-
- public static GenericMethodDescriptor parseMethodSignature(String signature) {
-
- GenericMethodDescriptor descriptor = new GenericMethodDescriptor();
-
- signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds);
-
- int to = signature.indexOf(")");
- String pars = signature.substring(1, to);
- signature = signature.substring(to+1);
-
- while(pars.length() > 0) {
- String par = GenericType.getNextType(pars);
- descriptor.params.add(new GenericType(par));
- pars = pars.substring(par.length());
- }
-
- String par = GenericType.getNextType(signature);
- descriptor.ret = new GenericType(par);
- signature = signature.substring(par.length());
-
- if(signature.length() > 0) {
- String[] excs = signature.split("\\^");
-
- for(int i=1;i<excs.length;i++) {
- descriptor.exceptions.add(new GenericType(excs[i]));
- }
- }
-
- return descriptor;
- }
-
- private static String parseFormalParameters(String signature, List<String> fparameters, List<List<GenericType>> fbounds) {
-
- if(signature.charAt(0) != '<') {
- return signature;
- }
-
- int counter = 1;
- int index = 1;
-
- loop:
- while(index < signature.length()) {
- switch(signature.charAt(index)) {
- case '<':
- counter++;
- break;
- case '>':
- counter--;
- if(counter == 0) {
- break loop;
- }
- }
-
- index++;
- }
-
- String value = signature.substring(1, index);
- signature = signature.substring(index+1);
-
- while(value.length() > 0) {
- int parto = value.indexOf(":");
-
- String param = value.substring(0, parto);
- value = value.substring(parto+1);
-
- List<GenericType> lstBounds = new ArrayList<GenericType>();
-
- for(;;) {
- if(value.charAt(0) == ':') {
- // empty superclass, skip
- value = value.substring(1);
- }
-
- String bound = GenericType.getNextType(value);
- lstBounds.add(new GenericType(bound));
- value = value.substring(bound.length());
-
-
- if(value.length() == 0 || value.charAt(0) != ':') {
- break;
- } else {
- value = value.substring(1);
- }
- }
-
- fparameters.add(param);
- fbounds.add(lstBounds);
- }
-
- return signature;
- }
-
- public static String getGenericCastTypeName(GenericType type) {
- String s = getTypeName(type);
- int dim = type.arraydim;
- while(dim-->0) {
- s+="[]";
- }
- return s;
- }
-
- public static String getTypeName(GenericType type) {
-
- int tp = type.type;
- if(tp <= CodeConstants.TYPE_BOOLEAN) {
- return typeNames[tp];
- } else if(tp == CodeConstants.TYPE_VOID) {
- return "void";
- } else if(tp == CodeConstants.TYPE_GENVAR) {
- return type.value;
- } else if(tp == CodeConstants.TYPE_OBJECT) {
- StringBuilder buffer = new StringBuilder();
- buffer.append(DecompilerContext.getImpcollector().getShortName(buildJavaClassName(type)));
-
- if(!type.getArguments().isEmpty()) {
- buffer.append("<");
- for(int i=0;i<type.getArguments().size();i++) {
- if(i>0) {
- buffer.append(", ");
- }
- int wildcard = type.getWildcards().get(i);
- if(wildcard != GenericType.WILDCARD_NO) {
- buffer.append("?");
-
- switch(wildcard){
- case GenericType.WILDCARD_EXTENDS:
- buffer.append(" extends ");
- break;
- case GenericType.WILDCARD_SUPER:
- buffer.append(" super ");
- }
- }
-
- GenericType genpar = type.getArguments().get(i);
- if(genpar != null) {
- buffer.append(GenericMain.getGenericCastTypeName(genpar));
- }
- }
- buffer.append(">");
- }
-
- return buffer.toString();
- }
-
- throw new RuntimeException("invalid type");
- }
-
- public static String buildJavaClassName(GenericType type) {
-
- String name = "";
- for(GenericType tp : type.getEnclosingClasses()) {
- name += tp.value+"$";
- }
- name+=type.value;
-
- String res = name.replace('/', '.');
-
- if(res.indexOf("$") >=0) {
- StructClass cl = DecompilerContext.getStructcontext().getClass(name);
- if(cl == null || !cl.isOwn()) {
- res = res.replace('$', '.');
- }
- }
-
- return res;
- }
-
+
+ private static final String[] typeNames = new String[]{
+ "byte",
+ "char",
+ "double",
+ "float",
+ "int",
+ "long",
+ "short",
+ "boolean",
+ };
+
+ public static GenericClassDescriptor parseClassSignature(String signature) {
+
+ GenericClassDescriptor descriptor = new GenericClassDescriptor();
+
+ signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds);
+
+ String supercl = GenericType.getNextType(signature);
+ descriptor.superclass = new GenericType(supercl);
+
+ signature = signature.substring(supercl.length());
+ while (signature.length() > 0) {
+ String superintr = GenericType.getNextType(signature);
+ descriptor.superinterfaces.add(new GenericType(superintr));
+ signature = signature.substring(superintr.length());
+ }
+
+ return descriptor;
+ }
+
+ public static GenericFieldDescriptor parseFieldSignature(String signature) {
+ GenericFieldDescriptor descriptor = new GenericFieldDescriptor();
+ descriptor.type = new GenericType(signature);
+ return descriptor;
+ }
+
+ public static GenericMethodDescriptor parseMethodSignature(String signature) {
+
+ GenericMethodDescriptor descriptor = new GenericMethodDescriptor();
+
+ signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds);
+
+ int to = signature.indexOf(")");
+ String pars = signature.substring(1, to);
+ signature = signature.substring(to + 1);
+
+ while (pars.length() > 0) {
+ String par = GenericType.getNextType(pars);
+ descriptor.params.add(new GenericType(par));
+ pars = pars.substring(par.length());
+ }
+
+ String par = GenericType.getNextType(signature);
+ descriptor.ret = new GenericType(par);
+ signature = signature.substring(par.length());
+
+ if (signature.length() > 0) {
+ String[] excs = signature.split("\\^");
+
+ for (int i = 1; i < excs.length; i++) {
+ descriptor.exceptions.add(new GenericType(excs[i]));
+ }
+ }
+
+ return descriptor;
+ }
+
+ private static String parseFormalParameters(String signature, List<String> fparameters, List<List<GenericType>> fbounds) {
+
+ if (signature.charAt(0) != '<') {
+ return signature;
+ }
+
+ int counter = 1;
+ int index = 1;
+
+ loop:
+ while (index < signature.length()) {
+ switch (signature.charAt(index)) {
+ case '<':
+ counter++;
+ break;
+ case '>':
+ counter--;
+ if (counter == 0) {
+ break loop;
+ }
+ }
+
+ index++;
+ }
+
+ String value = signature.substring(1, index);
+ signature = signature.substring(index + 1);
+
+ while (value.length() > 0) {
+ int parto = value.indexOf(":");
+
+ String param = value.substring(0, parto);
+ value = value.substring(parto + 1);
+
+ List<GenericType> lstBounds = new ArrayList<GenericType>();
+
+ for (; ; ) {
+ if (value.charAt(0) == ':') {
+ // empty superclass, skip
+ value = value.substring(1);
+ }
+
+ String bound = GenericType.getNextType(value);
+ lstBounds.add(new GenericType(bound));
+ value = value.substring(bound.length());
+
+
+ if (value.length() == 0 || value.charAt(0) != ':') {
+ break;
+ }
+ else {
+ value = value.substring(1);
+ }
+ }
+
+ fparameters.add(param);
+ fbounds.add(lstBounds);
+ }
+
+ return signature;
+ }
+
+ public static String getGenericCastTypeName(GenericType type) {
+ String s = getTypeName(type);
+ int dim = type.arraydim;
+ while (dim-- > 0) {
+ s += "[]";
+ }
+ return s;
+ }
+
+ public static String getTypeName(GenericType type) {
+
+ int tp = type.type;
+ if (tp <= CodeConstants.TYPE_BOOLEAN) {
+ return typeNames[tp];
+ }
+ else if (tp == CodeConstants.TYPE_VOID) {
+ return "void";
+ }
+ else if (tp == CodeConstants.TYPE_GENVAR) {
+ return type.value;
+ }
+ else if (tp == CodeConstants.TYPE_OBJECT) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(DecompilerContext.getImpcollector().getShortName(buildJavaClassName(type)));
+
+ if (!type.getArguments().isEmpty()) {
+ buffer.append("<");
+ for (int i = 0; i < type.getArguments().size(); i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ int wildcard = type.getWildcards().get(i);
+ if (wildcard != GenericType.WILDCARD_NO) {
+ buffer.append("?");
+
+ switch (wildcard) {
+ case GenericType.WILDCARD_EXTENDS:
+ buffer.append(" extends ");
+ break;
+ case GenericType.WILDCARD_SUPER:
+ buffer.append(" super ");
+ }
+ }
+
+ GenericType genpar = type.getArguments().get(i);
+ if (genpar != null) {
+ buffer.append(GenericMain.getGenericCastTypeName(genpar));
+ }
+ }
+ buffer.append(">");
+ }
+
+ return buffer.toString();
+ }
+
+ throw new RuntimeException("invalid type");
+ }
+
+ public static String buildJavaClassName(GenericType type) {
+
+ String name = "";
+ for (GenericType tp : type.getEnclosingClasses()) {
+ name += tp.value + "$";
+ }
+ name += type.value;
+
+ String res = name.replace('/', '.');
+
+ if (res.indexOf("$") >= 0) {
+ StructClass cl = DecompilerContext.getStructcontext().getClass(name);
+ if (cl == null || !cl.isOwn()) {
+ res = res.replace('$', '.');
+ }
+ }
+
+ return res;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java
index 7a0a4d1..7b4c9dc 100644
--- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java
+++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.gen.generics;
import java.util.ArrayList;
@@ -19,14 +20,13 @@ import java.util.List;
public class GenericMethodDescriptor {
- public List<String> fparameters = new ArrayList<String>();
+ public List<String> fparameters = new ArrayList<String>();
+
+ public List<List<GenericType>> fbounds = new ArrayList<List<GenericType>>();
+
+ public List<GenericType> params = new ArrayList<GenericType>();
- public List<List<GenericType>> fbounds = new ArrayList<List<GenericType>>();
+ public GenericType ret;
- public List<GenericType> params = new ArrayList<GenericType>();
-
- public GenericType ret;
-
- public List<GenericType> exceptions = new ArrayList<GenericType>();
-
+ public List<GenericType> exceptions = new ArrayList<GenericType>();
}
diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java
index 1f720e6..e2faa4a 100644
--- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java
+++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java
@@ -1,270 +1,268 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.gen.generics;
+import org.jetbrains.java.decompiler.code.CodeConstants;
+
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.java.decompiler.code.CodeConstants;
-
public class GenericType {
-
- public static final int WILDCARD_EXTENDS = 1;
- public static final int WILDCARD_SUPER = 2;
- public static final int WILDCARD_UNBOUND = 3;
- public static final int WILDCARD_NO = 4;
-
- public int type;
-
- public int arraydim;
-
- public String value;
-
-
- private List<GenericType> enclosingClasses = new ArrayList<GenericType>();
-
- private List<GenericType> arguments = new ArrayList<GenericType>();
-
- private List<Integer> wildcards = new ArrayList<Integer>();
-
-
- public GenericType(int type, int arraydim, String value) {
- this.type = type;
- this.arraydim = arraydim;
- this.value = value;
- }
-
-
- public GenericType(String strtype) {
-
- parseSignature(strtype);
-
- }
-
- private void parseSignature(String sig) {
-
- int index = 0;
- while(index < sig.length()) {
-
- switch(sig.charAt(index)){
- case '[':
- arraydim++;
- break;
- case 'T':
- type = CodeConstants.TYPE_GENVAR;
- value = sig.substring(index+1, sig.length()-1);
- return;
- case 'L':
- type = CodeConstants.TYPE_OBJECT;
- sig = sig.substring(index+1, sig.length()-1);
-
- for(;;) {
- String cl = getNextClassSignature(sig);
-
- String name = cl;
- String args = null;
-
- int argfrom = cl.indexOf("<");
- if(argfrom >= 0) {
- name = cl.substring(0, argfrom);
- args = cl.substring(argfrom+1, cl.length()-1);
- }
-
- if(cl.length() < sig.length()) {
- sig = sig.substring(cl.length()+1); // skip '.'
- GenericType type = new GenericType(CodeConstants.TYPE_OBJECT, 0, name);
- parseArgumentsList(args, type);
- enclosingClasses.add(type);
- } else {
- value = name;
- parseArgumentsList(args, this);
- break;
- }
- }
-
- return;
- default:
- value = sig.substring(index, index+1);
- type = getType(value.charAt(0));
- }
-
- index++;
- }
-
- }
-
- private String getNextClassSignature(String value) {
-
- int counter = 0;
- int index = 0;
-
- loop:
- while(index < value.length()) {
- switch(value.charAt(index)) {
- case '<':
- counter++;
- break;
- case '>':
- counter--;
- break;
- case '.':
- if(counter == 0) {
- break loop;
- }
- }
-
- index++;
- }
-
- return value.substring(0, index);
- }
-
- private void parseArgumentsList(String value, GenericType type) {
-
- if(value == null) {
- return;
- }
-
- while(value.length() > 0) {
-
- String tstr = getNextType(value);
- int len = tstr.length();
- int wildcard = WILDCARD_NO;
-
- switch(tstr.charAt(0)) {
- case '*':
- wildcard = WILDCARD_UNBOUND;
- break;
- case '+':
- wildcard = WILDCARD_EXTENDS;
- break;
- case '-':
- wildcard = WILDCARD_SUPER;
- break;
- }
-
- type.getWildcards().add(wildcard);
-
- if(wildcard != WILDCARD_NO) {
- tstr = tstr.substring(1);
- }
-
- type.getArguments().add(tstr.length() == 0?null:new GenericType(tstr));
-
- value = value.substring(len);
- }
-
- }
-
- public static String getNextType(String value) {
-
- int counter = 0;
- int index = 0;
-
- boolean contmode = false;
-
- loop:
- while(index < value.length()) {
- switch(value.charAt(index)) {
- case '*':
- if(!contmode) {
- break loop;
- }
- break;
- case 'L':
- case 'T':
- if(!contmode) {
- contmode = true;
- }
- case '[':
- case '+':
- case '-':
- break;
- default:
- if(!contmode) {
- break loop;
- }
- break;
- case '<':
- counter++;
- break;
- case '>':
- counter--;
- break;
- case ';':
- if(counter == 0) {
- break loop;
- }
- }
-
- index++;
- }
-
- return value.substring(0, index+1);
- }
-
- private int getType(char c) {
- switch(c) {
- case 'B':
- return CodeConstants.TYPE_BYTE;
- case 'C':
- return CodeConstants.TYPE_CHAR;
- case 'D':
- return CodeConstants.TYPE_DOUBLE;
- case 'F':
- return CodeConstants.TYPE_FLOAT;
- case 'I':
- return CodeConstants.TYPE_INT;
- case 'J':
- return CodeConstants.TYPE_LONG;
- case 'S':
- return CodeConstants.TYPE_SHORT;
- case 'Z':
- return CodeConstants.TYPE_BOOLEAN;
- case 'V':
- return CodeConstants.TYPE_VOID;
- case 'G':
- return CodeConstants.TYPE_GROUP2EMPTY;
- case 'N':
- return CodeConstants.TYPE_NOTINITIALIZED;
- case 'A':
- return CodeConstants.TYPE_ADDRESS;
- case 'X':
- return CodeConstants.TYPE_BYTECHAR;
- case 'Y':
- return CodeConstants.TYPE_SHORTCHAR;
- case 'U':
- return CodeConstants.TYPE_UNKNOWN;
- default:
- throw new RuntimeException("Invalid type");
- }
- }
-
-
- public List<GenericType> getArguments() {
- return arguments;
- }
-
-
- public List<GenericType> getEnclosingClasses() {
- return enclosingClasses;
- }
-
-
- public List<Integer> getWildcards() {
- return wildcards;
- }
-
+
+ public static final int WILDCARD_EXTENDS = 1;
+ public static final int WILDCARD_SUPER = 2;
+ public static final int WILDCARD_UNBOUND = 3;
+ public static final int WILDCARD_NO = 4;
+
+ public int type;
+
+ public int arraydim;
+
+ public String value;
+
+
+ private List<GenericType> enclosingClasses = new ArrayList<GenericType>();
+
+ private List<GenericType> arguments = new ArrayList<GenericType>();
+
+ private List<Integer> wildcards = new ArrayList<Integer>();
+
+
+ public GenericType(int type, int arraydim, String value) {
+ this.type = type;
+ this.arraydim = arraydim;
+ this.value = value;
+ }
+
+
+ public GenericType(String strtype) {
+
+ parseSignature(strtype);
+ }
+
+ private void parseSignature(String sig) {
+
+ int index = 0;
+ while (index < sig.length()) {
+
+ switch (sig.charAt(index)) {
+ case '[':
+ arraydim++;
+ break;
+ case 'T':
+ type = CodeConstants.TYPE_GENVAR;
+ value = sig.substring(index + 1, sig.length() - 1);
+ return;
+ case 'L':
+ type = CodeConstants.TYPE_OBJECT;
+ sig = sig.substring(index + 1, sig.length() - 1);
+
+ for (; ; ) {
+ String cl = getNextClassSignature(sig);
+
+ String name = cl;
+ String args = null;
+
+ int argfrom = cl.indexOf("<");
+ if (argfrom >= 0) {
+ name = cl.substring(0, argfrom);
+ args = cl.substring(argfrom + 1, cl.length() - 1);
+ }
+
+ if (cl.length() < sig.length()) {
+ sig = sig.substring(cl.length() + 1); // skip '.'
+ GenericType type = new GenericType(CodeConstants.TYPE_OBJECT, 0, name);
+ parseArgumentsList(args, type);
+ enclosingClasses.add(type);
+ }
+ else {
+ value = name;
+ parseArgumentsList(args, this);
+ break;
+ }
+ }
+
+ return;
+ default:
+ value = sig.substring(index, index + 1);
+ type = getType(value.charAt(0));
+ }
+
+ index++;
+ }
+ }
+
+ private String getNextClassSignature(String value) {
+
+ int counter = 0;
+ int index = 0;
+
+ loop:
+ while (index < value.length()) {
+ switch (value.charAt(index)) {
+ case '<':
+ counter++;
+ break;
+ case '>':
+ counter--;
+ break;
+ case '.':
+ if (counter == 0) {
+ break loop;
+ }
+ }
+
+ index++;
+ }
+
+ return value.substring(0, index);
+ }
+
+ private void parseArgumentsList(String value, GenericType type) {
+
+ if (value == null) {
+ return;
+ }
+
+ while (value.length() > 0) {
+
+ String tstr = getNextType(value);
+ int len = tstr.length();
+ int wildcard = WILDCARD_NO;
+
+ switch (tstr.charAt(0)) {
+ case '*':
+ wildcard = WILDCARD_UNBOUND;
+ break;
+ case '+':
+ wildcard = WILDCARD_EXTENDS;
+ break;
+ case '-':
+ wildcard = WILDCARD_SUPER;
+ break;
+ }
+
+ type.getWildcards().add(wildcard);
+
+ if (wildcard != WILDCARD_NO) {
+ tstr = tstr.substring(1);
+ }
+
+ type.getArguments().add(tstr.length() == 0 ? null : new GenericType(tstr));
+
+ value = value.substring(len);
+ }
+ }
+
+ public static String getNextType(String value) {
+
+ int counter = 0;
+ int index = 0;
+
+ boolean contmode = false;
+
+ loop:
+ while (index < value.length()) {
+ switch (value.charAt(index)) {
+ case '*':
+ if (!contmode) {
+ break loop;
+ }
+ break;
+ case 'L':
+ case 'T':
+ if (!contmode) {
+ contmode = true;
+ }
+ case '[':
+ case '+':
+ case '-':
+ break;
+ default:
+ if (!contmode) {
+ break loop;
+ }
+ break;
+ case '<':
+ counter++;
+ break;
+ case '>':
+ counter--;
+ break;
+ case ';':
+ if (counter == 0) {
+ break loop;
+ }
+ }
+
+ index++;
+ }
+
+ return value.substring(0, index + 1);
+ }
+
+ private int getType(char c) {
+ switch (c) {
+ case 'B':
+ return CodeConstants.TYPE_BYTE;
+ case 'C':
+ return CodeConstants.TYPE_CHAR;
+ case 'D':
+ return CodeConstants.TYPE_DOUBLE;
+ case 'F':
+ return CodeConstants.TYPE_FLOAT;
+ case 'I':
+ return CodeConstants.TYPE_INT;
+ case 'J':
+ return CodeConstants.TYPE_LONG;
+ case 'S':
+ return CodeConstants.TYPE_SHORT;
+ case 'Z':
+ return CodeConstants.TYPE_BOOLEAN;
+ case 'V':
+ return CodeConstants.TYPE_VOID;
+ case 'G':
+ return CodeConstants.TYPE_GROUP2EMPTY;
+ case 'N':
+ return CodeConstants.TYPE_NOTINITIALIZED;
+ case 'A':
+ return CodeConstants.TYPE_ADDRESS;
+ case 'X':
+ return CodeConstants.TYPE_BYTECHAR;
+ case 'Y':
+ return CodeConstants.TYPE_SHORTCHAR;
+ case 'U':
+ return CodeConstants.TYPE_UNKNOWN;
+ default:
+ throw new RuntimeException("Invalid type");
+ }
+ }
+
+
+ public List<GenericType> getArguments() {
+ return arguments;
+ }
+
+
+ public List<GenericType> getEnclosingClasses() {
+ return enclosingClasses;
+ }
+
+
+ public List<Integer> getWildcards() {
+ return wildcards;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java b/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
index 94cef9a..46a334e 100644
--- a/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
+++ b/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
@@ -1,186 +1,186 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.struct.lazy;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.util.DataInputFullStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+
public class LazyLoader {
- private HashMap<String, Link> mapClassLinks = new HashMap<String, Link>();
-
- private IBytecodeProvider provider;
-
- public LazyLoader(IBytecodeProvider provider) {
- this.provider = provider;
- }
-
- public void addClassLink(String classname, Link link) {
- mapClassLinks.put(classname, link);
- }
-
- public void removeClassLink(String classname) {
- mapClassLinks.remove(classname);
- }
-
- public Link getClassLink(String classname) {
- return mapClassLinks.get(classname);
- }
-
-
- public ConstantPool loadPool(String classname) {
-
- try {
-
- DataInputFullStream in = getClassStream(classname);
- if(in == null) {
- return null;
- }
-
- in.skip(8);
-
- return new ConstantPool(in);
-
- } catch(IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- public byte[] loadBytecode(StructMethod mt, int code_fulllength) {
-
- try {
-
- DataInputFullStream in = getClassStream(mt.getClassStruct().qualifiedName);
- if(in == null) {
- return null;
- }
-
- byte[] res = null;
-
- in.skip(8);
-
- ConstantPool pool = mt.getClassStruct().getPool();
- if(pool == null) {
- pool = new ConstantPool(in);
- } else {
- ConstantPool.skipPool(in);
- }
-
- in.skip(2);
- int this_class = in.readUnsignedShort();
- in.skip(2);
-
- // interfaces
- in.skip(in.readUnsignedShort() * 2);
-
- // fields
- int size = in.readUnsignedShort();
- for (int i = 0; i < size; i++) {
- in.skip(6);
- skipAttributes(in);
- }
-
- // methods
- size = in.readUnsignedShort();
- for (int i = 0; i < size; i++) {
- in.skip(2);
-
- int name_index = in.readUnsignedShort();
- int descriptor_index = in.readUnsignedShort();
-
- String elem_arr[] = pool.getClassElement(ConstantPool.METHOD, this_class, name_index, descriptor_index);
- String name = elem_arr[0];
-
- if(mt.getName().equals(name)) {
- String descriptor = elem_arr[1];
- if(mt.getDescriptor().equals(descriptor)) {
-
- int len = in.readUnsignedShort();
- for(int j=0;j<len;j++) {
-
- int attr_nameindex = in.readUnsignedShort();
- String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
-
- if(StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) {
- in.skip(12);
-
- res = new byte[code_fulllength];
- in.readFull(res);
- return res;
- } else {
- in.skip(in.readInt());
- }
- }
-
- return null;
- }
- }
-
- skipAttributes(in);
- }
-
- return null;
-
- } catch(IOException ex) {
- throw new RuntimeException(ex);
- }
-
- }
-
- public DataInputFullStream getClassStream(String externPath, String internPath) throws IOException {
- InputStream instream = provider.getBytecodeStream(externPath, internPath);
- return instream == null?null:new DataInputFullStream(instream);
- }
-
- public DataInputFullStream getClassStream(String qualifiedClassName) throws IOException {
- Link link = mapClassLinks.get(qualifiedClassName);
- return link == null?null:getClassStream(link.externPath, link.internPath);
- }
-
- private void skipAttributes(DataInputFullStream in) throws IOException {
-
- int length = in.readUnsignedShort();
- for (int i = 0; i < length; i++) {
- in.skip(2);
- in.skip(in.readInt());
- }
-
- }
-
-
- public static class Link {
-
- public static final int CLASS = 1;
- public static final int ENTRY = 2;
-
- public int type;
- public String externPath;
- public String internPath;
-
- public Link(int type, String externPath, String internPath) {
- this.type = type;
- this.externPath = externPath;
- this.internPath = internPath;
- }
- }
-
+ private HashMap<String, Link> mapClassLinks = new HashMap<String, Link>();
+
+ private IBytecodeProvider provider;
+
+ public LazyLoader(IBytecodeProvider provider) {
+ this.provider = provider;
+ }
+
+ public void addClassLink(String classname, Link link) {
+ mapClassLinks.put(classname, link);
+ }
+
+ public void removeClassLink(String classname) {
+ mapClassLinks.remove(classname);
+ }
+
+ public Link getClassLink(String classname) {
+ return mapClassLinks.get(classname);
+ }
+
+
+ public ConstantPool loadPool(String classname) {
+
+ try {
+
+ DataInputFullStream in = getClassStream(classname);
+ if (in == null) {
+ return null;
+ }
+
+ in.skip(8);
+
+ return new ConstantPool(in);
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public byte[] loadBytecode(StructMethod mt, int code_fulllength) {
+
+ try {
+
+ DataInputFullStream in = getClassStream(mt.getClassStruct().qualifiedName);
+ if (in == null) {
+ return null;
+ }
+
+ byte[] res = null;
+
+ in.skip(8);
+
+ ConstantPool pool = mt.getClassStruct().getPool();
+ if (pool == null) {
+ pool = new ConstantPool(in);
+ }
+ else {
+ ConstantPool.skipPool(in);
+ }
+
+ in.skip(2);
+ int this_class = in.readUnsignedShort();
+ in.skip(2);
+
+ // interfaces
+ in.skip(in.readUnsignedShort() * 2);
+
+ // fields
+ int size = in.readUnsignedShort();
+ for (int i = 0; i < size; i++) {
+ in.skip(6);
+ skipAttributes(in);
+ }
+
+ // methods
+ size = in.readUnsignedShort();
+ for (int i = 0; i < size; i++) {
+ in.skip(2);
+
+ int name_index = in.readUnsignedShort();
+ int descriptor_index = in.readUnsignedShort();
+
+ String elem_arr[] = pool.getClassElement(ConstantPool.METHOD, this_class, name_index, descriptor_index);
+ String name = elem_arr[0];
+
+ if (mt.getName().equals(name)) {
+ String descriptor = elem_arr[1];
+ if (mt.getDescriptor().equals(descriptor)) {
+
+ int len = in.readUnsignedShort();
+ for (int j = 0; j < len; j++) {
+
+ int attr_nameindex = in.readUnsignedShort();
+ String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
+
+ if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) {
+ in.skip(12);
+
+ res = new byte[code_fulllength];
+ in.readFull(res);
+ return res;
+ }
+ else {
+ in.skip(in.readInt());
+ }
+ }
+
+ return null;
+ }
+ }
+
+ skipAttributes(in);
+ }
+
+ return null;
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public DataInputFullStream getClassStream(String externPath, String internPath) throws IOException {
+ InputStream instream = provider.getBytecodeStream(externPath, internPath);
+ return instream == null ? null : new DataInputFullStream(instream);
+ }
+
+ public DataInputFullStream getClassStream(String qualifiedClassName) throws IOException {
+ Link link = mapClassLinks.get(qualifiedClassName);
+ return link == null ? null : getClassStream(link.externPath, link.internPath);
+ }
+
+ private void skipAttributes(DataInputFullStream in) throws IOException {
+
+ int length = in.readUnsignedShort();
+ for (int i = 0; i < length; i++) {
+ in.skip(2);
+ in.skip(in.readInt());
+ }
+ }
+
+
+ public static class Link {
+
+ public static final int CLASS = 1;
+ public static final int ENTRY = 2;
+
+ public int type;
+ public String externPath;
+ public String internPath;
+
+ public Link(int type, String externPath, String internPath) {
+ this.type = type;
+ this.externPath = externPath;
+ this.internPath = internPath;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java b/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java
index 94b68b5..a13b27c 100644
--- a/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java
+++ b/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.util;
import java.io.DataInputStream;
@@ -20,31 +21,30 @@ import java.io.InputStream;
public class DataInputFullStream extends DataInputStream {
- public DataInputFullStream(InputStream in) {
- super(in);
+ public DataInputFullStream(InputStream in) {
+ super(in);
+ }
+
+ public final int readFull(byte b[]) throws IOException {
+
+ int length = b.length;
+ byte[] btemp = new byte[length];
+ int pos = 0;
+
+ int bytes_read = -1;
+ for (; ; ) {
+ bytes_read = read(btemp, 0, length - pos);
+ if (bytes_read == -1) {
+ return -1;
+ }
+
+ System.arraycopy(btemp, 0, b, pos, bytes_read);
+ pos += bytes_read;
+ if (pos == length) {
+ break;
+ }
}
-
- public final int readFull(byte b[]) throws IOException {
-
- int length = b.length;
- byte[] btemp = new byte[length];
- int pos = 0;
-
- int bytes_read = -1;
- for(;;) {
- bytes_read = read(btemp, 0, length-pos);
- if(bytes_read==-1) {
- return -1;
- }
-
- System.arraycopy(btemp, 0, b, pos, bytes_read);
- pos+=bytes_read;
- if(pos == length) {
- break;
- }
- }
-
- return length;
- }
-
+
+ return length;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/util/FastFixedSetFactory.java b/src/org/jetbrains/java/decompiler/util/FastFixedSetFactory.java
index 524f50d..a26b77e 100644
--- a/src/org/jetbrains/java/decompiler/util/FastFixedSetFactory.java
+++ b/src/org/jetbrains/java/decompiler/util/FastFixedSetFactory.java
@@ -1,363 +1,360 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.util;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
public class FastFixedSetFactory<E> {
- private VBStyleCollection<int[], E> colValuesInternal = new VBStyleCollection<int[], E>();
-
- private int dataLength;
-
- public FastFixedSetFactory(Collection<E> set) {
-
- dataLength = set.size() / 32 + 1;
-
- int index = 0;
- int mask = 1;
-
- for(E element : set) {
-
- int block = index / 32;
-
- if(index % 32 == 0) {
- mask = 1;
- }
-
- colValuesInternal.putWithKey(new int[] {block, mask}, element);
-
- index++;
- mask <<= 1;
- }
- }
-
- public FastFixedSet<E> spawnEmptySet() {
- return new FastFixedSet<E>(this);
- }
-
- private int getDataLength() {
- return dataLength;
- }
-
- private VBStyleCollection<int[], E> getInternalValuesCollection() {
- return colValuesInternal;
- }
-
- public static class FastFixedSet<E> implements Iterable<E> {
-
- private FastFixedSetFactory<E> factory;
-
- private VBStyleCollection<int[], E> colValuesInternal;
-
- private int[] data;
-
-
- private FastFixedSet(FastFixedSetFactory<E> factory) {
- this.factory = factory;
- this.colValuesInternal = factory.getInternalValuesCollection();
- this.data = new int[factory.getDataLength()];
- }
-
- public FastFixedSet<E> getCopy() {
-
- FastFixedSet<E> copy = new FastFixedSet<E>(factory);
-
- int arrlength = data.length;
- int[] cpdata = new int[arrlength];
- System.arraycopy(data, 0, cpdata, 0, arrlength);
- copy.setData(cpdata);
-
- return copy;
- }
-
- public void setAllElements() {
-
- int[] lastindex = colValuesInternal.get(colValuesInternal.size()-1);
-
- for(int i=lastindex[0]-1;i>=0;i--) {
- data[i] = 0xFFFFFFFF;
- }
-
- data[lastindex[0]] = lastindex[1] | (lastindex[1]-1);
- }
-
- public void add(E element) {
- int[] index = colValuesInternal.getWithKey(element);
- data[index[0]] |= index[1];
- }
-
- public void addAll(Collection<E> set) {
- for(E element : set) {
- add(element);
- }
- }
-
- public void remove(E element) {
- int[] index = colValuesInternal.getWithKey(element);
- data[index[0]] &= ~index[1];
- }
-
- public void removeAll(Collection<E> set) {
- for(E element : set) {
- remove(element);
- }
- }
-
- public boolean contains(E element) {
- int[] index = colValuesInternal.getWithKey(element);
- return (data[index[0]] & index[1]) != 0;
- }
-
- public boolean contains(FastFixedSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- if((extdata[i] & ~intdata[i]) != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- public void union(FastFixedSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- intdata[i] |= extdata[i];
- }
- }
-
- public void intersection(FastFixedSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- intdata[i] &= extdata[i];
- }
- }
-
- public void symdiff(FastFixedSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- intdata[i] ^= extdata[i];
- }
- }
-
- public void complement(FastFixedSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- intdata[i] &= ~extdata[i];
- }
- }
-
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof FastFixedSet)) return false;
-
- int[] extdata = ((FastFixedSet)o).getData();
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- if(intdata[i] != extdata[i]) {
- return false;
- }
- }
-
- return true;
- }
-
- public boolean isEmpty() {
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- if(intdata[i] != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- public Iterator<E> iterator() {
- return new FastFixedSetIterator<E>(this);
- }
-
- public Set<E> toPlainSet() {
- return toPlainCollection(new HashSet<E>());
- }
-
- public List<E> toPlainList() {
- return toPlainCollection(new ArrayList<E>());
- }
-
-
- private <T extends Collection<E>> T toPlainCollection(T cl) {
-
- int[] intdata = data;
- for(int bindex=0; bindex < intdata.length; bindex++) {
- int block = intdata[bindex];
- if(block != 0) {
- int index = bindex << 5; // * 32
- for(int i = 31; i>=0; i--){
- if((block & 1) != 0) {
- cl.add(colValuesInternal.getKey(index));
- }
- index++;
- block >>>= 1;
- }
- }
- }
-
- return cl;
- }
-
- public String toBinary() {
-
- StringBuilder buffer = new StringBuilder();
- int[] intdata = data;
-
- for(int i=0;i<intdata.length;i++) {
- buffer.append(" ").append(Integer.toBinaryString(intdata[i]));
- }
-
- return buffer.toString();
- }
-
- public String toString() {
-
- StringBuilder buffer = new StringBuilder("{");
-
- int[] intdata = data;
- boolean first = true;
-
- for(int i=colValuesInternal.size()-1;i>=0;i--) {
- int[] index = colValuesInternal.get(i);
-
- if((intdata[index[0]] & index[1]) != 0) {
- if(first) {
- first = false;
- } else {
- buffer.append(",");
- }
- buffer.append(colValuesInternal.getKey(i));
- }
- }
-
- buffer.append("}");
-
- return buffer.toString();
- }
-
- private int[] getData() {
- return data;
- }
-
- private void setData(int[] data) {
- this.data = data;
- }
-
- public FastFixedSetFactory<E> getFactory() {
- return factory;
- }
- }
-
- public static class FastFixedSetIterator<E> implements Iterator<E> {
-
- private VBStyleCollection<int[], E> colValuesInternal;
- private int[] data;
- private int size;
-
- private int pointer = -1;
- private int next_pointer = -1;
-
- private FastFixedSetIterator(FastFixedSet<E> set) {
- colValuesInternal = set.getFactory().getInternalValuesCollection();
- data = set.getData();
- size = colValuesInternal.size();
- }
-
- private int getNextIndex(int index) {
-
- index++;
- int ret = index;
- int bindex = index / 32;
- int dindex = index % 32;
-
- while(bindex < data.length) {
- int block = data[bindex];
-
- if(block != 0) {
- block >>>= dindex;
- while(dindex < 32) {
- if((block & 1) != 0) {
- return ret;
- }
- block >>>= 1;
- dindex++;
- ret++;
- }
- } else {
- ret += (32 - dindex);
- }
-
- dindex = 0;
- bindex++;
- }
-
- return -1;
- }
-
- public boolean hasNext() {
- next_pointer = getNextIndex(pointer);
- return (next_pointer >= 0);
- }
-
- public E next() {
- if(next_pointer >= 0) {
- pointer = next_pointer;
- } else {
- pointer = getNextIndex(pointer);
- if(pointer == -1) {
- pointer = size;
- }
- }
-
- next_pointer = -1;
- return pointer<size?colValuesInternal.getKey(pointer):null;
- }
-
- public void remove() {
- int[] index = colValuesInternal.get(pointer);
- data[index[0]] &= ~index[1];
- }
-
- }
-
+ private VBStyleCollection<int[], E> colValuesInternal = new VBStyleCollection<int[], E>();
+
+ private int dataLength;
+
+ public FastFixedSetFactory(Collection<E> set) {
+
+ dataLength = set.size() / 32 + 1;
+
+ int index = 0;
+ int mask = 1;
+
+ for (E element : set) {
+
+ int block = index / 32;
+
+ if (index % 32 == 0) {
+ mask = 1;
+ }
+
+ colValuesInternal.putWithKey(new int[]{block, mask}, element);
+
+ index++;
+ mask <<= 1;
+ }
+ }
+
+ public FastFixedSet<E> spawnEmptySet() {
+ return new FastFixedSet<E>(this);
+ }
+
+ private int getDataLength() {
+ return dataLength;
+ }
+
+ private VBStyleCollection<int[], E> getInternalValuesCollection() {
+ return colValuesInternal;
+ }
+
+ public static class FastFixedSet<E> implements Iterable<E> {
+
+ private FastFixedSetFactory<E> factory;
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+
+ private int[] data;
+
+
+ private FastFixedSet(FastFixedSetFactory<E> factory) {
+ this.factory = factory;
+ this.colValuesInternal = factory.getInternalValuesCollection();
+ this.data = new int[factory.getDataLength()];
+ }
+
+ public FastFixedSet<E> getCopy() {
+
+ FastFixedSet<E> copy = new FastFixedSet<E>(factory);
+
+ int arrlength = data.length;
+ int[] cpdata = new int[arrlength];
+ System.arraycopy(data, 0, cpdata, 0, arrlength);
+ copy.setData(cpdata);
+
+ return copy;
+ }
+
+ public void setAllElements() {
+
+ int[] lastindex = colValuesInternal.get(colValuesInternal.size() - 1);
+
+ for (int i = lastindex[0] - 1; i >= 0; i--) {
+ data[i] = 0xFFFFFFFF;
+ }
+
+ data[lastindex[0]] = lastindex[1] | (lastindex[1] - 1);
+ }
+
+ public void add(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+ data[index[0]] |= index[1];
+ }
+
+ public void addAll(Collection<E> set) {
+ for (E element : set) {
+ add(element);
+ }
+ }
+
+ public void remove(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+ data[index[0]] &= ~index[1];
+ }
+
+ public void removeAll(Collection<E> set) {
+ for (E element : set) {
+ remove(element);
+ }
+ }
+
+ public boolean contains(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+ return (data[index[0]] & index[1]) != 0;
+ }
+
+ public boolean contains(FastFixedSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ if ((extdata[i] & ~intdata[i]) != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void union(FastFixedSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ intdata[i] |= extdata[i];
+ }
+ }
+
+ public void intersection(FastFixedSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ intdata[i] &= extdata[i];
+ }
+ }
+
+ public void symdiff(FastFixedSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ intdata[i] ^= extdata[i];
+ }
+ }
+
+ public void complement(FastFixedSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ intdata[i] &= ~extdata[i];
+ }
+ }
+
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FastFixedSet)) return false;
+
+ int[] extdata = ((FastFixedSet)o).getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ if (intdata[i] != extdata[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public boolean isEmpty() {
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ if (intdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public Iterator<E> iterator() {
+ return new FastFixedSetIterator<E>(this);
+ }
+
+ public Set<E> toPlainSet() {
+ return toPlainCollection(new HashSet<E>());
+ }
+
+ public List<E> toPlainList() {
+ return toPlainCollection(new ArrayList<E>());
+ }
+
+
+ private <T extends Collection<E>> T toPlainCollection(T cl) {
+
+ int[] intdata = data;
+ for (int bindex = 0; bindex < intdata.length; bindex++) {
+ int block = intdata[bindex];
+ if (block != 0) {
+ int index = bindex << 5; // * 32
+ for (int i = 31; i >= 0; i--) {
+ if ((block & 1) != 0) {
+ cl.add(colValuesInternal.getKey(index));
+ }
+ index++;
+ block >>>= 1;
+ }
+ }
+ }
+
+ return cl;
+ }
+
+ public String toBinary() {
+
+ StringBuilder buffer = new StringBuilder();
+ int[] intdata = data;
+
+ for (int i = 0; i < intdata.length; i++) {
+ buffer.append(" ").append(Integer.toBinaryString(intdata[i]));
+ }
+
+ return buffer.toString();
+ }
+
+ public String toString() {
+
+ StringBuilder buffer = new StringBuilder("{");
+
+ int[] intdata = data;
+ boolean first = true;
+
+ for (int i = colValuesInternal.size() - 1; i >= 0; i--) {
+ int[] index = colValuesInternal.get(i);
+
+ if ((intdata[index[0]] & index[1]) != 0) {
+ if (first) {
+ first = false;
+ }
+ else {
+ buffer.append(",");
+ }
+ buffer.append(colValuesInternal.getKey(i));
+ }
+ }
+
+ buffer.append("}");
+
+ return buffer.toString();
+ }
+
+ private int[] getData() {
+ return data;
+ }
+
+ private void setData(int[] data) {
+ this.data = data;
+ }
+
+ public FastFixedSetFactory<E> getFactory() {
+ return factory;
+ }
+ }
+
+ public static class FastFixedSetIterator<E> implements Iterator<E> {
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+ private int[] data;
+ private int size;
+
+ private int pointer = -1;
+ private int next_pointer = -1;
+
+ private FastFixedSetIterator(FastFixedSet<E> set) {
+ colValuesInternal = set.getFactory().getInternalValuesCollection();
+ data = set.getData();
+ size = colValuesInternal.size();
+ }
+
+ private int getNextIndex(int index) {
+
+ index++;
+ int ret = index;
+ int bindex = index / 32;
+ int dindex = index % 32;
+
+ while (bindex < data.length) {
+ int block = data[bindex];
+
+ if (block != 0) {
+ block >>>= dindex;
+ while (dindex < 32) {
+ if ((block & 1) != 0) {
+ return ret;
+ }
+ block >>>= 1;
+ dindex++;
+ ret++;
+ }
+ }
+ else {
+ ret += (32 - dindex);
+ }
+
+ dindex = 0;
+ bindex++;
+ }
+
+ return -1;
+ }
+
+ public boolean hasNext() {
+ next_pointer = getNextIndex(pointer);
+ return (next_pointer >= 0);
+ }
+
+ public E next() {
+ if (next_pointer >= 0) {
+ pointer = next_pointer;
+ }
+ else {
+ pointer = getNextIndex(pointer);
+ if (pointer == -1) {
+ pointer = size;
+ }
+ }
+
+ next_pointer = -1;
+ return pointer < size ? colValuesInternal.getKey(pointer) : null;
+ }
+
+ public void remove() {
+ int[] index = colValuesInternal.get(pointer);
+ data[index[0]] &= ~index[1];
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/util/FastSetFactory.java b/src/org/jetbrains/java/decompiler/util/FastSetFactory.java
index 4e5a631..e9cce03 100644
--- a/src/org/jetbrains/java/decompiler/util/FastSetFactory.java
+++ b/src/org/jetbrains/java/decompiler/util/FastSetFactory.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.util;
import java.util.Collection;
@@ -21,466 +22,468 @@ import java.util.Set;
public class FastSetFactory<E> {
- private VBStyleCollection<int[], E> colValuesInternal = new VBStyleCollection<int[], E>();
-
- private int lastBlock;
-
- private int lastMask;
-
- public FastSetFactory(Collection<E> set) {
-
- int block = -1;
- int mask = -1;
- int index = 0;
-
- for(E element : set) {
-
- block = index / 32;
-
- if(index % 32 == 0) {
- mask = 1;
- } else {
- mask <<= 1;
- }
-
- colValuesInternal.putWithKey(new int[] {block, mask}, element);
-
- index++;
- }
-
- lastBlock = block;
- lastMask = mask;
- }
-
- private int[] addElement(E element) {
-
- if(lastMask == -1 || lastMask == 0x80000000) {
- lastMask = 1;
- lastBlock++;
- } else {
- lastMask <<= 1;
- }
-
- int[] pointer = new int[] {lastBlock, lastMask};
- colValuesInternal.putWithKey(pointer, element);
-
- return pointer;
- }
-
- public FastSet<E> spawnEmptySet() {
- return new FastSet<E>(this);
- }
-
- public int getLastBlock() {
- return lastBlock;
- }
-
- public int getLastMask() {
- return lastMask;
- }
-
- private VBStyleCollection<int[], E> getInternalValuesCollection() {
- return colValuesInternal;
- }
-
-
- public static class FastSet<E> implements Iterable<E> {
-
- private FastSetFactory<E> factory;
-
- private VBStyleCollection<int[], E> colValuesInternal;
-
- private int[] data;
-
- private FastSet(FastSetFactory<E> factory) {
- this.factory = factory;
- this.colValuesInternal = factory.getInternalValuesCollection();
- this.data = new int[factory.getLastBlock()+1];
- }
-
- public FastSet<E> getCopy() {
-
- FastSet<E> copy = new FastSet<E>(factory);
-
- int arrlength = data.length;
- int[] cpdata = new int[arrlength];
-
- System.arraycopy(data, 0, cpdata, 0, arrlength);
- copy.setData(cpdata);
-
- return copy;
- }
-
- private int[] ensureCapacity(int index) {
-
- int newlength = data.length;
- if(newlength == 0) {
- newlength = 1;
- }
-
- while(newlength <= index) {
- newlength *=2;
- }
-
- int[] newdata = new int[newlength];
- System.arraycopy(data, 0, newdata, 0, data.length);
-
- return data = newdata;
- }
-
- public void add(E element) {
- int[] index = colValuesInternal.getWithKey(element);
-
- if(index == null) {
- index = factory.addElement(element);
- }
-
- if(index[0] >= data.length) {
- ensureCapacity(index[0]);
- }
-
- data[index[0]] |= index[1];
- }
-
- public void setAllElements() {
-
- int lastblock = factory.getLastBlock();
- int lastmask = factory.getLastMask();
-
- if(lastblock >= data.length) {
- ensureCapacity(lastblock);
- }
-
- for(int i=lastblock-1;i>=0;i--) {
- data[i] = 0xFFFFFFFF;
- }
-
- data[lastblock] = lastmask | (lastmask-1);
- }
-
- public void addAll(Set<E> set) {
- for(E element : set) {
- add(element);
- }
- }
-
- public void remove(E element) {
- int[] index = colValuesInternal.getWithKey(element);
-
- if(index == null) {
- index = factory.addElement(element);
- }
-
- if(index[0] < data.length) {
- data[index[0]] &= ~index[1];
- }
- }
-
- public void removeAll(Set<E> set) {
- for(E element : set) {
- remove(element);
- }
- }
-
- public boolean contains(E element) {
- int[] index = colValuesInternal.getWithKey(element);
-
- if(index == null) {
- index = factory.addElement(element);
- }
-
- return index[0] >= data.length?false:((data[index[0]] & index[1]) != 0);
- }
-
- public boolean contains(FastSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- int minlength = Math.min(extdata.length, intdata.length);
-
- for(int i=minlength-1;i>=0;i--) {
- if((extdata[i] & ~intdata[i]) != 0) {
- return false;
- }
- }
-
- for(int i=extdata.length-1;i>=minlength;i--) {
- if(extdata[i] != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- public void union(FastSet<E> set) {
-
- int[] extdata = set.getData();
- int[] intdata = data;
-
- int minlength = Math.min(extdata.length, intdata.length);
-
- for(int i=minlength-1;i>=0;i--) {
- intdata[i] |= extdata[i];
- }
-
- boolean expanded = false;
- for(int i=extdata.length-1;i>=minlength;i--) {
- if(extdata[i] != 0) {
- if(!expanded) {
- intdata = ensureCapacity(extdata.length - 1);
- }
- intdata[i] = extdata[i];
- }
- }
- }
-
- public void intersection(FastSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- int minlength = Math.min(extdata.length, intdata.length);
-
- for(int i=minlength-1;i>=0;i--) {
- intdata[i] &= extdata[i];
- }
-
- for(int i=intdata.length-1;i>=minlength;i--) {
- intdata[i] = 0;
- }
-
- }
-
- public void symdiff(FastSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- int minlength = Math.min(extdata.length, intdata.length);
-
- for(int i=minlength-1;i>=0;i--) {
- intdata[i] ^= extdata[i];
- }
-
- boolean expanded = false;
- for(int i=extdata.length-1;i>=minlength;i--) {
- if(extdata[i] != 0) {
- if(!expanded) {
- intdata = ensureCapacity(extdata.length - 1);
- }
- intdata[i] = extdata[i];
- }
- }
- }
-
- public void complement(FastSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- int minlength = Math.min(extdata.length, intdata.length);
-
- for(int i=minlength-1;i>=0;i--) {
- intdata[i] &= ~extdata[i];
- }
- }
-
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof FastSet)) return false;
-
- int[] longdata = ((FastSet)o).getData();
- int[] shortdata = data;
-
- if(data.length > longdata.length) {
- shortdata = longdata;
- longdata = data;
- }
-
- for(int i=shortdata.length-1;i>=0;i--) {
- if(shortdata[i] != longdata[i]) {
- return false;
- }
- }
-
- for(int i=longdata.length-1;i>=shortdata.length;i--) {
- if(longdata[i] != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- public int getCardinality() {
-
- boolean found = false;
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- int block = intdata[i];
- if(block != 0) {
- if(found) {
- return 2;
- } else {
- if ((block & (block-1)) == 0) {
- found = true;
- } else {
- return 2;
- }
- }
- }
- }
-
- return found?1:0;
- }
-
- public int size() {
-
- int size = 0;
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- size+=Integer.bitCount(intdata[i]);
- }
-
- return size;
- }
-
- public boolean isEmpty() {
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- if(intdata[i] != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- public Iterator<E> iterator() {
- return new FastSetIterator<E>(this);
- }
-
- public Set<E> toPlainSet() {
- HashSet<E> set = new HashSet<E>();
-
- int[] intdata = data;
-
- int size = data.length*32;
- if(size > colValuesInternal.size()) {
- size = colValuesInternal.size();
- }
-
- for(int i=size-1;i>=0;i--) {
- int[] index = colValuesInternal.get(i);
-
- if((intdata[index[0]] & index[1]) != 0) {
- set.add(colValuesInternal.getKey(i));
- }
- }
-
- return set;
- }
-
- public String toBinary() {
-
- StringBuilder buffer = new StringBuilder();
- int[] intdata = data;
-
- for(int i=0;i<intdata.length;i++) {
- buffer.append(" ").append(Integer.toBinaryString(intdata[i]));
- }
-
- return buffer.toString();
- }
-
- private int[] getData() {
- return data;
- }
-
- private void setData(int[] data) {
- this.data = data;
- }
-
- public int[] getLoad() {
- int[] intdata = data;
- int notempty = 0;
-
- for(int i=0;i<intdata.length;i++) {
- if(intdata[i] != 0) {
- notempty++;
- }
- }
-
- return new int[]{intdata.length, notempty};
- }
-
- public FastSetFactory<E> getFactory() {
- return factory;
- }
- }
-
- public static class FastSetIterator<E> implements Iterator<E> {
-
- private VBStyleCollection<int[], E> colValuesInternal;
- private int[] data;
- private int size;
-
- private int pointer = -1;
- private int next_pointer = -1;
-
- private FastSetIterator(FastSet<E> set) {
- colValuesInternal = set.getFactory().getInternalValuesCollection();
- data = set.getData();
-
- size = colValuesInternal.size();
- int datasize = data.length*32;
-
- if(datasize < size) {
- size = datasize;
- }
- }
-
- public boolean hasNext() {
-
- next_pointer = pointer;
-
- while(++next_pointer < size) {
- int[] index = colValuesInternal.get(next_pointer);
- if((data[index[0]] & index[1]) != 0) {
- return true;
- }
- }
-
- next_pointer = -1;
- return false;
- }
-
- public E next() {
- if(next_pointer >= 0) {
- pointer = next_pointer;
- } else {
- while(++pointer < size) {
- int[] index = colValuesInternal.get(pointer);
- if((data[index[0]] & index[1]) != 0) {
- break;
- }
- }
- }
-
- next_pointer = -1;
- return pointer<size?colValuesInternal.getKey(pointer):null;
- }
-
- public void remove() {
- int[] index = colValuesInternal.get(pointer);
- data[index[0]] &= ~index[1];
-
- pointer--;
- }
-
- }
-
+ private VBStyleCollection<int[], E> colValuesInternal = new VBStyleCollection<int[], E>();
+
+ private int lastBlock;
+
+ private int lastMask;
+
+ public FastSetFactory(Collection<E> set) {
+
+ int block = -1;
+ int mask = -1;
+ int index = 0;
+
+ for (E element : set) {
+
+ block = index / 32;
+
+ if (index % 32 == 0) {
+ mask = 1;
+ }
+ else {
+ mask <<= 1;
+ }
+
+ colValuesInternal.putWithKey(new int[]{block, mask}, element);
+
+ index++;
+ }
+
+ lastBlock = block;
+ lastMask = mask;
+ }
+
+ private int[] addElement(E element) {
+
+ if (lastMask == -1 || lastMask == 0x80000000) {
+ lastMask = 1;
+ lastBlock++;
+ }
+ else {
+ lastMask <<= 1;
+ }
+
+ int[] pointer = new int[]{lastBlock, lastMask};
+ colValuesInternal.putWithKey(pointer, element);
+
+ return pointer;
+ }
+
+ public FastSet<E> spawnEmptySet() {
+ return new FastSet<E>(this);
+ }
+
+ public int getLastBlock() {
+ return lastBlock;
+ }
+
+ public int getLastMask() {
+ return lastMask;
+ }
+
+ private VBStyleCollection<int[], E> getInternalValuesCollection() {
+ return colValuesInternal;
+ }
+
+
+ public static class FastSet<E> implements Iterable<E> {
+
+ private FastSetFactory<E> factory;
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+
+ private int[] data;
+
+ private FastSet(FastSetFactory<E> factory) {
+ this.factory = factory;
+ this.colValuesInternal = factory.getInternalValuesCollection();
+ this.data = new int[factory.getLastBlock() + 1];
+ }
+
+ public FastSet<E> getCopy() {
+
+ FastSet<E> copy = new FastSet<E>(factory);
+
+ int arrlength = data.length;
+ int[] cpdata = new int[arrlength];
+
+ System.arraycopy(data, 0, cpdata, 0, arrlength);
+ copy.setData(cpdata);
+
+ return copy;
+ }
+
+ private int[] ensureCapacity(int index) {
+
+ int newlength = data.length;
+ if (newlength == 0) {
+ newlength = 1;
+ }
+
+ while (newlength <= index) {
+ newlength *= 2;
+ }
+
+ int[] newdata = new int[newlength];
+ System.arraycopy(data, 0, newdata, 0, data.length);
+
+ return data = newdata;
+ }
+
+ public void add(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ if (index[0] >= data.length) {
+ ensureCapacity(index[0]);
+ }
+
+ data[index[0]] |= index[1];
+ }
+
+ public void setAllElements() {
+
+ int lastblock = factory.getLastBlock();
+ int lastmask = factory.getLastMask();
+
+ if (lastblock >= data.length) {
+ ensureCapacity(lastblock);
+ }
+
+ for (int i = lastblock - 1; i >= 0; i--) {
+ data[i] = 0xFFFFFFFF;
+ }
+
+ data[lastblock] = lastmask | (lastmask - 1);
+ }
+
+ public void addAll(Set<E> set) {
+ for (E element : set) {
+ add(element);
+ }
+ }
+
+ public void remove(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ if (index[0] < data.length) {
+ data[index[0]] &= ~index[1];
+ }
+ }
+
+ public void removeAll(Set<E> set) {
+ for (E element : set) {
+ remove(element);
+ }
+ }
+
+ public boolean contains(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ return index[0] >= data.length ? false : ((data[index[0]] & index[1]) != 0);
+ }
+
+ public boolean contains(FastSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ if ((extdata[i] & ~intdata[i]) != 0) {
+ return false;
+ }
+ }
+
+ for (int i = extdata.length - 1; i >= minlength; i--) {
+ if (extdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void union(FastSet<E> set) {
+
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] |= extdata[i];
+ }
+
+ boolean expanded = false;
+ for (int i = extdata.length - 1; i >= minlength; i--) {
+ if (extdata[i] != 0) {
+ if (!expanded) {
+ intdata = ensureCapacity(extdata.length - 1);
+ }
+ intdata[i] = extdata[i];
+ }
+ }
+ }
+
+ public void intersection(FastSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] &= extdata[i];
+ }
+
+ for (int i = intdata.length - 1; i >= minlength; i--) {
+ intdata[i] = 0;
+ }
+ }
+
+ public void symdiff(FastSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] ^= extdata[i];
+ }
+
+ boolean expanded = false;
+ for (int i = extdata.length - 1; i >= minlength; i--) {
+ if (extdata[i] != 0) {
+ if (!expanded) {
+ intdata = ensureCapacity(extdata.length - 1);
+ }
+ intdata[i] = extdata[i];
+ }
+ }
+ }
+
+ public void complement(FastSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] &= ~extdata[i];
+ }
+ }
+
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FastSet)) return false;
+
+ int[] longdata = ((FastSet)o).getData();
+ int[] shortdata = data;
+
+ if (data.length > longdata.length) {
+ shortdata = longdata;
+ longdata = data;
+ }
+
+ for (int i = shortdata.length - 1; i >= 0; i--) {
+ if (shortdata[i] != longdata[i]) {
+ return false;
+ }
+ }
+
+ for (int i = longdata.length - 1; i >= shortdata.length; i--) {
+ if (longdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int getCardinality() {
+
+ boolean found = false;
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ int block = intdata[i];
+ if (block != 0) {
+ if (found) {
+ return 2;
+ }
+ else {
+ if ((block & (block - 1)) == 0) {
+ found = true;
+ }
+ else {
+ return 2;
+ }
+ }
+ }
+ }
+
+ return found ? 1 : 0;
+ }
+
+ public int size() {
+
+ int size = 0;
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ size += Integer.bitCount(intdata[i]);
+ }
+
+ return size;
+ }
+
+ public boolean isEmpty() {
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ if (intdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public Iterator<E> iterator() {
+ return new FastSetIterator<E>(this);
+ }
+
+ public Set<E> toPlainSet() {
+ HashSet<E> set = new HashSet<E>();
+
+ int[] intdata = data;
+
+ int size = data.length * 32;
+ if (size > colValuesInternal.size()) {
+ size = colValuesInternal.size();
+ }
+
+ for (int i = size - 1; i >= 0; i--) {
+ int[] index = colValuesInternal.get(i);
+
+ if ((intdata[index[0]] & index[1]) != 0) {
+ set.add(colValuesInternal.getKey(i));
+ }
+ }
+
+ return set;
+ }
+
+ public String toBinary() {
+
+ StringBuilder buffer = new StringBuilder();
+ int[] intdata = data;
+
+ for (int i = 0; i < intdata.length; i++) {
+ buffer.append(" ").append(Integer.toBinaryString(intdata[i]));
+ }
+
+ return buffer.toString();
+ }
+
+ private int[] getData() {
+ return data;
+ }
+
+ private void setData(int[] data) {
+ this.data = data;
+ }
+
+ public int[] getLoad() {
+ int[] intdata = data;
+ int notempty = 0;
+
+ for (int i = 0; i < intdata.length; i++) {
+ if (intdata[i] != 0) {
+ notempty++;
+ }
+ }
+
+ return new int[]{intdata.length, notempty};
+ }
+
+ public FastSetFactory<E> getFactory() {
+ return factory;
+ }
+ }
+
+ public static class FastSetIterator<E> implements Iterator<E> {
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+ private int[] data;
+ private int size;
+
+ private int pointer = -1;
+ private int next_pointer = -1;
+
+ private FastSetIterator(FastSet<E> set) {
+ colValuesInternal = set.getFactory().getInternalValuesCollection();
+ data = set.getData();
+
+ size = colValuesInternal.size();
+ int datasize = data.length * 32;
+
+ if (datasize < size) {
+ size = datasize;
+ }
+ }
+
+ public boolean hasNext() {
+
+ next_pointer = pointer;
+
+ while (++next_pointer < size) {
+ int[] index = colValuesInternal.get(next_pointer);
+ if ((data[index[0]] & index[1]) != 0) {
+ return true;
+ }
+ }
+
+ next_pointer = -1;
+ return false;
+ }
+
+ public E next() {
+ if (next_pointer >= 0) {
+ pointer = next_pointer;
+ }
+ else {
+ while (++pointer < size) {
+ int[] index = colValuesInternal.get(pointer);
+ if ((data[index[0]] & index[1]) != 0) {
+ break;
+ }
+ }
+ }
+
+ next_pointer = -1;
+ return pointer < size ? colValuesInternal.getKey(pointer) : null;
+ }
+
+ public void remove() {
+ int[] index = colValuesInternal.get(pointer);
+ data[index[0]] &= ~index[1];
+
+ pointer--;
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java b/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java
index 352dc2a..301a1ff 100644
--- a/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java
+++ b/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.util;
import java.util.Collection;
@@ -21,529 +22,533 @@ import java.util.Set;
public class FastSparseSetFactory<E> {
- private VBStyleCollection<int[], E> colValuesInternal = new VBStyleCollection<int[], E>();
-
- private int lastBlock;
-
- private int lastMask;
-
- public FastSparseSetFactory(Collection<E> set) {
-
- int block = -1;
- int mask = -1;
- int index = 0;
-
- for(E element : set) {
-
- block = index / 32;
-
- if(index % 32 == 0) {
- mask = 1;
- } else {
- mask <<= 1;
- }
-
- colValuesInternal.putWithKey(new int[] {block, mask}, element);
-
- index++;
- }
-
- lastBlock = block;
- lastMask = mask;
- }
-
- private int[] addElement(E element) {
-
- if(lastMask == -1 || lastMask == 0x80000000) {
- lastMask = 1;
- lastBlock++;
- } else {
- lastMask <<= 1;
- }
-
- int[] pointer = new int[] {lastBlock, lastMask};
- colValuesInternal.putWithKey(pointer, element);
-
- return pointer;
- }
-
- public FastSparseSet<E> spawnEmptySet() {
- return new FastSparseSet<E>(this);
- }
-
- public int getLastBlock() {
- return lastBlock;
- }
-
- public int getLastMask() {
- return lastMask;
- }
-
- private VBStyleCollection<int[], E> getInternalValuesCollection() {
- return colValuesInternal;
- }
-
-
- public static class FastSparseSet<E> implements Iterable<E> {
-
- private FastSparseSetFactory<E> factory;
-
- private VBStyleCollection<int[], E> colValuesInternal;
-
- private int[] data;
- private int[] next;
-
- private FastSparseSet(FastSparseSetFactory<E> factory) {
- this.factory = factory;
- this.colValuesInternal = factory.getInternalValuesCollection();
-
- int length = factory.getLastBlock()+1;
- this.data = new int[length];
- this.next = new int[length];
- }
-
- private FastSparseSet(FastSparseSetFactory<E> factory, int[] data, int[] next) {
- this.factory = factory;
- this.colValuesInternal = factory.getInternalValuesCollection();
-
- this.data = data;
- this.next = next;
- }
-
- public FastSparseSet<E> getCopy() {
-
- int arrlength = data.length;
- int[] cpdata = new int[arrlength];
- int[] cpnext = new int[arrlength];
-
- System.arraycopy(data, 0, cpdata, 0, arrlength);
- System.arraycopy(next, 0, cpnext, 0, arrlength);
-
- FastSparseSet<E> copy = new FastSparseSet<E>(factory, cpdata, cpnext);
-
- return copy;
- }
-
- private int[] ensureCapacity(int index) {
-
- int newlength = data.length;
- if(newlength == 0) {
- newlength = 1;
- }
-
- while(newlength <= index) {
- newlength *=2;
- }
-
- int[] newdata = new int[newlength];
- System.arraycopy(data, 0, newdata, 0, data.length);
- data = newdata;
-
- int[] newnext = new int[newlength];
- System.arraycopy(next, 0, newnext, 0, next.length);
- next = newnext;
-
- return newdata;
- }
-
- public void add(E element) {
- int[] index = colValuesInternal.getWithKey(element);
-
- if(index == null) {
- index = factory.addElement(element);
- }
-
- int block = index[0];
- if(block >= data.length) {
- ensureCapacity(block);
- }
-
- data[block] |= index[1];
-
- changeNext(next, block, next[block], block);
- }
-
- public void setAllElements() {
-
- int lastblock = factory.getLastBlock();
- int lastmask = factory.getLastMask();
-
- if(lastblock >= data.length) {
- ensureCapacity(lastblock);
- }
-
- for(int i=lastblock-1;i>=0;i--) {
- data[i] = 0xFFFFFFFF;
- next[i] = i+1;
- }
-
- data[lastblock] = lastmask | (lastmask-1);
- next[lastblock] = 0;
- }
-
- public void addAll(Set<E> set) {
- for(E element : set) {
- add(element);
- }
- }
-
- public void remove(E element) {
- int[] index = colValuesInternal.getWithKey(element);
-
- if(index == null) {
- index = factory.addElement(element);
- }
-
- int block = index[0];
- if(block < data.length) {
- data[block] &= ~index[1];
-
- if(data[block] == 0) {
- changeNext(next, block, block, next[block]);
- }
- }
- }
-
- public void removeAll(Set<E> set) {
- for(E element : set) {
- remove(element);
- }
- }
-
- public boolean contains(E element) {
- int[] index = colValuesInternal.getWithKey(element);
-
- if(index == null) {
- index = factory.addElement(element);
- }
-
- return index[0] >= data.length?false:((data[index[0]] & index[1]) != 0);
- }
-
- public boolean contains(FastSparseSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- int minlength = Math.min(extdata.length, intdata.length);
-
- for(int i=minlength-1;i>=0;i--) {
- if((extdata[i] & ~intdata[i]) != 0) {
- return false;
- }
- }
-
- for(int i=extdata.length-1;i>=minlength;i--) {
- if(extdata[i] != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- private void setNext() {
-
- int link = 0;
- for(int i=data.length-1;i>=0;i--) {
- next[i] = link;
- if(data[i] != 0) {
- link = i;
- }
- }
- }
-
- private void changeNext(int[] arrnext, int key, int oldnext, int newnext) {
- for(int i=key-1;i>=0;i--) {
- if(arrnext[i] == oldnext) {
- arrnext[i] = newnext;
- } else {
- break;
- }
- }
- }
-
- public void union(FastSparseSet<E> set) {
-
- int[] extdata = set.getData();
- int[] extnext = set.getNext();
- int[] intdata = data;
- int intlength = intdata.length;
-
- int pointer = 0;
- do {
- if(pointer >= intlength) {
- intdata = ensureCapacity(extdata.length - 1);
- }
-
- boolean nextrec = (intdata[pointer] == 0);
- intdata[pointer] |= extdata[pointer];
-
- if(nextrec) {
- changeNext(next, pointer, next[pointer], pointer);
- }
-
- pointer = extnext[pointer];
-
- } while(pointer!=0);
- }
-
- public void intersection(FastSparseSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- int minlength = Math.min(extdata.length, intdata.length);
-
- for(int i=minlength-1;i>=0;i--) {
- intdata[i] &= extdata[i];
- }
-
- for(int i=intdata.length-1;i>=minlength;i--) {
- intdata[i] = 0;
- }
-
- setNext();
- }
-
- public void symdiff(FastSparseSet<E> set) {
- int[] extdata = set.getData();
- int[] intdata = data;
-
- int minlength = Math.min(extdata.length, intdata.length);
-
- for(int i=minlength-1;i>=0;i--) {
- intdata[i] ^= extdata[i];
- }
-
- boolean expanded = false;
- for(int i=extdata.length-1;i>=minlength;i--) {
- if(extdata[i] != 0) {
- if(!expanded) {
- intdata = ensureCapacity(extdata.length - 1);
- }
- intdata[i] = extdata[i];
- }
- }
-
- setNext();
- }
-
- public void complement(FastSparseSet<E> set) {
-
- int[] extdata = set.getData();
- int[] intdata = data;
- int extlength = extdata.length;
-
- int pointer = 0;
- do {
- if(pointer >= extlength) {
- break;
- }
-
- intdata[pointer] &= ~extdata[pointer];
- if(intdata[pointer] == 0) {
- changeNext(next, pointer, pointer, next[pointer]);
- }
-
- pointer = next[pointer];
-
- } while(pointer!=0);
- }
-
-
- public boolean equals(Object o) {
- if(o == this) return true;
- if(o == null || !(o instanceof FastSparseSet)) return false;
-
- int[] longdata = ((FastSparseSet)o).getData();
- int[] shortdata = data;
-
- if(data.length > longdata.length) {
- shortdata = longdata;
- longdata = data;
- }
-
- for(int i=shortdata.length-1;i>=0;i--) {
- if(shortdata[i] != longdata[i]) {
- return false;
- }
- }
-
- for(int i=longdata.length-1;i>=shortdata.length;i--) {
- if(longdata[i] != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- public int getCardinality() {
-
- boolean found = false;
- int[] intdata = data;
-
- for(int i=intdata.length-1;i>=0;i--) {
- int block = intdata[i];
- if(block != 0) {
- if(found) {
- return 2;
- } else {
- if ((block & (block-1)) == 0) {
- found = true;
- } else {
- return 2;
- }
- }
- }
- }
-
- return found?1:0;
- }
-
- public boolean isEmpty() {
- return data.length == 0 || (next[0] == 0 && data[0] == 0);
- }
-
- public Iterator<E> iterator() {
- return new FastSparseSetIterator<E>(this);
- }
-
- public Set<E> toPlainSet() {
- HashSet<E> set = new HashSet<E>();
-
- int[] intdata = data;
-
- int size = data.length*32;
- if(size > colValuesInternal.size()) {
- size = colValuesInternal.size();
- }
-
- for(int i=size-1;i>=0;i--) {
- int[] index = colValuesInternal.get(i);
-
- if((intdata[index[0]] & index[1]) != 0) {
- set.add(colValuesInternal.getKey(i));
- }
- }
-
- return set;
- }
-
- public String toString() {
- return toPlainSet().toString();
- }
-
- public String toBinary() {
-
- StringBuilder buffer = new StringBuilder();
- int[] intdata = data;
-
- for(int i=0;i<intdata.length;i++) {
- buffer.append(" ").append(Integer.toBinaryString(intdata[i]));
- }
-
- return buffer.toString();
- }
-
- private int[] getData() {
- return data;
- }
-
- private int[] getNext() {
- return next;
- }
-
- public int[] getLoad() {
- int[] intdata = data;
- int notempty = 0;
-
- for(int i=0;i<intdata.length;i++) {
- if(intdata[i] != 0) {
- notempty++;
- }
- }
-
- return new int[]{intdata.length, notempty};
- }
-
- public FastSparseSetFactory<E> getFactory() {
- return factory;
- }
- }
-
- public static class FastSparseSetIterator<E> implements Iterator<E> {
-
- private VBStyleCollection<int[], E> colValuesInternal;
- private int[] data;
- private int[] next;
- private int size;
-
- private int pointer = -1;
- private int next_pointer = -1;
-
- private FastSparseSetIterator(FastSparseSet<E> set) {
- colValuesInternal = set.getFactory().getInternalValuesCollection();
- data = set.getData();
- next = set.getNext();
- size = colValuesInternal.size();
- }
-
- private int getNextIndex(int index) {
-
- index++;
- int bindex = index >>> 5;
- int dindex = index & 0x1F;
-
- while(bindex < data.length) {
- int block = data[bindex];
-
- if(block != 0) {
- block >>>= dindex;
- while(dindex < 32) {
- if((block & 1) != 0) {
- return (bindex << 5) + dindex;
- }
- block >>>= 1;
- dindex++;
- }
- }
-
- dindex = 0;
- bindex = next[bindex];
-
- if(bindex == 0) {
- break;
- }
- }
-
- return -1;
- }
-
- public boolean hasNext() {
- next_pointer = getNextIndex(pointer);
- return (next_pointer >= 0);
- }
-
- public E next() {
- if(next_pointer >= 0) {
- pointer = next_pointer;
- } else {
- pointer = getNextIndex(pointer);
- if(pointer == -1) {
- pointer = size;
- }
- }
-
- next_pointer = -1;
- return pointer<size?colValuesInternal.getKey(pointer):null;
- }
-
- public void remove() {
- int[] index = colValuesInternal.get(pointer);
- data[index[0]] &= ~index[1];
- }
-
- }
-
+ private VBStyleCollection<int[], E> colValuesInternal = new VBStyleCollection<int[], E>();
+
+ private int lastBlock;
+
+ private int lastMask;
+
+ public FastSparseSetFactory(Collection<E> set) {
+
+ int block = -1;
+ int mask = -1;
+ int index = 0;
+
+ for (E element : set) {
+
+ block = index / 32;
+
+ if (index % 32 == 0) {
+ mask = 1;
+ }
+ else {
+ mask <<= 1;
+ }
+
+ colValuesInternal.putWithKey(new int[]{block, mask}, element);
+
+ index++;
+ }
+
+ lastBlock = block;
+ lastMask = mask;
+ }
+
+ private int[] addElement(E element) {
+
+ if (lastMask == -1 || lastMask == 0x80000000) {
+ lastMask = 1;
+ lastBlock++;
+ }
+ else {
+ lastMask <<= 1;
+ }
+
+ int[] pointer = new int[]{lastBlock, lastMask};
+ colValuesInternal.putWithKey(pointer, element);
+
+ return pointer;
+ }
+
+ public FastSparseSet<E> spawnEmptySet() {
+ return new FastSparseSet<E>(this);
+ }
+
+ public int getLastBlock() {
+ return lastBlock;
+ }
+
+ public int getLastMask() {
+ return lastMask;
+ }
+
+ private VBStyleCollection<int[], E> getInternalValuesCollection() {
+ return colValuesInternal;
+ }
+
+
+ public static class FastSparseSet<E> implements Iterable<E> {
+
+ private FastSparseSetFactory<E> factory;
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+
+ private int[] data;
+ private int[] next;
+
+ private FastSparseSet(FastSparseSetFactory<E> factory) {
+ this.factory = factory;
+ this.colValuesInternal = factory.getInternalValuesCollection();
+
+ int length = factory.getLastBlock() + 1;
+ this.data = new int[length];
+ this.next = new int[length];
+ }
+
+ private FastSparseSet(FastSparseSetFactory<E> factory, int[] data, int[] next) {
+ this.factory = factory;
+ this.colValuesInternal = factory.getInternalValuesCollection();
+
+ this.data = data;
+ this.next = next;
+ }
+
+ public FastSparseSet<E> getCopy() {
+
+ int arrlength = data.length;
+ int[] cpdata = new int[arrlength];
+ int[] cpnext = new int[arrlength];
+
+ System.arraycopy(data, 0, cpdata, 0, arrlength);
+ System.arraycopy(next, 0, cpnext, 0, arrlength);
+
+ FastSparseSet<E> copy = new FastSparseSet<E>(factory, cpdata, cpnext);
+
+ return copy;
+ }
+
+ private int[] ensureCapacity(int index) {
+
+ int newlength = data.length;
+ if (newlength == 0) {
+ newlength = 1;
+ }
+
+ while (newlength <= index) {
+ newlength *= 2;
+ }
+
+ int[] newdata = new int[newlength];
+ System.arraycopy(data, 0, newdata, 0, data.length);
+ data = newdata;
+
+ int[] newnext = new int[newlength];
+ System.arraycopy(next, 0, newnext, 0, next.length);
+ next = newnext;
+
+ return newdata;
+ }
+
+ public void add(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ int block = index[0];
+ if (block >= data.length) {
+ ensureCapacity(block);
+ }
+
+ data[block] |= index[1];
+
+ changeNext(next, block, next[block], block);
+ }
+
+ public void setAllElements() {
+
+ int lastblock = factory.getLastBlock();
+ int lastmask = factory.getLastMask();
+
+ if (lastblock >= data.length) {
+ ensureCapacity(lastblock);
+ }
+
+ for (int i = lastblock - 1; i >= 0; i--) {
+ data[i] = 0xFFFFFFFF;
+ next[i] = i + 1;
+ }
+
+ data[lastblock] = lastmask | (lastmask - 1);
+ next[lastblock] = 0;
+ }
+
+ public void addAll(Set<E> set) {
+ for (E element : set) {
+ add(element);
+ }
+ }
+
+ public void remove(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ int block = index[0];
+ if (block < data.length) {
+ data[block] &= ~index[1];
+
+ if (data[block] == 0) {
+ changeNext(next, block, block, next[block]);
+ }
+ }
+ }
+
+ public void removeAll(Set<E> set) {
+ for (E element : set) {
+ remove(element);
+ }
+ }
+
+ public boolean contains(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ return index[0] >= data.length ? false : ((data[index[0]] & index[1]) != 0);
+ }
+
+ public boolean contains(FastSparseSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ if ((extdata[i] & ~intdata[i]) != 0) {
+ return false;
+ }
+ }
+
+ for (int i = extdata.length - 1; i >= minlength; i--) {
+ if (extdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void setNext() {
+
+ int link = 0;
+ for (int i = data.length - 1; i >= 0; i--) {
+ next[i] = link;
+ if (data[i] != 0) {
+ link = i;
+ }
+ }
+ }
+
+ private void changeNext(int[] arrnext, int key, int oldnext, int newnext) {
+ for (int i = key - 1; i >= 0; i--) {
+ if (arrnext[i] == oldnext) {
+ arrnext[i] = newnext;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ public void union(FastSparseSet<E> set) {
+
+ int[] extdata = set.getData();
+ int[] extnext = set.getNext();
+ int[] intdata = data;
+ int intlength = intdata.length;
+
+ int pointer = 0;
+ do {
+ if (pointer >= intlength) {
+ intdata = ensureCapacity(extdata.length - 1);
+ }
+
+ boolean nextrec = (intdata[pointer] == 0);
+ intdata[pointer] |= extdata[pointer];
+
+ if (nextrec) {
+ changeNext(next, pointer, next[pointer], pointer);
+ }
+
+ pointer = extnext[pointer];
+ }
+ while (pointer != 0);
+ }
+
+ public void intersection(FastSparseSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] &= extdata[i];
+ }
+
+ for (int i = intdata.length - 1; i >= minlength; i--) {
+ intdata[i] = 0;
+ }
+
+ setNext();
+ }
+
+ public void symdiff(FastSparseSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] ^= extdata[i];
+ }
+
+ boolean expanded = false;
+ for (int i = extdata.length - 1; i >= minlength; i--) {
+ if (extdata[i] != 0) {
+ if (!expanded) {
+ intdata = ensureCapacity(extdata.length - 1);
+ }
+ intdata[i] = extdata[i];
+ }
+ }
+
+ setNext();
+ }
+
+ public void complement(FastSparseSet<E> set) {
+
+ int[] extdata = set.getData();
+ int[] intdata = data;
+ int extlength = extdata.length;
+
+ int pointer = 0;
+ do {
+ if (pointer >= extlength) {
+ break;
+ }
+
+ intdata[pointer] &= ~extdata[pointer];
+ if (intdata[pointer] == 0) {
+ changeNext(next, pointer, pointer, next[pointer]);
+ }
+
+ pointer = next[pointer];
+ }
+ while (pointer != 0);
+ }
+
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FastSparseSet)) return false;
+
+ int[] longdata = ((FastSparseSet)o).getData();
+ int[] shortdata = data;
+
+ if (data.length > longdata.length) {
+ shortdata = longdata;
+ longdata = data;
+ }
+
+ for (int i = shortdata.length - 1; i >= 0; i--) {
+ if (shortdata[i] != longdata[i]) {
+ return false;
+ }
+ }
+
+ for (int i = longdata.length - 1; i >= shortdata.length; i--) {
+ if (longdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int getCardinality() {
+
+ boolean found = false;
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ int block = intdata[i];
+ if (block != 0) {
+ if (found) {
+ return 2;
+ }
+ else {
+ if ((block & (block - 1)) == 0) {
+ found = true;
+ }
+ else {
+ return 2;
+ }
+ }
+ }
+ }
+
+ return found ? 1 : 0;
+ }
+
+ public boolean isEmpty() {
+ return data.length == 0 || (next[0] == 0 && data[0] == 0);
+ }
+
+ public Iterator<E> iterator() {
+ return new FastSparseSetIterator<E>(this);
+ }
+
+ public Set<E> toPlainSet() {
+ HashSet<E> set = new HashSet<E>();
+
+ int[] intdata = data;
+
+ int size = data.length * 32;
+ if (size > colValuesInternal.size()) {
+ size = colValuesInternal.size();
+ }
+
+ for (int i = size - 1; i >= 0; i--) {
+ int[] index = colValuesInternal.get(i);
+
+ if ((intdata[index[0]] & index[1]) != 0) {
+ set.add(colValuesInternal.getKey(i));
+ }
+ }
+
+ return set;
+ }
+
+ public String toString() {
+ return toPlainSet().toString();
+ }
+
+ public String toBinary() {
+
+ StringBuilder buffer = new StringBuilder();
+ int[] intdata = data;
+
+ for (int i = 0; i < intdata.length; i++) {
+ buffer.append(" ").append(Integer.toBinaryString(intdata[i]));
+ }
+
+ return buffer.toString();
+ }
+
+ private int[] getData() {
+ return data;
+ }
+
+ private int[] getNext() {
+ return next;
+ }
+
+ public int[] getLoad() {
+ int[] intdata = data;
+ int notempty = 0;
+
+ for (int i = 0; i < intdata.length; i++) {
+ if (intdata[i] != 0) {
+ notempty++;
+ }
+ }
+
+ return new int[]{intdata.length, notempty};
+ }
+
+ public FastSparseSetFactory<E> getFactory() {
+ return factory;
+ }
+ }
+
+ public static class FastSparseSetIterator<E> implements Iterator<E> {
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+ private int[] data;
+ private int[] next;
+ private int size;
+
+ private int pointer = -1;
+ private int next_pointer = -1;
+
+ private FastSparseSetIterator(FastSparseSet<E> set) {
+ colValuesInternal = set.getFactory().getInternalValuesCollection();
+ data = set.getData();
+ next = set.getNext();
+ size = colValuesInternal.size();
+ }
+
+ private int getNextIndex(int index) {
+
+ index++;
+ int bindex = index >>> 5;
+ int dindex = index & 0x1F;
+
+ while (bindex < data.length) {
+ int block = data[bindex];
+
+ if (block != 0) {
+ block >>>= dindex;
+ while (dindex < 32) {
+ if ((block & 1) != 0) {
+ return (bindex << 5) + dindex;
+ }
+ block >>>= 1;
+ dindex++;
+ }
+ }
+
+ dindex = 0;
+ bindex = next[bindex];
+
+ if (bindex == 0) {
+ break;
+ }
+ }
+
+ return -1;
+ }
+
+ public boolean hasNext() {
+ next_pointer = getNextIndex(pointer);
+ return (next_pointer >= 0);
+ }
+
+ public E next() {
+ if (next_pointer >= 0) {
+ pointer = next_pointer;
+ }
+ else {
+ pointer = getNextIndex(pointer);
+ if (pointer == -1) {
+ pointer = size;
+ }
+ }
+
+ next_pointer = -1;
+ return pointer < size ? colValuesInternal.getKey(pointer) : null;
+ }
+
+ public void remove() {
+ int[] index = colValuesInternal.get(pointer);
+ data[index[0]] &= ~index[1];
+ }
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java b/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java
index 4914d36..f429636 100644
--- a/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java
+++ b/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java
@@ -1,157 +1,155 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.util;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+
+import java.io.*;
import java.nio.channels.FileChannel;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
-import org.jetbrains.java.decompiler.main.DecompilerContext;
-import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
-
public class InterpreterUtil {
-
- public static void copyFile(File in, File out) throws IOException {
- FileChannel inChannel = new FileInputStream(in).getChannel();
- FileChannel outChannel = new FileOutputStream(out).getChannel();
- try {
- // magic number for Windows, 64Mb - 32Kb)
- int maxCount = (64 * 1024 * 1024) - (32 * 1024);
- long size = inChannel.size();
- long position = 0;
- while (position < size) {
- position += inChannel.transferTo(position, maxCount, outChannel);
- }
- } catch (IOException e) {
- throw e;
- }
- finally {
- if (inChannel != null) {
- inChannel.close();
- }
- if (outChannel != null) {
- outChannel.close();
- }
- }
- }
-
- public static void copyInputStream(InputStream in, OutputStream out)throws IOException {
-
- byte[] buffer = new byte[1024];
- int len;
-
- while((len = in.read(buffer)) >= 0) {
- out.write(buffer, 0, len);
- }
-
- }
-
- public static String getIndentString(int length) {
- String indent = (String) DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING);
+
+ public static void copyFile(File in, File out) throws IOException {
+ FileChannel inChannel = new FileInputStream(in).getChannel();
+ FileChannel outChannel = new FileOutputStream(out).getChannel();
+ try {
+ // magic number for Windows, 64Mb - 32Kb)
+ int maxCount = (64 * 1024 * 1024) - (32 * 1024);
+ long size = inChannel.size();
+ long position = 0;
+ while (position < size) {
+ position += inChannel.transferTo(position, maxCount, outChannel);
+ }
+ }
+ catch (IOException e) {
+ throw e;
+ }
+ finally {
+ if (inChannel != null) {
+ inChannel.close();
+ }
+ if (outChannel != null) {
+ outChannel.close();
+ }
+ }
+ }
+
+ public static void copyInputStream(InputStream in, OutputStream out) throws IOException {
+
+ byte[] buffer = new byte[1024];
+ int len;
+
+ while ((len = in.read(buffer)) >= 0) {
+ out.write(buffer, 0, len);
+ }
+ }
+
+ public static String getIndentString(int length) {
+ String indent = (String)DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING);
StringBuilder buf = new StringBuilder();
- while(length-->0) {
- buf.append(indent);
- }
- return buf.toString();
- }
-
-
- public static boolean equalSets(Collection<?> c1, Collection<?> c2) {
-
- if(c1 == null) {
- return c2 == null?true:false;
- } else {
- if(c2 == null) {
- return false;
- }
- }
-
- if(c1.size() != c2.size()) {
- return false;
- }
-
- HashSet<?> set = new HashSet(c1);
- set.removeAll(c2);
-
- return (set.size() == 0);
- }
-
- public static boolean equalObjects(Object first, Object second) {
- return first==null?second==null:first.equals(second);
- }
-
- public static boolean equalObjectArrays(Object[] first, Object[] second) {
-
- if(first == null || second == null) {
- return equalObjects(first, second);
- } else {
- if(first.length != second.length) {
- return false;
- }
-
- for(int i=0;i<first.length;i++) {
- if(!equalObjects(first[i], second[i])) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- public static boolean equalLists(List<?> first, List<?> second) {
-
- if(first == null) {
- return second == null;
- } else if(second == null) {
- return first == null;
- }
-
- if(first.size() == second.size()) {
- for(int i=0;i<first.size();i++) {
- if(!equalObjects(first.get(i), second.get(i))) {
- return false;
- }
- }
- return true;
- }
-
- return false;
- }
-
- public static boolean isPrintableUnicode(char c) {
+ while (length-- > 0) {
+ buf.append(indent);
+ }
+ return buf.toString();
+ }
+
+
+ public static boolean equalSets(Collection<?> c1, Collection<?> c2) {
+
+ if (c1 == null) {
+ return c2 == null ? true : false;
+ }
+ else {
+ if (c2 == null) {
+ return false;
+ }
+ }
+
+ if (c1.size() != c2.size()) {
+ return false;
+ }
+
+ HashSet<?> set = new HashSet(c1);
+ set.removeAll(c2);
+
+ return (set.size() == 0);
+ }
+
+ public static boolean equalObjects(Object first, Object second) {
+ return first == null ? second == null : first.equals(second);
+ }
+
+ public static boolean equalObjectArrays(Object[] first, Object[] second) {
+
+ if (first == null || second == null) {
+ return equalObjects(first, second);
+ }
+ else {
+ if (first.length != second.length) {
+ return false;
+ }
+
+ for (int i = 0; i < first.length; i++) {
+ if (!equalObjects(first[i], second[i])) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean equalLists(List<?> first, List<?> second) {
+
+ if (first == null) {
+ return second == null;
+ }
+ else if (second == null) {
+ return first == null;
+ }
+
+ if (first.size() == second.size()) {
+ for (int i = 0; i < first.size(); i++) {
+ if (!equalObjects(first.get(i), second.get(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ public static boolean isPrintableUnicode(char c) {
int t = Character.getType(c);
return t != Character.UNASSIGNED && t != Character.LINE_SEPARATOR && t != Character.PARAGRAPH_SEPARATOR &&
t != Character.CONTROL && t != Character.FORMAT && t != Character.PRIVATE_USE && t != Character.SURROGATE;
}
- public static String charToUnicodeLiteral(int value) {
- String sTemp = Integer.toHexString(value);
- sTemp = ("0000"+sTemp).substring(sTemp.length());
- return "\\u"+sTemp;
- }
-
- public static String makeUniqueKey(String name, String descriptor) {
- return name+" "+descriptor;
- }
-
+ public static String charToUnicodeLiteral(int value) {
+ String sTemp = Integer.toHexString(value);
+ sTemp = ("0000" + sTemp).substring(sTemp.length());
+ return "\\u" + sTemp;
+ }
+
+ public static String makeUniqueKey(String name, String descriptor) {
+ return name + " " + descriptor;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/util/ListStack.java b/src/org/jetbrains/java/decompiler/util/ListStack.java
index fa36a0b..20c6614 100644
--- a/src/org/jetbrains/java/decompiler/util/ListStack.java
+++ b/src/org/jetbrains/java/decompiler/util/ListStack.java
@@ -1,101 +1,101 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.util;
import java.util.ArrayList;
public class ListStack<T> extends ArrayList<T> {
- protected int pointer = 0;
-
- public ListStack(){
- super();
- }
-
- public ListStack(ArrayList<T> list){
- super(list);
- }
-
- public ListStack<T> clone() {
- ListStack<T> newstack = new ListStack<T>(this);
- newstack.pointer = this.pointer;
- return newstack;
- }
-
- public T push(T item) {
- this.add(item);
- pointer++;
- return item;
- }
-
- public T pop() {
- pointer--;
- T o = this.get(pointer);
- this.remove(pointer);
- return o;
- }
-
- public T pop(int count) {
- T o = null;
- for(int i=count;i>0;i--) {
- o = this.pop();
- }
- return o;
- }
-
- public void remove() {
- pointer--;
- this.remove(pointer);
- }
-
- public void removeMultiple(int count) {
- while(count>0) {
- pointer--;
- this.remove(pointer);
- count--;
- }
- }
-
- public boolean empty() {
- return (pointer==0);
- }
-
- public int getPointer() {
- return pointer;
- }
-
- public T get(int index) {
- return super.get(index);
- }
-
- public T set(int index, T element) {
- return super.set(index, element);
- }
-
- public T getByOffset(int offset) {
- return this.get(pointer+offset);
- }
-
- public void insertByOffset(int offset, T item) {
- this.add(pointer+offset, item);
- pointer++;
- }
-
- public void clear() {
- super.clear();
- pointer = 0;
- }
-
+ protected int pointer = 0;
+
+ public ListStack() {
+ super();
+ }
+
+ public ListStack(ArrayList<T> list) {
+ super(list);
+ }
+
+ public ListStack<T> clone() {
+ ListStack<T> newstack = new ListStack<T>(this);
+ newstack.pointer = this.pointer;
+ return newstack;
+ }
+
+ public T push(T item) {
+ this.add(item);
+ pointer++;
+ return item;
+ }
+
+ public T pop() {
+ pointer--;
+ T o = this.get(pointer);
+ this.remove(pointer);
+ return o;
+ }
+
+ public T pop(int count) {
+ T o = null;
+ for (int i = count; i > 0; i--) {
+ o = this.pop();
+ }
+ return o;
+ }
+
+ public void remove() {
+ pointer--;
+ this.remove(pointer);
+ }
+
+ public void removeMultiple(int count) {
+ while (count > 0) {
+ pointer--;
+ this.remove(pointer);
+ count--;
+ }
+ }
+
+ public boolean empty() {
+ return (pointer == 0);
+ }
+
+ public int getPointer() {
+ return pointer;
+ }
+
+ public T get(int index) {
+ return super.get(index);
+ }
+
+ public T set(int index, T element) {
+ return super.set(index, element);
+ }
+
+ public T getByOffset(int offset) {
+ return this.get(pointer + offset);
+ }
+
+ public void insertByOffset(int offset, T item) {
+ this.add(pointer + offset, item);
+ pointer++;
+ }
+
+ public void clear() {
+ super.clear();
+ pointer = 0;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/util/SFormsFastMap.java b/src/org/jetbrains/java/decompiler/util/SFormsFastMap.java
index 546e32e..26fb216 100644
--- a/src/org/jetbrains/java/decompiler/util/SFormsFastMap.java
+++ b/src/org/jetbrains/java/decompiler/util/SFormsFastMap.java
@@ -1,232 +1,251 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.util;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
-
public class SFormsFastMap<E> {
- private int size;
-
- private List<E[]> lstElements = new ArrayList<E[]>(3);
-
- {
- lstElements.add((E[])new Object[5]);
- lstElements.add((E[])new Object[5]);
- lstElements.add((E[])new Object[5]);
- }
-
- public SFormsFastMap() {}
-
- public SFormsFastMap(SFormsFastMap<E> map) {
- for(int i=2;i>=0;i--) {
- E[] arr = map.lstElements.get(i);
- E[] arrnew = (E[])new Object[arr.length];
-
- System.arraycopy(arr, 0, arrnew, 0, arr.length);
-
- lstElements.set(i, arrnew);
-
- for(E element : arrnew) {
- if(element != null) {
- size++;
- }
- }
- }
-
- }
-
- public int size() {
- return size;
- }
-
- public boolean isEmpty() {
- return size == 0;
- }
-
- public void put(int key, E value) {
- putInternal(key, value, false);
- }
-
- public void remove(int key) {
- putInternal(key, null, true);
- }
-
- public void removeAllFields() {
- E[] arr = lstElements.get(2);
- for(int i=arr.length-1;i>=0;i--) {
- E val = arr[i];
- if(val != null) {
- arr[i] = null;
- size--;
- }
- }
- }
-
- public void putInternal(final int key, final E value, boolean remove) {
-
- int index = 0;
- int ikey = key;
- if(ikey < 0) {
- index = 2;
- ikey = -ikey;
- } else if(ikey >= VarExprent.STACK_BASE) {
- index = 1;
- ikey -= VarExprent.STACK_BASE;
- }
-
- E[] arr = lstElements.get(index);
- if(ikey >= arr.length) {
- if(remove) {
- return;
- } else {
- arr = ensureCapacity(arr, ikey+1, false);
- lstElements.set(index, arr);
- }
- }
-
- E oldval = arr[ikey];
- arr[ikey] = value;
-
- if(oldval == null && value != null) {
- size++;
- } else if(oldval != null && value == null) {
- size--;
- }
- }
-
- public boolean containsKey(int key) {
- return get(key) != null;
- }
-
- public E get(int key) {
-
- int index = 0;
- if(key < 0) {
- index = 2;
- key = -key;
- } else if(key >= VarExprent.STACK_BASE) {
- index = 1;
- key -= VarExprent.STACK_BASE;
- }
-
- E[] arr = lstElements.get(index);
-
- if(key < arr.length) {
- return arr[key];
- }
- return null;
- }
-
- public void union(SFormsFastMap<E> map, IElementsUnion<E> union) {
-
- for(int i=2;i>=0;i--) {
- E[] lstOwn = lstElements.get(i);
- E[] lstExtern = map.lstElements.get(i);
-
- int externsize = lstExtern.length;
-
- if(lstOwn.length<externsize) {
- lstOwn = ensureCapacity(lstOwn, externsize, true);
- lstElements.set(i, lstOwn);
- }
-
- int ownsize = lstOwn.length;
- int minsize = ownsize>externsize?externsize:ownsize;
-
- for(int j=minsize-1;j>=0;j--) {
- E second = lstExtern[j];
-
- if(second != null) {
- E first = lstOwn[j];
-
- if(first == null) {
- lstOwn[j] = union.copy(second);
- size++;
- } else {
- union.union(first, second);
- }
- }
- }
-
-// ITimer timer = TimerFactory.newTimer();
-// timer.start();
-//
-// if(externsize > minsize) {
-// for(int j=minsize;j<externsize;j++) {
-// E second = lstExtern.get(j);
-// if(second != null) {
-// lstOwn.add(union.copy(second));
-// size++;
-// } else {
-// lstOwn.add(null);
-// }
-// }
-// }
-//
-// timer.stop();
-// Timer.addTime("sformunion", timer.getDuration());
-
- }
-
- }
-
- public List<Entry<Integer, E>> entryList() {
- List<Entry<Integer, E>> list = new ArrayList<Entry<Integer, E>>();
-
- for(int i=2;i>=0;i--) {
- int ikey = 0;
- for(final E ent : lstElements.get(i)) {
- if(ent != null) {
- final int key = i==0?ikey:(i==1?ikey+VarExprent.STACK_BASE:-ikey);
-
- list.add(new Entry<Integer, E>() {
-
- private Integer var = key;
- private E val = ent;
-
- public Integer getKey() {
- return var;
- }
-
- public E getValue() {
- return val;
- }
-
- public E setValue(E newvalue) {
- return null;
- }
- });
- }
-
- ikey++;
- }
- }
-
- return list;
- }
-
- private E[] ensureCapacity(E[] arr, int size, boolean exact) {
-
- int minsize = size;
- if(!exact) {
- minsize = 2*arr.length/3 +1;
- if(size > minsize) {
- minsize = size;
- }
- }
-
- E[] arrnew = (E[])new Object[minsize];
- System.arraycopy(arr, 0, arrnew, 0, arr.length);
-
- return arrnew;
- }
-
- public static interface IElementsUnion<E> {
- public E union(E first, E second);
- public E copy(E element);
- }
-
+ private int size;
+
+ private List<E[]> lstElements = new ArrayList<E[]>(3);
+
+ {
+ lstElements.add((E[])new Object[5]);
+ lstElements.add((E[])new Object[5]);
+ lstElements.add((E[])new Object[5]);
+ }
+
+ public SFormsFastMap() {
+ }
+
+ public SFormsFastMap(SFormsFastMap<E> map) {
+ for (int i = 2; i >= 0; i--) {
+ E[] arr = map.lstElements.get(i);
+ E[] arrnew = (E[])new Object[arr.length];
+
+ System.arraycopy(arr, 0, arrnew, 0, arr.length);
+
+ lstElements.set(i, arrnew);
+
+ for (E element : arrnew) {
+ if (element != null) {
+ size++;
+ }
+ }
+ }
+ }
+
+ public int size() {
+ return size;
+ }
+
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ public void put(int key, E value) {
+ putInternal(key, value, false);
+ }
+
+ public void remove(int key) {
+ putInternal(key, null, true);
+ }
+
+ public void removeAllFields() {
+ E[] arr = lstElements.get(2);
+ for (int i = arr.length - 1; i >= 0; i--) {
+ E val = arr[i];
+ if (val != null) {
+ arr[i] = null;
+ size--;
+ }
+ }
+ }
+
+ public void putInternal(final int key, final E value, boolean remove) {
+
+ int index = 0;
+ int ikey = key;
+ if (ikey < 0) {
+ index = 2;
+ ikey = -ikey;
+ }
+ else if (ikey >= VarExprent.STACK_BASE) {
+ index = 1;
+ ikey -= VarExprent.STACK_BASE;
+ }
+
+ E[] arr = lstElements.get(index);
+ if (ikey >= arr.length) {
+ if (remove) {
+ return;
+ }
+ else {
+ arr = ensureCapacity(arr, ikey + 1, false);
+ lstElements.set(index, arr);
+ }
+ }
+
+ E oldval = arr[ikey];
+ arr[ikey] = value;
+
+ if (oldval == null && value != null) {
+ size++;
+ }
+ else if (oldval != null && value == null) {
+ size--;
+ }
+ }
+
+ public boolean containsKey(int key) {
+ return get(key) != null;
+ }
+
+ public E get(int key) {
+
+ int index = 0;
+ if (key < 0) {
+ index = 2;
+ key = -key;
+ }
+ else if (key >= VarExprent.STACK_BASE) {
+ index = 1;
+ key -= VarExprent.STACK_BASE;
+ }
+
+ E[] arr = lstElements.get(index);
+
+ if (key < arr.length) {
+ return arr[key];
+ }
+ return null;
+ }
+
+ public void union(SFormsFastMap<E> map, IElementsUnion<E> union) {
+
+ for (int i = 2; i >= 0; i--) {
+ E[] lstOwn = lstElements.get(i);
+ E[] lstExtern = map.lstElements.get(i);
+
+ int externsize = lstExtern.length;
+
+ if (lstOwn.length < externsize) {
+ lstOwn = ensureCapacity(lstOwn, externsize, true);
+ lstElements.set(i, lstOwn);
+ }
+
+ int ownsize = lstOwn.length;
+ int minsize = ownsize > externsize ? externsize : ownsize;
+
+ for (int j = minsize - 1; j >= 0; j--) {
+ E second = lstExtern[j];
+
+ if (second != null) {
+ E first = lstOwn[j];
+
+ if (first == null) {
+ lstOwn[j] = union.copy(second);
+ size++;
+ }
+ else {
+ union.union(first, second);
+ }
+ }
+ }
+
+ // ITimer timer = TimerFactory.newTimer();
+ // timer.start();
+ //
+ // if(externsize > minsize) {
+ // for(int j=minsize;j<externsize;j++) {
+ // E second = lstExtern.get(j);
+ // if(second != null) {
+ // lstOwn.add(union.copy(second));
+ // size++;
+ // } else {
+ // lstOwn.add(null);
+ // }
+ // }
+ // }
+ //
+ // timer.stop();
+ // Timer.addTime("sformunion", timer.getDuration());
+
+ }
+ }
+
+ public List<Entry<Integer, E>> entryList() {
+ List<Entry<Integer, E>> list = new ArrayList<Entry<Integer, E>>();
+
+ for (int i = 2; i >= 0; i--) {
+ int ikey = 0;
+ for (final E ent : lstElements.get(i)) {
+ if (ent != null) {
+ final int key = i == 0 ? ikey : (i == 1 ? ikey + VarExprent.STACK_BASE : -ikey);
+
+ list.add(new Entry<Integer, E>() {
+
+ private Integer var = key;
+ private E val = ent;
+
+ public Integer getKey() {
+ return var;
+ }
+
+ public E getValue() {
+ return val;
+ }
+
+ public E setValue(E newvalue) {
+ return null;
+ }
+ });
+ }
+
+ ikey++;
+ }
+ }
+
+ return list;
+ }
+
+ private E[] ensureCapacity(E[] arr, int size, boolean exact) {
+
+ int minsize = size;
+ if (!exact) {
+ minsize = 2 * arr.length / 3 + 1;
+ if (size > minsize) {
+ minsize = size;
+ }
+ }
+
+ E[] arrnew = (E[])new Object[minsize];
+ System.arraycopy(arr, 0, arrnew, 0, arr.length);
+
+ return arrnew;
+ }
+
+ public static interface IElementsUnion<E> {
+ public E union(E first, E second);
+
+ public E copy(E element);
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java b/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java
index 615162f..089225d 100644
--- a/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java
+++ b/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java
@@ -1,411 +1,413 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.util;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import java.util.Map.Entry;
-
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
-import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+import java.util.Set;
public class SFormsFastMapDirect {
- private int size;
-
- private FastSparseSet<Integer>[][] elements = new FastSparseSet[3][];
-
- private int[][] next = new int[3][];
-
- public SFormsFastMapDirect() {
- this(true);
- }
-
- private SFormsFastMapDirect(boolean initialize) {
- if(initialize) {
- for(int i=2; i>=0; i--) {
- elements[i] = new FastSparseSet[0];
- next[i] = new int[0];
- }
- }
- }
-
- public SFormsFastMapDirect(SFormsFastMapDirect map) {
- for(int i=2;i>=0;i--) {
- FastSparseSet<Integer>[] arr = map.elements[i];
- int[] arrnext = map.next[i];
-
- int length = arr.length;
- FastSparseSet<Integer>[] arrnew = new FastSparseSet[length];
- int[] arrnextnew = new int[length];
-
- System.arraycopy(arr, 0, arrnew, 0, length);
- System.arraycopy(arrnext, 0, arrnextnew, 0, length);
-
- elements[i] = arrnew;
- next[i] = arrnextnew;
-
- size = map.size;
- }
- }
-
- public SFormsFastMapDirect getCopy() {
-
- SFormsFastMapDirect map = new SFormsFastMapDirect(false);
- map.size = size;
-
- FastSparseSet[][] mapelements = map.elements;
- int[][] mapnext = map.next;
-
- for(int i=2;i>=0;i--) {
- FastSparseSet<Integer>[] arr = elements[i];
- int length = arr.length;
-
- if(length > 0) {
- int[] arrnext = next[i];
-
- FastSparseSet<Integer>[] arrnew = new FastSparseSet[length];
- int[] arrnextnew = new int[length];
-
- System.arraycopy(arrnext, 0, arrnextnew, 0, length);
-
- mapelements[i] = arrnew;
- mapnext[i] = arrnextnew;
-
- int pointer = 0;
- do {
- FastSparseSet<Integer> set = arr[pointer];
- if(set != null) {
- arrnew[pointer] = set.getCopy();
- }
-
- pointer = arrnext[pointer];
- } while(pointer != 0);
-
- } else {
- mapelements[i] = new FastSparseSet[0];
- mapnext[i] = new int[0];
- }
- }
-
- return map;
- }
-
- public int size() {
- return size;
- }
-
- public boolean isEmpty() {
- return size == 0;
- }
-
- public void put(int key, FastSparseSet<Integer> value) {
- putInternal(key, value, false);
- }
-
- public void remove(int key) {
- putInternal(key, null, true);
- }
-
- public void removeAllFields() {
- FastSparseSet<Integer>[] arr = elements[2];
- int[] arrnext = next[2];
-
- for(int i=arr.length-1;i>=0;i--) {
- FastSparseSet<Integer> val = arr[i];
- if(val != null) {
- arr[i] = null;
- size--;
- }
- arrnext[i] = 0;
- }
- }
-
- public void putInternal(final int key, final FastSparseSet<Integer> value, boolean remove) {
-
- int index = 0;
- int ikey = key;
- if(ikey < 0) {
- index = 2;
- ikey = -ikey;
- } else if(ikey >= VarExprent.STACK_BASE) {
- index = 1;
- ikey -= VarExprent.STACK_BASE;
- }
-
- FastSparseSet<Integer>[] arr = elements[index];
- if(ikey >= arr.length) {
- if(remove) {
- return;
- } else {
- arr = ensureCapacity(index, ikey+1, false);
- }
- }
-
- FastSparseSet<Integer> oldval = arr[ikey];
- arr[ikey] = value;
-
- int[] arrnext = next[index];
-
- if(oldval == null && value != null) {
- size++;
- changeNext(arrnext, ikey, arrnext[ikey], ikey);
- } else if(oldval != null && value == null) {
- size--;
- changeNext(arrnext, ikey, ikey, arrnext[ikey]);
- }
- }
-
- private void changeNext(int[] arrnext, int key, int oldnext, int newnext) {
- for(int i=key-1;i>=0;i--) {
- if(arrnext[i] == oldnext) {
- arrnext[i] = newnext;
- } else {
- break;
- }
- }
- }
-
- public boolean containsKey(int key) {
- return get(key) != null;
- }
-
- public FastSparseSet<Integer> get(int key) {
-
- int index = 0;
- if(key < 0) {
- index = 2;
- key = -key;
- } else if(key >= VarExprent.STACK_BASE) {
- index = 1;
- key -= VarExprent.STACK_BASE;
- }
-
- FastSparseSet<Integer>[] arr = elements[index];
-
- if(key < arr.length) {
- return arr[key];
- }
- return null;
- }
-
- public void complement(SFormsFastMapDirect map) {
-
- for(int i=2;i>=0;i--) {
- FastSparseSet<Integer>[] lstOwn = elements[i];
-
- if(lstOwn.length == 0) {
- continue;
- }
-
- FastSparseSet<Integer>[] lstExtern = map.elements[i];
- int[] arrnext = next[i];
-
- int pointer = 0;
- do {
- FastSparseSet<Integer> first = lstOwn[pointer];
-
- if(first != null) {
- if(pointer >= lstExtern.length) {
- break;
- }
- FastSparseSet<Integer> second = lstExtern[pointer];
-
- if(second != null) {
- first.complement(second);
- if(first.isEmpty()) {
- lstOwn[pointer] = null;
- size--;
- changeNext(arrnext, pointer, pointer, arrnext[pointer]);
- }
- }
- }
-
- pointer = arrnext[pointer];
-
- } while(pointer != 0);
-
- }
-
- }
-
- public void intersection(SFormsFastMapDirect map) {
-
- for(int i=2;i>=0;i--) {
- FastSparseSet<Integer>[] lstOwn = elements[i];
-
- if(lstOwn.length == 0) {
- continue;
- }
-
- FastSparseSet<Integer>[] lstExtern = map.elements[i];
- int[] arrnext = next[i];
-
- int pointer = 0;
- do {
- FastSparseSet<Integer> first = lstOwn[pointer];
-
- if(first != null) {
- FastSparseSet<Integer> second = null;
- if(pointer < lstExtern.length) {
- second = lstExtern[pointer];
- }
-
- if(second != null) {
- first.intersection(second);
- }
-
- if(second == null || first.isEmpty()) {
- lstOwn[pointer] = null;
- size--;
- changeNext(arrnext, pointer, pointer, arrnext[pointer]);
- }
- }
-
- pointer = arrnext[pointer];
-
- } while(pointer != 0);
-
- }
-
- }
-
- public void union(SFormsFastMapDirect map) {
-
- for(int i=2;i>=0;i--) {
- FastSparseSet<Integer>[] lstExtern = map.elements[i];
-
- if(lstExtern.length == 0) {
- continue;
- }
-
- FastSparseSet<Integer>[] lstOwn = elements[i];
- int[] arrnext = next[i];
- int[] arrnextExtern = map.next[i];
-
- int pointer = 0;
- do {
- if(pointer >= lstOwn.length) {
- lstOwn = ensureCapacity(i, lstExtern.length, true);
- arrnext = next[i];
- }
-
- FastSparseSet<Integer> second = lstExtern[pointer];
-
- if(second != null) {
- FastSparseSet<Integer> first = lstOwn[pointer];
-
- if(first == null) {
- lstOwn[pointer] = second.getCopy();
- size++;
- changeNext(arrnext, pointer, arrnext[pointer], pointer);
- } else {
- first.union(second);
- }
- }
-
- pointer = arrnextExtern[pointer];
-
- } while(pointer != 0);
-
- }
-
- }
-
- public String toString() {
-
- StringBuilder buffer = new StringBuilder("{");
-
- List<Entry<Integer, FastSparseSet<Integer>>> lst = entryList();
- if(lst != null) {
- boolean first = true;
- for(Entry<Integer, FastSparseSet<Integer>> entry : lst) {
- if(!first) {
- buffer.append(", ");
- } else {
- first = false;
- }
-
- Set<Integer> set = entry.getValue().toPlainSet();
- buffer.append(entry.getKey()+"={"+set.toString()+"}");
- }
- }
-
- buffer.append("}");
- return buffer.toString();
- }
-
- public List<Entry<Integer, FastSparseSet<Integer>>> entryList() {
- List<Entry<Integer, FastSparseSet<Integer>>> list = new ArrayList<Entry<Integer, FastSparseSet<Integer>>>();
-
- for(int i=2;i>=0;i--) {
- int ikey = 0;
- for(final FastSparseSet<Integer> ent : elements[i]) {
- if(ent != null) {
- final int key = i==0?ikey:(i==1?ikey+VarExprent.STACK_BASE:-ikey);
-
- list.add(new Entry<Integer, FastSparseSet<Integer>>() {
-
- private Integer var = key;
- private FastSparseSet<Integer> val = ent;
-
- public Integer getKey() {
- return var;
- }
-
- public FastSparseSet<Integer> getValue() {
- return val;
- }
-
- public FastSparseSet<Integer> setValue(FastSparseSet<Integer> newvalue) {
- return null;
- }
- });
- }
-
- ikey++;
- }
- }
-
- return list;
- }
-
- private FastSparseSet<Integer>[] ensureCapacity(int index, int size, boolean exact) {
-
- FastSparseSet<Integer>[] arr = elements[index];
- int[] arrnext = next[index];
-
- int minsize = size;
- if(!exact) {
- minsize = 2*arr.length/3 +1;
- if(size > minsize) {
- minsize = size;
- }
- }
-
- FastSparseSet<Integer>[] arrnew = new FastSparseSet[minsize];
- System.arraycopy(arr, 0, arrnew, 0, arr.length);
-
- int[] arrnextnew = new int[minsize];
- System.arraycopy(arrnext, 0, arrnextnew, 0, arrnext.length);
-
- elements[index] = arrnew;
- next[index] = arrnextnew;
-
- return arrnew;
- }
-
+ private int size;
+
+ private FastSparseSet<Integer>[][] elements = new FastSparseSet[3][];
+
+ private int[][] next = new int[3][];
+
+ public SFormsFastMapDirect() {
+ this(true);
+ }
+
+ private SFormsFastMapDirect(boolean initialize) {
+ if (initialize) {
+ for (int i = 2; i >= 0; i--) {
+ elements[i] = new FastSparseSet[0];
+ next[i] = new int[0];
+ }
+ }
+ }
+
+ public SFormsFastMapDirect(SFormsFastMapDirect map) {
+ for (int i = 2; i >= 0; i--) {
+ FastSparseSet<Integer>[] arr = map.elements[i];
+ int[] arrnext = map.next[i];
+
+ int length = arr.length;
+ FastSparseSet<Integer>[] arrnew = new FastSparseSet[length];
+ int[] arrnextnew = new int[length];
+
+ System.arraycopy(arr, 0, arrnew, 0, length);
+ System.arraycopy(arrnext, 0, arrnextnew, 0, length);
+
+ elements[i] = arrnew;
+ next[i] = arrnextnew;
+
+ size = map.size;
+ }
+ }
+
+ public SFormsFastMapDirect getCopy() {
+
+ SFormsFastMapDirect map = new SFormsFastMapDirect(false);
+ map.size = size;
+
+ FastSparseSet[][] mapelements = map.elements;
+ int[][] mapnext = map.next;
+
+ for (int i = 2; i >= 0; i--) {
+ FastSparseSet<Integer>[] arr = elements[i];
+ int length = arr.length;
+
+ if (length > 0) {
+ int[] arrnext = next[i];
+
+ FastSparseSet<Integer>[] arrnew = new FastSparseSet[length];
+ int[] arrnextnew = new int[length];
+
+ System.arraycopy(arrnext, 0, arrnextnew, 0, length);
+
+ mapelements[i] = arrnew;
+ mapnext[i] = arrnextnew;
+
+ int pointer = 0;
+ do {
+ FastSparseSet<Integer> set = arr[pointer];
+ if (set != null) {
+ arrnew[pointer] = set.getCopy();
+ }
+
+ pointer = arrnext[pointer];
+ }
+ while (pointer != 0);
+ }
+ else {
+ mapelements[i] = new FastSparseSet[0];
+ mapnext[i] = new int[0];
+ }
+ }
+
+ return map;
+ }
+
+ public int size() {
+ return size;
+ }
+
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ public void put(int key, FastSparseSet<Integer> value) {
+ putInternal(key, value, false);
+ }
+
+ public void remove(int key) {
+ putInternal(key, null, true);
+ }
+
+ public void removeAllFields() {
+ FastSparseSet<Integer>[] arr = elements[2];
+ int[] arrnext = next[2];
+
+ for (int i = arr.length - 1; i >= 0; i--) {
+ FastSparseSet<Integer> val = arr[i];
+ if (val != null) {
+ arr[i] = null;
+ size--;
+ }
+ arrnext[i] = 0;
+ }
+ }
+
+ public void putInternal(final int key, final FastSparseSet<Integer> value, boolean remove) {
+
+ int index = 0;
+ int ikey = key;
+ if (ikey < 0) {
+ index = 2;
+ ikey = -ikey;
+ }
+ else if (ikey >= VarExprent.STACK_BASE) {
+ index = 1;
+ ikey -= VarExprent.STACK_BASE;
+ }
+
+ FastSparseSet<Integer>[] arr = elements[index];
+ if (ikey >= arr.length) {
+ if (remove) {
+ return;
+ }
+ else {
+ arr = ensureCapacity(index, ikey + 1, false);
+ }
+ }
+
+ FastSparseSet<Integer> oldval = arr[ikey];
+ arr[ikey] = value;
+
+ int[] arrnext = next[index];
+
+ if (oldval == null && value != null) {
+ size++;
+ changeNext(arrnext, ikey, arrnext[ikey], ikey);
+ }
+ else if (oldval != null && value == null) {
+ size--;
+ changeNext(arrnext, ikey, ikey, arrnext[ikey]);
+ }
+ }
+
+ private void changeNext(int[] arrnext, int key, int oldnext, int newnext) {
+ for (int i = key - 1; i >= 0; i--) {
+ if (arrnext[i] == oldnext) {
+ arrnext[i] = newnext;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ public boolean containsKey(int key) {
+ return get(key) != null;
+ }
+
+ public FastSparseSet<Integer> get(int key) {
+
+ int index = 0;
+ if (key < 0) {
+ index = 2;
+ key = -key;
+ }
+ else if (key >= VarExprent.STACK_BASE) {
+ index = 1;
+ key -= VarExprent.STACK_BASE;
+ }
+
+ FastSparseSet<Integer>[] arr = elements[index];
+
+ if (key < arr.length) {
+ return arr[key];
+ }
+ return null;
+ }
+
+ public void complement(SFormsFastMapDirect map) {
+
+ for (int i = 2; i >= 0; i--) {
+ FastSparseSet<Integer>[] lstOwn = elements[i];
+
+ if (lstOwn.length == 0) {
+ continue;
+ }
+
+ FastSparseSet<Integer>[] lstExtern = map.elements[i];
+ int[] arrnext = next[i];
+
+ int pointer = 0;
+ do {
+ FastSparseSet<Integer> first = lstOwn[pointer];
+
+ if (first != null) {
+ if (pointer >= lstExtern.length) {
+ break;
+ }
+ FastSparseSet<Integer> second = lstExtern[pointer];
+
+ if (second != null) {
+ first.complement(second);
+ if (first.isEmpty()) {
+ lstOwn[pointer] = null;
+ size--;
+ changeNext(arrnext, pointer, pointer, arrnext[pointer]);
+ }
+ }
+ }
+
+ pointer = arrnext[pointer];
+ }
+ while (pointer != 0);
+ }
+ }
+
+ public void intersection(SFormsFastMapDirect map) {
+
+ for (int i = 2; i >= 0; i--) {
+ FastSparseSet<Integer>[] lstOwn = elements[i];
+
+ if (lstOwn.length == 0) {
+ continue;
+ }
+
+ FastSparseSet<Integer>[] lstExtern = map.elements[i];
+ int[] arrnext = next[i];
+
+ int pointer = 0;
+ do {
+ FastSparseSet<Integer> first = lstOwn[pointer];
+
+ if (first != null) {
+ FastSparseSet<Integer> second = null;
+ if (pointer < lstExtern.length) {
+ second = lstExtern[pointer];
+ }
+
+ if (second != null) {
+ first.intersection(second);
+ }
+
+ if (second == null || first.isEmpty()) {
+ lstOwn[pointer] = null;
+ size--;
+ changeNext(arrnext, pointer, pointer, arrnext[pointer]);
+ }
+ }
+
+ pointer = arrnext[pointer];
+ }
+ while (pointer != 0);
+ }
+ }
+
+ public void union(SFormsFastMapDirect map) {
+
+ for (int i = 2; i >= 0; i--) {
+ FastSparseSet<Integer>[] lstExtern = map.elements[i];
+
+ if (lstExtern.length == 0) {
+ continue;
+ }
+
+ FastSparseSet<Integer>[] lstOwn = elements[i];
+ int[] arrnext = next[i];
+ int[] arrnextExtern = map.next[i];
+
+ int pointer = 0;
+ do {
+ if (pointer >= lstOwn.length) {
+ lstOwn = ensureCapacity(i, lstExtern.length, true);
+ arrnext = next[i];
+ }
+
+ FastSparseSet<Integer> second = lstExtern[pointer];
+
+ if (second != null) {
+ FastSparseSet<Integer> first = lstOwn[pointer];
+
+ if (first == null) {
+ lstOwn[pointer] = second.getCopy();
+ size++;
+ changeNext(arrnext, pointer, arrnext[pointer], pointer);
+ }
+ else {
+ first.union(second);
+ }
+ }
+
+ pointer = arrnextExtern[pointer];
+ }
+ while (pointer != 0);
+ }
+ }
+
+ public String toString() {
+
+ StringBuilder buffer = new StringBuilder("{");
+
+ List<Entry<Integer, FastSparseSet<Integer>>> lst = entryList();
+ if (lst != null) {
+ boolean first = true;
+ for (Entry<Integer, FastSparseSet<Integer>> entry : lst) {
+ if (!first) {
+ buffer.append(", ");
+ }
+ else {
+ first = false;
+ }
+
+ Set<Integer> set = entry.getValue().toPlainSet();
+ buffer.append(entry.getKey() + "={" + set.toString() + "}");
+ }
+ }
+
+ buffer.append("}");
+ return buffer.toString();
+ }
+
+ public List<Entry<Integer, FastSparseSet<Integer>>> entryList() {
+ List<Entry<Integer, FastSparseSet<Integer>>> list = new ArrayList<Entry<Integer, FastSparseSet<Integer>>>();
+
+ for (int i = 2; i >= 0; i--) {
+ int ikey = 0;
+ for (final FastSparseSet<Integer> ent : elements[i]) {
+ if (ent != null) {
+ final int key = i == 0 ? ikey : (i == 1 ? ikey + VarExprent.STACK_BASE : -ikey);
+
+ list.add(new Entry<Integer, FastSparseSet<Integer>>() {
+
+ private Integer var = key;
+ private FastSparseSet<Integer> val = ent;
+
+ public Integer getKey() {
+ return var;
+ }
+
+ public FastSparseSet<Integer> getValue() {
+ return val;
+ }
+
+ public FastSparseSet<Integer> setValue(FastSparseSet<Integer> newvalue) {
+ return null;
+ }
+ });
+ }
+
+ ikey++;
+ }
+ }
+
+ return list;
+ }
+
+ private FastSparseSet<Integer>[] ensureCapacity(int index, int size, boolean exact) {
+
+ FastSparseSet<Integer>[] arr = elements[index];
+ int[] arrnext = next[index];
+
+ int minsize = size;
+ if (!exact) {
+ minsize = 2 * arr.length / 3 + 1;
+ if (size > minsize) {
+ minsize = size;
+ }
+ }
+
+ FastSparseSet<Integer>[] arrnew = new FastSparseSet[minsize];
+ System.arraycopy(arr, 0, arrnew, 0, arr.length);
+
+ int[] arrnextnew = new int[minsize];
+ System.arraycopy(arrnext, 0, arrnextnew, 0, arrnext.length);
+
+ elements[index] = arrnew;
+ next[index] = arrnextnew;
+
+ return arrnew;
+ }
}
diff --git a/src/org/jetbrains/java/decompiler/util/SFormsFastMapOld.java b/src/org/jetbrains/java/decompiler/util/SFormsFastMapOld.java
index be3e7b7..834b3b6 100644
--- a/src/org/jetbrains/java/decompiler/util/SFormsFastMapOld.java
+++ b/src/org/jetbrains/java/decompiler/util/SFormsFastMapOld.java
@@ -1,270 +1,290 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.jetbrains.java.decompiler.util;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
-import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
-
public class SFormsFastMapOld<E> {
- private List<ArrayList<Entry<Integer, E>>> lstElements = new ArrayList<ArrayList<Entry<Integer, E>>>(3);
-
- {
- lstElements.add(new ArrayList<Entry<Integer, E>>());
- lstElements.add(new ArrayList<Entry<Integer, E>>());
- lstElements.add(new ArrayList<Entry<Integer, E>>());
- }
-
- public SFormsFastMapOld() {}
-
- public SFormsFastMapOld(SFormsFastMapOld<E> map) {
- for(int i=2;i>=0;i--) {
- lstElements.set(i, new ArrayList<Entry<Integer, E>>(map.lstElements.get(i)));
- }
- }
-
- public int size() {
- int size = 0;
- for(int i=2;i>=0;i--) {
- size += lstElements.get(i).size();
- }
- return size;
- }
-
- public boolean isEmpty() {
-
- for(int i=2;i>=0;i--) {
- if(!lstElements.get(i).isEmpty()) {
- return false;
- }
- }
-
- return true;
- }
-
- public void put(int key, E value) {
- putInternal(key, value, false);
- }
-
- public void remove(int key) {
- putInternal(key, null, true);
- }
-
- public void removeAllFields() {
- lstElements.get(2).clear();
- }
-
- public void putInternal(final int key, final E value, boolean remove) {
-
- int index = 0;
- int ikey = key;
- if(ikey < 0) {
- index = 2;
- ikey = -ikey;
- } else if(ikey >= VarExprent.STACK_BASE) {
- index = 1;
- ikey -= VarExprent.STACK_BASE;
- }
-
- ArrayList<Entry<Integer, E>> lst = lstElements.get(index);
- if(ikey >= lst.size()) {
- if(remove) {
- return;
- } else {
- ensureCapacity(lst, ikey+1, false);
- }
- }
-
- lst.set(ikey, value==null?null:new Entry<Integer, E>() {
-
- private Integer var = key;
- private E val = value;
-
- public Integer getKey() {
- return var;
- }
-
- public E getValue() {
- return val;
- }
-
- public E setValue(E newvalue) {
- val = newvalue;
- return null;
- }});
- }
-
- public boolean containsKey(int key) {
- return get(key) != null;
- }
-
- public E get(int key) {
-
- int index = 0;
- if(key < 0) {
- index = 2;
- key = -key;
- } else if(key >= VarExprent.STACK_BASE) {
- index = 1;
- key -= VarExprent.STACK_BASE;
- }
-
- ArrayList<Entry<Integer, E>> lst = lstElements.get(index);
-
- Entry<Integer, E> ent;
- if(key < lst.size() && (ent = lst.get(key)) != null) {
- return ent.getValue();
- }
- return null;
- }
-
- public void union(SFormsFastMapOld<E> map, IElementsUnion<E> union) {
-
- for(int i=2;i>=0;i--) {
- ArrayList<Entry<Integer, E>> lstOwn = lstElements.get(i);
- ArrayList<Entry<Integer, E>> lstExtern = map.lstElements.get(i);
-
- int ownsize = lstOwn.size();
- int externsize = lstExtern.size();
-
- int minsize = ownsize>externsize?externsize:ownsize;
-
- for(int j=minsize-1;j>=0;j--) {
- Entry<Integer, E> second = lstExtern.get(j);
-
- if(second != null) {
- Entry<Integer, E> first = lstOwn.get(j);
-
- if(first == null) {
- putInternal(second.getKey(), union.copy(second.getValue()), false);
- } else {
- first.setValue(union.union(first.getValue(), second.getValue()));
- }
- }
- }
-
- if(externsize > minsize) {
-// ensureCapacity(lstOwn, externsize, true);
-// lstOwn.addAll(lstExtern.subList(minsize, externsize));
-
- for(int j=minsize;j<externsize;j++) {
- Entry<Integer, E> second = lstExtern.get(j);
-// if(first != null) {
-// first.setValue(union.copy(first.getValue()));
-// }
-
- if(second != null) {
- putInternal(second.getKey(), union.copy(second.getValue()), false);
- }
-// lstOwn.add(lstExtern.get(j));
- }
- }
- }
-
- }
-
- public List<Entry<Integer, E>> entryList() {
- List<Entry<Integer, E>> list = new ArrayList<Entry<Integer, E>>();
-
- for(int i=2;i>=0;i--) {
- for(Entry<Integer, E> ent : lstElements.get(i)) {
- if(ent != null) {
- list.add(ent);
- }
- }
- }
-
- return list;
- }
-
-// public SFormsFastMapIterator iterator() {
-// return new SFormsFastMapIterator();
-// }
-
- private void ensureCapacity(ArrayList<Entry<Integer, E>> lst, int size, boolean exact) {
-
- if(!exact) {
- int minsize = 2*lst.size()/3 +1;
- if(minsize > size) {
- size = minsize;
- }
- }
-
- lst.ensureCapacity(size);
- for(int i=size-lst.size();i>0;i--) {
- lst.add(null);
- }
- }
-
- public static interface IElementsUnion<E> {
- public E union(E first, E second);
- public E copy(E element);
- }
-
-// public class SFormsFastMapIterator implements Iterator<Entry<Integer, E>> {
-//
-// private int[] pointer = new int[]{0, -1};
-// private int[] next_pointer = null;
-//
-// private int[] getNextIndex(int list, int index) {
-//
-// while(list < 3) {
-// ArrayList<E> lst = lstElements.get(list);
-//
-// while(++index < lst.size()) {
-// E element = lst.get(index);
-// if(element != null) {
-// return new int[] {list, index};
-// }
-// }
-//
-// index = -1;
-// list++;
-// }
-//
-// return null;
-// }
-//
-// public boolean hasNext() {
-// next_pointer = getNextIndex(pointer[0], pointer[1]);
-// return (next_pointer != null);
-// }
-//
-// public Entry<Integer, E> next() {
-// if(next_pointer != null) {
-// pointer = next_pointer;
-// } else {
-// int[] nextpointer = getNextIndex(pointer[0], pointer[1]);
-// if(nextpointer != null) {
-// pointer = nextpointer;
-// } else {
-// return null;
-// }
-// }
-//
-// next_pointer = null;
-//
-// return new Entry<Integer, E>() {
-// public Integer getKey() {
-// return null;
-// }
-//
-// public E getValue() {
-// return null;
-// }
-//
-// public E setValue(E value) {
-// throw new RuntimeException("not implemented!");
-// }
-// };
-// //lstElements.get(pointer[0]).get(pointer[1]);
-// }
-//
-// public void remove() {
-// throw new RuntimeException("not implemented!");
-// }
-//
-// }
-
+ private List<ArrayList<Entry<Integer, E>>> lstElements = new ArrayList<ArrayList<Entry<Integer, E>>>(3);
+
+ {
+ lstElements.add(new ArrayList<Entry<Integer, E>>());
+ lstElements.add(new ArrayList<Entry<Integer, E>>());
+ lstElements.add(new ArrayList<Entry<Integer, E>>());
+ }
+
+ public SFormsFastMapOld() {
+ }
+
+ public SFormsFastMapOld(SFormsFastMapOld<E> map) {
+ for (int i = 2; i >= 0; i--) {
+ lstElements.set(i, new ArrayList<Entry<Integer, E>>(map.lstElements.get(i)));
+ }
+ }
+
+ public int size() {
+ int size = 0;
+ for (int i = 2; i >= 0; i--) {
+ size += lstElements.get(i).size();
+ }
+ return size;
+ }
+
+ public boolean isEmpty() {
+
+ for (int i = 2; i >= 0; i--) {
+ if (!lstElements.get(i).isEmpty()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void put(int key, E value) {
+ putInternal(key, value, false);
+ }
+
+ public void remove(int key) {
+ putInternal(key, null, true);
+ }
+
+ public void removeAllFields() {
+ lstElements.get(2).clear();
+ }
+
+ public void putInternal(final int key, final E value, boolean remove) {
+
+ int index = 0;
+ int ikey = key;
+ if (ikey < 0) {
+ index = 2;
+ ikey = -ikey;
+ }
+ else if (ikey >= VarExprent.STACK_BASE) {
+ index = 1;
+ ikey -= VarExprent.STACK_BASE;
+ }
+
+ ArrayList<Entry<Integer, E>> lst = lstElements.get(index);
+ if (ikey >= lst.size()) {
+ if (remove) {
+ return;
+ }
+ else {
+ ensureCapacity(lst, ikey + 1, false);
+ }
+ }
+
+ lst.set(ikey, value == null ? null : new Entry<Integer, E>() {
+
+ private Integer var = key;
+ private E val = value;
+
+ public Integer getKey() {
+ return var;
+ }
+
+ public E getValue() {
+ return val;
+ }
+
+ public E setValue(E newvalue) {
+ val = newvalue;
+ return null;
+ }
+ });
+ }
+
+ public boolean containsKey(int key) {
+ return get(key) != null;
+ }
+
+ public E get(int key) {
+
+ int index = 0;
+ if (key < 0) {
+ index = 2;
+ key = -key;
+ }
+ else if (key >= VarExprent.STACK_BASE) {
+ index = 1;
+ key -= VarExprent.STACK_BASE;
+ }
+
+ ArrayList<Entry<Integer, E>> lst = lstElements.get(index);
+
+ Entry<Integer, E> ent;
+ if (key < lst.size() && (ent = lst.get(key)) != null) {
+ return ent.getValue();
+ }
+ return null;
+ }
+
+ public void union(SFormsFastMapOld<E> map, IElementsUnion<E> union) {
+
+ for (int i = 2; i >= 0; i--) {
+ ArrayList<Entry<Integer, E>> lstOwn = lstElements.get(i);
+ ArrayList<Entry<Integer, E>> lstExtern = map.lstElements.get(i);
+
+ int ownsize = lstOwn.size();
+ int externsize = lstExtern.size();
+
+ int minsize = ownsize > externsize ? externsize : ownsize;
+
+ for (int j = minsize - 1; j >= 0; j--) {
+ Entry<Integer, E> second = lstExtern.get(j);
+
+ if (second != null) {
+ Entry<Integer, E> first = lstOwn.get(j);
+
+ if (first == null) {
+ putInternal(second.getKey(), union.copy(second.getValue()), false);
+ }
+ else {
+ first.setValue(union.union(first.getValue(), second.getValue()));
+ }
+ }
+ }
+
+ if (externsize > minsize) {
+ // ensureCapacity(lstOwn, externsize, true);
+ // lstOwn.addAll(lstExtern.subList(minsize, externsize));
+
+ for (int j = minsize; j < externsize; j++) {
+ Entry<Integer, E> second = lstExtern.get(j);
+ // if(first != null) {
+ // first.setValue(union.copy(first.getValue()));
+ // }
+
+ if (second != null) {
+ putInternal(second.getKey(), union.copy(second.getValue()), false);
+ }
+ // lstOwn.add(lstExtern.get(j));
+ }
+ }
+ }
+ }
+
+ public List<Entry<Integer, E>> entryList() {
+ List<Entry<Integer, E>> list = new ArrayList<Entry<Integer, E>>();
+
+ for (int i = 2; i >= 0; i--) {
+ for (Entry<Integer, E> ent : lstElements.get(i)) {
+ if (ent != null) {
+ list.add(ent);
+ }
+ }
+ }
+
+ return list;
+ }
+
+ // public SFormsFastMapIterator iterator() {
+ // return new SFormsFastMapIterator();
+ // }
+
+ private void ensureCapacity(ArrayList<Entry<Integer, E>> lst, int size, boolean exact) {
+
+ if (!exact) {
+ int minsize = 2 * lst.size() / 3 + 1;
+ if (minsize > size) {
+ size = minsize;
+ }
+ }
+
+ lst.ensureCapacity(size);
+ for (int i = size - lst.size(); i > 0; i--) {
+ lst.add(null);
+ }
+ }
+
+ public static interface IElementsUnion<E> {
+ public E union(E first, E second);
+
+ public E copy(E element);
+ }
+
+ // public class SFormsFastMapIterator implements Iterator<Entry<Integer, E>> {
+ //
+ // private int[] pointer = new int[]{0, -1};
+ // private int[] next_pointer = null;
+ //
+ // private int[] getNextIndex(int list, int index) {
+ //
+ // while(list < 3) {
+ // ArrayList<E> lst = lstElements.get(list);
+ //
+ // while(++index < lst.size()) {
+ // E element = lst.get(index);
+ // if(element != null) {
+ // return new int[] {list, index};
+ // }
+ // }
+ //
+ // index = -1;
+ // list++;
+ // }
+ //
+ // return null;
+ // }
+ //
+ // public boolean hasNext() {
+ // next_pointer = getNextIndex(pointer[0], pointer[1]);
+ // return (next_pointer != null);
+ // }
+ //
+ // public Entry<Integer, E> next() {
+ // if(next_pointer != null) {
+ // pointer = next_pointer;
+ // } else {
+ // int[] nextpointer = getNextIndex(pointer[0], pointer[1]);
+ // if(nextpointer != null) {
+ // pointer = nextpointer;
+ // } else {
+ // return null;
+ // }
+ // }
+ //
+ // next_pointer = null;
+ //
+ // return new Entry<Integer, E>() {
+ // public Integer getKey() {
+ // return null;
+ // }
+ //
+ // public E getValue() {
+ // return null;
+ // }
+ //
+ // public E setValue(E value) {
+ // throw new RuntimeException("not implemented!");
+ // }
+ // };
+ // //lstElements.get(pointer[0]).get(pointer[1]);
+ // }
+ //
+ // public void remove() {
+ // throw new RuntimeException("not implemented!");
+ // }
+ //
+ // }
}
diff --git a/src/org/jetbrains/java/decompiler/util/VBStyleCollection.java b/src/org/jetbrains/java/decompiler/util/VBStyleCollection.java
index 8542019..fcb579d 100644
--- a/src/org/jetbrains/java/decompiler/util/VBStyleCollection.java
+++ b/src/org/jetbrains/java/decompiler/util/VBStyleCollection.java
@@ -1,17 +1,18 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
package org.jetbrains.java.decompiler.util;
import java.util.ArrayList;
@@ -20,185 +21,184 @@ import java.util.Collections;
import java.util.HashMap;
public class VBStyleCollection<E, K> extends ArrayList<E> {
-
- private HashMap<K, Integer> map = new HashMap<K, Integer>();
-
- private ArrayList<K> lstKeys = new ArrayList<K>();
-
- public VBStyleCollection() {
- super();
- }
-
- public VBStyleCollection(int initialCapacity) {
- super(initialCapacity);
- lstKeys = new ArrayList<K>(initialCapacity);
- map = new HashMap<K, Integer>(initialCapacity);
- }
-
- public VBStyleCollection(Collection<E> c) {
- super(c);
- }
-
- public boolean add(E element) {
- lstKeys.add(null);
- super.add(element);
- return true;
- }
-
- public boolean remove(Object element) { // TODO: error on void remove(E element)
- throw new RuntimeException("not implemented!");
- }
-
- public boolean addAll(Collection<? extends E> c) {
- for(int i=c.size()-1;i>=0;i--) {
- lstKeys.add(null);
- }
- return super.addAll(c);
- }
-
- public void addAllWithKey(VBStyleCollection<E, K> c) {
- for(int i=0;i<c.size();i++) {
- addWithKey(c.get(i), c.getKey(i));
- }
- }
-
- public void addAllWithKey(Collection<E> elements, Collection<K> keys) {
- int index = super.size();
-
- for(K key : keys) {
- map.put(key, index++);
- }
-
- super.addAll(elements);
- lstKeys.addAll(keys);
- }
-
- public void addWithKey(E element, K key) {
- map.put(key, super.size());
- super.add(element);
- lstKeys.add(key);
- }
-
- // TODO: speed up the method
- public E putWithKey(E element, K key) {
- Integer index = map.get(key);
- if (index == null) {
- addWithKey(element, key);
- } else {
- return super.set(index, element);
- }
- return null;
- }
-
- public void add(int index, E element) {
- addToListIndex(index, 1);
- lstKeys.add(index, null);
- super.add(index, element);
- }
-
- public void addWithKeyAndIndex(int index, E element, K key) {
- addToListIndex(index, 1);
- map.put(key, new Integer(index));
- super.add(index, element);
- lstKeys.add(index, key);
- }
-
- public void removeWithKey(K key) {
- int index = ((Integer) map.get(key)).intValue();
- addToListIndex(index + 1, -1);
- super.remove(index);
- lstKeys.remove(index);
- map.remove(key);
- }
-
- public E remove(int index) {
- addToListIndex(index + 1, -1);
- Object obj = lstKeys.get(index);
- if (obj != null) {
- map.remove(obj);
- }
- lstKeys.remove(index);
- return super.remove(index);
- }
-
- public E getWithKey(K key) {
- Integer index = map.get(key);
- if (index == null) {
- return null;
- }
- return super.get(index.intValue());
- }
-
- public int getIndexByKey(K key) {
- return map.get(key).intValue();
- }
-
- public E getLast() {
- return super.get(super.size()-1);
- }
-
- public boolean containsKey(K key) {
- return map.containsKey(key);
- }
-
- public void clear() {
- map.clear();
- lstKeys.clear();
- super.clear();
- }
-
- public VBStyleCollection<E, K> clone() {
- VBStyleCollection<E, K> c = new VBStyleCollection<E, K>();
- c.addAll(new ArrayList<E>(this));
- c.setMap(new HashMap<K, Integer>(map));
- c.setLstKeys(new ArrayList<K>(lstKeys));
- return c;
- }
-
- public void swap(int index1, int index2) {
-
- Collections.swap(this, index1, index2);
- Collections.swap(lstKeys, index1, index2);
-
- K key = lstKeys.get(index1);
- if(key!=null) {
- map.put(key, new Integer(index1));
- }
-
- key = lstKeys.get(index2);
- if(key!=null) {
- map.put(key, new Integer(index2));
- }
-
- }
-
- public HashMap<K, Integer> getMap() {
- return map;
- }
-
- public void setMap(HashMap<K, Integer> map) {
- this.map = map;
- }
-
- public K getKey(int index) {
- return lstKeys.get(index);
- }
-
- public ArrayList<K> getLstKeys() {
- return lstKeys;
- }
-
- public void setLstKeys(ArrayList<K> lstKeys) {
- this.lstKeys = lstKeys;
- }
-
- private void addToListIndex(int index, int diff) {
- for (int i = lstKeys.size() - 1; i >= index; i--) {
- K obj = lstKeys.get(i);
- if (obj != null) {
- map.put(obj, new Integer(i + diff));
- }
- }
- }
-
+
+ private HashMap<K, Integer> map = new HashMap<K, Integer>();
+
+ private ArrayList<K> lstKeys = new ArrayList<K>();
+
+ public VBStyleCollection() {
+ super();
+ }
+
+ public VBStyleCollection(int initialCapacity) {
+ super(initialCapacity);
+ lstKeys = new ArrayList<K>(initialCapacity);
+ map = new HashMap<K, Integer>(initialCapacity);
+ }
+
+ public VBStyleCollection(Collection<E> c) {
+ super(c);
+ }
+
+ public boolean add(E element) {
+ lstKeys.add(null);
+ super.add(element);
+ return true;
+ }
+
+ public boolean remove(Object element) { // TODO: error on void remove(E element)
+ throw new RuntimeException("not implemented!");
+ }
+
+ public boolean addAll(Collection<? extends E> c) {
+ for (int i = c.size() - 1; i >= 0; i--) {
+ lstKeys.add(null);
+ }
+ return super.addAll(c);
+ }
+
+ public void addAllWithKey(VBStyleCollection<E, K> c) {
+ for (int i = 0; i < c.size(); i++) {
+ addWithKey(c.get(i), c.getKey(i));
+ }
+ }
+
+ public void addAllWithKey(Collection<E> elements, Collection<K> keys) {
+ int index = super.size();
+
+ for (K key : keys) {
+ map.put(key, index++);
+ }
+
+ super.addAll(elements);
+ lstKeys.addAll(keys);
+ }
+
+ public void addWithKey(E element, K key) {
+ map.put(key, super.size());
+ super.add(element);
+ lstKeys.add(key);
+ }
+
+ // TODO: speed up the method
+ public E putWithKey(E element, K key) {
+ Integer index = map.get(key);
+ if (index == null) {
+ addWithKey(element, key);
+ }
+ else {
+ return super.set(index, element);
+ }
+ return null;
+ }
+
+ public void add(int index, E element) {
+ addToListIndex(index, 1);
+ lstKeys.add(index, null);
+ super.add(index, element);
+ }
+
+ public void addWithKeyAndIndex(int index, E element, K key) {
+ addToListIndex(index, 1);
+ map.put(key, new Integer(index));
+ super.add(index, element);
+ lstKeys.add(index, key);
+ }
+
+ public void removeWithKey(K key) {
+ int index = ((Integer)map.get(key)).intValue();
+ addToListIndex(index + 1, -1);
+ super.remove(index);
+ lstKeys.remove(index);
+ map.remove(key);
+ }
+
+ public E remove(int index) {
+ addToListIndex(index + 1, -1);
+ Object obj = lstKeys.get(index);
+ if (obj != null) {
+ map.remove(obj);
+ }
+ lstKeys.remove(index);
+ return super.remove(index);
+ }
+
+ public E getWithKey(K key) {
+ Integer index = map.get(key);
+ if (index == null) {
+ return null;
+ }
+ return super.get(index.intValue());
+ }
+
+ public int getIndexByKey(K key) {
+ return map.get(key).intValue();
+ }
+
+ public E getLast() {
+ return super.get(super.size() - 1);
+ }
+
+ public boolean containsKey(K key) {
+ return map.containsKey(key);
+ }
+
+ public void clear() {
+ map.clear();
+ lstKeys.clear();
+ super.clear();
+ }
+
+ public VBStyleCollection<E, K> clone() {
+ VBStyleCollection<E, K> c = new VBStyleCollection<E, K>();
+ c.addAll(new ArrayList<E>(this));
+ c.setMap(new HashMap<K, Integer>(map));
+ c.setLstKeys(new ArrayList<K>(lstKeys));
+ return c;
+ }
+
+ public void swap(int index1, int index2) {
+
+ Collections.swap(this, index1, index2);
+ Collections.swap(lstKeys, index1, index2);
+
+ K key = lstKeys.get(index1);
+ if (key != null) {
+ map.put(key, new Integer(index1));
+ }
+
+ key = lstKeys.get(index2);
+ if (key != null) {
+ map.put(key, new Integer(index2));
+ }
+ }
+
+ public HashMap<K, Integer> getMap() {
+ return map;
+ }
+
+ public void setMap(HashMap<K, Integer> map) {
+ this.map = map;
+ }
+
+ public K getKey(int index) {
+ return lstKeys.get(index);
+ }
+
+ public ArrayList<K> getLstKeys() {
+ return lstKeys;
+ }
+
+ public void setLstKeys(ArrayList<K> lstKeys) {
+ this.lstKeys = lstKeys;
+ }
+
+ private void addToListIndex(int index, int diff) {
+ for (int i = lstKeys.size() - 1; i >= index; i--) {
+ K obj = lstKeys.get(i);
+ if (obj != null) {
+ map.put(obj, new Integer(i + diff));
+ }
+ }
+ }
}