blob: 1542015208d8bd71bec76886cd307e3136ec1f84 [file] [log] [blame]
// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
import static com.android.tools.r8.dex.Constants.U4BIT_MAX;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
/** Format45cc for instructions of size 4, with 5 registers and 2 constant pool index. */
public abstract class Format45cc extends Base4Format {
public final byte A;
public final byte C;
public final byte D;
public final byte E;
public final byte F;
public final byte G;
public DexMethod BBBB;
public DexProto HHHH;
private static void specify(StructuralSpecification<Format45cc, ?> spec) {
spec.withInt(i -> i.A)
.withInt(i -> i.C)
.withInt(i -> i.D)
.withInt(i -> i.E)
.withInt(i -> i.F)
.withInt(i -> i.G)
.withItem(i -> i.BBBB)
.withItem(i -> i.HHHH);
}
Format45cc(int high, BytecodeStream stream, DexMethod[] methodMap, DexProto[] protoMap) {
super(stream);
G = (byte) (high & 0xf);
A = (byte) ((high >> 4) & 0xf);
BBBB = methodMap[read16BitValue(stream)];
int next = read8BitValue(stream);
E = (byte) (next & 0xf);
F = (byte) ((next >> 4) & 0xf);
next = read8BitValue(stream);
C = (byte) (next & 0xf);
D = (byte) ((next >> 4) & 0xf);
HHHH = protoMap[read16BitValue(stream)];
}
// A | G | op | [meth]@BBBB | F | E | D | C | [proto]@HHHH
protected Format45cc(int A, DexMethod BBBB, DexProto HHHH, int C, int D, int E, int F, int G) {
assert 0 <= A && A <= U4BIT_MAX;
assert 0 <= C && C <= U4BIT_MAX;
assert 0 <= D && D <= U4BIT_MAX;
assert 0 <= E && E <= U4BIT_MAX;
assert 0 <= F && F <= U4BIT_MAX;
assert 0 <= G && G <= U4BIT_MAX;
this.A = (byte) A;
this.BBBB = BBBB;
this.HHHH = HHHH;
this.C = (byte) C;
this.D = (byte) D;
this.E = (byte) E;
this.F = (byte) F;
this.G = (byte) G;
}
@Override
public final int hashCode() {
return ((HHHH.hashCode() << 28)
| (BBBB.hashCode() << 24)
| (A << 20)
| (C << 16)
| (D << 12)
| (E << 8)
| (F << 4)
| G)
^ getClass().hashCode();
}
@Override
final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
return visitor.visit(this, (Format45cc) other, Format45cc::specify);
}
@Override
public void collectIndexedItems(
IndexedItemCollection indexedItems,
ProgramMethod context,
GraphLens graphLens,
LensCodeRewriterUtils rewriter) {
MethodLookupResult lookup =
graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
assert lookup.getType() == Type.POLYMORPHIC;
lookup.getReference().collectIndexedItems(indexedItems);
DexProto rewrittenProto = rewriter.rewriteProto(getProto());
rewrittenProto.collectIndexedItems(indexedItems);
}
@Override
public void write(
ShortBuffer dest,
ProgramMethod context,
GraphLens graphLens,
ObjectToOffsetMapping mapping,
LensCodeRewriterUtils rewriter) {
MethodLookupResult lookup =
graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
assert lookup.getType() == Type.POLYMORPHIC;
writeFirst(A, G, dest);
write16BitReference(lookup.getReference(), dest, mapping);
write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest);
DexProto rewrittenProto = rewriter.rewriteProto(getProto());
write16BitReference(rewrittenProto, dest, mapping);
}
@Override
public String toSmaliString(ClassNameMapper naming) {
StringBuilder builder = new StringBuilder();
appendRegisterArguments(builder, ", ");
builder.append(", ");
// TODO(sgjesse): Add support for smali name mapping.
builder.append(BBBB.toSmaliString());
builder.append(", ");
builder.append(HHHH.toSmaliString());
return formatSmaliString(builder.toString());
}
@Override
public String toString(ClassNameMapper naming) {
StringBuilder builder = new StringBuilder();
appendRegisterArguments(builder, " ");
builder.append(" ");
builder.append(itemToString(BBBB, naming));
builder.append(", ");
builder.append(itemToString(HHHH, naming));
return formatString(builder.toString());
}
private String itemToString(IndexedDexItem indexedDexItem, ClassNameMapper naming) {
String str;
if (naming == null) {
str = indexedDexItem.toSmaliString();
} else {
str = naming.originalNameOf(indexedDexItem);
}
return str;
}
private void appendRegisterArguments(StringBuilder builder, String separator) {
builder.append("{ ");
int[] values = new int[] {C, D, E, F, G};
for (int i = 0; i < A; i++) {
if (i != 0) {
builder.append(separator);
}
builder.append("v").append(values[i]);
}
builder.append(" }");
}
@Override
public DexMethod getMethod() {
return BBBB;
}
@Override
public DexProto getProto() {
return HHHH;
}
}