1 5 package com.tc.object.bytecode; 6 7 import com.tc.asm.MethodVisitor; 8 import com.tc.asm.Opcodes; 9 import com.tc.asm.Type; 10 import com.tc.object.LiteralValues; 11 import com.tc.object.ObjectID; 12 import com.tc.util.Assert; 13 14 import java.lang.reflect.Modifier ; 15 import java.util.ArrayList ; 16 import java.util.Arrays ; 17 import java.util.Collections ; 18 import java.util.HashSet ; 19 import java.util.List ; 20 import java.util.Set ; 21 22 public class ByteCodeUtil implements Opcodes { 23 private static final String AUTOLOCK_PREFIX = "@"; 24 private static final String NAMED_LOCK_PREFIX = "^"; 25 private static final String LITERAL_LOCK_PREFIX = "#"; 26 27 public static final String TC_FIELD_PREFIX = "$__tc_"; 28 public static final String TC_METHOD_PREFIX = "__tc_"; 29 public static final String METHOD_RENAME_PREFIX = TC_METHOD_PREFIX + "wrapped_"; 30 public static final String DMI_METHOD_RENAME_PREFIX = TC_METHOD_PREFIX + "dmi_"; 31 32 public static final String VALUES_GETTER = TC_METHOD_PREFIX + "getallfields"; 33 public static final String VALUES_GETTER_DESCRIPTION = "(Ljava/util/Map;)V"; 34 public static final String VALUES_SETTER = TC_METHOD_PREFIX + "setfield"; 35 public static final String VALUES_SETTER_DESCRIPTION = "(Ljava/lang/String;Ljava/lang/Object;)V"; 36 public static final String MANAGED_VALUES_GETTER = TC_METHOD_PREFIX + "getmanagedfield"; 37 public static final String MANAGED_VALUES_GETTER_DESCRIPTION = "(Ljava/lang/String;)Ljava/lang/Object;"; 38 public static final String MANAGED_VALUES_SETTER = TC_METHOD_PREFIX + "setmanagedfield"; 39 40 private static final LiteralValues LITERAL_VALUES = new LiteralValues(); 41 42 public static String [] addInterfaces(String [] existing, String [] toAdd) { 43 if (existing == null) { return toAdd; } 44 if (toAdd == null) { return existing; } 45 46 List newList = new ArrayList (Arrays.asList(existing)); 47 Set existingAsSet = Collections.unmodifiableSet(new HashSet (newList)); 48 49 for (int i = 0, n = toAdd.length; i < n; i++) { 50 if (!existingAsSet.contains(toAdd[i])) { 51 newList.add(toAdd[i]); 52 } 53 } 54 55 return (String []) newList.toArray(new String [newList.size()]); 56 } 57 58 public static boolean isPrimitive(Type t) { 59 final int sort = t.getSort(); 60 switch (sort) { 61 case Type.BOOLEAN: 62 case Type.BYTE: 63 case Type.CHAR: 64 case Type.DOUBLE: 65 case Type.FLOAT: 66 case Type.INT: 67 case Type.LONG: 68 case Type.SHORT: 69 return true; 70 default: 71 return false; 72 } 73 74 } 76 77 public static String sortToWrapperName(int sort) { 78 switch (sort) { 79 case Type.BOOLEAN: return "java/lang/Boolean"; 81 82 case Type.CHAR: return "java/lang/Character"; 84 85 case Type.BYTE: return "java/lang/Byte"; 87 88 case Type.SHORT: return "java/lang/Short"; 90 91 case Type.INT: return "java/lang/Integer"; 93 94 case Type.FLOAT: return "java/lang/Float"; 96 97 case Type.LONG: return "java/lang/Long"; 99 100 case Type.DOUBLE: return "java/lang/Double"; 102 default: 103 throw new AssertionError (); 104 } 105 106 } 107 108 public static String codeToName(String typeCode) { 109 if ((typeCode == null) || (typeCode.length() != 1)) { throw new IllegalArgumentException ("invalid type code: " 110 + typeCode); } 111 char code = typeCode.charAt(0); 112 113 switch (code) { 114 case 'B': { 115 return "byte"; 116 } 117 case 'C': { 118 return "char"; 119 } 120 case 'D': { 121 return "double"; 122 } 123 case 'F': { 124 return "float"; 125 } 126 case 'I': { 127 return "int"; 128 } 129 case 'J': { 130 return "long"; 131 } 132 case 'S': { 133 return "short"; 134 } 135 case 'Z': { 136 return "boolean"; 137 } 138 default: { 139 throw new IllegalArgumentException ("unknown code: " + code); 140 } 141 142 } 144 } 145 146 public static boolean isAutolockName(String lockName) { 147 return lockName == null ? false : lockName.startsWith(AUTOLOCK_PREFIX); 148 } 149 150 public static long objectIdFromLockName(String lockName) { 151 if (lockName == null || (!lockName.startsWith(AUTOLOCK_PREFIX))) { 152 throw new IllegalArgumentException ("not an autolock name: " + lockName); 154 } 155 return Long.valueOf(lockName.substring(AUTOLOCK_PREFIX.length())).longValue(); 156 157 } 158 159 public static boolean isSynthetic(String fieldName) { 160 return fieldName.indexOf("$") >= 0; 161 } 162 163 public static boolean isTCSynthetic(String fieldName) { 164 return fieldName.startsWith(TC_FIELD_PREFIX) || isParent(fieldName); 165 } 166 167 public static boolean isSynthetic(int access) { 168 return (ACC_SYNTHETIC & access) > 0; 169 } 170 171 public static boolean isParent(String fieldName) { 172 return fieldName.matches("^this\\$\\d+$"); 173 174 } 176 177 public static void pushThis(MethodVisitor c) { 178 c.visitVarInsn(ALOAD, 0); 179 } 180 181 public static void pushInstanceVariable(MethodVisitor c, String className, String fieldName, String description) { 182 c.visitFieldInsn(GETFIELD, className, fieldName, description); 183 } 184 185 public static void createParametersToArrayByteCode(MethodVisitor c, Type[] parameters) { 186 createParametersToArrayByteCode(c, parameters, 1); 187 } 188 189 public static void createParametersToArrayByteCode(MethodVisitor c, Type[] parameters, int offset) { 190 c.visitLdcInsn(new Integer (parameters.length)); 191 c.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 192 for (int i = 0; i < parameters.length; i++) { 193 c.visitInsn(DUP); 194 c.visitLdcInsn(new Integer (i)); 195 addTypeSpecificParameterLoad(c, parameters[i], offset); 196 c.visitInsn(AASTORE); 197 offset += parameters[i].getSize(); 198 } 199 } 200 201 public static void addTypeSpecificParameterLoad(MethodVisitor c, Type type, int offset) { 202 203 switch (type.getSort()) { 204 case Type.ARRAY: 205 case Type.OBJECT: 206 c.visitVarInsn(type.getOpcode(ILOAD), offset); 207 break; 208 case Type.BOOLEAN: 209 c.visitTypeInsn(NEW, "java/lang/Boolean"); 210 c.visitInsn(DUP); 211 c.visitVarInsn(type.getOpcode(ILOAD), offset); 212 c.visitMethodInsn(INVOKESPECIAL, "java/lang/Boolean", "<init>", "(Z)V"); 213 break; 214 case Type.BYTE: 215 c.visitTypeInsn(NEW, "java/lang/Byte"); 216 c.visitInsn(DUP); 217 c.visitVarInsn(type.getOpcode(ILOAD), offset); 218 c.visitMethodInsn(INVOKESPECIAL, "java/lang/Byte", "<init>", "(B)V"); 219 break; 220 case Type.CHAR: 221 c.visitTypeInsn(NEW, "java/lang/Character"); 222 c.visitInsn(DUP); 223 c.visitVarInsn(type.getOpcode(ILOAD), offset); 224 c.visitMethodInsn(INVOKESPECIAL, "java/lang/Character", "<init>", "(C)V"); 225 break; 226 case Type.DOUBLE: 227 c.visitTypeInsn(NEW, "java/lang/Double"); 228 c.visitInsn(DUP); 229 c.visitVarInsn(type.getOpcode(ILOAD), offset); 230 c.visitMethodInsn(INVOKESPECIAL, "java/lang/Double", "<init>", "(D)V"); 231 break; 232 case Type.FLOAT: 233 c.visitTypeInsn(NEW, "java/lang/Float"); 234 c.visitInsn(DUP); 235 c.visitVarInsn(type.getOpcode(ILOAD), offset); 236 c.visitMethodInsn(INVOKESPECIAL, "java/lang/Float", "<init>", "(F)V"); 237 break; 238 case Type.INT: 239 c.visitTypeInsn(NEW, "java/lang/Integer"); 240 c.visitInsn(DUP); 241 c.visitVarInsn(type.getOpcode(ILOAD), offset); 242 c.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer", "<init>", "(I)V"); 243 break; 244 case Type.LONG: 245 c.visitTypeInsn(NEW, "java/lang/Long"); 246 c.visitInsn(DUP); 247 c.visitVarInsn(type.getOpcode(ILOAD), offset); 248 c.visitMethodInsn(INVOKESPECIAL, "java/lang/Long", "<init>", "(J)V"); 249 break; 250 case Type.SHORT: 251 c.visitTypeInsn(NEW, "java/lang/Short"); 252 c.visitInsn(DUP); 253 c.visitVarInsn(type.getOpcode(ILOAD), offset); 254 c.visitMethodInsn(INVOKESPECIAL, "java/lang/Short", "<init>", "(S)V"); 255 break; 256 default: 257 throw new AssertionError ("can't happen:" + type); 258 } 259 } 260 261 public static void pushMethodArguments(int callingMethodModifier, String desc, MethodVisitor c) { 262 int localVariableOffset = getLocalVariableOffset(callingMethodModifier); 263 Type[] args = Type.getArgumentTypes(desc); 264 265 int pos = 0; 266 for (int i = 0; i < args.length; i++) { 267 c.visitVarInsn(args[i].getOpcode(ILOAD), pos + localVariableOffset); 268 pos += args[i].getSize(); 269 } 270 } 271 272 public static int getFirstLocalVariableOffset(int callingMethodModifier, String desc) { 273 int localVariableOffset = getLocalVariableOffset(callingMethodModifier); 274 Type[] args = Type.getArgumentTypes(desc); 275 for (int i = 0; i < args.length; i++) { 276 localVariableOffset += args[i].getSize(); 277 } 278 return localVariableOffset; 279 } 280 281 public static void prepareStackForMethodCall(int callingMethodModifier, String desc, MethodVisitor c) { 282 if (!Modifier.isStatic(callingMethodModifier)) { 283 pushThis(c); 284 } 285 pushMethodArguments(callingMethodModifier, desc, c); 286 } 287 288 291 public static int getLocalVariableOffset(int methodModifier) { 292 return Modifier.isStatic(methodModifier) ? 0 : 1; 293 } 294 295 public static String generateVolatileLockName(ObjectID id, String fieldName) { 296 Assert.assertNotNull(id); 297 return AUTOLOCK_PREFIX + id.toLong() + fieldName; 298 } 299 300 public static String generateAutolockName(ObjectID id) { 301 Assert.assertNotNull(id); 302 return generateAutolockName(id.toLong()); 303 } 304 305 public static String generateNamedLockName(Object obj) { 306 Assert.assertNotNull(obj); 307 return NAMED_LOCK_PREFIX + obj; 308 } 309 310 public static String generateLiteralLockName(Object obj) { 311 Assert.assertNotNull(obj); 312 return LITERAL_VALUES.valueFor(obj) + LITERAL_LOCK_PREFIX + obj; 313 } 314 315 private static String generateAutolockName(long objectId) { 316 return AUTOLOCK_PREFIX + objectId; 317 } 318 319 public static String stripGeneratedLockHeader(String lockName) { 320 int index = lockName.indexOf(LITERAL_LOCK_PREFIX); 321 index = index < 0 ? 1 : index; 322 return lockName.substring(index); 323 } 324 325 public static String sortToPrimitiveMethodName(int sort) { 326 switch (sort) { 327 case Type.BOOLEAN: return "booleanValue"; 329 330 case Type.CHAR: return "charValue"; 332 333 case Type.BYTE: return "byteValue"; 335 336 case Type.SHORT: return "shortValue"; 338 339 case Type.INT: return "intValue"; 341 342 case Type.FLOAT: return "floatValue"; 344 345 case Type.LONG: return "longValue"; 347 348 case Type.DOUBLE: return "doubleValue"; 350 default: 351 throw new AssertionError (); 352 } 353 } 354 355 public static String methodDescriptionToReturnType(String desc) { 356 Type type = Type.getReturnType(desc); 357 return type.getClassName(); 358 } 359 360 public static String methodDescriptionToMethodArgument(String desc) { 361 Type[] types = Type.getArgumentTypes(desc); 362 StringBuffer sb = new StringBuffer ("("); 363 for (int i = 0; i < types.length; i++) { 364 sb.append(types[i].getClassName()); 365 if (i < types.length - 1) { 366 sb.append(","); 367 } 368 } 369 sb.append(")"); 370 return sb.toString(); 371 } 372 373 public static String fieldGetterMethod(String fieldName) { 374 return TC_METHOD_PREFIX + "get" + fieldName; 375 } 376 377 public static String fieldSetterMethod(String fieldName) { 378 return TC_METHOD_PREFIX + "set" + fieldName; 379 } 380 381 } | Popular Tags |