diff options
Diffstat (limited to 'dx/src/com/android/dx/dex/code/ArrayData.java')
-rw-r--r-- | dx/src/com/android/dx/dex/code/ArrayData.java | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/dx/src/com/android/dx/dex/code/ArrayData.java b/dx/src/com/android/dx/dex/code/ArrayData.java new file mode 100644 index 0000000..6674b75 --- /dev/null +++ b/dx/src/com/android/dx/dex/code/ArrayData.java @@ -0,0 +1,199 @@ +/* + * 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.io.Opcodes; +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(Opcodes.FILL_ARRAY_DATA_PAYLOAD); + 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("fill-array-data-payload // 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(); + } +} |