FileDocCategorySizeDatePackage
HighRegisterPrefix.javaAPI DocAndroid 1.5 API4379Wed May 06 22:41:02 BST 2009com.android.dx.dex.code

HighRegisterPrefix.java

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