/ *
* 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.decompiler ;
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.* ;
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_BOOL_NOT :
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 ( ) , funcexpr . bytecode ) ;
}
}
}
}
}
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_BIT_NOT , lstBitNotOperand , fexpr . bytecode ) ;
}
}
}
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_BOOL_NOT , lstNotOperand , fexpr . bytecode ) ;
}
}
}
}
break ;
case FunctionExprent . FUNCTION_BOOL_NOT :
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 ) , fexpr . bytecode ) ;
}
else {
return new ConstExprent ( VarType . VARTYPE_BOOLEAN , new Integer ( 0 ) , fexpr . bytecode ) ;
}
}
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_BOOL_NOT , Arrays . asList ( lstOperands . get ( 0 ) ) , fexpr . bytecode ) ;
}
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 FunctionExprent ( FunctionExprent . FUNCTION_LT , Arrays . asList ( new VarExprent ( var , type , processor ) ,
ConstExprent . getZeroConstant ( type . type ) ) , null ) ,
new ConstExprent ( VarType . VARTYPE_INT , new Integer ( - 1 ) , null ) ,
new ConstExprent ( VarType . VARTYPE_INT , new Integer ( 1 ) , null ) ) , null ) ;
FunctionExprent head = new FunctionExprent ( FunctionExprent . FUNCTION_EQ , Arrays . asList (
new AssignmentExprent ( new VarExprent ( var , type , processor ) , new FunctionExprent ( FunctionExprent . FUNCTION_SUB ,
Arrays . asList ( lstOperands . get ( 0 ) ,
lstOperands . get ( 1 ) ) , null ) , null ) ,
ConstExprent . getZeroConstant ( type . type ) ) , null ) ;
processor . setVarType ( new VarVersionPaar ( var , 0 ) , type ) ;
return new FunctionExprent ( FunctionExprent . FUNCTION_IIF , Arrays . asList (
head , new ConstExprent ( VarType . VARTYPE_INT , new Integer ( 0 ) , null ) , iff ) , fexpr . bytecode ) ;
}
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_BOOL_NOT ) {
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_BOOL_NOT :
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_BOOL_NOT ,
Arrays . asList ( operands . get ( i ) ) , operands . get ( i ) . bytecode ) ;
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 ;
}
}