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

sootup.java.bytecode.interceptors.LocalPacker Maven / Gradle / Ivy

There is a newer version: 1.3.0
Show newest version
package sootup.java.bytecode.interceptors;
/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 1997 - 2021 Raja Vallee-Rai, Zun Wang
 * %%
 * 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.*;
import javax.annotation.Nonnull;
import sootup.core.graph.StmtGraph;
import sootup.core.jimple.basic.Local;
import sootup.core.jimple.basic.Value;
import sootup.core.jimple.common.stmt.AbstractDefinitionStmt;
import sootup.core.jimple.common.stmt.JIdentityStmt;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.Body;
import sootup.core.transform.BodyInterceptor;
import sootup.core.types.Type;
import sootup.core.views.View;

/** @author Zun Wang * */
public class LocalPacker implements BodyInterceptor {

  @Override
  public void interceptBody(@Nonnull Body.BodyBuilder builder, @Nonnull View view) {

    Map localToColor = assignLocalsColor(builder);
    // map each original local to a new local
    Map localToNewLocal = new HashMap<>();
    // map each new local to corresponding list of original local
    Map> newLocalToLocals = new HashMap<>();
    List originalLocals = new ArrayList<>(builder.getLocals());

    Map typeColorToLocal = new HashMap<>();
    int localIndex = 0;
    for (Local original : originalLocals) {
      Type type = original.getType();
      int color = localToColor.get(original);
      TypeColorPair pair = new TypeColorPair(type, color);

      Local newLocal;

      if (typeColorToLocal.containsKey(pair)) {
        newLocal = typeColorToLocal.get(pair);
      } else {
        String name = original.getName();
        int i = 0;
        for (; i < name.length(); i++) {
          if (Character.isDigit(name.charAt(i))) {
            break;
          }
        }
        String newName = name.substring(0, i) + '*' + localIndex;
        localIndex++;
        newLocal = original.withName(newName);

        typeColorToLocal.put(pair, newLocal);
      }
      localToNewLocal.put(original, newLocal);
      if (!newLocalToLocals.containsKey(newLocal)) {
        newLocalToLocals.put(newLocal, new ArrayList<>());
      }
      newLocalToLocals.get(newLocal).add(original);
    }

    // Correct a reasonable name for each new local and change them in BodyBuilder
    // store all new locals with reasonable name, if a local is not in newLoals, means that it
    // doesn't has reasonable name
    Set newLocals = new LinkedHashSet<>();
    for (Stmt stmt : builder.getStmts()) {
      Stmt newStmt = stmt;
      for (Value use : stmt.getUses()) {
        if (use instanceof Local) {
          Local newLocal = localToNewLocal.get(use);
          // assign a reasonable name
          if (!newLocals.contains(newLocal)) {
            int starPos = newLocal.getName().indexOf('*');
            String reasonableName = newLocal.getName().substring(0, starPos) + newLocals.size();
            List oriLocals = newLocalToLocals.get(newLocal);
            newLocal = newLocal.withName(reasonableName);
            newLocals.add(newLocal);
            for (Local ori : oriLocals) {
              localToNewLocal.put(ori, newLocal);
            }
          }
          newStmt = newStmt.withNewUse(use, newLocal);
        }
      }
      if (!stmt.getDefs().isEmpty() && stmt.getDefs().get(0) instanceof Local) {
        Local def = (Local) stmt.getDefs().get(0);
        Local newLocal = localToNewLocal.get(def);
        // assign a reasonable name
        if (!newLocals.contains(newLocal)) {
          int starPos = newLocal.getName().indexOf('*');
          String reasonableName = newLocal.getName().substring(0, starPos) + newLocals.size();
          List oriLocals = newLocalToLocals.get(newLocal);
          newLocal = newLocal.withName(reasonableName);
          newLocals.add(newLocal);
          for (Local ori : oriLocals) {
            localToNewLocal.put(ori, newLocal);
          }
        }
        newStmt = ((AbstractDefinitionStmt) newStmt).withNewDef(newLocal);
      }
      if (!stmt.equals(newStmt)) {
        builder.replaceStmt(stmt, newStmt);
      }
    }
    builder.setLocals(newLocals);
  }

  /**
   * Assign each local from a Bodybuilder an integer color
   *
   * @param builder an instance of BodyBuilder
   * @return a Map that maps local to a integer color
   */
  private Map assignLocalsColor(Body.BodyBuilder builder) {
    Map localToColor = new HashMap<>();

    // initial typeToColorCount, ColorCount is also the next free color for corresponding Type.
    Map typeToColorCount = new HashMap<>();
    for (Local local : builder.getLocals()) {
      Type type = local.getType();
      if (!typeToColorCount.containsKey(type)) {
        typeToColorCount.put(type, 0);
      }
    }
    // assign each parameter local a color (local from IdentityStmt)
    for (Stmt stmt : builder.getStmts()) {
      if (stmt instanceof JIdentityStmt) {
        if (((JIdentityStmt) stmt).getLeftOp() instanceof Local) {
          Local l = (Local) ((JIdentityStmt) stmt).getLeftOp();
          Type type = l.getType();
          int count = typeToColorCount.get(type);
          localToColor.put(l, count);
          count++;
          typeToColorCount.put(type, count);
        }
      }
    }
    // Sort locals according to their number of interference-locals, local with more interferences <
    // local with less interferences
    Map> localInterferenceMap = buildLocalInterferenceMap(builder);
    List sortedLocals = new ArrayList<>(builder.getLocals());
    sortedLocals.sort(
        (o1, o2) -> {
          int num1 = localInterferenceMap.containsKey(o1) ? localInterferenceMap.get(o1).size() : 0;
          int num2 = localInterferenceMap.containsKey(o2) ? localInterferenceMap.get(o2).size() : 0;
          return num2 - num1;
        });

    // assign color
    for (Local local : sortedLocals) {
      if (!localToColor.containsKey(local)) {
        Type type = local.getType();
        int colorCount = typeToColorCount.get(type);
        // determine which colors are unavailable for this local
        BitSet unavailableColors = new BitSet(colorCount);
        if (localInterferenceMap.containsKey(local)) {
          Set interferences = localInterferenceMap.get(local);
          for (Local interference : interferences) {
            if (localToColor.containsKey(interference)) {
              unavailableColors.set(localToColor.get(interference));
            }
          }
        }
        int assignedColor = -1;
        for (int i = 0; i < colorCount; i++) {
          if (!unavailableColors.get(i)) {
            assignedColor = i;
            break;
          }
        }
        if (assignedColor < 0) {
          colorCount++;
          assignedColor = colorCount;
          typeToColorCount.put(type, colorCount);
        }
        localToColor.put(local, assignedColor);
      }
    }
    return localToColor;
  }

  /**
   * Find interference-local for each local from the given BodyBuilder. Two locals "l1" and "l2"
   * interfere each other, iff "l1" is alive before a successor of a stmt which defines "l2", vice
   * versa.
   *
   * @param builder a given BodyBuilder
   * @return a Map that maps local to a set of interference-locals
   */
  private Map> buildLocalInterferenceMap(Body.BodyBuilder builder) {
    // Maps local to its interfering locals
    Map> localToLocals = new HashMap<>();
    StmtGraph graph = builder.getStmtGraph();
    LocalLivenessAnalyser analyser = new LocalLivenessAnalyser(graph);

    for (Stmt stmt : builder.getStmts()) {
      if (!stmt.getDefs().isEmpty() && stmt.getDefs().get(0) instanceof Local) {

        Local def = (Local) stmt.getDefs().get(0);

        Set aliveLocals = new HashSet<>();
        for (Stmt succ : graph.successors(stmt)) {
          aliveLocals.addAll(analyser.getLiveLocalsBeforeStmt(succ));
        }
        for (Stmt esucc : graph.exceptionalSuccessors(stmt).values()) {
          aliveLocals.addAll(analyser.getLiveLocalsBeforeStmt(esucc));
        }
        for (Local aliveLocal : aliveLocals) {
          if (aliveLocal != def && aliveLocal.getType().equals(def.getType())) {
            // set interference for both locals: aliveLocal, def
            if (localToLocals.containsKey(def)) {
              localToLocals.get(def).add(aliveLocal);
            } else {
              Set locals = new HashSet<>();
              locals.add(aliveLocal);
              localToLocals.put(def, locals);
            }

            if (localToLocals.containsKey(aliveLocal)) {
              localToLocals.get(aliveLocal).add(def);
            } else {
              Set locals = new HashSet<>();
              locals.add(def);
              localToLocals.put(aliveLocal, locals);
            }
          }
        }
      }
    }
    return localToLocals;
  }

  private static class TypeColorPair {
    private Type type;
    private int color;

    public TypeColorPair(Type type, int color) {
      this.setType(type);
      this.setColor(color);
    }

    public Type getType() {
      return type;
    }

    public void setType(Type type) {
      this.type = type;
    }

    public int getColor() {
      return color;
    }

    public void setColor(int color) {
      this.color = color;
    }

    public int hashCode() {
      return getType().hashCode() + 1013 * getColor();
    }

    public boolean equals(Object other) {
      if (other instanceof TypeColorPair) {
        return ((TypeColorPair) other).getType().equals(this.getType())
            && ((TypeColorPair) other).getColor() == this.getColor();
      } else {
        return false;
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy