/* * 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.util.AnnotatedOutput; /** * Combination instruction which turns into a variable number of {@code move*} * instructions to move a set of registers into registers starting at {@code 0} * 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 { /** {@code null-ok;} cached instructions, if constructed */ private SimpleInsn[] insns; /** * Constructs an instance. The output address of this instance is initially * unknown ({@code -1}). * * @param position * {@code non-null;} source position * @param registers * {@code 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); } public SimpleInsn[] getMoveInstructions() { RegisterSpecList registers = getRegisters(); int sz = registers.size(); SimpleInsn[] result = new SimpleInsn[sz]; for (int i = 0, outAt = 0; i < sz; i++) { RegisterSpec src = registers.get(i); result[i] = moveInsnFor(src, outAt); outAt += src.getCategory(); } return result; } /** {@inheritDoc} */ @Override protected String argString() { return null; } /** {@inheritDoc} */ @Override protected String listingString0(boolean noteIndices) { StringBuffer sb = new StringBuffer(100); SimpleInsn[] insns = getMoveInstructions(); boolean first = true; for (SimpleInsn insn : insns) { if (!first) { sb.append('\n'); } first = false; sb.append(insn.listingString0(noteIndices)); } return sb.toString(); } /** * Returns the proper move instruction for the given source spec and * destination index. * * @param src * {@code non-null;} the source register spec * @param destIndex * {@code >= 0;} the destination register index * @return {@code 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); } }