blob: 6674b7553f5dc673e3744282b8e8cd0313c9f045 [file] [log] [blame]
/*
* 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();
}
}