| // Copyright (c) 2020, 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.dex.IndexedItemCollection; |
| import com.android.tools.r8.errors.Unreachable; |
| import com.android.tools.r8.graph.DexField; |
| import com.android.tools.r8.graph.DexMethod; |
| import com.android.tools.r8.graph.DexType; |
| import com.android.tools.r8.graph.ObjectToOffsetMapping; |
| import com.android.tools.r8.graph.UseRegistry; |
| import com.android.tools.r8.ir.code.FieldMemberType; |
| import com.android.tools.r8.ir.conversion.IRBuilder; |
| import com.android.tools.r8.naming.ClassNameMapper; |
| import java.nio.ShortBuffer; |
| |
| public class DexInitClass extends Base2Format { |
| |
| public static final int OPCODE = 0x60; |
| public static final String NAME = "InitClass"; |
| public static final String SMALI_NAME = "initclass"; |
| |
| private final int dest; |
| private final DexType clazz; |
| |
| public DexInitClass(int dest, DexType clazz) { |
| assert clazz.isClassType(); |
| this.dest = dest; |
| this.clazz = clazz; |
| } |
| |
| @Override |
| public void buildIR(IRBuilder builder) { |
| builder.addInitClass(dest, clazz); |
| } |
| |
| @Override |
| public void collectIndexedItems( |
| IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) { |
| DexField field = indexedItems.getInitClassLens().getInitClassField(clazz); |
| field.collectIndexedItems(indexedItems, method, instructionOffset); |
| } |
| |
| @Override |
| public boolean canThrow() { |
| return true; |
| } |
| |
| @Override |
| public String getName() { |
| return NAME; |
| } |
| |
| @Override |
| public String getSmaliName() { |
| return SMALI_NAME; |
| } |
| |
| @Override |
| public int getOpcode() { |
| throw new Unreachable(); |
| } |
| |
| private int getOpcode(DexField field) { |
| FieldMemberType type = FieldMemberType.fromDexType(field.type); |
| switch (type) { |
| case INT: |
| case FLOAT: |
| return Sget.OPCODE; |
| case LONG: |
| case DOUBLE: |
| return SgetWide.OPCODE; |
| case OBJECT: |
| return SgetObject.OPCODE; |
| case BOOLEAN: |
| return SgetBoolean.OPCODE; |
| case BYTE: |
| return SgetByte.OPCODE; |
| case CHAR: |
| return SgetChar.OPCODE; |
| case SHORT: |
| return SgetShort.OPCODE; |
| default: |
| throw new Unreachable("Unexpected type: " + type); |
| } |
| } |
| |
| @Override |
| public void registerUse(UseRegistry registry) { |
| registry.registerInitClass(clazz); |
| } |
| |
| @Override |
| public void write(ShortBuffer buffer, ObjectToOffsetMapping mapping) { |
| DexField field = mapping.getClinitField(clazz); |
| writeFirst(dest, buffer, getOpcode(field)); |
| write16BitReference(field, buffer, mapping); |
| } |
| |
| @Override |
| public int hashCode() { |
| return ((clazz.hashCode() << 8) | dest) ^ getClass().hashCode(); |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == null || getClass() != other.getClass()) { |
| return false; |
| } |
| DexInitClass initClass = (DexInitClass) other; |
| return dest == initClass.dest && clazz == initClass.clazz; |
| } |
| |
| @Override |
| public String toSmaliString(ClassNameMapper naming) { |
| return formatSmaliString("v" + dest + ", " + clazz.toSmaliString()); |
| } |
| |
| @Override |
| public String toString(ClassNameMapper naming) { |
| StringBuilder builder = new StringBuilder("v").append(dest).append(", "); |
| if (naming == null) { |
| builder.append(clazz.toSourceString()); |
| } else { |
| builder.append(naming.originalNameOf(clazz)); |
| } |
| return formatString(builder.toString()); |
| } |
| } |