fix type detect on arrays

fix https://github.com/pxb1988/dex2jar/issues/28
This commit is contained in:
Bob Pan 2016-03-04 19:55:13 +08:00
parent d9baaa5779
commit 0d48e49275
2 changed files with 498 additions and 428 deletions

View File

@ -16,8 +16,6 @@
*/
package com.googlecode.dex2jar.ir.ts;
import java.util.*;
import com.googlecode.dex2jar.ir.IrMethod;
import com.googlecode.dex2jar.ir.TypeClass;
import com.googlecode.dex2jar.ir.expr.*;
@ -29,6 +27,8 @@ import com.googlecode.dex2jar.ir.stmt.Stmt.E1Stmt;
import com.googlecode.dex2jar.ir.stmt.Stmt.E2Stmt;
import com.googlecode.dex2jar.ir.stmt.Stmt.ST;
import java.util.*;
/**
* Type and correct Exprs
*
@ -100,7 +100,7 @@ public class TypeTransformer implements Transformer {
public final Value value;
/**
* same use, have same {@link #clz}
* same use, have same
*/
public Set<TypeRef> sameValues = null;
/**
@ -111,82 +111,120 @@ public class TypeTransformer implements Transformer {
/**
* reference to root
*/
public TypeRef arrayRoot = null;
public Set<TypeRef> arrayRoots = null;
public TypeRef mergedArrayRoot;
public TypeRef mergedArrayValue;
public Set<TypeRef> parents = null;
public Set<TypeRef> children = null;
public void setArrayValueShareT(SharedT arrayValueShareT) {
this.arrayValueShareT = arrayValueShareT;
public TypeClass clz = TypeClass.UNKNOWN;
public String provideDesc = null;
public Set<String> uses;
private TypeRef next;
public void linkArray() {
if (arrayRoots != null) {
for (TypeRef root : arrayRoots) {
if (mergedArrayRoot == null) {
mergedArrayRoot = root;
} else {
mergedArrayRoot.merge(root);
}
if (root.mergedArrayValue == null) {
root.mergedArrayValue = this;
} else {
root.mergedArrayValue.merge(this);
}
}
}
if (gArrayValues != null) {
for (TypeRef leafe : gArrayValues) {
if (mergedArrayValue == null) {
mergedArrayValue = leafe;
} else {
mergedArrayValue.merge(leafe);
}
public TypeClass getClz() {
return t.getReal().clz;
if (leafe.mergedArrayRoot == null) {
leafe.mergedArrayRoot = this;
} else {
leafe.mergedArrayRoot.merge(this);
}
}
}
if (sArrayValues != null) {
for (TypeRef leafe : sArrayValues) {
if (mergedArrayValue == null) {
mergedArrayValue = leafe;
} else {
mergedArrayValue.merge(leafe);
}
if (leafe.mergedArrayRoot == null) {
leafe.mergedArrayRoot = this;
} else {
leafe.mergedArrayRoot.merge(this);
}
}
}
}
public void setClz(TypeClass clz) {
this.t.getReal().clz = clz;
}
static class SharedT {
private TypeClass clz = TypeClass.UNKNOWN;
private String provideDesc = null;
private Set<String> uses;
SharedT next;
SharedT getReal() {
SharedT _this = this;
SharedT _next = this.next;
while (_next != null) {
_this = _next;
_next = _next.next;
}
return _this;
}
boolean merge(SharedT b) {
SharedT a = this;
public void merge(TypeRef other) {
TypeRef a = getReal();
TypeRef b = other.getReal();
if (a == b) {
return false;
return;
}
if (a.mergedArrayRoot != null && b.mergedArrayRoot != null) {
a.mergedArrayRoot.merge(b.mergedArrayRoot);
} else if (a.mergedArrayRoot != null) {
b.mergedArrayRoot = a.mergedArrayRoot;
} else {
a.mergedArrayRoot = b.mergedArrayRoot;
}
if (a.mergedArrayValue != null && b.mergedArrayValue != null) {
a.mergedArrayValue.merge(b.mergedArrayValue);
} else if (a.mergedArrayValue != null) {
b.mergedArrayValue = a.mergedArrayValue;
} else {
a.mergedArrayValue = b.mergedArrayValue;
}
b.next = a;
if (a.provideDesc == null) {
a.provideDesc = b.provideDesc;
} else if (b.provideDesc != null) {
a.provideDesc = TypeAnalyze.mergeProviderType(a.provideDesc, b.provideDesc);
b.provideDesc = null;
}
if (b.uses != null) {
if (a.uses == null) {
a.uses = new HashSet<>();
}
a.uses.addAll(b.uses);
}
return true;
}
b.uses = null;
}
private SharedT arrayValueShareT;
SharedT getArrayValueShareT() {
if (arrayValueShareT == null) {
arrayValueShareT = new SharedT();
return arrayValueShareT;
} else {
return arrayValueShareT.getReal();
}
}
boolean mergeT(TypeRef other) {
SharedT a = t.getReal();
SharedT b = other.t.getReal();
this.t = a;
other.t = a;
if (a != b) {
updateTypeClass(other.getClz());
return a.merge(b);
public TypeClass getClz() {
return this.getReal().clz;
}
return false;
public void setClz(TypeClass clz) {
this.getReal().clz = clz;
}
private TypeRef getReal() {
TypeRef x = this;
while (x.next != null) {
x = x.next;
}
return x;
}
SharedT t = new SharedT();
public TypeRef(Value value) {
super();
@ -195,25 +233,27 @@ public class TypeTransformer implements Transformer {
@Override
public String toString() {
String p = this.getUses() == null ? "[]" : this.getUses().toString();
return getClz() + "::" + value + ": " + this.getProvideDesc() + " > {" + p.substring(1, p.length() - 1) + "}";
TypeRef real = getReal();
String p = real.uses == null ? "[]" : real.uses.toString();
return real.clz + "::" + value + ": " + real.provideDesc + " > {" + p.substring(1, p.length() - 1) + "}";
}
public String getType() {
if (getClz() == TypeClass.OBJECT) {
TypeClass clz = getClz();
if (clz == TypeClass.OBJECT) {
if (getProvideDesc().length() == 1) {
return "Ljava/lang/Object;";
} else {
return getProvideDesc();
}
}
if (getClz().fixed && getClz() != TypeClass.INT) {
if (clz.fixed && clz != TypeClass.INT) {
if (getProvideDesc() == null) {
throw new RuntimeException();
}
return getProvideDesc();
}
if (getClz() == TypeClass.JD) { // prefere Long if wide
if (clz == TypeClass.JD) { // prefere Long if wide
return "J";
}
if (getUses() != null) {
@ -224,7 +264,7 @@ public class TypeTransformer implements Transformer {
}
}
switch (getClz()) {
switch (clz) {
case ZI:
return "I";
case ZIFL:
@ -260,23 +300,23 @@ public class TypeTransformer implements Transformer {
}
public Set<String> getUses() {
return t.getReal().uses;
return getReal().uses;
}
public String getProvideDesc() {
return t.getReal().provideDesc;
return getReal().provideDesc;
}
public void setProvideDesc(String provideDesc) {
this.t.getReal().provideDesc = provideDesc;
this.getReal().provideDesc = provideDesc;
}
public boolean addUses(String ele) {
SharedT t=this.t.getReal();
if (t.uses != null) {
TypeRef t = this.getReal();
if (uses != null) {
return t.uses.add(ele);
} else {
t.uses = new HashSet<>();
uses = new HashSet<>();
return t.uses.add(ele);
}
}
@ -309,24 +349,16 @@ public class TypeTransformer implements Transformer {
private void fixTypes() {
// 1. collect all Array Roots
UniqueQueue<TypeRef> q = new UniqueQueue<>();
Set<TypeRef> arrayRoots = new HashSet<>();
for (TypeRef t : refs) {
if (t.gArrayValues != null || t.sArrayValues != null) {
arrayRoots.add(t);
q.add(t);
}
}
while (!q.isEmpty()) {
TypeRef ref = q.poll();
TypeRef.SharedT arrayValue=ref.getArrayValueShareT();
if(ref.gArrayValues!=null){
for(TypeRef t:ref.gArrayValues){
}
for (TypeRef ref : refs) {
if (ref.gArrayValues != null || ref.sArrayValues != null) {
arrayRoots.add(ref);
}
ref.linkArray();
}
UniqueQueue<TypeRef> q = new UniqueQueue<>();
q.addAll(refs);
while (!q.isEmpty()) {
// 2. merge provided type to children. merge uses to parent. merge TypeClass to sameValues
@ -364,25 +396,28 @@ public class TypeTransformer implements Transformer {
}
private static void mergeTypeToArrayGetValue(String type, TypeRef target, UniqueQueue<TypeRef> q) {
if (target.getProvideDesc() == null) {
target.setProvideDesc(type);
target = target.getReal();
if (target.provideDesc == null) {
target.provideDesc = type;
q.add(target);
} else {
String mergedType = mergeTypeEx(type, target.getProvideDesc());
if (!mergedType.equals(target.getProvideDesc())) {
target.setProvideDesc(mergedType);
String mergedType = mergeTypeEx(type, target.provideDesc);
if (!mergedType.equals(target.provideDesc)) {
target.provideDesc = mergedType;
q.add(target);
}
}
}
private static void mergeTypeToSubRef(String type, TypeRef target, UniqueQueue<TypeRef> q) {
if (target.getProvideDesc() == null) {
target.setProvideDesc(type);
target = target.getReal();
if (target.provideDesc == null) {
target.provideDesc = type;
q.add(target);
} else {
String mergedType = mergeProviderType(type, target.getProvideDesc());
if (!mergedType.equals(target.getProvideDesc())) {
target.setProvideDesc(mergedType);
String mergedType = mergeProviderType(type, target.provideDesc);
if (!mergedType.equals(target.provideDesc)) {
target.provideDesc = mergedType;
q.add(target);
}
}
@ -927,7 +962,10 @@ public class TypeTransformer implements Transformer {
root.gArrayValues = new HashSet<>(3);
}
root.gArrayValues.add(value);
value.arrayRoot = root;
if (value.arrayRoots == null) {
value.arrayRoots = new HashSet<>(3);
}
value.arrayRoots.add(root);
}
private void linkSetArray(Value array, Value v) {
@ -937,7 +975,10 @@ public class TypeTransformer implements Transformer {
root.sArrayValues = new HashSet<>(3);
}
root.sArrayValues.add(value);
value.arrayRoot = root;
if (value.arrayRoots == null) {
value.arrayRoots = new HashSet<>(3);
}
value.arrayRoots.add(root);
}
private void linkFromTo(Value from, Value to) {
@ -954,8 +995,8 @@ public class TypeTransformer implements Transformer {
}
private void provideAs(Value op, String type) {
TypeRef typeRef = getDefTypeRef(op);
typeRef.setProvideDesc(type);
TypeRef typeRef = getDefTypeRef(op).getReal();
typeRef.provideDesc = (type);
typeRef.updateTypeClass(TypeClass.clzOf(type));
}

View File

@ -0,0 +1,29 @@
package res;
import java.lang.reflect.Array;
/**
* https://github.com/pxb1988/dex2jar/issues/28
*/
public class Gh28Type {
protected void onCreate() {
double t0[] = new double[1];
t0[0] = 0;
double t1[] = (double[]) Array.newInstance(Double.TYPE, 1);
t1[0] = 0;
double t2[][] = new double[1][1];
t2[0][0] = 0; // incorrectly translated to 0L (long) rather than 0.0 (double)
double t3[][] = (double[][]) Array.newInstance(Double.TYPE, 1, 1);
t3[0][0] = 0; // incorrectly translated to 0L (long) rather than 0.0 (double)
a(t0);
a(t1);
a(t2[0]);
a(t3[0]);
}
private void a(double[] t0) {
// Just to avoid optimization of unused local variables in onCreate here above
}
}