com.android.dx.dex.file.CodeItem Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of builder Show documentation
Show all versions of builder Show documentation
Library to build Android applications.
/*
* Copyright (C) 2007 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.file;
import com.android.dex.util.ExceptionWithContext;
import com.android.dx.dex.code.DalvCode;
import com.android.dx.dex.code.DalvInsnList;
import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.cst.CstMethodRef;
import com.android.dx.rop.type.StdTypeList;
import com.android.dx.rop.type.Type;
import com.android.dx.rop.type.TypeList;
import com.android.dx.util.AnnotatedOutput;
import com.android.dx.util.Hex;
import java.io.PrintWriter;
/**
* Representation of all the parts needed for concrete methods in a
* {@code dex} file.
*/
public final class CodeItem extends OffsettedItem {
/** file alignment of this class, in bytes */
private static final int ALIGNMENT = 4;
/** write size of the header of this class, in bytes */
private static final int HEADER_SIZE = 16;
/** {@code non-null;} method that this code implements */
private final CstMethodRef ref;
/** {@code non-null;} the bytecode instructions and associated data */
private final DalvCode code;
/** {@code null-ok;} the catches, if needed; set in {@link #addContents} */
private CatchStructs catches;
/** whether this instance is for a {@code static} method */
private final boolean isStatic;
/**
* {@code non-null;} list of possibly-thrown exceptions; just used in
* generating debugging output (listings)
*/
private final TypeList throwsList;
/**
* {@code null-ok;} the debug info or {@code null} if there is none;
* set in {@link #addContents}
*/
private DebugInfoItem debugInfo;
/**
* Constructs an instance.
*
* @param ref {@code non-null;} method that this code implements
* @param code {@code non-null;} the underlying code
* @param isStatic whether this instance is for a {@code static}
* method
* @param throwsList {@code non-null;} list of possibly-thrown exceptions,
* just used in generating debugging output (listings)
*/
public CodeItem(CstMethodRef ref, DalvCode code, boolean isStatic,
TypeList throwsList) {
super(ALIGNMENT, -1);
if (ref == null) {
throw new NullPointerException("ref == null");
}
if (code == null) {
throw new NullPointerException("code == null");
}
if (throwsList == null) {
throw new NullPointerException("throwsList == null");
}
this.ref = ref;
this.code = code;
this.isStatic = isStatic;
this.throwsList = throwsList;
this.catches = null;
this.debugInfo = null;
}
/** {@inheritDoc} */
@Override
public ItemType itemType() {
return ItemType.TYPE_CODE_ITEM;
}
/** {@inheritDoc} */
public void addContents(DexFile file) {
MixedItemSection byteData = file.getByteData();
TypeIdsSection typeIds = file.getTypeIds();
if (code.hasPositions() || code.hasLocals()) {
debugInfo = new DebugInfoItem(code, isStatic, ref);
byteData.add(debugInfo);
}
if (code.hasAnyCatches()) {
for (Type type : code.getCatchTypes()) {
typeIds.intern(type);
}
catches = new CatchStructs(code);
}
for (Constant c : code.getInsnConstants()) {
file.internIfAppropriate(c);
}
}
/** {@inheritDoc} */
@Override
public String toString() {
return "CodeItem{" + toHuman() + "}";
}
/** {@inheritDoc} */
@Override
public String toHuman() {
return ref.toHuman();
}
/**
* Gets the reference to the method this instance implements.
*
* @return {@code non-null;} the method reference
*/
public CstMethodRef getRef() {
return ref;
}
/**
* Does a human-friendly dump of this instance.
*
* @param out {@code non-null;} where to dump
* @param prefix {@code non-null;} per-line prefix to use
* @param verbose whether to be verbose with the output
*/
public void debugPrint(PrintWriter out, String prefix, boolean verbose) {
out.println(ref.toHuman() + ":");
DalvInsnList insns = code.getInsns();
out.println("regs: " + Hex.u2(getRegistersSize()) +
"; ins: " + Hex.u2(getInsSize()) + "; outs: " +
Hex.u2(getOutsSize()));
insns.debugPrint(out, prefix, verbose);
String prefix2 = prefix + " ";
if (catches != null) {
out.print(prefix);
out.println("catches");
catches.debugPrint(out, prefix2);
}
if (debugInfo != null) {
out.print(prefix);
out.println("debug info");
debugInfo.debugPrint(out, prefix2);
}
}
/** {@inheritDoc} */
@Override
protected void place0(Section addedTo, int offset) {
final DexFile file = addedTo.getFile();
int catchesSize;
/*
* In order to get the catches and insns, all the code's
* constants need to be assigned indices.
*/
code.assignIndices(new DalvCode.AssignIndicesCallback() {
public int getIndex(Constant cst) {
IndexedItem item = file.findItemOrNull(cst);
if (item == null) {
return -1;
}
return item.getIndex();
}
});
if (catches != null) {
catches.encode(file);
catchesSize = catches.writeSize();
} else {
catchesSize = 0;
}
/*
* The write size includes the header, two bytes per code
* unit, post-code padding if necessary, and however much
* space the catches need.
*/
int insnsSize = code.getInsns().codeSize();
if ((insnsSize & 1) != 0) {
insnsSize++;
}
setWriteSize(HEADER_SIZE + (insnsSize * 2) + catchesSize);
}
/** {@inheritDoc} */
@Override
protected void writeTo0(DexFile file, AnnotatedOutput out) {
boolean annotates = out.annotates();
int regSz = getRegistersSize();
int outsSz = getOutsSize();
int insSz = getInsSize();
int insnsSz = code.getInsns().codeSize();
boolean needPadding = (insnsSz & 1) != 0;
int triesSz = (catches == null) ? 0 : catches.triesSize();
int debugOff = (debugInfo == null) ? 0 : debugInfo.getAbsoluteOffset();
if (annotates) {
out.annotate(0, offsetString() + ' ' + ref.toHuman());
out.annotate(2, " registers_size: " + Hex.u2(regSz));
out.annotate(2, " ins_size: " + Hex.u2(insSz));
out.annotate(2, " outs_size: " + Hex.u2(outsSz));
out.annotate(2, " tries_size: " + Hex.u2(triesSz));
out.annotate(4, " debug_off: " + Hex.u4(debugOff));
out.annotate(4, " insns_size: " + Hex.u4(insnsSz));
// This isn't represented directly here, but it is useful to see.
int size = throwsList.size();
if (size != 0) {
out.annotate(0, " throws " + StdTypeList.toHuman(throwsList));
}
}
out.writeShort(regSz);
out.writeShort(insSz);
out.writeShort(outsSz);
out.writeShort(triesSz);
out.writeInt(debugOff);
out.writeInt(insnsSz);
writeCodes(file, out);
if (catches != null) {
if (needPadding) {
if (annotates) {
out.annotate(2, " padding: 0");
}
out.writeShort(0);
}
catches.writeTo(file, out);
}
if (annotates) {
/*
* These are pointed at in the code header (above), but it's less
* distracting to expand on them at the bottom of the code.
*/
if (debugInfo != null) {
out.annotate(0, " debug info");
debugInfo.annotateTo(file, out, " ");
}
}
}
/**
* Helper for {@link #writeTo0} which writes out the actual bytecode.
*
* @param file {@code non-null;} file we are part of
* @param out {@code non-null;} where to write to
*/
private void writeCodes(DexFile file, AnnotatedOutput out) {
DalvInsnList insns = code.getInsns();
try {
insns.writeTo(out);
} catch (RuntimeException ex) {
throw ExceptionWithContext.withContext(ex, "...while writing " +
"instructions for " + ref.toHuman());
}
}
/**
* Get the in registers count.
*
* @return the count
*/
private int getInsSize() {
return ref.getParameterWordCount(isStatic);
}
/**
* Get the out registers count.
*
* @return the count
*/
private int getOutsSize() {
return code.getInsns().getOutsSize();
}
/**
* Get the total registers count.
*
* @return the count
*/
private int getRegistersSize() {
return code.getInsns().getRegistersSize();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy