/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.dx.dex.code; import com.android.dx.rop.code.RegisterSpecList; import com.android.dx.rop.code.SourcePosition; import com.android.dx.rop.cst.*; import com.android.dx.util.AnnotatedOutput; import com.android.dx.util.Hex; import com.android.dx.rop.type.Type; import java.util.ArrayList; /** * Pseudo-instruction which holds fill array data. */ public final class ArrayData extends VariableSizeInsn { /** * {@code non-null;} address representing the instruction that uses this * instance */ private final CodeAddress user; /** {@code non-null;} initial values to be filled into an array */ private final ArrayList<Constant> values; /** non-null: type of constant that initializes the array */ private final Constant arrayType; /** Width of the init value element */ private final int elemWidth; /** Length of the init list */ private final int initLength; /** * Constructs an instance. The output address of this instance is initially * unknown ({@code -1}). * * @param position {@code non-null;} source position * @param user {@code non-null;} address representing the instruction that * uses this instance * @param values {@code non-null;} initial values to be filled into an array */ public ArrayData(SourcePosition position, CodeAddress user, ArrayList<Constant> values, Constant arrayType) { super(position, RegisterSpecList.EMPTY); if (user == null) { throw new NullPointerException("user == null"); } if (values == null) { throw new NullPointerException("values == null"); } int sz = values.size(); if (sz <= 0) { throw new IllegalArgumentException("Illegal number of init values"); } this.arrayType = arrayType; if (arrayType == CstType.BYTE_ARRAY || arrayType == CstType.BOOLEAN_ARRAY) { elemWidth = 1; } else if (arrayType == CstType.SHORT_ARRAY || arrayType == CstType.CHAR_ARRAY) { elemWidth = 2; } else if (arrayType == CstType.INT_ARRAY || arrayType == CstType.FLOAT_ARRAY) { elemWidth = 4; } else if (arrayType == CstType.LONG_ARRAY || arrayType == CstType.DOUBLE_ARRAY) { elemWidth = 8; } else { throw new IllegalArgumentException("Unexpected constant type"); } this.user = user; this.values = values; initLength = values.size(); } /** {@inheritDoc} */ @Override public int codeSize() { int sz = initLength; // Note: the unit here is 16-bit return 4 + ((sz * elemWidth) + 1) / 2; } /** {@inheritDoc} */ @Override public void writeTo(AnnotatedOutput out) { int sz = values.size(); out.writeShort(0x300 | DalvOps.NOP); out.writeShort(elemWidth); out.writeInt(initLength); // For speed reasons, replicate the for loop in each case switch (elemWidth) { case 1: { for (int i = 0; i < sz; i++) { Constant cst = values.get(i); out.writeByte((byte) ((CstLiteral32) cst).getIntBits()); } break; } case 2: { for (int i = 0; i < sz; i++) { Constant cst = values.get(i); out.writeShort((short) ((CstLiteral32) cst).getIntBits()); } break; } case 4: { for (int i = 0; i < sz; i++) { Constant cst = values.get(i); out.writeInt(((CstLiteral32) cst).getIntBits()); } break; } case 8: { for (int i = 0; i < sz; i++) { Constant cst = values.get(i); out.writeLong(((CstLiteral64) cst).getLongBits()); } break; } default: break; } // Pad one byte to make the size of data table multiples of 16-bits if (elemWidth == 1 && (sz % 2 != 0)) { out.writeByte(0x00); } } /** {@inheritDoc} */ @Override public DalvInsn withRegisters(RegisterSpecList registers) { return new ArrayData(getPosition(), user, values, arrayType); } /** {@inheritDoc} */ @Override protected String argString() { StringBuffer sb = new StringBuffer(100); int sz = values.size(); for (int i = 0; i < sz; i++) { sb.append("\n "); sb.append(i); sb.append(": "); sb.append(values.get(i).toHuman()); } return sb.toString(); } /** {@inheritDoc} */ @Override protected String listingString0(boolean noteIndices) { int baseAddress = user.getAddress(); StringBuffer sb = new StringBuffer(100); int sz = values.size(); sb.append("array-data // for fill-array-data @ "); sb.append(Hex.u2(baseAddress)); for (int i = 0; i < sz; i++) { sb.append("\n "); sb.append(i); sb.append(": "); sb.append(values.get(i).toHuman()); } return sb.toString(); } public ArrayList<Constant> getValues() { return values; } }