1 /*
2  * Copyright (C) 2007 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.dexgen.dex.code;
18 
19 import com.android.dexgen.rop.code.RegisterSpec;
20 import com.android.dexgen.rop.code.RegisterSpecList;
21 import com.android.dexgen.rop.code.SourcePosition;
22 import com.android.dexgen.rop.type.Type;
23 import com.android.dexgen.util.AnnotatedOutput;
24 
25 /**
26  * Combination instruction which turns into a variable number of
27  * {@code move*} instructions to move a set of registers into
28  * registers starting at {@code 0} sequentially. This is used
29  * in translating an instruction whose register requirements cannot
30  * be met using a straightforward choice of a single opcode.
31  */
32 public final class HighRegisterPrefix extends VariableSizeInsn {
33     /** {@code null-ok;} cached instructions, if constructed */
34     private SimpleInsn[] insns;
35 
36     /**
37      * Constructs an instance. The output address of this instance is initially
38      * unknown ({@code -1}).
39      *
40      * @param position {@code non-null;} source position
41      * @param registers {@code non-null;} source registers
42      */
HighRegisterPrefix(SourcePosition position, RegisterSpecList registers)43     public HighRegisterPrefix(SourcePosition position,
44                               RegisterSpecList registers) {
45         super(position, registers);
46 
47         if (registers.size() == 0) {
48             throw new IllegalArgumentException("registers.size() == 0");
49         }
50 
51         insns = null;
52     }
53 
54     /** {@inheritDoc} */
55     @Override
codeSize()56     public int codeSize() {
57         int result = 0;
58 
59         calculateInsnsIfNecessary();
60 
61         for (SimpleInsn insn : insns) {
62             result += insn.codeSize();
63         }
64 
65         return result;
66     }
67 
68     /** {@inheritDoc} */
69     @Override
writeTo(AnnotatedOutput out)70     public void writeTo(AnnotatedOutput out) {
71         calculateInsnsIfNecessary();
72 
73         for (SimpleInsn insn : insns) {
74             insn.writeTo(out);
75         }
76     }
77 
78     /**
79      * Helper for {@link #codeSize} and {@link #writeTo} which sets up
80      * {@link #insns} if not already done.
81      */
calculateInsnsIfNecessary()82     private void calculateInsnsIfNecessary() {
83         if (insns != null) {
84             return;
85         }
86 
87         RegisterSpecList registers = getRegisters();
88         int sz = registers.size();
89 
90         insns = new SimpleInsn[sz];
91 
92         for (int i = 0, outAt = 0; i < sz; i++) {
93             RegisterSpec src = registers.get(i);
94             insns[i] = moveInsnFor(src, outAt);
95             outAt += src.getCategory();
96         }
97     }
98 
99     /** {@inheritDoc} */
100     @Override
withRegisters(RegisterSpecList registers)101     public DalvInsn withRegisters(RegisterSpecList registers) {
102         return new HighRegisterPrefix(getPosition(), registers);
103     }
104 
105     /** {@inheritDoc} */
106     @Override
argString()107     protected String argString() {
108         return null;
109     }
110 
111     /** {@inheritDoc} */
112     @Override
listingString0(boolean noteIndices)113     protected String listingString0(boolean noteIndices) {
114         RegisterSpecList registers = getRegisters();
115         int sz = registers.size();
116         StringBuffer sb = new StringBuffer(100);
117 
118         for (int i = 0, outAt = 0; i < sz; i++) {
119             RegisterSpec src = registers.get(i);
120             SimpleInsn insn = moveInsnFor(src, outAt);
121 
122             if (i != 0) {
123                 sb.append('\n');
124             }
125 
126             sb.append(insn.listingString0(noteIndices));
127 
128             outAt += src.getCategory();
129         }
130 
131         return sb.toString();
132     }
133 
134     /**
135      * Returns the proper move instruction for the given source spec
136      * and destination index.
137      *
138      * @param src {@code non-null;} the source register spec
139      * @param destIndex {@code >= 0;} the destination register index
140      * @return {@code non-null;} the appropriate move instruction
141      */
moveInsnFor(RegisterSpec src, int destIndex)142     private static SimpleInsn moveInsnFor(RegisterSpec src, int destIndex) {
143         return DalvInsn.makeMove(SourcePosition.NO_INFO,
144                 RegisterSpec.make(destIndex, src.getType()),
145                 src);
146     }
147 }
148