| /* |
| * 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*} 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); |
| } |
| |
| /** {@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 {@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); |
| } |
| } |