| // 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; | 
 |   } | 
 | } |