| // 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.ObjectToOffsetMapping; |
| import com.android.tools.r8.naming.ClassNameMapper; |
| import com.android.tools.r8.utils.StringUtils; |
| import java.nio.ShortBuffer; |
| import java.util.Arrays; |
| |
| public class SparseSwitchPayload extends SwitchPayload { |
| |
| public final int size; |
| public final int[] keys; |
| public final /* offset */ int[] targets; |
| |
| public SparseSwitchPayload(int high, BytecodeStream stream) { |
| super(high, stream); |
| size = read16BitValue(stream); |
| keys = new int[size]; |
| for (int i = 0; i < size; i++) { |
| keys[i] = readSigned32BitValue(stream); |
| } |
| |
| targets = new int[size]; |
| for (int i = 0; i < size; i++) { |
| targets[i] = readSigned32BitValue(stream); |
| } |
| } |
| |
| public SparseSwitchPayload(int[] keys, int[] targets) { |
| assert targets.length > 0; // Empty switches should be eliminated. |
| this.size = targets.length; |
| this.keys = keys; |
| this.targets = targets; |
| } |
| |
| public boolean isPayload() { |
| return true; |
| } |
| |
| public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { |
| writeFirst(2, dest); // Pseudo-opcode = 0x0200 |
| write16BitValue(size, dest); |
| for (int i = 0; i < size; i++) { |
| write32BitValue(keys[i], dest); |
| } |
| for (int i = 0; i < size; i++) { |
| write32BitValue(targets[i], dest); |
| } |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (!super.equals(other)) { |
| return false; |
| } |
| SparseSwitchPayload that = (SparseSwitchPayload) other; |
| return size == that.size && Arrays.equals(keys, that.keys) && Arrays |
| .equals(targets, that.targets); |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = super.hashCode(); |
| result = 31 * result + size; |
| result = 31 * result + Arrays.hashCode(keys); |
| result = 31 * result + Arrays.hashCode(targets); |
| return result; |
| } |
| |
| public int getSize() { |
| return 2 + (2 * keys.length) + (2 * targets.length); |
| } |
| |
| @Override |
| public int numberOfKeys() { |
| return size; |
| } |
| |
| @Override |
| public int[] keys() { |
| return keys; |
| } |
| |
| public int[] switchTargetOffsets() { |
| return targets; |
| } |
| |
| public String toString(ClassNameMapper naming) { |
| return toString(naming, null); |
| } |
| |
| public String toString(ClassNameMapper naming, Instruction payloadUser) { |
| StringBuilder builder = new StringBuilder("[SparseSwitchPayload"); |
| if (payloadUser == null) { |
| builder.append(" offsets relative to associated SparseSwitch"); |
| } |
| 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 = StringUtils.hexString(targets[i] + payloadUser.getOffset(), 2); |
| } else { |
| offsetString = targets[i] >= 0 ? ("+" + targets[i]) : Integer.toString(targets[i]); |
| } |
| StringUtils.appendLeftPadded(builder, keys[i] + " -> " + offsetString + "\n", 20); |
| } |
| return super.toString(naming) + builder.toString(); |
| } |
| |
| public String toSmaliString(Instruction payloadUser) { |
| StringBuilder builder = new StringBuilder(); |
| builder.append(" "); |
| builder.append(".sparse-switch"); |
| builder.append("\n"); |
| for (int i = 0; i < keys.length; i++) { |
| builder.append(" "); |
| builder.append(StringUtils.hexString(keys[i], 8)); |
| builder.append(" -> :label_"); |
| builder.append(payloadUser.getOffset() + targets[i]); |
| builder.append(" # "); |
| builder.append(keys[i]); |
| builder.append("\n"); |
| } |
| builder.append(" "); |
| builder.append(".end sparse-switch"); |
| return builder.toString(); |
| } |
| } |