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