• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 package com.android.tools.r8.graph;
5 
6 import java.util.IdentityHashMap;
7 import java.util.Map;
8 
9 /**
10  * A GraphLense implements a virtual view on top of the graph, used to delay global rewrites until
11  * later IR processing stages.
12  * <p>
13  * Valid remappings are limited to the following operations:
14  * <ul>
15  * <li>Mapping a classes type to one of the super/subtypes.</li>
16  * <li>Renaming private methods/fields.</li>
17  * <li>Moving methods/fields to a super/subclass.</li>
18  * <li>Replacing method/field references by the same method/field on a super/subtype</li>
19  * </ul>
20  * Note that the latter two have to take visibility into account.
21  */
22 public abstract class GraphLense {
23 
24   public static class Builder {
25 
Builder()26     private Builder() {
27 
28     }
29 
30     private final Map<DexType, DexType> typeMap = new IdentityHashMap<>();
31     private final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>();
32     private final Map<DexField, DexField> fieldMap = new IdentityHashMap<>();
33 
map(DexType from, DexType to)34     public void map(DexType from, DexType to) {
35       typeMap.put(from, to);
36     }
37 
map(DexMethod from, DexMethod to)38     public void map(DexMethod from, DexMethod to) {
39       methodMap.put(from, to);
40     }
41 
map(DexField from, DexField to)42     public void map(DexField from, DexField to) {
43       fieldMap.put(from, to);
44     }
45 
build(DexItemFactory dexItemFactory)46     public GraphLense build(DexItemFactory dexItemFactory) {
47       return build(new IdentityGraphLense(), dexItemFactory);
48     }
49 
build(GraphLense previousLense, DexItemFactory dexItemFactory)50     public GraphLense build(GraphLense previousLense, DexItemFactory dexItemFactory) {
51       return new NestedGraphLense(typeMap, methodMap, fieldMap, previousLense, dexItemFactory);
52     }
53 
54   }
55 
builder()56   public static Builder builder() {
57     return new Builder();
58   }
59 
lookupType(DexType type, DexEncodedMethod context)60   public abstract DexType lookupType(DexType type, DexEncodedMethod context);
61 
lookupMethod(DexMethod method, DexEncodedMethod context)62   public abstract DexMethod lookupMethod(DexMethod method, DexEncodedMethod context);
63 
lookupField(DexField field, DexEncodedMethod context)64   public abstract DexField lookupField(DexField field, DexEncodedMethod context);
65 
isContextFree()66   public abstract boolean isContextFree();
67 
getIdentityLense()68   public static GraphLense getIdentityLense() {
69     return new IdentityGraphLense();
70   }
71 
isIdentityLense()72   public final boolean isIdentityLense() {
73     return this instanceof IdentityGraphLense;
74   }
75 
76   private static class IdentityGraphLense extends GraphLense {
77 
78     @Override
lookupType(DexType type, DexEncodedMethod context)79     public DexType lookupType(DexType type, DexEncodedMethod context) {
80       return type;
81     }
82 
83     @Override
lookupMethod(DexMethod method, DexEncodedMethod context)84     public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context) {
85       return method;
86     }
87 
88     @Override
lookupField(DexField field, DexEncodedMethod context)89     public DexField lookupField(DexField field, DexEncodedMethod context) {
90       return field;
91     }
92 
93     @Override
isContextFree()94     public boolean isContextFree() {
95       return true;
96     }
97   }
98 
99   private static class NestedGraphLense extends GraphLense {
100 
101     private final GraphLense previousLense;
102     private final DexItemFactory dexItemFactory;
103 
104     private final Map<DexType, DexType> typeMap;
105     private final Map<DexType, DexType> arrayTypeCache = new IdentityHashMap<>();
106     private final Map<DexMethod, DexMethod> methodMap;
107     private final Map<DexField, DexField> fieldMap;
108 
NestedGraphLense(Map<DexType, DexType> typeMap, Map<DexMethod, DexMethod> methodMap, Map<DexField, DexField> fieldMap, GraphLense previousLense, DexItemFactory dexItemFactory)109     private NestedGraphLense(Map<DexType, DexType> typeMap, Map<DexMethod, DexMethod> methodMap,
110         Map<DexField, DexField> fieldMap, GraphLense previousLense, DexItemFactory dexItemFactory) {
111       this.typeMap = typeMap;
112       this.methodMap = methodMap;
113       this.fieldMap = fieldMap;
114       this.previousLense = previousLense;
115       this.dexItemFactory = dexItemFactory;
116     }
117 
118     @Override
lookupType(DexType type, DexEncodedMethod context)119     public DexType lookupType(DexType type, DexEncodedMethod context) {
120       if (type.isArrayType()) {
121         DexType result = arrayTypeCache.get(type);
122         if (result == null) {
123           DexType baseType = type.toBaseType(dexItemFactory);
124           DexType newType = lookupType(baseType, context);
125           if (baseType == newType) {
126             result = type;
127           } else {
128             result = type.replaceBaseType(newType, dexItemFactory);
129           }
130           arrayTypeCache.put(type, result);
131         }
132         return result;
133       }
134       DexType previous = previousLense.lookupType(type, context);
135       return typeMap.getOrDefault(previous, previous);
136     }
137 
138     @Override
lookupMethod(DexMethod method, DexEncodedMethod context)139     public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context) {
140       DexMethod previous = previousLense.lookupMethod(method, context);
141       return methodMap.getOrDefault(previous, previous);
142     }
143 
144     @Override
lookupField(DexField field, DexEncodedMethod context)145     public DexField lookupField(DexField field, DexEncodedMethod context) {
146       DexField previous = previousLense.lookupField(field, context);
147       return fieldMap.getOrDefault(previous, previous);
148     }
149 
150     @Override
isContextFree()151     public boolean isContextFree() {
152       return previousLense.isContextFree();
153     }
154   }
155 }
156