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