• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dx.merge;
18 
19 import com.android.dex.DexException;
20 import com.android.dex.DexIndexOverflowException;
21 import com.android.dx.io.CodeReader;
22 import com.android.dx.io.Opcodes;
23 import com.android.dx.io.instructions.DecodedInstruction;
24 import com.android.dx.io.instructions.ShortArrayCodeOutput;
25 
26 final class InstructionTransformer {
27     private final CodeReader reader;
28 
29     private DecodedInstruction[] mappedInstructions;
30     private int mappedAt;
31     private IndexMap indexMap;
32 
InstructionTransformer()33     public InstructionTransformer() {
34         this.reader = new CodeReader();
35         this.reader.setAllVisitors(new GenericVisitor());
36         this.reader.setStringVisitor(new StringVisitor());
37         this.reader.setTypeVisitor(new TypeVisitor());
38         this.reader.setFieldVisitor(new FieldVisitor());
39         this.reader.setMethodVisitor(new MethodVisitor());
40         this.reader.setMethodAndProtoVisitor(new MethodAndProtoVisitor());
41         this.reader.setCallSiteVisitor(new CallSiteVisitor());
42     }
43 
transform(IndexMap indexMap, short[] encodedInstructions)44     public short[] transform(IndexMap indexMap, short[] encodedInstructions) throws DexException {
45         DecodedInstruction[] decodedInstructions =
46             DecodedInstruction.decodeAll(encodedInstructions);
47         int size = decodedInstructions.length;
48 
49         this.indexMap = indexMap;
50         mappedInstructions = new DecodedInstruction[size];
51         mappedAt = 0;
52         reader.visitAll(decodedInstructions);
53 
54         ShortArrayCodeOutput out = new ShortArrayCodeOutput(size);
55         for (DecodedInstruction instruction : mappedInstructions) {
56             if (instruction != null) {
57                 instruction.encode(out);
58             }
59         }
60 
61         this.indexMap = null;
62         return out.getArray();
63     }
64 
65     private class GenericVisitor implements CodeReader.Visitor {
66         @Override
visit(DecodedInstruction[] all, DecodedInstruction one)67         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
68             mappedInstructions[mappedAt++] = one;
69         }
70     }
71 
72     private class StringVisitor implements CodeReader.Visitor {
73         @Override
visit(DecodedInstruction[] all, DecodedInstruction one)74         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
75             int stringId = one.getIndex();
76             int mappedId = indexMap.adjustString(stringId);
77             boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
78             jumboCheck(isJumbo, mappedId);
79             mappedInstructions[mappedAt++] = one.withIndex(mappedId);
80         }
81     }
82 
83     private class FieldVisitor implements CodeReader.Visitor {
84         @Override
visit(DecodedInstruction[] all, DecodedInstruction one)85         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
86             int fieldId = one.getIndex();
87             int mappedId = indexMap.adjustField(fieldId);
88             boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
89             jumboCheck(isJumbo, mappedId);
90             mappedInstructions[mappedAt++] = one.withIndex(mappedId);
91         }
92     }
93 
94     private class TypeVisitor implements CodeReader.Visitor {
95         @Override
visit(DecodedInstruction[] all, DecodedInstruction one)96         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
97             int typeId = one.getIndex();
98             int mappedId = indexMap.adjustType(typeId);
99             boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
100             jumboCheck(isJumbo, mappedId);
101             mappedInstructions[mappedAt++] = one.withIndex(mappedId);
102         }
103     }
104 
105     private class MethodVisitor implements CodeReader.Visitor {
106         @Override
visit(DecodedInstruction[] all, DecodedInstruction one)107         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
108             int methodId = one.getIndex();
109             int mappedId = indexMap.adjustMethod(methodId);
110             boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
111             jumboCheck(isJumbo, mappedId);
112             mappedInstructions[mappedAt++] = one.withIndex(mappedId);
113         }
114     }
115 
116     private class MethodAndProtoVisitor implements CodeReader.Visitor {
117         @Override
visit(DecodedInstruction[] all, DecodedInstruction one)118         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
119             int methodId = one.getIndex();
120             int protoId = one.getProtoIndex();
121             mappedInstructions[mappedAt++] =
122                 one.withProtoIndex(indexMap.adjustMethod(methodId), indexMap.adjustProto(protoId));
123         }
124     }
125 
126     private class CallSiteVisitor implements CodeReader.Visitor {
127         @Override
visit(DecodedInstruction[] all, DecodedInstruction one)128         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
129             int callSiteId = one.getIndex();
130             int mappedCallSiteId = indexMap.adjustCallSite(callSiteId);
131             mappedInstructions[mappedAt++] = one.withIndex(mappedCallSiteId);
132         }
133     }
134 
jumboCheck(boolean isJumbo, int newIndex)135     private static void jumboCheck(boolean isJumbo, int newIndex) {
136         if (!isJumbo && (newIndex > 0xffff)) {
137             throw new DexIndexOverflowException("Cannot merge new index " + newIndex +
138                                    " into a non-jumbo instruction!");
139         }
140     }
141 }
142