1081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson/* 2081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Copyright (C) 2011 The Android Open Source Project 3081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * 4081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * you may not use this file except in compliance with the License. 6081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * You may obtain a copy of the License at 7081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * 8081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * 10081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Unless required by applicable law or agreed to in writing, software 11081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * See the License for the specific language governing permissions and 14081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * limitations under the License. 15081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson */ 16081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson 17081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonpackage com.android.dx.merge; 18081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson 19e31a42442bbd2cdc69e959f5209b793cf0aa7217Jesse Wilsonimport com.android.dx.io.CodeReader; 20f870f2dce9300c8dec620613371f08e5c234245bjeffhaoimport com.android.dx.io.Opcodes; 21537939ca06a47668f719ee06159303bcd3175c69Dan Bornsteinimport com.android.dx.io.instructions.DecodedInstruction; 22537939ca06a47668f719ee06159303bcd3175c69Dan Bornsteinimport com.android.dx.io.instructions.ShortArrayCodeOutput; 237baa3b69f87348aa2f4f16375a66be59965e8dd4Dan Bornsteinimport com.android.dx.util.DexException; 24081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson 25dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilsonfinal class InstructionTransformer { 26081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson private final IndexMap indexMap; 27e31a42442bbd2cdc69e959f5209b793cf0aa7217Jesse Wilson private final CodeReader reader; 2838b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein private DecodedInstruction[] mappedInstructions; 2938b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein private int mappedAt; 30081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson 31081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson public InstructionTransformer(IndexMap indexMap) { 32081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson this.indexMap = indexMap; 33e31a42442bbd2cdc69e959f5209b793cf0aa7217Jesse Wilson this.reader = new CodeReader(); 3438b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein this.reader.setAllVisitors(new GenericVisitor()); 3538b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein this.reader.setStringVisitor(new StringVisitor()); 36e31a42442bbd2cdc69e959f5209b793cf0aa7217Jesse Wilson this.reader.setTypeVisitor(new TypeVisitor()); 37e31a42442bbd2cdc69e959f5209b793cf0aa7217Jesse Wilson this.reader.setFieldVisitor(new FieldVisitor()); 38e31a42442bbd2cdc69e959f5209b793cf0aa7217Jesse Wilson this.reader.setMethodVisitor(new MethodVisitor()); 39081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson } 40081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson 4138b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein public short[] transform(short[] encodedInstructions) throws DexException { 4238b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein DecodedInstruction[] decodedInstructions = 4338b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein DecodedInstruction.decodeAll(encodedInstructions); 4438b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein int size = decodedInstructions.length; 4538b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein 4638b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein mappedInstructions = new DecodedInstruction[size]; 4738b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein mappedAt = 0; 4838b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein reader.visitAll(decodedInstructions); 4938b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein 5038b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein ShortArrayCodeOutput out = new ShortArrayCodeOutput(size); 5138b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein for (DecodedInstruction instruction : mappedInstructions) { 5238b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein if (instruction != null) { 5338b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein instruction.encode(out); 5438b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein } 5538b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein } 5638b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein 5738b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein return out.getArray(); 58081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson } 59081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson 6038b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein private class GenericVisitor implements CodeReader.Visitor { 61a754fbb1555f9ac2d14de0ffd0046c780732da5aDan Bornstein public void visit(DecodedInstruction[] all, DecodedInstruction one) { 6238b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein mappedInstructions[mappedAt++] = one; 6338b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein } 6438b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein } 6538b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein 6638b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein private class StringVisitor implements CodeReader.Visitor { 67a754fbb1555f9ac2d14de0ffd0046c780732da5aDan Bornstein public void visit(DecodedInstruction[] all, DecodedInstruction one) { 6838b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein int stringId = one.getIndex(); 6938b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein int mappedId = indexMap.adjustString(stringId); 70f870f2dce9300c8dec620613371f08e5c234245bjeffhao boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO); 71f870f2dce9300c8dec620613371f08e5c234245bjeffhao jumboCheck(isJumbo, mappedId); 7238b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein mappedInstructions[mappedAt++] = one.withIndex(mappedId); 73081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson } 74081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson } 75081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson 76e31a42442bbd2cdc69e959f5209b793cf0aa7217Jesse Wilson private class FieldVisitor implements CodeReader.Visitor { 77a754fbb1555f9ac2d14de0ffd0046c780732da5aDan Bornstein public void visit(DecodedInstruction[] all, DecodedInstruction one) { 7838b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein int fieldId = one.getIndex(); 7938b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein int mappedId = indexMap.adjustField(fieldId); 80f870f2dce9300c8dec620613371f08e5c234245bjeffhao boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO); 81f870f2dce9300c8dec620613371f08e5c234245bjeffhao jumboCheck(isJumbo, mappedId); 8238b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein mappedInstructions[mappedAt++] = one.withIndex(mappedId); 83081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson } 84081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson } 85081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson 86e31a42442bbd2cdc69e959f5209b793cf0aa7217Jesse Wilson private class TypeVisitor implements CodeReader.Visitor { 87a754fbb1555f9ac2d14de0ffd0046c780732da5aDan Bornstein public void visit(DecodedInstruction[] all, DecodedInstruction one) { 8838b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein int typeId = one.getIndex(); 8938b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein int mappedId = indexMap.adjustType(typeId); 90f870f2dce9300c8dec620613371f08e5c234245bjeffhao boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO); 91f870f2dce9300c8dec620613371f08e5c234245bjeffhao jumboCheck(isJumbo, mappedId); 9238b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein mappedInstructions[mappedAt++] = one.withIndex(mappedId); 93081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson } 94081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson } 95081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson 96e31a42442bbd2cdc69e959f5209b793cf0aa7217Jesse Wilson private class MethodVisitor implements CodeReader.Visitor { 97a754fbb1555f9ac2d14de0ffd0046c780732da5aDan Bornstein public void visit(DecodedInstruction[] all, DecodedInstruction one) { 9838b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein int methodId = one.getIndex(); 9938b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein int mappedId = indexMap.adjustMethod(methodId); 100f870f2dce9300c8dec620613371f08e5c234245bjeffhao boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO); 101f870f2dce9300c8dec620613371f08e5c234245bjeffhao jumboCheck(isJumbo, mappedId); 10238b861bc63b91114d52ba01e74d31fbf316a5784Dan Bornstein mappedInstructions[mappedAt++] = one.withIndex(mappedId); 103081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson } 104081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson } 10517cae2df2191566bf17783cb591c9800b1efb07dDan Bornstein 106f870f2dce9300c8dec620613371f08e5c234245bjeffhao private static void jumboCheck(boolean isJumbo, int newIndex) { 107f870f2dce9300c8dec620613371f08e5c234245bjeffhao if (!isJumbo && (newIndex > 0xffff)) { 108f870f2dce9300c8dec620613371f08e5c234245bjeffhao throw new DexException("Cannot merge new index " + newIndex + 109f870f2dce9300c8dec620613371f08e5c234245bjeffhao " into a non-jumbo instruction!"); 11017cae2df2191566bf17783cb591c9800b1efb07dDan Bornstein } 11117cae2df2191566bf17783cb591c9800b1efb07dDan Bornstein } 112081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson} 113