|  | // 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.IndexedDexItem; | 
|  | import com.android.tools.r8.graph.ObjectToOffsetMapping; | 
|  | import com.android.tools.r8.naming.ClassNameMapper; | 
|  | 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; | 
|  |  | 
|  | 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 | 
|  | public final boolean equals(Object other) { | 
|  | if (other == null || (this.getClass() != other.getClass())) { | 
|  | return false; | 
|  | } | 
|  | Format45cc o = (Format45cc) other; | 
|  | return o.A == A | 
|  | && o.C == C | 
|  | && o.D == D | 
|  | && o.E == E | 
|  | && o.F == F | 
|  | && o.G == G | 
|  | && o.BBBB.equals(BBBB) | 
|  | && o.HHHH.equals(HHHH); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void collectIndexedItems(IndexedItemCollection indexedItems, | 
|  | DexMethod method, int instructionOffset) { | 
|  | BBBB.collectIndexedItems(indexedItems, method, instructionOffset); | 
|  | HHHH.collectIndexedItems(indexedItems, method, instructionOffset); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) { | 
|  | writeFirst(A, G, dest); | 
|  | write16BitReference(BBBB, dest, mapping); | 
|  | write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest); | 
|  | write16BitReference(HHHH, 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; | 
|  | } | 
|  | } |