Home | History | Annotate | Download | only in code
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dx.dex.code;
     18 
     19 import com.android.dx.rop.code.RegisterSpec;
     20 import com.android.dx.rop.code.RegisterSpecList;
     21 import com.android.dx.rop.code.SourcePosition;
     22 import com.android.dx.util.AnnotatedOutput;
     23 
     24 /**
     25  * Combination instruction which turns into a variable number of
     26  * {@code move*} instructions to move a set of registers into
     27  * registers starting at {@code 0} sequentially. This is used
     28  * in translating an instruction whose register requirements cannot
     29  * be met using a straightforward choice of a single opcode.
     30  */
     31 public final class HighRegisterPrefix extends VariableSizeInsn {
     32     /** {@code null-ok;} cached instructions, if constructed */
     33     private SimpleInsn[] insns;
     34 
     35     /**
     36      * Constructs an instance. The output address of this instance is initially
     37      * unknown ({@code -1}).
     38      *
     39      * @param position {@code non-null;} source position
     40      * @param registers {@code non-null;} source registers
     41      */
     42     public HighRegisterPrefix(SourcePosition position,
     43                               RegisterSpecList registers) {
     44         super(position, registers);
     45 
     46         if (registers.size() == 0) {
     47             throw new IllegalArgumentException("registers.size() == 0");
     48         }
     49 
     50         insns = null;
     51     }
     52 
     53     /** {@inheritDoc} */
     54     @Override
     55     public int codeSize() {
     56         int result = 0;
     57 
     58         calculateInsnsIfNecessary();
     59 
     60         for (SimpleInsn insn : insns) {
     61             result += insn.codeSize();
     62         }
     63 
     64         return result;
     65     }
     66 
     67     /** {@inheritDoc} */
     68     @Override
     69     public void writeTo(AnnotatedOutput out) {
     70         calculateInsnsIfNecessary();
     71 
     72         for (SimpleInsn insn : insns) {
     73             insn.writeTo(out);
     74         }
     75     }
     76 
     77     /**
     78      * Helper for {@link #codeSize} and {@link #writeTo} which sets up
     79      * {@link #insns} if not already done.
     80      */
     81     private void calculateInsnsIfNecessary() {
     82         if (insns != null) {
     83             return;
     84         }
     85 
     86         RegisterSpecList registers = getRegisters();
     87         int sz = registers.size();
     88 
     89         insns = new SimpleInsn[sz];
     90 
     91         for (int i = 0, outAt = 0; i < sz; i++) {
     92             RegisterSpec src = registers.get(i);
     93             insns[i] = moveInsnFor(src, outAt);
     94             outAt += src.getCategory();
     95         }
     96     }
     97 
     98     /** {@inheritDoc} */
     99     @Override
    100     public DalvInsn withRegisters(RegisterSpecList registers) {
    101         return new HighRegisterPrefix(getPosition(), registers);
    102     }
    103 
    104     /** {@inheritDoc} */
    105     @Override
    106     protected String argString() {
    107         return null;
    108     }
    109 
    110     /** {@inheritDoc} */
    111     @Override
    112     protected String listingString0(boolean noteIndices) {
    113         RegisterSpecList registers = getRegisters();
    114         int sz = registers.size();
    115         StringBuffer sb = new StringBuffer(100);
    116 
    117         for (int i = 0, outAt = 0; i < sz; i++) {
    118             RegisterSpec src = registers.get(i);
    119             SimpleInsn insn = moveInsnFor(src, outAt);
    120 
    121             if (i != 0) {
    122                 sb.append('\n');
    123             }
    124 
    125             sb.append(insn.listingString0(noteIndices));
    126 
    127             outAt += src.getCategory();
    128         }
    129 
    130         return sb.toString();
    131     }
    132 
    133     /**
    134      * Returns the proper move instruction for the given source spec
    135      * and destination index.
    136      *
    137      * @param src {@code non-null;} the source register spec
    138      * @param destIndex {@code >= 0;} the destination register index
    139      * @return {@code non-null;} the appropriate move instruction
    140      */
    141     private static SimpleInsn moveInsnFor(RegisterSpec src, int destIndex) {
    142         return DalvInsn.makeMove(SourcePosition.NO_INFO,
    143                 RegisterSpec.make(destIndex, src.getType()),
    144                 src);
    145     }
    146 }
    147