All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.dava.toolkits.base.AST.transformations.DeInliningFinalFields Maven / Gradle / Ivy

package soot.dava.toolkits.base.AST.transformations;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 2006 Nomair A. Naeem ([email protected])
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 2.1 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import soot.BooleanType;
import soot.ByteType;
import soot.CharType;
import soot.DoubleType;
import soot.FloatType;
import soot.IntType;
import soot.LongType;
import soot.Scene;
import soot.ShortType;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Type;
import soot.Value;
import soot.ValueBox;
import soot.dava.DavaBody;
import soot.dava.internal.AST.ASTAggregatedCondition;
import soot.dava.internal.AST.ASTBinaryCondition;
import soot.dava.internal.AST.ASTCondition;
import soot.dava.internal.AST.ASTDoWhileNode;
import soot.dava.internal.AST.ASTForLoopNode;
import soot.dava.internal.AST.ASTIfElseNode;
import soot.dava.internal.AST.ASTIfNode;
import soot.dava.internal.AST.ASTMethodNode;
import soot.dava.internal.AST.ASTNode;
import soot.dava.internal.AST.ASTStatementSequenceNode;
import soot.dava.internal.AST.ASTSwitchNode;
import soot.dava.internal.AST.ASTSynchronizedBlockNode;
import soot.dava.internal.AST.ASTWhileNode;
import soot.dava.internal.asg.AugmentedStmt;
import soot.dava.internal.javaRep.DStaticFieldRef;
import soot.dava.toolkits.base.AST.analysis.DepthFirstAdapter;
import soot.jimple.DoubleConstant;
import soot.jimple.FloatConstant;
import soot.jimple.IntConstant;
import soot.jimple.LongConstant;
import soot.jimple.Stmt;
import soot.jimple.StringConstant;
import soot.tagkit.DoubleConstantValueTag;
import soot.tagkit.FloatConstantValueTag;
import soot.tagkit.IntegerConstantValueTag;
import soot.tagkit.LongConstantValueTag;
import soot.tagkit.StringConstantValueTag;
import soot.util.Chain;

//import soot.jimple.internal.*;
//import soot.grimp.internal.*;
//import soot.dava.toolkits.base.AST.traversals.*;
//import soot.dava.toolkits.base.AST.structuredAnalysis.*;

/**
 * Maintained by: Nomair A. Naeem
 */

/**
 * CHANGE LOG: 2nd February 2006:
 *
 */

/*
 * Both static and non-static BUT FINAL fields if initialized with constants get inlined A final initialized with an object
 * (even if its a string) is NOT inlined e.g. public static final String temp = "hello"; //use of temp will get inlined
 * public static final String temp1 = new String("hello"); //use of temp will NOT get inlined
 *
 *
 * If its a static field we can get the info from a tag in the case of a non static we cant decide since the field is
 * initialized inside a constructor and depending on different constructors there coul dbe different
 * values...conservative....
 *
 *
 * Need to be very clear when a SootField can be used It can be used in the following places:
 *
 * a, NOT used inside a Synchronized Block ........ HOWEVER ADD IT SINCE I DONT SEE WHY THIS RESTRICTION EXISTS!!! TICK b,
 * CAN BE USED in a condition TICK c, CAN BE USED in the for init for update TICK d, CAN BE USED in a switch TICK e, CAN BE
 * USED in a stmt TICK
 *
 * These are the exact places to look for constants...a constant is StringConstant DoubleConstant FloatConstant IntConstant
 * (shortype, booltype, charType intType, byteType LongConstant
 */

public class DeInliningFinalFields extends DepthFirstAdapter {
  SootClass sootClass = null;
  SootMethod sootMethod = null;
  DavaBody davaBody = null;

  HashMap finalFields;

  // ASTParentNodeFinder parentFinder;

  public DeInliningFinalFields() {
  }

  public DeInliningFinalFields(boolean verbose) {
    super(verbose);
  }

  public void inASTMethodNode(ASTMethodNode node) {
    DavaBody davaBody = node.getDavaBody();
    sootMethod = davaBody.getMethod();
    // System.out.println("Deiniling method: "+sootMethod.getName());
    sootClass = sootMethod.getDeclaringClass();

    finalFields = new HashMap();

    ArrayList fieldChain = new ArrayList();

    Chain appClasses = Scene.v().getApplicationClasses();
    Iterator it = appClasses.iterator();
    while (it.hasNext()) {
      SootClass tempClass = (SootClass) it.next();
      // System.out.println("DeInlining"+tempClass.getName());
      Chain tempChain = tempClass.getFields();
      Iterator tempIt = tempChain.iterator();
      while (tempIt.hasNext()) {
        fieldChain.add(tempIt.next());
      }

    }

    // Iterator fieldIt = sootClass.getFields().iterator();
    Iterator fieldIt = fieldChain.iterator();
    while (fieldIt.hasNext()) {
      SootField f = (SootField) fieldIt.next();
      if (f.isFinal()) {

        // check for constant value tags
        Type fieldType = f.getType();
        if (fieldType instanceof DoubleType && f.hasTag("DoubleConstantValueTag")) {
          double val = ((DoubleConstantValueTag) f.getTag("DoubleConstantValueTag")).getDoubleValue();
          finalFields.put(new Double(val), f);
        } else if (fieldType instanceof FloatType && f.hasTag("FloatConstantValueTag")) {
          float val = ((FloatConstantValueTag) f.getTag("FloatConstantValueTag")).getFloatValue();
          finalFields.put(new Float(val), f);
        } else if (fieldType instanceof LongType && f.hasTag("LongConstantValueTag")) {
          long val = ((LongConstantValueTag) f.getTag("LongConstantValueTag")).getLongValue();
          finalFields.put(new Long(val), f);
        } else if (fieldType instanceof CharType && f.hasTag("IntegerConstantValueTag")) {
          int val = ((IntegerConstantValueTag) f.getTag("IntegerConstantValueTag")).getIntValue();
          finalFields.put(new Integer(val), f);
        } else if (fieldType instanceof BooleanType && f.hasTag("IntegerConstantValueTag")) {
          int val = ((IntegerConstantValueTag) f.getTag("IntegerConstantValueTag")).getIntValue();
          if (val == 0) {
            finalFields.put(new Boolean(false), f);
          } else {
            finalFields.put(new Boolean(true), f);
          }
        } else if ((fieldType instanceof IntType || fieldType instanceof ByteType || fieldType instanceof ShortType)
            && f.hasTag("IntegerConstantValueTag")) {
          int val = ((IntegerConstantValueTag) f.getTag("IntegerConstantValueTag")).getIntValue();
          finalFields.put(new Integer(val), f);
        } else if (f.hasTag("StringConstantValueTag")) {
          String val = ((StringConstantValueTag) f.getTag("StringConstantValueTag")).getStringValue();
          // System.out.println("adding string constant"+val);
          finalFields.put(val, f);
        }
      } // end if final
    } // going through fields
  }

  /*
   * StringConstant DoubleConstant FloatConstant IntConstant (shortype, booltype, charType intType, byteType LongConstant
   */
  private boolean isConstant(Value val) {
    if (val instanceof StringConstant || val instanceof DoubleConstant || val instanceof FloatConstant
        || val instanceof IntConstant || val instanceof LongConstant) {
      return true;
    }
    return false;
  }

  /*
   * Notice as things stand synchblocks cant have the use of a SootField
   */
  public void inASTSynchronizedBlockNode(ASTSynchronizedBlockNode node) {
    // hence nothing is implemented here
  }

  public void checkAndSwitch(ValueBox valBox) {
    Value val = valBox.getValue();

    Object finalField = check(val);
    if (finalField != null) {
      // System.out.println("Final field with this value exists"+finalField);

      /*
       * If the final field belongs to the same class then we should supress declaring class
       */
      SootField field = (SootField) finalField;

      if (sootClass.declaresField(field.getName(), field.getType())) {
        // this field is of this class so supress the declaring class
        if (valBox.canContainValue(new DStaticFieldRef(field.makeRef(), true))) {
          valBox.setValue(new DStaticFieldRef(field.makeRef(), true));
        }
      } else {
        if (valBox.canContainValue(new DStaticFieldRef(field.makeRef(), true))) {
          valBox.setValue(new DStaticFieldRef(field.makeRef(), false));
        }
      }

    }
    // else
    // System.out.println("Final field not found");
  }

  public Object check(Value val) {
    Object finalField = null;
    if (isConstant(val)) {
      // System.out.println("Found constant in code"+val);

      // can be a byte or short or char......or an int ...in the case of
      // int you also have to check for Booleans
      if (val instanceof StringConstant) {
        String myString = ((StringConstant) val).toString();
        myString = myString.substring(1, myString.length() - 1);
        // System.out.println("looking for:"+myString);
        finalField = finalFields.get(myString);
      } else if (val instanceof DoubleConstant) {
        String myString = ((DoubleConstant) val).toString();

        finalField = finalFields.get(new Double(myString));
      } else if (val instanceof FloatConstant) {
        String myString = ((FloatConstant) val).toString();

        finalField = finalFields.get(new Float(myString));
      } else if (val instanceof LongConstant) {
        String myString = ((LongConstant) val).toString();

        finalField = finalFields.get(new Long(myString.substring(0, myString.length() - 1)));
      } else if (val instanceof IntConstant) {
        String myString = ((IntConstant) val).toString();
        if (myString.length() == 0) {
          return null;
        }

        Type valType = ((IntConstant) val).getType();

        Integer myInt = null;
        try {
          if (myString.charAt(0) == '\'') {
            // character
            if (myString.length() < 2) {
              return null;
            }

            myInt = new Integer(myString.charAt(1));
          } else {
            myInt = new Integer(myString);
          }
        } catch (Exception e) {
          // System.out.println("exception occured...gracefully exitting method..string was"+myString);
          return finalField;
        }

        if (valType instanceof ByteType) {
          finalField = finalFields.get(myInt);
        } else if (valType instanceof IntType) {
          if (myString.equals("false")) {
            finalField = finalFields.get(new Boolean(false));
          } else if (myString.equals("true")) {
            finalField = finalFields.get(new Boolean(true));
          } else {
            finalField = finalFields.get(myInt);
          }
        } else if (valType instanceof ShortType) {
          finalField = finalFields.get(myInt);
        }
      }
    }
    return finalField;
  }

  /*
   * The key in a switch stmt can be a local or a SootField or a value which can contain constant
   *
   * Hence the some what indirect approach........notice we will work with valueBoxes so that by changing the value in the
   * value box we can deInline any field
   */
  public void inASTSwitchNode(ASTSwitchNode node) {
    Value val = node.get_Key();

    if (isConstant(val)) {
      // find if there is a SootField with this constant
      // System.out.println("Found constant as key to switch");

      checkAndSwitch(node.getKeyBox());
      return;
    }
    // val is not a constant but it might have other constants in it

    Iterator it = val.getUseBoxes().iterator();
    while (it.hasNext()) {
      ValueBox tempBox = (ValueBox) it.next();
      // System.out.println("Checking useBox of switch key");
      checkAndSwitch(tempBox);
    }
  }

  public void inASTStatementSequenceNode(ASTStatementSequenceNode node) {
    for (AugmentedStmt as : node.getStatements()) {
      Stmt s = as.get_Stmt();
      Iterator tempIt = s.getUseBoxes().iterator();
      while (tempIt.hasNext()) {
        ValueBox tempBox = (ValueBox) tempIt.next();
        // System.out.println("Checking useBox of stmt");
        checkAndSwitch(tempBox);
      }
    }
  }

  public void inASTForLoopNode(ASTForLoopNode node) {

    // checking uses in init
    for (AugmentedStmt as : node.getInit()) {
      Stmt s = as.get_Stmt();
      Iterator tempIt = s.getUseBoxes().iterator();
      while (tempIt.hasNext()) {
        ValueBox tempBox = (ValueBox) tempIt.next();
        // System.out.println("Checking useBox of init stmt");
        checkAndSwitch(tempBox);
      }
    }

    // checking uses in condition
    ASTCondition cond = node.get_Condition();
    checkConditionalUses(cond, node);

    // checking uses in update
    for (AugmentedStmt as : node.getUpdate()) {
      Stmt s = as.get_Stmt();
      Iterator tempIt = s.getUseBoxes().iterator();
      while (tempIt.hasNext()) {
        ValueBox tempBox = (ValueBox) tempIt.next();
        // System.out.println("Checking useBox of update stmt");
        checkAndSwitch(tempBox);
      }
    }
  }

  /*
   * checking for unary conditions doesnt matter since this was definetly lost.
   */
  public void checkConditionalUses(Object cond, ASTNode node) {
    if (cond instanceof ASTAggregatedCondition) {
      checkConditionalUses((((ASTAggregatedCondition) cond).getLeftOp()), node);
      checkConditionalUses(((ASTAggregatedCondition) cond).getRightOp(), node);
      return;
    } else if (cond instanceof ASTBinaryCondition) {
      // get uses from binaryCondition
      Value val = ((ASTBinaryCondition) cond).getConditionExpr();
      Iterator tempIt = val.getUseBoxes().iterator();
      while (tempIt.hasNext()) {
        ValueBox tempBox = (ValueBox) tempIt.next();
        // System.out.println("Checking useBox of binary condition");
        checkAndSwitch(tempBox);
      }
    }
  }

  /*
   * The condition of an if node can use a local
   */
  public void inASTIfNode(ASTIfNode node) {
    ASTCondition cond = node.get_Condition();
    checkConditionalUses(cond, node);
  }

  /*
   * The condition of an ifElse node can use a local
   */
  public void inASTIfElseNode(ASTIfElseNode node) {
    ASTCondition cond = node.get_Condition();
    checkConditionalUses(cond, node);
  }

  /*
   * The condition of a while node can use a local
   */
  public void inASTWhileNode(ASTWhileNode node) {
    ASTCondition cond = node.get_Condition();
    checkConditionalUses(cond, node);
  }

  /*
   * The condition of a doWhile node can use a local
   */
  public void inASTDoWhileNode(ASTDoWhileNode node) {
    ASTCondition cond = node.get_Condition();
    checkConditionalUses(cond, node);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy