1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file 2 // for details. All rights reserved. Use of this source code is governed by a 3 // BSD-style license that can be found in the LICENSE file. 4 package com.android.tools.r8.code; 5 6 import com.android.tools.r8.dex.IndexedItemCollection; 7 import com.android.tools.r8.errors.InternalCompilerError; 8 import com.android.tools.r8.graph.DexCallSite; 9 import com.android.tools.r8.graph.DexField; 10 import com.android.tools.r8.graph.DexMethod; 11 import com.android.tools.r8.graph.DexProto; 12 import com.android.tools.r8.graph.IndexedDexItem; 13 import com.android.tools.r8.graph.ObjectToOffsetMapping; 14 import com.android.tools.r8.graph.UseRegistry; 15 import com.android.tools.r8.ir.conversion.IRBuilder; 16 import com.android.tools.r8.naming.ClassNameMapper; 17 import com.android.tools.r8.utils.StringUtils; 18 import java.nio.ShortBuffer; 19 import java.util.function.BiPredicate; 20 21 public abstract class Instruction { 22 23 public final static int[] NO_TARGETS = null; 24 public final static int[] EXIT_TARGET = new int[]{}; 25 26 public int offset; 27 Instruction(BytecodeStream stream)28 Instruction(BytecodeStream stream) { 29 // When this constructor is invoked, we have already read 1 ushort from the stream. 30 this.offset = stream.getOffset() - 1; 31 } 32 Instruction()33 protected Instruction() { 34 this.offset = -1; 35 } 36 readSigned8BitValue(BytecodeStream stream)37 static int readSigned8BitValue(BytecodeStream stream) { 38 return (byte) stream.nextByte(); 39 } 40 read8BitValue(BytecodeStream stream)41 static int read8BitValue(BytecodeStream stream) { 42 int result = stream.nextByte(); 43 return result; 44 } 45 readSigned16BitValue(BytecodeStream stream)46 static int readSigned16BitValue(BytecodeStream stream) { 47 // Convert to signed. 48 return (short) stream.nextShort(); 49 } 50 read16BitValue(BytecodeStream stream)51 static int read16BitValue(BytecodeStream stream) { 52 return stream.nextShort() & 0xffff; 53 } 54 readSigned32BitValue(BytecodeStream stream)55 static int readSigned32BitValue(BytecodeStream stream) { 56 int low = read16BitValue(stream); 57 int high = read16BitValue(stream); 58 int result = ((high << 16) & 0xffff0000) | (low & 0xffff); 59 return result; 60 } 61 read32BitValue(BytecodeStream stream)62 static long read32BitValue(BytecodeStream stream) { 63 long low = read16BitValue(stream); 64 long high = read16BitValue(stream); 65 long result = ((high & 0xffff) << 16) | (low & 0xffff); 66 return result; 67 } 68 read64BitValue(BytecodeStream stream)69 static long read64BitValue(BytecodeStream stream) { 70 long low = read32BitValue(stream); 71 long high = read32BitValue(stream); 72 long result = (high << 32) | low; 73 return result; 74 } 75 combineBytes(int high, int low)76 protected static short combineBytes(int high, int low) { 77 return (short) (((high & 0xff) << 8) | (low & 0xff)); 78 } 79 makeByte(int high, int low)80 protected static int makeByte(int high, int low) { 81 return ((high & 0xf) << 4) | low & 0xf; 82 } 83 writeFirst(int aa, ShortBuffer dest)84 protected void writeFirst(int aa, ShortBuffer dest) { 85 dest.put((short) (((aa & 0xff) << 8) | (getOpcode() & 0xff))); 86 } 87 writeFirst(int a, int b, ShortBuffer dest)88 protected void writeFirst(int a, int b, ShortBuffer dest) { 89 dest.put((short) (((a & 0xf) << 12) | ((b & 0xf) << 8) | (getOpcode() & 0xff))); 90 } 91 write16BitValue(int value, ShortBuffer dest)92 protected void write16BitValue(int value, ShortBuffer dest) { 93 dest.put((short) value); 94 } 95 write32BitValue(long value, ShortBuffer dest)96 protected void write32BitValue(long value, ShortBuffer dest) { 97 dest.put((short) (value & 0xffff)); 98 dest.put((short) ((value >> 16) & 0xffff)); 99 } 100 write64BitValue(long value, ShortBuffer dest)101 protected void write64BitValue(long value, ShortBuffer dest) { 102 write32BitValue(value & 0xffffffff, dest); 103 write32BitValue((value >> 32) & 0xffffffff, dest); 104 } 105 write16BitReference(IndexedDexItem item, ShortBuffer dest, ObjectToOffsetMapping mapping)106 protected void write16BitReference(IndexedDexItem item, ShortBuffer dest, 107 ObjectToOffsetMapping mapping) { 108 int index = item.getOffset(mapping); 109 assert index == (index & 0xffff); 110 write16BitValue(index, dest); 111 } 112 write32BitReference(IndexedDexItem item, ShortBuffer dest, ObjectToOffsetMapping mapping)113 protected void write32BitReference(IndexedDexItem item, ShortBuffer dest, 114 ObjectToOffsetMapping mapping) { 115 write32BitValue(item.getOffset(mapping), dest); 116 } 117 getOffset()118 public int getOffset() { 119 return offset; 120 } 121 setOffset(int offset)122 public void setOffset(int offset) { 123 this.offset = offset; 124 } 125 isPayload()126 public boolean isPayload() { 127 return false; 128 } 129 isSwitchPayload()130 public boolean isSwitchPayload() { 131 return false; 132 } 133 hasPayload()134 public boolean hasPayload() { 135 return false; 136 } 137 isSwitch()138 public boolean isSwitch() { 139 return false; 140 } 141 getPayloadOffset()142 public int getPayloadOffset() { 143 return 0; 144 } 145 formatString(String left)146 String formatString(String left) { 147 StringBuilder builder = new StringBuilder(); 148 StringUtils.appendLeftPadded(builder, Integer.toString(getOffset()), 6); 149 builder.append(": "); 150 StringUtils.appendRightPadded(builder, getName(), 20); 151 builder.append(left == null ? "" : left); 152 return builder.toString(); 153 } 154 formatSmaliString(String left)155 String formatSmaliString(String left) { 156 StringBuilder builder = new StringBuilder(); 157 builder.append(" "); 158 if (left != null) { 159 StringUtils.appendRightPadded(builder, getSmaliName(), 20); 160 builder.append(left); 161 } else { 162 builder.append(getSmaliName()); 163 } 164 return builder.toString(); 165 } 166 getTargets()167 public int[] getTargets() { 168 return NO_TARGETS; 169 } 170 buildIR(IRBuilder builder)171 public abstract void buildIR(IRBuilder builder); 172 getCallSite()173 public DexCallSite getCallSite() { 174 return null; 175 } 176 getMethod()177 public DexMethod getMethod() { 178 return null; 179 } 180 getProto()181 public DexProto getProto() { 182 return null; 183 } 184 getField()185 public DexField getField() { 186 return null; 187 } 188 189 @Override equals(Object obj)190 public abstract boolean equals(Object obj); 191 192 @Override hashCode()193 public abstract int hashCode(); 194 getName()195 public abstract String getName(); 196 getSmaliName()197 public abstract String getSmaliName(); 198 getOpcode()199 public abstract int getOpcode(); 200 getSize()201 public abstract int getSize(); 202 toSmaliString(Instruction payloadUser)203 public String toSmaliString(Instruction payloadUser) { 204 throw new InternalCompilerError("Instruction " + payloadUser + " is not a payload user"); 205 } 206 toSmaliString(ClassNameMapper naming)207 public abstract String toSmaliString(ClassNameMapper naming); 208 toSmaliString()209 public String toSmaliString() { 210 return toSmaliString((ClassNameMapper) null); 211 } 212 toString(ClassNameMapper naming)213 public abstract String toString(ClassNameMapper naming); 214 toString()215 public String toString() { 216 return toString(null); 217 } 218 write(ShortBuffer buffer, ObjectToOffsetMapping mapping)219 public abstract void write(ShortBuffer buffer, ObjectToOffsetMapping mapping); 220 collectIndexedItems(IndexedItemCollection indexedItems)221 public abstract void collectIndexedItems(IndexedItemCollection indexedItems); 222 equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality)223 public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) { 224 // In the default case, there is nothing to substitute. 225 return this.equals(other); 226 } 227 registerUse(UseRegistry registry)228 public void registerUse(UseRegistry registry) { 229 // Intentionally empty 230 } 231 canThrow()232 public boolean canThrow() { 233 return false; 234 } 235 } 236