1 4 package com.tc.object.bytecode; 5 6 import com.tc.asm.Type; 7 import com.tc.aspectwerkz.reflect.ClassInfo; 8 import com.tc.exception.TCLogicalSubclassNotPortableException; 9 import com.tc.object.LiteralValues; 10 import com.tc.object.Portability; 11 import com.tc.object.config.TransparencyClassSpec; 12 import com.tc.object.config.TransparencyClassSpecUtil; 13 import com.tc.util.Assert; 14 15 import java.lang.reflect.Field ; 16 import java.lang.reflect.Method ; 17 import java.lang.reflect.Modifier ; 18 import java.util.Collection ; 19 import java.util.HashMap ; 20 import java.util.HashSet ; 21 import java.util.Map ; 22 import java.util.Set ; 23 24 class InstrumentationSpec { 25 public static final byte IS_NOT_NEEDED = 0x04; 26 public static final byte IS_NEEDED = 0x05; 27 public static final byte IS_PRESENT = 0x06; 28 29 private static final LiteralValues literalValues = new LiteralValues(); 30 31 private byte instrumentationAction = TransparencyClassSpec.NOT_ADAPTABLE; 32 33 private byte managedMethods = IS_NOT_NEEDED; 34 private byte valuesGetterMethod = IS_NOT_NEEDED; 35 private byte valuesSetterMethod = IS_NOT_NEEDED; 36 private byte managedValuesGetterMethod = IS_NOT_NEEDED; 37 private byte managedValuesSetterMethod = IS_NOT_NEEDED; 38 private byte managedField = IS_NOT_NEEDED; 39 private byte delegateLogicalField = IS_NOT_NEEDED; 40 private byte writeObjectSerializedMethod = IS_NOT_NEEDED; 41 private byte readObjectSerializedMethod = IS_NOT_NEEDED; 42 43 private String classNameSlashes; 44 private String superNameSlashes; 45 private String classNameDots; 46 private String superNameDots; 47 private boolean isInterface; 48 private ParentClassInfo parentClassInfo; 49 private boolean classHierarchyInitialized = false; 50 private int classAccess; 51 private String classSignature; 52 private String [] classInterfaces; 53 private int classVersion; 54 private boolean hasVisitedField; 55 private boolean isSubclassOfLogicalClass; 56 private TransparencyClassSpec superClassSpec; 57 58 private final ClassInfo classInfo; 59 private final TransparencyClassSpec spec; 60 private final ManagerHelper mgrHelper; 61 private final ClassLoader caller; 62 63 private final Set classHierarchy; 64 private final Map shouldOverrideMethods; 65 private final Set logicalExtendingMethodSpec; 66 private final Set logicalExtendingFieldSpec; 67 68 InstrumentationSpec(ClassInfo classInfo, TransparencyClassSpec spec, ManagerHelper mgrHelper, ClassLoader caller) { 69 this.classInfo = classInfo; 70 this.spec = spec; 71 this.mgrHelper = mgrHelper; 72 this.caller = caller; 73 this.classHierarchy = new HashSet (); 74 this.shouldOverrideMethods = new HashMap (); 75 this.logicalExtendingMethodSpec = new HashSet (); 76 this.logicalExtendingFieldSpec = new HashSet (); 77 } 78 79 public ClassInfo getClassInfo() { 80 return classInfo; 81 } 82 83 84 void initialize(int version, int access, String name, String signature, String superName, String [] interfaces, 86 Portability portability) { 87 this.classNameSlashes = name; 88 this.superNameSlashes = superName; 89 this.classNameDots = name.replace('/', '.'); 90 this.superNameDots = superName.replace('/', '.'); 91 this.classHierarchy.add(this.classNameSlashes); 92 this.classHierarchy.add(this.superNameSlashes); 93 this.classAccess = access; 94 this.classSignature = signature; 95 this.classInterfaces = interfaces; 96 this.classVersion = version; 97 decideOnInstrumentationAction(portability); 98 handleSubclassOfLogicalClass(access, classNameDots, superNameDots); 99 } 100 101 private boolean isArray(String className) { 102 return literalValues.valueForClassName(className) == LiteralValues.ARRAY; 103 } 104 105 private void handleSubclassOfLogicalClass(int access, String className, String superName) { 106 if (isLogical()) { return; } 107 if (isArray(className)) { return; } 108 if (TransparencyClassSpecUtil.ignoreChecks(className)) { return; } 109 if (TransparencyClassSpecUtil.ignoreChecks(superName)) { return; } 110 111 superClassSpec = spec.getClassSpec(superName); 112 if (superClassSpec != null && superClassSpec.isLogical()) { 113 isSubclassOfLogicalClass = true; 114 } 115 } 116 117 public int getClassVersion() { 118 return classVersion; 119 } 120 121 public int getClassAccess() { 122 return classAccess; 123 } 124 125 private void initClassHierarchy() { 126 String superClassName = superNameSlashes.replace('/', '.'); 127 try { 128 Class superClazz = Class.forName(superClassName, false, this.classInfo.getClassLoader()).getSuperclass(); 131 while (superClazz != null) { 132 String superName = superClazz.getName(); 133 classHierarchy.add(superName.replace('.', '/')); 134 superClazz = superClazz.getSuperclass(); 135 } 136 } catch (ClassNotFoundException e) { 137 e.printStackTrace(); 138 } finally { 139 classHierarchyInitialized = true; 140 } 141 } 142 143 String getClassNameSlashes() { 144 return this.classNameSlashes; 145 } 146 147 String getClassNameDots() { 148 return this.classNameDots; 149 } 150 151 String getSuperClassNameSlashes() { 152 return this.superNameSlashes; 153 } 154 155 String getSuperClassNameDots() { 156 return this.superNameDots; 157 } 158 159 String [] getClassInterfaces() { 160 return classInterfaces; 161 } 162 163 String getClassSignature() { 164 return classSignature; 165 } 166 167 void decideOnInstrumentationAction(Portability portability) { 168 Assert.assertNotNull(classNameSlashes); 169 Assert.assertNotNull(superNameSlashes); 170 171 this.isInterface = Modifier.isInterface(classAccess); 172 173 if (isInterface) { 174 this.instrumentationAction = TransparencyClassSpec.NOT_ADAPTABLE; 175 } else if (spec.getInstrumentationAction() == TransparencyClassSpec.PORTABLE) { 176 this.instrumentationAction = TransparencyClassSpec.PORTABLE; 177 } else if (spec.getInstrumentationAction() == TransparencyClassSpec.ADAPTABLE) { 178 this.instrumentationAction = TransparencyClassSpec.ADAPTABLE; 179 } else if (spec.isLogical() || spec.ignoreChecks()) { 180 this.instrumentationAction = TransparencyClassSpec.PORTABLE; 183 } else if (superClassChecks(portability)) { 184 this.instrumentationAction = TransparencyClassSpec.ADAPTABLE; 185 } else { 186 this.instrumentationAction = TransparencyClassSpec.PORTABLE; 187 } 188 decideOnInstrumentationsToDo(portability); 189 } 190 191 private void decideOnInstrumentationsToDo(Portability portability) { 192 if (this.instrumentationAction == TransparencyClassSpec.PORTABLE) { 193 if (!isLogical()) { 194 valuesGetterMethod = IS_NEEDED; 195 valuesSetterMethod = IS_NEEDED; 196 managedValuesGetterMethod = IS_NEEDED; 197 managedValuesSetterMethod = IS_NEEDED; 198 } 199 managedField = isNeedManagedField(portability); 200 managedMethods = managedField; 201 } 202 } 203 204 210 private byte isNeedManagedField(Portability portability) { 211 if (isSubclassOfLogicalClass) { return IS_NOT_NEEDED; } 212 ClassInfo superClassInfo = classInfo.getSuperclass(); 213 if (portability.isInstrumentationNotNeeded(superClassInfo.getName())) { return IS_NEEDED; } 214 if (!spec.hasPhysicallyPortableSpecs(superClassInfo)) { return IS_NEEDED; } 215 if (spec.isLogical()) { return IS_NEEDED; } 216 return IS_NOT_NEEDED; 217 } 218 219 private boolean superClassChecks(Portability portability) { 220 String superClassName = superNameSlashes.replace('/', '.'); 221 if (portability.isInstrumentationNotNeeded(superClassName)) { return false; } 222 223 final Class superClazz; 224 try { 225 superClazz = Class.forName(superClassName, false, this.classInfo.getClassLoader()); 226 } catch (ClassNotFoundException e) { 227 throw new RuntimeException (e); 228 } 229 230 if (!portability.isPortableClass(superClazz)) { return true; } 231 return false; 232 } 233 234 boolean isInClassHierarchy(String classname) { 235 boolean inClassHierarchy = classHierarchy.contains(classname); 236 if (inClassHierarchy || classHierarchyInitialized) return inClassHierarchy; 237 initClassHierarchy(); 238 return classHierarchy.contains(classname); 239 } 240 241 boolean isClassNotAdaptable() { 242 return this.instrumentationAction == TransparencyClassSpec.NOT_ADAPTABLE; 243 } 244 245 boolean isClassAdaptable() { 246 return this.instrumentationAction == TransparencyClassSpec.ADAPTABLE; 247 } 248 249 boolean isClassPortable() { 250 return this.instrumentationAction == TransparencyClassSpec.PORTABLE; 251 } 252 253 boolean isSubclassofLogicalClass() { 254 return this.isSubclassOfLogicalClass; 255 } 256 257 void moveToLogicalIfNecessary() { 258 if (isSubclassOfLogicalClass && !hasVisitedField) { 259 spec.moveToLogical(superClassSpec); 260 } 261 } 262 263 boolean hasDelegatedToLogicalClass() { 264 return needDelegateField(); 265 } 266 267 boolean needDelegateField() { 268 return this.delegateLogicalField == IS_NEEDED; 269 } 270 271 boolean isWriteObjectMethodNeeded() { 272 return this.writeObjectSerializedMethod == IS_NEEDED; 273 } 274 275 boolean isReadObjectMethodNeeded() { 276 return this.readObjectSerializedMethod == IS_NEEDED; 277 } 278 279 void handleSubclassOfLogicalClassWithFieldsIfNecessary(int access) { 280 if (ByteCodeUtil.isSynthetic(access) || Modifier.isStatic(access)) { 281 return; 282 } else if (isSubclassOfLogicalClass && !hasVisitedField) { 283 hasVisitedField = true; 284 try { 285 Class superClazz = Class.forName(superNameDots, false, this.classInfo.getClassLoader()); 286 287 Method [] methods = superClazz.getMethods(); 288 for (int i = 0; i < methods.length; i++) { 289 Method m = methods[i]; 290 String methodName = m.getName(); 291 int modifier = m.getModifiers(); 292 if (!shouldVisitMethod(modifier, methodName) || Modifier.isFinal(modifier)) { 293 continue; 294 } 295 296 String methodDesc = Type.getMethodDescriptor(m); 297 shouldOverrideMethods.put(methodName + methodDesc, m); 298 } 299 300 methods = superClazz.getDeclaredMethods(); 301 for (int i = 0; i < methods.length; i++) { 302 Method m = methods[i]; 303 String methodName = m.getName(); 304 int modifier = m.getModifiers(); 305 if (shouldVisitMethod(modifier, methodName) && !Modifier.isFinal(modifier) && Modifier.isProtected(modifier)) { 306 String methodDesc = Type.getMethodDescriptor(m); 307 logicalExtendingMethodSpec.add(methodName + methodDesc); 308 } 309 } 310 311 Field [] fields = superClazz.getDeclaredFields(); 312 for (int i = 0; i < fields.length; i++) { 313 Field f = fields[i]; 314 String fieldName = f.getName(); 315 int modifier = f.getModifiers(); 316 if (!shouldVisitField(fieldName) || Modifier.isFinal(modifier) || Modifier.isPrivate(modifier)) { 317 continue; 318 } 319 String fieldDesc = Type.getDescriptor(f.getType()); 320 logicalExtendingFieldSpec.add(fieldName + fieldDesc); 321 } 322 } catch (ClassNotFoundException e) { 323 e.printStackTrace(); 324 } 325 delegateLogicalField = IS_NEEDED; 326 writeObjectSerializedMethod = IS_NEEDED; 327 readObjectSerializedMethod = IS_NEEDED; 328 } 329 } 330 331 void recordExistingFields(String name, String desc, String signature) { 332 if (ClassAdapterBase.MANAGED_FIELD_NAME.equals(name)) { 333 managedField = IS_PRESENT; 334 } else if (ByteCodeUtil.isParent(name)) { 335 Assert.assertNull(parentClassInfo); 336 this.parentClassInfo = new ParentClassInfo(name, desc); 337 } 338 339 } 340 341 void recordExistingMethods(String name, String desc, String signature) { 342 if (ClassAdapterBase.MANAGED_METHOD.equals(name)) { 343 managedMethods = IS_PRESENT; 344 } else if (ClassAdapterBase.VALUES_GETTER.endsWith(name)) { 345 valuesGetterMethod = IS_PRESENT; 346 } else if (ClassAdapterBase.VALUES_SETTER.endsWith(name)) { 347 valuesSetterMethod = IS_PRESENT; 348 } else if (ClassAdapterBase.MANAGED_VALUES_GETTER.endsWith(name)) { 349 managedValuesGetterMethod = IS_PRESENT; 350 } else if (ClassAdapterBase.MANAGED_VALUES_SETTER.endsWith(name)) { 351 managedValuesSetterMethod = IS_PRESENT; 352 } else if (LogicalClassSerializationAdapter.READ_OBJECT_SIGNATURE.equals(name + desc)) { 353 readObjectSerializedMethod = IS_NOT_NEEDED; 354 } else if (LogicalClassSerializationAdapter.WRITE_OBJECT_SIGNATURE.equals(name + desc)) { 355 writeObjectSerializedMethod = IS_NOT_NEEDED; 356 } 357 shouldOverrideMethods.remove(name + desc); 358 } 359 360 boolean shouldVisitField(String name) { 361 return !(name.startsWith(ByteCodeUtil.TC_FIELD_PREFIX)); 362 } 363 364 boolean shouldVisitMethod(int methodAccess, String name) { 365 if (name.startsWith(ByteCodeUtil.TC_METHOD_PREFIX)) { return false; } 366 if (Modifier.isAbstract(methodAccess) || Modifier.isNative(methodAccess)) { return false; } 367 return true; 368 } 369 370 boolean isManagedMethodsNeeded() { 371 return (managedMethods == IS_NEEDED); 372 } 373 374 boolean isValuesGetterMethodNeeded() { 375 return (valuesGetterMethod == IS_NEEDED); 376 } 377 378 boolean isValuesSetterMethodNeeded() { 379 return (valuesSetterMethod == IS_NEEDED); 380 } 381 382 boolean isManagedValuesGetterMethodNeeded() { 383 return (managedValuesGetterMethod == IS_NEEDED); 384 } 385 386 boolean isManagedValuesSetterMethodNeeded() { 387 return (managedValuesSetterMethod == IS_NEEDED); 388 } 389 390 boolean isManagedFieldNeeded() { 391 return (managedField == IS_NEEDED); 392 } 393 394 TransparencyClassSpec getTransparencyClassSpec() { 395 return spec; 396 } 397 398 TransparencyClassSpec getSuperclassTransparencyClassSpec() { 399 return spec.getClassSpec(superNameDots); 400 } 401 402 boolean isLogical() { 403 return spec.isLogical(); 404 } 405 406 boolean needInstrumentFieldInsn() { 407 return !spec.isLogical() && !(isSubclassOfLogicalClass && !hasVisitedField); 408 } 409 410 void shouldProceedInstrumentation(int access, String name, String desc) { 411 if (isSubclassOfLogicalClass && shouldVisitMethod(access, name) 412 && logicalExtendingMethodSpec.contains(name + desc)) { 413 throw new TCLogicalSubclassNotPortableException(classNameDots, superNameDots); 415 } 416 } 417 418 void shouldProceedInstrumentation(String fieldName, String fieldDesc) { 419 if (isSubclassOfLogicalClass && shouldVisitField(fieldName) 420 && logicalExtendingFieldSpec.contains(fieldName + fieldDesc)) { throw new TCLogicalSubclassNotPortableException( 421 classNameDots, 422 superNameDots); } 423 } 424 425 boolean isPhysical() { 426 return spec.isPhysical(); 427 } 428 429 boolean generateNonStaticTCFields() { 430 return spec.generateNonStaticTCFields(); 431 } 432 433 Collection getShouldOverrideMethods() { 434 return shouldOverrideMethods.values(); 435 } 436 437 ManagerHelper getManagerHelper() { 438 return mgrHelper; 439 } 440 441 boolean isInner() { 442 return this.parentClassInfo != null; 443 } 444 445 String getParentClassType() { 446 Assert.assertTrue(isInner()); 447 return parentClassInfo.getType(); 448 } 449 450 String getParentClassFieldName() { 451 Assert.assertTrue(isInner()); 452 return parentClassInfo.getFieldName(); 453 } 454 455 private static class ParentClassInfo { 456 private final String type; 457 private final String fieldName; 458 459 ParentClassInfo(String fieldName, String type) { 460 this.fieldName = fieldName; 461 this.type = type; 462 } 463 464 String getFieldName() { 465 return fieldName; 466 } 467 468 String getType() { 469 return type; 470 } 471 472 } 473 } 474 | Popular Tags |