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