diff --git a/dex-ir/src/main/java/com/googlecode/dex2jar/ir/ts/TypeTransformer.java b/dex-ir/src/main/java/com/googlecode/dex2jar/ir/ts/TypeTransformer.java index b095c9ca1..d72bda2ed 100644 --- a/dex-ir/src/main/java/com/googlecode/dex2jar/ir/ts/TypeTransformer.java +++ b/dex-ir/src/main/java/com/googlecode/dex2jar/ir/ts/TypeTransformer.java @@ -96,6 +96,75 @@ public void transform(IrMethod irMethod) { } } + enum Relation { + + R_sameValues { + @Override + Set get(TypeRef obj) { + return obj.sameValues; + } + + @Override + void set(TypeRef obj, Set v) { + obj.sameValues = v; + } + }, R_gArrayValues { + @Override + Set get(TypeRef obj) { + return obj.gArrayValues; + } + + @Override + void set(TypeRef obj, Set v) { + obj.gArrayValues = v; + } + }, R_sArrayValues { + @Override + Set get(TypeRef obj) { + return obj.sArrayValues; + } + + @Override + void set(TypeRef obj, Set v) { + obj.sArrayValues = v; + } + }, R_arrayRoots { + @Override + Set get(TypeRef obj) { + return obj.arrayRoots; + } + + @Override + void set(TypeRef obj, Set v) { + obj.arrayRoots = v; + } + }, R_parents { + @Override + Set get(TypeRef obj) { + return obj.parents; + } + + @Override + void set(TypeRef obj, Set v) { + obj.parents = v; + } + }, R_children { + @Override + Set get(TypeRef obj) { + return obj.children; + } + + @Override + void set(TypeRef obj, Set v) { + obj.children = v; + } + }; + + abstract Set get(TypeRef obj); + + abstract void set(TypeRef obj, Set v); + } + public static class TypeRef { public final Value value; @@ -113,9 +182,6 @@ public static class TypeRef { */ public Set arrayRoots = null; - public TypeRef mergedArrayRoot; - public TypeRef mergedArrayValue; - public Set parents = null; public Set children = null; @@ -125,97 +191,56 @@ public static class TypeRef { 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); - } - - 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 merge(TypeRef other) { - TypeRef a = getReal(); + assert this.next == null; + TypeRef a = this; TypeRef b = other.getReal(); if (a == b) { 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; + relationMerge(a, b, Relation.R_sameValues); + relationMerge(a, b, Relation.R_gArrayValues); + relationMerge(a, b, Relation.R_sArrayValues); + relationMerge(a, b, Relation.R_arrayRoots); + relationMerge(a, b, Relation.R_parents); + relationMerge(a, b, Relation.R_children); + if (a.provideDesc == null) { a.provideDesc = b.provideDesc; } else if (b.provideDesc != null) { a.provideDesc = TypeAnalyze.mergeProviderType(a.provideDesc, b.provideDesc); - b.provideDesc = null; } + b.provideDesc = null; if (b.uses != null) { if (a.uses == null) { - a.uses = new HashSet<>(); + a.uses = b.uses; + } else { + a.uses.addAll(b.uses); } - a.uses.addAll(b.uses); b.uses = null; } } - public TypeClass getClz() { - return this.getReal().clz; - } - - public void setClz(TypeClass clz) { - this.getReal().clz = clz; + private static void relationMerge(TypeRef a, TypeRef b, Relation r) { + Set bv = r.get(b); + if (bv != null) { + Set av = r.get(a); + Set merged; + if (av == null) { + merged = bv; + r.set(a, merged); + } else { + merged = av; + merged.addAll(bv); + } + merged.remove(a); + merged.remove(b); + r.set(b, null); + } } private TypeRef getReal() { @@ -242,26 +267,27 @@ public String toString() { } public String getType() { - TypeClass clz = getClz(); + TypeRef thiz = getReal(); + TypeClass clz = thiz.clz; if (clz == TypeClass.OBJECT) { - if (getProvideDesc().length() == 1) { + if (thiz.provideDesc.length() == 1) { return "Ljava/lang/Object;"; } else { - return getProvideDesc(); + return thiz.provideDesc; } } if (clz.fixed && clz != TypeClass.INT) { - if (getProvideDesc() == null) { + if (thiz.provideDesc == null) { throw new RuntimeException(); } - return getProvideDesc(); + return thiz.provideDesc; } if (clz == TypeClass.JD) { // prefere Long if wide return "J"; } - if (getUses() != null) { + if (thiz.uses != null) { for (String t : possibleIntTypes) { - if (getUses().contains(t)) { + if (thiz.uses.contains(t)) { return t; } } @@ -283,49 +309,42 @@ public String getType() { } public boolean updateTypeClass(TypeClass clz) { - TypeClass thizClz = this.getClz(); + assert this.next == null; + TypeClass thizClz = this.clz; TypeClass merged = TypeClass.merge(thizClz, clz); if (merged == thizClz) { return false; } - this.setClz(merged); + this.clz = merged; return true; } public void clear() { this.sArrayValues = null; - // this.sArryRoots = null; this.gArrayValues = null; - // this.gArryRoots = null; + this.arrayRoots = null; this.parents = null; this.children = null; - this.children = null; this.sameValues = null; } - public Set getUses() { - return getReal().uses; - } - - public String getProvideDesc() { + String getProvideDesc() { return getReal().provideDesc; } - public void setProvideDesc(String provideDesc) { - this.getReal().provideDesc = provideDesc; - } - public boolean addUses(String ele) { - TypeRef t = this.getReal(); - if (uses != null) { + assert this.next == null; + TypeRef t = this; + if (t.uses != null) { return t.uses.add(ele); } else { - uses = new HashSet<>(); + t.uses = new HashSet<>(); return t.uses.add(ele); } } public boolean addAllUses(Set uses) { + assert this.next == null; if (uses != null) { return uses.addAll(uses); } else { @@ -351,15 +370,16 @@ public List analyze() { } private void fixTypes() { - // 1. collect all Array Roots - Set arrayRoots = new HashSet<>(); for (TypeRef ref : refs) { + ref = ref.getReal(); if (ref.gArrayValues != null || ref.sArrayValues != null) { arrayRoots.add(ref); } - ref.linkArray(); + mergeArrayRelation(ref, Relation.R_gArrayValues); + mergeArrayRelation(ref, Relation.R_sArrayValues); + mergeArrayRelation(ref, Relation.R_arrayRoots); } UniqueQueue q = new UniqueQueue<>(); @@ -372,13 +392,16 @@ private void fixTypes() { } // 3. merge type from Array Roots to Array Values for (TypeRef ref : arrayRoots) { - String provideDesc = ref.getProvideDesc(); + ref = ref.getReal(); + String provideDesc = ref.provideDesc; if (provideDesc != null && provideDesc.charAt(0) == '[') { String ele = provideDesc.substring(1); + TypeClass clz = TypeClass.clzOf(ele); if (ref.gArrayValues != null) { for (TypeRef p : ref.gArrayValues) { - if (p.updateTypeClass(TypeClass.clzOf(ele))) { + p = p.getReal(); + if (p.updateTypeClass(clz)) { q.add(p); } mergeTypeToArrayGetValue(ele, p, q); @@ -386,7 +409,8 @@ private void fixTypes() { } if (ref.sArrayValues != null) { for (TypeRef p : ref.sArrayValues) { - if (p.updateTypeClass(TypeClass.clzOf(ele))) { + p = p.getReal(); + if (p.updateTypeClass(clz)) { q.add(p); } if (p.addUses(ele)) { @@ -399,6 +423,17 @@ private void fixTypes() { } } + private void mergeArrayRelation(TypeRef ref, Relation r) { + Set v = r.get(ref); + if (v != null && v.size() > 1) { + List copy = new ArrayList<>(v); + TypeRef mergeTo = copy.get(0).getReal(); + for (int i = 1; i < copy.size(); i++) { + mergeTo.merge(copy.get(i)); + } + } + } + private static void mergeTypeToArrayGetValue(String type, TypeRef target, UniqueQueue q) { target = target.getReal(); if (target.provideDesc == null) { @@ -414,7 +449,6 @@ private static void mergeTypeToArrayGetValue(String type, TypeRef target, Unique } private static void mergeTypeToSubRef(String type, TypeRef target, UniqueQueue q) { - target = target.getReal(); if (target.provideDesc == null) { target.provideDesc = type; q.add(target); @@ -482,7 +516,8 @@ private static String mergeTypeEx(String a, String b) { } private void copyTypes(UniqueQueue q, TypeRef ref) { - TypeClass clz = ref.getClz(); + ref = ref.getReal(); + TypeClass clz = ref.clz; switch (clz) { case BOOLEAN: @@ -490,23 +525,24 @@ private void copyTypes(UniqueQueue q, TypeRef ref) { case LONG: case DOUBLE: case VOID: - ref.setProvideDesc(clz.name); + ref.provideDesc = clz.name; break; default: } - String provideDesc = ref.getProvideDesc(); + String provideDesc = ref.provideDesc; if (provideDesc == null && ref.parents != null && ref.parents.size() > 1) { if (isAllParentSetted(ref)) { - ref.setProvideDesc(provideDesc = mergeParentType(ref.parents)); + ref.provideDesc = provideDesc = mergeParentType(ref.parents); } } if (ref.parents != null) { for (TypeRef p : ref.parents) { + p = p.getReal(); if (p.updateTypeClass(clz)) { q.add(p); } - if (ref.getUses() != null) { - if (p.addAllUses(ref.getUses())) { + if (ref.uses != null) { + if (p.addAllUses(ref.uses)) { q.add(p); } } @@ -514,6 +550,7 @@ private void copyTypes(UniqueQueue q, TypeRef ref) { } if (ref.children != null) { for (TypeRef p : ref.children) { + p = p.getReal(); if (p.updateTypeClass(clz)) { q.add(p); } @@ -525,6 +562,7 @@ private void copyTypes(UniqueQueue q, TypeRef ref) { } if (ref.sameValues != null) { for (TypeRef p : ref.sameValues) { + p = p.getReal(); if (p.updateTypeClass(clz)) { q.add(p); } diff --git a/dex-translator/src/test/java/res/Gh28Type.java b/dex-translator/src/test/java/res/Gh28Type.java index 7e8740057..b8b6c82fb 100644 --- a/dex-translator/src/test/java/res/Gh28Type.java +++ b/dex-translator/src/test/java/res/Gh28Type.java @@ -8,8 +8,9 @@ public class Gh28Type { protected void onCreate() { - double t0[] = new double[1]; - t0[0] = 0; + double t0[] = new double[2]; + t0[0] = 1.0; + t0[1] = 2.0; // for https://github.com/pxb1988/dex2jar/issues/101 double t1[] = (double[]) Array.newInstance(Double.TYPE, 1); t1[0] = 0; double t2[][] = new double[1][1];