Package org.candle.decompiler.intermediate.graph.enhancer

Source Code of org.candle.decompiler.intermediate.graph.enhancer.ConstantArrayCompressor

package org.candle.decompiler.intermediate.graph.enhancer;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.bcel.generic.Type;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.candle.decompiler.intermediate.code.AbstractIntermediate;
import org.candle.decompiler.intermediate.code.StatementIntermediate;
import org.candle.decompiler.intermediate.expression.ArrayAccess;
import org.candle.decompiler.intermediate.expression.Assignment;
import org.candle.decompiler.intermediate.expression.ConstantArray;
import org.candle.decompiler.intermediate.expression.Declaration;
import org.candle.decompiler.intermediate.expression.Expression;
import org.candle.decompiler.intermediate.expression.NewConstantArrayInstance;
import org.candle.decompiler.intermediate.expression.Resolved;
import org.candle.decompiler.intermediate.graph.GraphIntermediateVisitor;
import org.candle.decompiler.intermediate.graph.context.IntermediateGraphContext;
import org.jgrapht.Graphs;

public class ConstantArrayCompressor extends GraphIntermediateVisitor {
 
  private static final Log LOG = LogFactory.getLog(ConstantArrayCompressor.class);
 
  public ConstantArrayCompressor(IntermediateGraphContext igc) {
    super(igc, false);
  }

  @Override
  public void visitStatementIntermediate(StatementIntermediate line) {
    //first, look for the
    Assignment assignment = extractConstantArrayAssignment(line.getExpression());
    if(assignment == null) {
      return;
    }
   
    //at this point, we know both the statement is an assignment, and that the left assignment is to a constant array value.
    //find the one that is right before the array assignment.
   
    Declaration declaration = extractNextDeclaration(line);

    //if we didn't find the declaration, this must not be the constant array assignment proceeding the declaration.
    if(declaration == null) {
      return;
    }
   
    //check the right hand of the declaration...
    if(!(declaration.getAssignment().getRightHandSide() instanceof NewConstantArrayInstance)) {
      return;
    }
    NewConstantArrayInstance ncai = (NewConstantArrayInstance)declaration.getAssignment().getRightHandSide();
    Expression countExpression = ncai.getCount();
   
   
    AbstractIntermediate current = line;
    Map<Integer, Expression> values = new HashMap<Integer, Expression>();
    collectConstantAssignments(current, values);
   
    //create a new array...
    Integer count = toInteger(countExpression);
    List<Expression> expressions = new ArrayList<Expression>(count);
    for(int i=0, j=count; i<j; i++) {
      Expression exp = null;
      if(values.containsKey(i)) {
        exp = values.get(i);
      }
      else {
        exp = new Resolved(ncai.getInstructionHandle(), Type.NULL, "null");
      }
      expressions.add(i, exp);
    }
   
   
    //ok, we have the stack... now we need to just create a new expression.

    //create the contant...
    ConstantArray constantArray = new ConstantArray(declaration.getAssignment().getRightHandSide().getInstructionHandle(), expressions);
    declaration.getAssignment().setRightHandSide(constantArray);
   
   
    //excellent.  we have reordered the statements into the appropriate ContantArray assignment.  Now, we need to remove the dead nodes and heal the graph.
    AbstractIntermediate next = Graphs.successorListOf(igc.getGraph(), line).get(0);
   
    //loop through the dead elements...
    //we know the number of dead items is equal to the number of values we found.
    healGraph(line, next, values.size());
  }
 
  public void healGraph(AbstractIntermediate current, AbstractIntermediate next, int deadElements) {
    for(int i=0, j=deadElements; i<j; i++) {
      //if this is the last element, redirect it's predecessors to the next node.
      if(i+1 == j) {
        igc.redirectPredecessors(current, next);
      }
     
     
      AbstractIntermediate temp = null;
      //move back..
      List<AbstractIntermediate> predecessor = Graphs.predecessorListOf(igc.getGraph(), current);
      if(predecessor.size() > 0) {
        temp = predecessor.get(0);
      }
      //retract current..
      igc.getGraph().removeVertex(current);
     
      //set next...
      current = temp;
     
    }
  }
 
  public void collectConstantAssignments(AbstractIntermediate current, Map<Integer, Expression> assignments) {
    StatementIntermediate si = (StatementIntermediate)current;
   
    //get the assignment...
    Assignment assignment = extractConstantArrayAssignment(si.getExpression());
    if(assignment == null) {
      return;
    }
   
    Expression right = assignment.getRightHandSide();
    ArrayAccess apr = (ArrayAccess)assignment.getLeftHandSide();
    assignments.put(toInteger(apr.getIndex()), right);
   
    List<AbstractIntermediate> predecessor = Graphs.predecessorListOf(igc.getGraph(), current);
   
    if(predecessor.size() != 1) {
      return;
    }
   
    if(!(predecessor.get(0) instanceof StatementIntermediate)) {
      return;
    }
   
    for(AbstractIntermediate a : predecessor) {
      collectConstantAssignments(a, assignments);
    }
  }
 
  public Integer toInteger(Expression apr) {
    StringWriter pos = new StringWriter();
    try {
      apr.write(pos);
    } catch (IOException e) {
      throw new IllegalStateException("Position is not an integer.", e);
    }
   
    return Integer.parseInt(pos.toString());
  }
 
  public Declaration extractNextDeclaration(StatementIntermediate statement) {
    List<AbstractIntermediate> successors = Graphs.successorListOf(igc.getGraph(), statement);
    if(successors.size() != 1) {
      return null;
    }
   
    if(!(successors.get(0) instanceof StatementIntermediate)) {
      return null;
    }
   
    StatementIntermediate si = (StatementIntermediate)successors.get(0);
   
    if(si.getExpression() instanceof Declaration)  {
      return (Declaration)si.getExpression();
    }
   
    return null;
  }
 
  public Assignment extractConstantArrayAssignment(Expression line) {
    if(!(line instanceof Assignment)) {
      return null;
    }
   
    Assignment assignment = (Assignment)line;
   
    if(!(assignment.getLeftHandSide() instanceof ArrayAccess)) {
      return null;
    }
   
    ArrayAccess apr = (ArrayAccess)assignment.getLeftHandSide();
    if(!(apr.getArray() instanceof NewConstantArrayInstance)) {
      return null;
    }
   
    return assignment;
  }
}
TOP

Related Classes of org.candle.decompiler.intermediate.graph.enhancer.ConstantArrayCompressor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.