|  | // 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.IRBuilder; | 
|  | 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 FillArrayDataPayload extends Nop { | 
|  |  | 
|  | public final int element_width; | 
|  | public final long size; | 
|  | public final short[] data; | 
|  |  | 
|  | private static void specify(StructuralSpecification<FillArrayDataPayload, ?> spec) { | 
|  | spec.withInt(i -> i.element_width).withLong(i -> i.size).withShortArray(i -> i.data); | 
|  | } | 
|  |  | 
|  | FillArrayDataPayload(int high, BytecodeStream stream) { | 
|  | super(high, stream); | 
|  | element_width = read16BitValue(stream); | 
|  | size = read32BitValue(stream); | 
|  | assert size * element_width < Integer.MAX_VALUE; | 
|  | // Read the data as shorts (which is faster than reading bytes) as they are always 2-byte | 
|  | // aligned and the size is 2-byte aligned as well. | 
|  | int numberOfShorts = (int) (size * element_width + 1) / 2; | 
|  | data = new short[numberOfShorts]; | 
|  | for (int i = 0; i < data.length; i++) { | 
|  | data[i] = readSigned16BitValue(stream); | 
|  | } | 
|  | } | 
|  |  | 
|  | public FillArrayDataPayload(int element_width, long size, short[] data) { | 
|  | this.element_width = element_width; | 
|  | this.size = size; | 
|  | this.data = data; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean isPayload() { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void write( | 
|  | ShortBuffer dest, | 
|  | ProgramMethod context, | 
|  | GraphLens graphLens, | 
|  | ObjectToOffsetMapping mapping, | 
|  | LensCodeRewriterUtils rewriter) { | 
|  | writeFirst(3, dest);  // Pseudo-opcode = 0x0300 | 
|  | write16BitValue(element_width, dest); | 
|  | write32BitValue(size, dest); | 
|  | for (short datum : data) { | 
|  | write16BitValue(datum, dest); | 
|  | } | 
|  | } | 
|  |  | 
|  | @Override | 
|  | final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) { | 
|  | return visitor.visit(this, (FillArrayDataPayload) other, FillArrayDataPayload::specify); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int hashCode() { | 
|  | int result = super.hashCode(); | 
|  | result = 31 * result + element_width; | 
|  | result = 31 * result + (int) (size ^ (size >>> 32)); | 
|  | result = 31 * result + Arrays.hashCode(data); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int getSize() { | 
|  | return 4 + data.length; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String toString(ClassNameMapper naming) { | 
|  | return super.toString(naming) + "[FillArrayPayload], " + | 
|  | "width: " + element_width + ", size:  " + size; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String toSmaliString(ClassNameMapper naming) { | 
|  | StringBuilder builder = new StringBuilder(); | 
|  | builder.append("    "); | 
|  | builder.append(".array-data "); | 
|  | builder.append(StringUtils.hexString(element_width, 1)); | 
|  | builder.append("  # "); | 
|  | builder.append(element_width); | 
|  | builder.append("\n"); | 
|  | if (element_width == 1) { | 
|  | // For element width 1 split the 16-bit data units into bytes. | 
|  | for (int i = 0; i < data.length; i++) { | 
|  | for (int j = 0; j < 2; j++) { | 
|  | int value = (data[i] >> (j * 8)) & 0xff; | 
|  | if (i * 2 + j < size) { | 
|  | builder.append("      "); | 
|  | builder.append(StringUtils.hexString(value, 2)); | 
|  | builder.append("  # "); | 
|  | builder.append(value); | 
|  | builder.append("\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  | } else { | 
|  | // For element width > 1 combine the 16-bit data units into 16-bit/32-bit or 64-bit values. | 
|  | assert element_width == 2 || element_width == 4 || element_width == 8; | 
|  | long value = 0; | 
|  | for (int i = 0; i < data.length; i++) { | 
|  | value = (Short.toUnsignedLong(data[i]) << (16 * (i % (element_width / 2)))) | value; | 
|  | if ((((i + 1) * 2) % element_width) == 0) { | 
|  | builder.append("      "); | 
|  | builder.append(StringUtils.hexString(value, element_width * 2)); | 
|  | builder.append("  # "); | 
|  | builder.append(value); | 
|  | builder.append("\n"); | 
|  | value = 0; | 
|  | } | 
|  | } | 
|  | } | 
|  | builder.append("    "); | 
|  | builder.append(".end array-data"); | 
|  | return builder.toString(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void buildIR(IRBuilder builder) { | 
|  | // FilledArrayData payloads are not represented in the IR. | 
|  | } | 
|  | } |