1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.dex.code;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegisterSpec;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegisterSpecList;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.SourcePosition;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.Type;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.AnnotatedOutput;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Combination instruction which turns into a variable number of
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * {@code move*} instructions to move a set of registers into
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * registers starting at {@code 0} sequentially. This is used
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * in translating an instruction whose register requirements cannot
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * be met using a straightforward choice of a single opcode.
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class HighRegisterPrefix extends VariableSizeInsn {
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code null-ok;} cached instructions, if constructed */
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private SimpleInsn[] insns;
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance. The output address of this instance is initially
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * unknown ({@code -1}).
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param position {@code non-null;} source position
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param registers {@code non-null;} source registers
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public HighRegisterPrefix(SourcePosition position,
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                              RegisterSpecList registers) {
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        super(position, registers);
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (registers.size() == 0) {
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("registers.size() == 0");
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        insns = null;
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int codeSize() {
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int result = 0;
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        calculateInsnsIfNecessary();
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (SimpleInsn insn : insns) {
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result += insn.codeSize();
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void writeTo(AnnotatedOutput out) {
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        calculateInsnsIfNecessary();
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (SimpleInsn insn : insns) {
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            insn.writeTo(out);
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper for {@link #codeSize} and {@link #writeTo} which sets up
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link #insns} if not already done.
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void calculateInsnsIfNecessary() {
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (insns != null) {
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return;
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RegisterSpecList registers = getRegisters();
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int sz = registers.size();
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        insns = new SimpleInsn[sz];
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0, outAt = 0; i < sz; i++) {
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec src = registers.get(i);
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            insns[i] = moveInsnFor(src, outAt);
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            outAt += src.getCategory();
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public DalvInsn withRegisters(RegisterSpecList registers) {
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new HighRegisterPrefix(getPosition(), registers);
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected String argString() {
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return null;
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected String listingString0(boolean noteIndices) {
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RegisterSpecList registers = getRegisters();
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int sz = registers.size();
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StringBuffer sb = new StringBuffer(100);
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0, outAt = 0; i < sz; i++) {
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec src = registers.get(i);
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            SimpleInsn insn = moveInsnFor(src, outAt);
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (i != 0) {
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append('\n');
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(insn.listingString0(noteIndices));
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            outAt += src.getCategory();
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return sb.toString();
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns the proper move instruction for the given source spec
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * and destination index.
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param src {@code non-null;} the source register spec
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param destIndex {@code >= 0;} the destination register index
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the appropriate move instruction
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static SimpleInsn moveInsnFor(RegisterSpec src, int destIndex) {
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return DalvInsn.makeMove(SourcePosition.NO_INFO,
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec.make(destIndex, src.getType()),
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                src);
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
148