RegisterType.java revision a555aa0c0177f26fdd99b1a8b31d80ba104dbe6e
1/* 2 * Copyright 2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32package org.jf.dexlib2.analysis; 33 34 35import org.jf.util.ExceptionWithContext; 36 37import javax.annotation.Nonnull; 38import javax.annotation.Nullable; 39import java.io.IOException; 40import java.io.Writer; 41 42public class RegisterType { 43 public final byte category; 44 @Nullable public final String type; 45 46 private RegisterType(byte category, @Nullable String type) { 47 assert ((category == REFERENCE || category == UNINIT_REF || category == UNINIT_THIS) && type != null) || 48 ((category != REFERENCE && category != UNINIT_REF && category != UNINIT_THIS) && type == null); 49 50 this.category = category; 51 this.type = type; 52 } 53 54 @Override 55 public String toString() { 56 return "(" + CATEGORY_NAMES[category] + (type==null?"":("," + type)) + ")"; 57 } 58 59 public void writeTo(Writer writer) throws IOException { 60 writer.write('('); 61 writer.write(CATEGORY_NAMES[category]); 62 if (type != null) { 63 writer.write(','); 64 writer.write(type); 65 } 66 writer.write(')'); 67 } 68 69 @Override 70 public boolean equals(Object o) { 71 if (this == o) return true; 72 if (o == null || getClass() != o.getClass()) return false; 73 74 RegisterType that = (RegisterType) o; 75 76 if (category != that.category) { 77 return false; 78 } 79 return (type != null ? type.equals(that.type) : that.type == null); 80 } 81 82 @Override 83 public int hashCode() { 84 int result = category; 85 result = 31 * result + (type != null ? type.hashCode() : 0); 86 return result; 87 } 88 89 //the Unknown category denotes a register type that hasn't been determined yet 90 public static final byte UNKNOWN = 0; 91 public static final byte UNINIT = 1; 92 public static final byte NULL = 2; 93 public static final byte ONE = 3; 94 public static final byte BOOLEAN = 4; 95 public static final byte BYTE = 5; 96 public static final byte POS_BYTE = 6; 97 public static final byte SHORT = 7; 98 public static final byte POS_SHORT = 8; 99 public static final byte CHAR = 9; 100 public static final byte INTEGER = 10; 101 public static final byte FLOAT = 11; 102 public static final byte LONG_LO = 12; 103 public static final byte LONG_HI = 13; 104 public static final byte DOUBLE_LO = 14; 105 public static final byte DOUBLE_HI = 15; 106 //the UninitRef category is used after a new-instance operation, and before the corresponding <init> is called 107 public static final byte UNINIT_REF = 16; 108 //the UninitThis category is used the "this" register inside an <init> method, before the superclass' <init> 109 //method is called 110 public static final byte UNINIT_THIS = 17; 111 public static final byte REFERENCE = 18; 112 //This is used when there are multiple incoming execution paths that have incompatible register types. For 113 //example if the register's type is an Integer on one incoming code path, but is a Reference type on another 114 //incomming code path. There is no register type that can hold either an Integer or a Reference. 115 public static final byte CONFLICTED = 19; 116 117 public static final String[] CATEGORY_NAMES = new String[] { 118 "Unknown", 119 "Uninit", 120 "Null", 121 "One", 122 "Boolean", 123 "Byte", 124 "PosByte", 125 "Short", 126 "PosShort", 127 "Char", 128 "Integer", 129 "Float", 130 "LongLo", 131 "LongHi", 132 "DoubleLo", 133 "DoubleHi", 134 "UninitRef", 135 "UninitThis", 136 "Reference", 137 "Conflicted" 138 }; 139 140 //this table is used when merging register types. For example, if a particular register can be either a BYTE 141 //or a Char, then the "merged" type of that register would be Integer, because it is the "smallest" type can 142 //could hold either type of value. 143 protected static byte[][] mergeTable = 144 { 145 /* UNKNOWN UNINIT NULL ONE, BOOLEAN BYTE POS_BYTE SHORT POS_SHORT CHAR INTEGER, FLOAT, LONG_LO LONG_HI DOUBLE_LO DOUBLE_HI UNINIT_REF UNINIT_THIS REFERENCE CONFLICTED*/ 146 /*UNKNOWN*/ {UNKNOWN, UNINIT, NULL, ONE, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, LONG_LO, LONG_HI, DOUBLE_LO, DOUBLE_HI, UNINIT_REF, UNINIT_THIS,REFERENCE, CONFLICTED}, 147 /*UNINIT*/ {UNINIT, UNINIT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 148 /*NULL*/ {NULL, CONFLICTED, NULL, BOOLEAN, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, REFERENCE, CONFLICTED}, 149 /*ONE*/ {ONE, CONFLICTED, BOOLEAN, ONE, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 150 /*BOOLEAN*/ {BOOLEAN, CONFLICTED, BOOLEAN, BOOLEAN, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 151 /*BYTE*/ {BYTE, CONFLICTED, BYTE, BYTE, BYTE, BYTE, BYTE, SHORT, SHORT, INTEGER, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 152 /*POS_BYTE*/ {POS_BYTE, CONFLICTED, POS_BYTE, POS_BYTE, POS_BYTE, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 153 /*SHORT*/ {SHORT, CONFLICTED, SHORT, SHORT, SHORT, SHORT, SHORT, SHORT, SHORT, INTEGER, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 154 /*POS_SHORT*/ {POS_SHORT, CONFLICTED, POS_SHORT, POS_SHORT, POS_SHORT, SHORT, POS_SHORT, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 155 /*CHAR*/ {CHAR, CONFLICTED, CHAR, CHAR, CHAR, INTEGER, CHAR, INTEGER, CHAR, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 156 /*INTEGER*/ {INTEGER, CONFLICTED, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 157 /*FLOAT*/ {FLOAT, CONFLICTED, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 158 /*LONG_LO*/ {LONG_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_LO, CONFLICTED, LONG_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 159 /*LONG_HI*/ {LONG_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_HI, CONFLICTED, LONG_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 160 /*DOUBLE_LO*/ {DOUBLE_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_LO, CONFLICTED, DOUBLE_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 161 /*DOUBLE_HI*/ {DOUBLE_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_HI, CONFLICTED, DOUBLE_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 162 /*UNINIT_REF*/ {UNINIT_REF, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, 163 /*UNINIT_THIS*/{UNINIT_THIS, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, UNINIT_THIS,CONFLICTED, CONFLICTED}, 164 /*REFERENCE*/ {REFERENCE, CONFLICTED, REFERENCE, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, REFERENCE, CONFLICTED}, 165 /*CONFLICTED*/ {CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED} 166 }; 167 168 169 public static final RegisterType UNKNOWN_TYPE = new RegisterType(UNKNOWN, null); 170 public static final RegisterType UNINIT_TYPE = new RegisterType(UNINIT, null); 171 public static final RegisterType NULL_TYPE = new RegisterType(NULL, null); 172 public static final RegisterType ONE_TYPE = new RegisterType(ONE, null); 173 public static final RegisterType BOOLEAN_TYPE = new RegisterType(BOOLEAN, null); 174 public static final RegisterType BYTE_TYPE = new RegisterType(BYTE, null); 175 public static final RegisterType POS_BYTE_TYPE = new RegisterType(POS_BYTE, null); 176 public static final RegisterType SHORT_TYPE = new RegisterType(SHORT, null); 177 public static final RegisterType POS_SHORT_TYPE = new RegisterType(POS_SHORT, null); 178 public static final RegisterType CHAR_TYPE = new RegisterType(CHAR, null); 179 public static final RegisterType INTEGER_TYPE = new RegisterType(INTEGER, null); 180 public static final RegisterType FLOAT_TYPE = new RegisterType(FLOAT, null); 181 public static final RegisterType LONG_LO_TYPE = new RegisterType(LONG_LO, null); 182 public static final RegisterType LONG_HI_TYPE = new RegisterType(LONG_HI, null); 183 public static final RegisterType DOUBLE_LO_TYPE = new RegisterType(DOUBLE_LO, null); 184 public static final RegisterType DOUBLE_HI_TYPE = new RegisterType(DOUBLE_HI, null); 185 public static final RegisterType CONFLICTED_TYPE = new RegisterType(CONFLICTED, null); 186 187 @Nonnull 188 public static RegisterType getRegisterTypeForType(@Nonnull String type) { 189 switch (type.charAt(0)) { 190 case 'Z': 191 return getRegisterType(BOOLEAN, null); 192 case 'B': 193 return getRegisterType(BYTE, null); 194 case 'S': 195 return getRegisterType(SHORT, null); 196 case 'C': 197 return getRegisterType(CHAR, null); 198 case 'I': 199 return getRegisterType(INTEGER, null); 200 case 'F': 201 return getRegisterType(FLOAT, null); 202 case 'J': 203 return getRegisterType(LONG_LO, null); 204 case 'D': 205 return getRegisterType(DOUBLE_LO, null); 206 case 'L': 207 case 'U': 208 case '[': 209 return getRegisterType(REFERENCE, type); 210 default: 211 throw new RuntimeException("Invalid type: " + type); 212 } 213 } 214 215 @Nonnull 216 public static RegisterType getWideRegisterTypeForType(@Nonnull String type, boolean firstRegister) { 217 switch (type.charAt(0)) { 218 case 'J': 219 if (firstRegister) { 220 return getRegisterType(LONG_LO, null); 221 } else { 222 return getRegisterType(LONG_HI, null); 223 } 224 case 'D': 225 if (firstRegister) { 226 return getRegisterType(DOUBLE_LO, null); 227 } else { 228 return getRegisterType(DOUBLE_HI, null); 229 } 230 default: 231 throw new ExceptionWithContext("Cannot use this method for narrow register type: %s", type); 232 } 233 } 234 235 public static RegisterType getRegisterTypeForLiteral(long literalValue) { 236 if (literalValue < -32768) { 237 return getRegisterType(INTEGER, null); 238 } 239 if (literalValue < -128) { 240 return getRegisterType(SHORT, null); 241 } 242 if (literalValue < 0) { 243 return getRegisterType(BYTE, null); 244 } 245 if (literalValue == 0) { 246 return getRegisterType(NULL, null); 247 } 248 if (literalValue == 1) { 249 return getRegisterType(ONE, null); 250 } 251 if (literalValue < 128) { 252 return getRegisterType(POS_BYTE, null); 253 } 254 if (literalValue < 32768) { 255 return getRegisterType(POS_SHORT, null); 256 } 257 if (literalValue < 65536) { 258 return getRegisterType(CHAR, null); 259 } 260 return getRegisterType(INTEGER, null); 261 } 262 263 public RegisterType merge(RegisterType other) { 264 if (other == null || other == this) { 265 return this; 266 } 267 268 byte mergedCategory = mergeTable[this.category][other.category]; 269 270 String mergedType = null; 271 if (mergedCategory == REFERENCE) { 272 // TODO: uncomment 273 // TODO: make sure to handle unresolved types in getCommonSuperclass (using U prefix?) 274 //mergedType = ClassPath.getCommonSuperclass(this.type, other.type); 275 } else if (mergedCategory == UNINIT_REF || mergedCategory == UNINIT_THIS) { 276 if (this.category == UNKNOWN) { 277 return other; 278 } 279 assert other.category == UNKNOWN; 280 return this; 281 } 282 283 if (mergedType != null) { 284 if (mergedType.equals(this.type)) { 285 return this; 286 } 287 if (mergedType.equals(other.type)) { 288 return other; 289 } 290 } 291 return RegisterType.getRegisterType(mergedCategory, mergedType); 292 } 293 294 public static RegisterType getRegisterType(byte category, String classType) { 295 switch (category) { 296 case UNKNOWN: 297 return UNKNOWN_TYPE; 298 case UNINIT: 299 return UNINIT_TYPE; 300 case NULL: 301 return NULL_TYPE; 302 case ONE: 303 return ONE_TYPE; 304 case BOOLEAN: 305 return BOOLEAN_TYPE; 306 case BYTE: 307 return BYTE_TYPE; 308 case POS_BYTE: 309 return POS_BYTE_TYPE; 310 case SHORT: 311 return SHORT_TYPE; 312 case POS_SHORT: 313 return POS_BYTE_TYPE; 314 case CHAR: 315 return CHAR_TYPE; 316 case INTEGER: 317 return INTEGER_TYPE; 318 case FLOAT: 319 return FLOAT_TYPE; 320 case LONG_LO: 321 return LONG_LO_TYPE; 322 case LONG_HI: 323 return LONG_HI_TYPE; 324 case DOUBLE_LO: 325 return DOUBLE_LO_TYPE; 326 case DOUBLE_HI: 327 return DOUBLE_HI_TYPE; 328 case CONFLICTED: 329 return CONFLICTED_TYPE; 330 } 331 332 return new RegisterType(category, classType); 333 } 334} 335