| /* |
| * 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 { |
| /** |
| * non-null; address representing the instruction that uses this |
| * instance |
| */ |
| private final CodeAddress user; |
| |
| /** 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</code>). |
| * |
| * @param position non-null; source position |
| * @param user non-null; address representing the instruction that |
| * uses this instance |
| * @param values 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 baseAddress = user.getAddress(); |
| 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(); |
| } |
| } |