HighRegisterPrefix.java revision 579d7739c53a2707ad711a2d2cae46d7d782f061
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
17package com.android.dx.dex.code;
18
19import com.android.dx.rop.code.RegisterSpec;
20import com.android.dx.rop.code.RegisterSpecList;
21import com.android.dx.rop.code.SourcePosition;
22import com.android.dx.rop.type.Type;
23import com.android.dx.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 */
32public 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     */
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
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
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     */
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
101    public DalvInsn withRegisters(RegisterSpecList registers) {
102        return new HighRegisterPrefix(getPosition(), registers);
103    }
104
105    /** {@inheritDoc} */
106    @Override
107    protected String argString() {
108        return null;
109    }
110
111    /** {@inheritDoc} */
112    @Override
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     */
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