Example #1
0
  @Override
  public void transform(IrMethod method) {
    final Map<Local, NewExpr> nAssign = new HashMap<>();
    final Map<Local, AssignStmt> init = new HashMap<>();
    for (Iterator<Stmt> it = method.stmts.iterator(); it.hasNext(); ) {
      Stmt p = it.next();
      if (p.st == ASSIGN && p.getOp1().vt == LOCAL && p.getOp2().vt == NEW) {
        // the stmt is a new assign stmt
        Local local = (Local) p.getOp1();
        nAssign.put(local, (NewExpr) p.getOp2());
        init.put(local, (AssignStmt) p);
      }
    }
    if (nAssign.size() == 0) {
      return;
    }
    int[] reads = Cfg.countLocalReads(method);
    final Set<Local> oneOrLess = new HashSet<>();
    final boolean changed[] = {true};
    while (changed[0]) {
      changed[0] = false;
      for (Local local : nAssign.keySet()) {
        if (reads[local._ls_index] < 2) {
          oneOrLess.add(local);
          method.stmts.remove(init.remove(local));
          method.locals.remove(local);
        }
      }

      if (oneOrLess.size() > 0) {
        new StmtTraveler() {
          @Override
          public Stmt travel(Stmt stmt) {
            Stmt p = super.travel(stmt);
            if (p.st == ASSIGN && p.getOp1().vt == LOCAL && p.getOp2().vt == NEW) {
              // the stmt is a new assign stmt
              Local local = (Local) p.getOp1();
              if (!nAssign.containsKey(local)) {
                nAssign.put(local, (NewExpr) p.getOp2());
                init.put(local, (AssignStmt) p);
                changed[0] = true;
              }
            }
            return p;
          }

          @Override
          public Value travel(Value op) {
            if (op.vt == LOCAL) {
              Local local = (Local) op;
              if (oneOrLess.contains(local)) {
                return nAssign.get(local);
              }
            }
            return super.travel(op);
          }
        }.travel(method.stmts);
        for (Local local : oneOrLess) {
          nAssign.remove(local);
        }
        oneOrLess.clear();
      }
    }

    Set<Local> replaced = new HashSet<>();
    for (Iterator<Stmt> it = method.stmts.iterator(); it.hasNext(); ) {
      Stmt p = it.next();

      InvokeExpr ie = null;

      if (p.st == ASSIGN) {
        if (p.getOp2().vt == INVOKE_SPECIAL) {
          ie = (InvokeExpr) p.getOp2();
        }
      } else if (p.st == VOID_INVOKE) {
        ie = (InvokeExpr) p.getOp();
      }

      if (ie != null) {
        if ("<init>".equals(ie.name) && "V".equals(ie.ret)) {
          Value[] orgOps = ie.getOps();
          if (orgOps[0].vt == LOCAL) {
            Local objToInit = (Local) ie.getOps()[0];
            NewExpr newExpr = nAssign.get(objToInit);
            if (newExpr != null) {
              if (!ie.owner.equals(newExpr.type)) {
                throw new RuntimeException("");
              }

              Value[] nOps = new Value[orgOps.length - 1];
              System.arraycopy(orgOps, 1, nOps, 0, nOps.length);
              InvokeExpr invokeNew = Exprs.nInvokeNew(nOps, ie.args, ie.owner);
              method.stmts.insertBefore(p, Stmts.nAssign(objToInit, invokeNew));
              it.remove();
              replaced.add(objToInit);
            }
          } else if (orgOps[0].vt == NEW) {
            NewExpr newExpr = (NewExpr) ie.getOps()[0];
            if (newExpr != null) {
              Value[] nOps = new Value[orgOps.length - 1];
              System.arraycopy(orgOps, 1, nOps, 0, nOps.length);
              InvokeExpr invokeNew = Exprs.nInvokeNew(nOps, ie.args, ie.owner);
              method.stmts.insertBefore(p, Stmts.nVoidInvoke(invokeNew));
              it.remove();
            }
          }
        }
      }
    }
    nAssign.clear();
    for (Local x : replaced) {
      method.stmts.remove(init.remove(x));
    }
  }
Example #2
0
  /**
   * the statements must be simplest.
   *
   * <pre>
   * a = b + c; // ok
   * a = b[0] + c;// may cause exception, must expend to tmp1=b[0];a=tmp1+c;
   * </pre>
   *
   * @see com.googlecode.dex2jar.ir.ts.Transformer#transform(com.googlecode.dex2jar.ir.IrMethod)
   */
  @Override
  public void transform(IrMethod je) {
    StmtList list = je.stmts;
    List<Stmt> orderList = list._ls_visit_order;

    for (int p = 0; p < orderList.size(); p++) {
      Stmt st = orderList.get(p);
      if (st == null || !list.contains(st)) {
        continue;
      }
      switch (st.st) {
        case ASSIGN:
        case IDENTITY:
          AssignStmt as = (AssignStmt) st;
          if (as.op1.value.vt == VT.LOCAL) {
            Local aLeft = (Local) as.op1.value;
            if (as.op2.value.vt == VT.NEW) { // remove new
              NewExpr c = (NewExpr) as.op2.value;
              boolean replaced = false;
              for (Iterator<AssignStmt> it = list._ls_inits.iterator(); it.hasNext(); ) {
                AssignStmt stmt = it.next();
                InvokeExpr ie = (InvokeExpr) stmt.op2.value;
                if (ie.ops[0].value == aLeft && ie.methodOwnerType.equals(c.type)) {
                  list.remove(st);
                  it.remove();
                  je.locals.remove(stmt.op1.value);
                  ValueBox[] vb = new ValueBox[ie.ops.length - 1];
                  System.arraycopy(ie.ops, 1, vb, 0, vb.length);
                  AssignStmt nas =
                      Stmts.nAssign(
                          as.op1,
                          new ValueBox(Exprs.nInvokeNew(vb, ie.argmentTypes, ie.methodOwnerType)));
                  list.replace(stmt, nas);
                  aLeft._ls_read_count--;
                  orderList.set(orderList.indexOf(stmt), nas);
                  replaced = true;
                  break;
                }
              }
              if (replaced) {
                continue;
              }
            }
            if (aLeft._ls_write_count == 1) {
              switch (as.op2.value.vt) {
                case LOCAL:
                  {
                    Local b = (Local) as.op2.value;
                    if (b._ls_write_count == 1) { // if b is only write for once
                      b._ls_read_count += aLeft._ls_read_count - 1;
                      je.locals.remove(aLeft);
                      aLeft._ls_vb.value = b;
                      list.remove(st);
                      orderList.set(p, null);
                    }
                    continue;
                  }
                case CONSTANT:
                  {
                    as.op1.value = as.op2.value;
                    je.locals.remove(aLeft);
                    list.remove(st);
                    orderList.set(p, null);
                    continue;
                  }
              }
            }
          }
      }
    }

    /*
     * Merge some simple filled arrays
     * merge:
     * a[][]=new xx[2][];a[0]=new xx[2];a[0][0]=b;a[0][1]=c;a[1]=new xx[2];a[1][0]=d;a[1][1]=e;	->	a[][]=new xx[][]{{b,c},{d,e}};
     * tmp[][]=new xx[][]{{b,c},{d,e}};a=tmp;	->	a=new xx[][]{{b,c},{d,e}};
     * not merge:
     * a[]=new xx[3];a[0]=b;a[1]=c;(Not full)
     * a[]=new xx[2];a[0]=b;a[1]=c.gg();(Not simple)
     */
    boolean changed = false;
    do {
      changed = false;
      for (int p = 0; p < orderList.size(); p++) {
        Stmt st = orderList.get(p);
        if (st == null || !list.contains(st)) {
          continue;
        }
        switch (st.st) {
          case ASSIGN:
            AssignStmt as = (AssignStmt) st;
            if (as.op2.value.vt == VT.NEW_ARRAY) {
              TypeExpr te = (TypeExpr) as.op2.value;
              Value val = as.op1.value;
              if (te.op.value instanceof Constant) {
                int arraySize = (Integer) ((Constant) te.op.value).value;
                Type type = te.type;
                int size = 0;
                int empty = 0;
                // Verify array data
                for (int j = 1; j < orderList.size() - p; j++) {
                  Stmt st2 = orderList.get(p + j);
                  if (st2 == null) {
                    empty++;
                    continue;
                  }
                  if (st2.st == ST.ASSIGN) {
                    AssignStmt as2 = (AssignStmt) st2;
                    if (as2.op1.value.vt == VT.ARRAY) {
                      ArrayExpr ae2 = (ArrayExpr) as2.op1.value;
                      if ((ae2.op1.value == val) && (ae2.op2.value instanceof Constant)) {
                        int idx = (Integer) ((Constant) ae2.op2.value).value;
                        if (idx == (j - empty - 1)) {
                          continue;
                        }
                      }
                    }
                  }
                  size = j - 1;
                  break;
                }
                int dataSize = size - empty;
                if (dataSize == arraySize) { // Not full array may cause some NullPoint problems
                  Value[] vbs = new Value[arraySize];
                  for (int j = 1; j <= size; j++) {
                    Stmt st2 = orderList.get(p + j);
                    if (st2 == null) {
                      continue;
                    }
                    AssignStmt as2 = (AssignStmt) st2;
                    ArrayExpr ae2 = (ArrayExpr) as2.op1.value;
                    int idx = ((Integer) ((Constant) ae2.op2.value).value);
                    vbs[idx] = as2.op2.value;
                    orderList.set((p + j), null);
                    list.remove(st2);
                  }
                  Local loc = (Local) val;
                  loc._ls_read_count -= dataSize;
                  FilledArrayExpr fa = Exprs.nFilledArray(type, vbs);
                  AssignStmt nas = Stmts.nAssign(loc, fa);
                  list.replace(st, nas);
                  orderList.set(p, nas);
                  changed = true;
                  // Merge tmp Locals
                  if (loc._ls_write_count == 1 && loc._ls_read_count == 1) {
                    Stmt st3 = null;
                    for (int j = size + 1; j < orderList.size() - p; j++) {
                      st3 = orderList.get(p + j);
                      if (st3 != null) {
                        break;
                      }
                    }
                    if (st3 != null && (st3.st == ST.ASSIGN || st3.st == ST.IDENTITY)) {
                      AssignStmt as3 = (AssignStmt) st3;
                      if (as3.op2.value == loc) {
                        loc._ls_read_count = 0;
                        loc._ls_write_count = 0;

                        list.remove(nas);
                        orderList.set(p, null);

                        AssignStmt nas3 = Stmts.nAssign(as3.op1.value, fa);
                        list.replace(st3, nas3);
                        orderList.set(orderList.indexOf(st3), nas3);

                        je.locals.remove(loc);
                      }
                    }
                  }
                }
              }
            }
        }
      }
    } while (changed);

    {
      List<ValueBox> vbs = new ArrayList<ValueBox>(20);

      Stack<ValueBox> tmp = new Stack<ValueBox>();

      for (int p = 0; p < orderList.size(); p++) {
        Stmt st = orderList.get(p);
        if (st == null || !list.contains(st)) {
          continue;
        }

        switch (st.st) {
          case RETURN_VOID:
          case LABEL:
          case GOTO:
          case NOP:
          case IDENTITY:
            continue;
        }

        Stmt pre = st.getPre();
        if (pre == null) {
          continue;
        }

        if (canRemove(pre)) {
          vbs.clear();
          tmp.clear();
          AssignStmt as = (AssignStmt) pre;
          Local preLocal = (Local) as.op1.value;
          execStmt(vbs, st, preLocal);
          for (ValueBox vb : vbs) {
            switch (vb.value.vt) {
              case CONSTANT:
                continue;
              case LOCAL:
                tmp.push(vb);
                continue;
            }
            break;
          }
          while (!tmp.isEmpty()) {
            ValueBox vb = tmp.pop();
            if (vb.value == preLocal) {
              vb.value = as.op2.value;
              list.remove(as);
              je.locals.remove(preLocal);
              pre = st.getPre();
              if (pre != null && canRemove(pre)) {
                as = (AssignStmt) pre;
                preLocal = (Local) as.op1.value;
              } else {
                break;
              }
            }
          }
        }
      }
    }

    if (list._ls_inits.size() > 0) {
      // replace new again
      for (int p = 0; p < orderList.size(); p++) {
        Stmt st = orderList.get(p);
        if (st == null || !list.contains(st)) {
          continue;
        }
        switch (st.st) {
          case ASSIGN:
          case IDENTITY:
            AssignStmt as = (AssignStmt) st;
            if (as.op1.value.vt == VT.LOCAL) {
              Local aLeft = (Local) as.op1.value;
              if (as.op2.value.vt == VT.NEW) { // remove new
                NewExpr c = (NewExpr) as.op2.value;
                boolean replaced = false;
                for (Iterator<AssignStmt> it = list._ls_inits.iterator(); it.hasNext(); ) {
                  AssignStmt stmt = it.next();
                  InvokeExpr ie = (InvokeExpr) stmt.op2.value;
                  if (ie.ops[0].value == aLeft && ie.methodOwnerType.equals(c.type)) {
                    list.remove(st);
                    it.remove();
                    ValueBox[] vb = new ValueBox[ie.ops.length - 1];
                    System.arraycopy(ie.ops, 1, vb, 0, vb.length);
                    AssignStmt nas =
                        Stmts.nAssign(
                            as.op1,
                            new ValueBox(
                                Exprs.nInvokeNew(vb, ie.argmentTypes, ie.methodOwnerType)));
                    list.replace(stmt, nas);
                    aLeft._ls_read_count--;
                    orderList.set(orderList.indexOf(stmt), nas);
                    replaced = true;
                    break;
                  }
                }
                if (replaced) {
                  continue;
                }
              }
            }
        }
      }
    }
    list._ls_inits = null;
  }