| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.dx.dex.code; |
| |
| import com.android.dx.rop.code.RegisterSpec; |
| import com.android.dx.rop.code.RegisterSpecList; |
| import com.android.dx.rop.code.SourcePosition; |
| import com.android.dx.rop.type.Type; |
| import com.android.dx.util.AnnotatedOutput; |
| |
| /** |
| * Combination instruction which turns into a variable number of |
| * <code>move*</code> instructions to move a set of registers into |
| * registers starting at <code>0</code> sequentially. This is used |
| * in translating an instruction whose register requirements cannot |
| * be met using a straightforward choice of a single opcode. |
| */ |
| public final class HighRegisterPrefix extends VariableSizeInsn { |
| /** null-ok; cached instructions, if constructed */ |
| private SimpleInsn[] insns; |
| |
| /** |
| * Constructs an instance. The output address of this instance is initially |
| * unknown (<code>-1</code>). |
| * |
| * @param position non-null; source position |
| * @param registers non-null; source registers |
| */ |
| public HighRegisterPrefix(SourcePosition position, |
| RegisterSpecList registers) { |
| super(position, registers); |
| |
| if (registers.size() == 0) { |
| throw new IllegalArgumentException("registers.size() == 0"); |
| } |
| |
| insns = null; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public int codeSize() { |
| int result = 0; |
| |
| calculateInsnsIfNecessary(); |
| |
| for (SimpleInsn insn : insns) { |
| result += insn.codeSize(); |
| } |
| |
| return result; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void writeTo(AnnotatedOutput out) { |
| calculateInsnsIfNecessary(); |
| |
| for (SimpleInsn insn : insns) { |
| insn.writeTo(out); |
| } |
| } |
| |
| /** |
| * Helper for {@link #codeSize} and {@link #writeTo} which sets up |
| * {@link #insns} if not already done. |
| */ |
| private void calculateInsnsIfNecessary() { |
| if (insns != null) { |
| return; |
| } |
| |
| RegisterSpecList registers = getRegisters(); |
| int sz = registers.size(); |
| |
| insns = new SimpleInsn[sz]; |
| |
| for (int i = 0, outAt = 0; i < sz; i++) { |
| RegisterSpec src = registers.get(i); |
| insns[i] = moveInsnFor(src, outAt); |
| outAt += src.getCategory(); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public DalvInsn withRegisters(RegisterSpecList registers) { |
| return new HighRegisterPrefix(getPosition(), registers); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| protected String argString() { |
| return null; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| protected String listingString0(boolean noteIndices) { |
| RegisterSpecList registers = getRegisters(); |
| int sz = registers.size(); |
| StringBuffer sb = new StringBuffer(100); |
| |
| for (int i = 0, outAt = 0; i < sz; i++) { |
| RegisterSpec src = registers.get(i); |
| SimpleInsn insn = moveInsnFor(src, outAt); |
| |
| if (i != 0) { |
| sb.append('\n'); |
| } |
| |
| sb.append(insn.listingString0(noteIndices)); |
| |
| outAt += src.getCategory(); |
| } |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * Returns the proper move instruction for the given source spec |
| * and destination index. |
| * |
| * @param src non-null; the source register spec |
| * @param destIndex >= 0; the destination register index |
| * @return non-null; the appropriate move instruction |
| */ |
| private static SimpleInsn moveInsnFor(RegisterSpec src, int destIndex) { |
| return DalvInsn.makeMove(SourcePosition.NO_INFO, |
| RegisterSpec.make(destIndex, src.getType()), |
| src); |
| } |
| } |