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