Home | History | Annotate | Download | only in code
      1 /*
      2  * Copyright (C) 2008 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.io.Opcodes;
     20 import com.android.dx.rop.code.RegisterSpecList;
     21 import com.android.dx.rop.code.SourcePosition;
     22 import com.android.dx.rop.cst.Constant;
     23 import com.android.dx.rop.cst.CstLiteral32;
     24 import com.android.dx.rop.cst.CstLiteral64;
     25 import com.android.dx.rop.cst.CstType;
     26 import com.android.dx.util.AnnotatedOutput;
     27 import com.android.dx.util.Hex;
     28 import java.util.ArrayList;
     29 
     30 /**
     31  * Pseudo-instruction which holds fill array data.
     32  */
     33 public final class ArrayData extends VariableSizeInsn {
     34     /**
     35      * {@code non-null;} address representing the instruction that uses this
     36      * instance
     37      */
     38     private final CodeAddress user;
     39 
     40     /** {@code non-null;} initial values to be filled into an array */
     41     private final ArrayList<Constant> values;
     42 
     43     /** non-null: type of constant that initializes the array */
     44     private final Constant arrayType;
     45 
     46     /** Width of the init value element */
     47     private final int elemWidth;
     48 
     49     /** Length of the init list */
     50     private final int initLength;
     51 
     52     /**
     53      * Constructs an instance. The output address of this instance is initially
     54      * unknown ({@code -1}).
     55      *
     56      * @param position {@code non-null;} source position
     57      * @param user {@code non-null;} address representing the instruction that
     58      * uses this instance
     59      * @param values {@code non-null;} initial values to be filled into an array
     60      */
     61     public ArrayData(SourcePosition position, CodeAddress user,
     62                      ArrayList<Constant> values,
     63                      Constant arrayType) {
     64         super(position, RegisterSpecList.EMPTY);
     65 
     66         if (user == null) {
     67             throw new NullPointerException("user == null");
     68         }
     69 
     70         if (values == null) {
     71             throw new NullPointerException("values == null");
     72         }
     73 
     74         int sz = values.size();
     75 
     76         if (sz <= 0) {
     77             throw new IllegalArgumentException("Illegal number of init values");
     78         }
     79 
     80         this.arrayType = arrayType;
     81 
     82         if (arrayType == CstType.BYTE_ARRAY ||
     83                 arrayType == CstType.BOOLEAN_ARRAY) {
     84             elemWidth = 1;
     85         } else if (arrayType == CstType.SHORT_ARRAY ||
     86                 arrayType == CstType.CHAR_ARRAY) {
     87             elemWidth = 2;
     88         } else if (arrayType == CstType.INT_ARRAY ||
     89                 arrayType == CstType.FLOAT_ARRAY) {
     90             elemWidth = 4;
     91         } else if (arrayType == CstType.LONG_ARRAY ||
     92                 arrayType == CstType.DOUBLE_ARRAY) {
     93             elemWidth = 8;
     94         } else {
     95             throw new IllegalArgumentException("Unexpected constant type");
     96         }
     97         this.user = user;
     98         this.values = values;
     99         initLength = values.size();
    100     }
    101 
    102     /** {@inheritDoc} */
    103     @Override
    104     public int codeSize() {
    105         int sz = initLength;
    106         // Note: the unit here is 16-bit
    107         return 4 + ((sz * elemWidth) + 1) / 2;
    108     }
    109 
    110     /** {@inheritDoc} */
    111     @Override
    112     public void writeTo(AnnotatedOutput out) {
    113         int sz = values.size();
    114 
    115         out.writeShort(Opcodes.FILL_ARRAY_DATA_PAYLOAD);
    116         out.writeShort(elemWidth);
    117         out.writeInt(initLength);
    118 
    119 
    120         // For speed reasons, replicate the for loop in each case
    121         switch (elemWidth) {
    122             case 1: {
    123                 for (int i = 0; i < sz; i++) {
    124                     Constant cst = values.get(i);
    125                     out.writeByte((byte) ((CstLiteral32) cst).getIntBits());
    126                 }
    127                 break;
    128             }
    129             case 2: {
    130                 for (int i = 0; i < sz; i++) {
    131                     Constant cst = values.get(i);
    132                     out.writeShort((short) ((CstLiteral32) cst).getIntBits());
    133                 }
    134                 break;
    135             }
    136             case 4: {
    137                 for (int i = 0; i < sz; i++) {
    138                     Constant cst = values.get(i);
    139                     out.writeInt(((CstLiteral32) cst).getIntBits());
    140                 }
    141                 break;
    142             }
    143             case 8: {
    144                 for (int i = 0; i < sz; i++) {
    145                     Constant cst = values.get(i);
    146                     out.writeLong(((CstLiteral64) cst).getLongBits());
    147                 }
    148                 break;
    149             }
    150             default:
    151                 break;
    152         }
    153 
    154         // Pad one byte to make the size of data table multiples of 16-bits
    155         if (elemWidth == 1 && (sz % 2 != 0)) {
    156             out.writeByte(0x00);
    157         }
    158     }
    159 
    160     /** {@inheritDoc} */
    161     @Override
    162     public DalvInsn withRegisters(RegisterSpecList registers) {
    163         return new ArrayData(getPosition(), user, values, arrayType);
    164     }
    165 
    166     /** {@inheritDoc} */
    167     @Override
    168     protected String argString() {
    169         StringBuilder sb = new StringBuilder(100);
    170 
    171         int sz = values.size();
    172         for (int i = 0; i < sz; i++) {
    173             sb.append("\n    ");
    174             sb.append(i);
    175             sb.append(": ");
    176             sb.append(values.get(i).toHuman());
    177         }
    178 
    179         return sb.toString();
    180     }
    181 
    182     /** {@inheritDoc} */
    183     @Override
    184     protected String listingString0(boolean noteIndices) {
    185         int baseAddress = user.getAddress();
    186         StringBuilder sb = new StringBuilder(100);
    187         int sz = values.size();
    188 
    189         sb.append("fill-array-data-payload // for fill-array-data @ ");
    190         sb.append(Hex.u2(baseAddress));
    191 
    192         for (int i = 0; i < sz; i++) {
    193             sb.append("\n  ");
    194             sb.append(i);
    195             sb.append(": ");
    196             sb.append(values.get(i).toHuman());
    197         }
    198 
    199         return sb.toString();
    200     }
    201 }
    202