blob: 3d297bb06aebac0d2c82edbbe7b36b40d83915d0 [file] [log] [blame]
// Copyright (c) 2016, 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 com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
import java.util.Arrays;
public class PackedSwitchPayload extends SwitchPayload {
public final int size;
public final int first_key;
public final /* offset */ int[] targets;
private static void specify(StructuralSpecification<PackedSwitchPayload, ?> spec) {
spec.withInt(i -> i.size).withInt(i -> i.first_key).withIntArray(i -> i.targets);
}
public PackedSwitchPayload(int high, BytecodeStream stream) {
super(high, stream);
size = read16BitValue(stream);
first_key = readSigned32BitValue(stream);
targets = new int[size];
for (int i = 0; i < size; i++) {
targets[i] = readSigned32BitValue(stream);
}
}
public PackedSwitchPayload(int first_key, int[] targets) {
assert targets.length > 0; // Empty switches should be eliminated.
this.size = targets.length;
this.first_key = first_key;
this.targets = targets;
}
@Override
public boolean isPayload() {
return true;
}
@Override
public void write(
ShortBuffer dest,
ProgramMethod context,
GraphLens graphLens,
ObjectToOffsetMapping mapping,
LensCodeRewriterUtils rewriter) {
writeFirst(1, dest); // Pseudo-opcode = 0x0100
write16BitValue(size, dest);
write32BitValue(first_key, dest);
for (int i = 0; i < size; i++) {
write32BitValue(targets[i], dest);
}
}
@Override
final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
return visitor.visit(this, (PackedSwitchPayload) other, PackedSwitchPayload::specify);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + size;
result = 31 * result + first_key;
result = 31 * result + Arrays.hashCode(targets);
return result;
}
@Override
public int getSize() {
return 4 + (2 * targets.length);
}
@Override
public int numberOfKeys() {
return size;
}
@Override
public int[] switchTargetOffsets() {
return targets;
}
@Override
public int[] keys() {
return new int[]{first_key};
}
@Override
public String toString(ClassNameMapper naming) {
return toString(naming, null);
}
@Override
public String toString(ClassNameMapper naming, Instruction payloadUser) {
StringBuilder builder = new StringBuilder("[PackedSwitchPayload");
if (payloadUser == null) {
builder.append(" offsets relative to associated PackedSwitch");
}
builder.append("]\n");
for (int i = 0; i < size; i++) {
String offsetString;
if (payloadUser != null) {
// Don't show the decimal offset, as these are relative to the associated switch.
offsetString = formatOffset(targets[i] + payloadUser.getOffset());
} else {
offsetString = formatDecimalOffset(targets[i]);
}
StringUtils.appendLeftPadded(builder, (first_key + i) + " -> " + offsetString + "\n", 20);
}
return super.toString(naming) + builder.toString();
}
@Override
public String toSmaliString(Instruction payloadUser) {
StringBuilder builder = new StringBuilder();
builder.append(" ");
builder.append(".packed-switch ");
builder.append(StringUtils.hexString(first_key, 8));
builder.append(" # ");
builder.append(first_key);
builder.append("\n");
for (int target : targets) {
builder.append(" :label_");
builder.append(payloadUser.getOffset() + target);
builder.append("\n");
}
builder.append(" ");
builder.append(".end packed-switch");
return builder.toString();
}
}