• 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.dx.io.CodeReader;
20 import com.android.dx.io.Opcodes;
21 import com.android.dx.io.instructions.DecodedInstruction;
22 import com.android.dx.io.instructions.ShortArrayCodeOutput;
23 import com.android.dx.util.DexException;
24 
25 final class InstructionTransformer {
26     private final IndexMap indexMap;
27     private final CodeReader reader;
28     private DecodedInstruction[] mappedInstructions;
29     private int mappedAt;
30 
InstructionTransformer(IndexMap indexMap)31     public InstructionTransformer(IndexMap indexMap) {
32         this.indexMap = indexMap;
33         this.reader = new CodeReader();
34         this.reader.setAllVisitors(new GenericVisitor());
35         this.reader.setStringVisitor(new StringVisitor());
36         this.reader.setTypeVisitor(new TypeVisitor());
37         this.reader.setFieldVisitor(new FieldVisitor());
38         this.reader.setMethodVisitor(new MethodVisitor());
39     }
40 
transform(short[] encodedInstructions)41     public short[] transform(short[] encodedInstructions) throws DexException {
42         DecodedInstruction[] decodedInstructions =
43             DecodedInstruction.decodeAll(encodedInstructions);
44         int size = decodedInstructions.length;
45 
46         mappedInstructions = new DecodedInstruction[size];
47         mappedAt = 0;
48         reader.visitAll(decodedInstructions);
49 
50         ShortArrayCodeOutput out = new ShortArrayCodeOutput(size);
51         for (DecodedInstruction instruction : mappedInstructions) {
52             if (instruction != null) {
53                 instruction.encode(out);
54             }
55         }
56 
57         return out.getArray();
58     }
59 
60     private class GenericVisitor implements CodeReader.Visitor {
visit(DecodedInstruction[] all, DecodedInstruction one)61         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
62             mappedInstructions[mappedAt++] = one;
63         }
64     }
65 
66     private class StringVisitor implements CodeReader.Visitor {
visit(DecodedInstruction[] all, DecodedInstruction one)67         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
68             int stringId = one.getIndex();
69             int mappedId = indexMap.adjustString(stringId);
70             boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
71             jumboCheck(isJumbo, mappedId);
72             mappedInstructions[mappedAt++] = one.withIndex(mappedId);
73         }
74     }
75 
76     private class FieldVisitor implements CodeReader.Visitor {
visit(DecodedInstruction[] all, DecodedInstruction one)77         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
78             int fieldId = one.getIndex();
79             int mappedId = indexMap.adjustField(fieldId);
80             boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
81             jumboCheck(isJumbo, mappedId);
82             mappedInstructions[mappedAt++] = one.withIndex(mappedId);
83         }
84     }
85 
86     private class TypeVisitor implements CodeReader.Visitor {
visit(DecodedInstruction[] all, DecodedInstruction one)87         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
88             int typeId = one.getIndex();
89             int mappedId = indexMap.adjustType(typeId);
90             boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
91             jumboCheck(isJumbo, mappedId);
92             mappedInstructions[mappedAt++] = one.withIndex(mappedId);
93         }
94     }
95 
96     private class MethodVisitor implements CodeReader.Visitor {
visit(DecodedInstruction[] all, DecodedInstruction one)97         public void visit(DecodedInstruction[] all, DecodedInstruction one) {
98             int methodId = one.getIndex();
99             int mappedId = indexMap.adjustMethod(methodId);
100             boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
101             jumboCheck(isJumbo, mappedId);
102             mappedInstructions[mappedAt++] = one.withIndex(mappedId);
103         }
104     }
105 
jumboCheck(boolean isJumbo, int newIndex)106     private static void jumboCheck(boolean isJumbo, int newIndex) {
107         if (!isJumbo && (newIndex > 0xffff)) {
108             throw new DexException("Cannot merge new index " + newIndex +
109                                    " into a non-jumbo instruction!");
110         }
111     }
112 }
113