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