1 5 package com.tc.object.bytecode; 6 7 import com.tc.asm.ClassVisitor; 8 import com.tc.asm.FieldVisitor; 9 import com.tc.asm.Label; 10 import com.tc.asm.MethodVisitor; 11 import com.tc.asm.Type; 12 import com.tc.aspectwerkz.exception.DefinitionException; 13 import com.tc.aspectwerkz.reflect.ClassInfo; 14 import com.tc.logging.TCLogger; 15 import com.tc.logging.TCLogging; 16 import com.tc.object.Portability; 17 import com.tc.object.config.LockDefinition; 18 import com.tc.object.config.TransparencyClassSpec; 19 import com.tc.object.lockmanager.api.LockLevel; 20 import com.tc.object.logging.InstrumentationLogger; 21 import com.tc.util.Assert; 22 23 import java.lang.reflect.Modifier ; 24 import java.util.HashSet ; 25 import java.util.Set ; 26 27 30 public class TransparencyClassAdapter extends ClassAdapterBase { 31 private static final TCLogger logger = TCLogging.getLogger(TransparencyClassAdapter.class); 32 33 private final Set doNotInstrument = new HashSet (); 34 private final PhysicalClassAdapterLogger physicalClassLogger; 35 private final InstrumentationLogger instrumentationLogger; 36 37 public TransparencyClassAdapter(ClassInfo classInfo, TransparencyClassSpec spec, final ClassVisitor cv, ManagerHelper mgrHelper, 38 InstrumentationLogger instrumentationLogger, ClassLoader caller, 39 Portability portability) { 40 super(classInfo, spec, cv, mgrHelper, caller, portability); 41 this.instrumentationLogger = instrumentationLogger; 42 this.physicalClassLogger = new PhysicalClassAdapterLogger(logger); 43 } 44 45 protected void basicVisit(final int version, final int access, final String name, String signature, 46 final String superClassName, final String [] interfaces) { 47 48 try { 49 logger.debug("ADAPTING CLASS: " + name); 50 super.basicVisit(version, access, name, signature, superClassName, interfaces); 51 getTransparencyClassSpec().createClassSupportMethods(cv); 52 } catch (RuntimeException e) { 53 handleInstrumentationException(e); 54 throw e; 55 } catch (Error e) { 56 handleInstrumentationException(e); 57 throw e; 58 } 59 } 60 61 private void handleInstrumentationException(Throwable e) { 62 logger.fatal(e); 63 logger.fatal("Calling System.exit(1)"); 64 System.exit(1); 65 } 66 67 private boolean isRoot(int access, String fieldName) { 68 try { 69 boolean isRoot = getTransparencyClassSpec().isRootInThisClass(fieldName); 70 boolean isTransient = getTransparencyClassSpec().isTransient(access, fieldName); 71 if (isTransient && isRoot) { 72 if (instrumentationLogger.transientRootWarning()) { 73 instrumentationLogger.transientRootWarning(this.spec.getClassNameDots(), fieldName); 74 } 75 } 76 return isRoot; 77 } catch (RuntimeException e) { 78 handleInstrumentationException(e); 79 throw e; 80 } catch (Error e) { 81 handleInstrumentationException(e); 82 throw e; 83 } 84 } 85 86 private String rootNameFor(String className, String fieldName) { 87 try { 88 return getTransparencyClassSpec().rootNameFor(fieldName); 89 } catch (RuntimeException e) { 90 handleInstrumentationException(e); 91 throw e; 92 } catch (Error e) { 93 handleInstrumentationException(e); 94 throw e; 95 } 96 } 97 98 protected FieldVisitor basicVisitField(final int access, final String name, final String desc, String signature, 99 final Object value) { 100 101 FieldVisitor fieldVisitor = null; 102 try { 103 104 if ((spec.isClassPortable() && spec.isPhysical() && !ByteCodeUtil.isTCSynthetic(name)) 105 || (spec.isClassAdaptable() && isRoot(access, name))) { 106 if (Modifier.isFinal(access) && !isMagicSerializationField(access, name, desc)) { 108 fieldVisitor = cv.visitField(~Modifier.FINAL & access, name, desc, signature, value); 109 } else { 110 fieldVisitor = cv.visitField(access, name, desc, signature, value); 111 } 112 generateGettersSetters(access, name, desc, Modifier.isStatic(access)); 113 } else { 114 fieldVisitor = cv.visitField(access, name, desc, signature, value); 115 } 116 } catch (RuntimeException e) { 117 e.printStackTrace(); 118 handleInstrumentationException(e); 119 } catch (Error e) { 120 handleInstrumentationException(e); 121 throw e; 122 } 123 return fieldVisitor; 124 } 125 126 private static boolean isStatic(int access) { 127 return Modifier.isStatic(access); 128 } 129 130 private static boolean isFinal(int access) { 131 return Modifier.isFinal(access); 132 } 133 134 private static boolean isPrivate(int access) { 135 return Modifier.isPrivate(access); 136 } 137 138 private boolean isMagicSerializationField(int access, String fieldName, String fieldDesc) { 139 142 boolean isStatic = isStatic(access); 143 boolean isFinal = isFinal(access); 144 boolean isPrivate = isPrivate(access); 145 146 if (isStatic && isFinal) { 147 if ("J".equals(fieldDesc) && "serialVersionUID".equals(fieldName)) { return true; } 148 if (isPrivate && "serialPersistentFields".equals(fieldName) && "[Ljava/io/ObjectStreamField;".equals(fieldDesc)) { return true; } 149 } 150 151 return false; 152 } 153 154 private void generateGettersSetters(final int fieldAccess, final String name, final String desc, boolean isStatic) { 155 boolean isTransient = getTransparencyClassSpec().isTransient(fieldAccess, name); 156 boolean createPlainAccessors = isTransient && !isStatic; 158 boolean createInstrumentedAccessors = !isTransient && !isStatic; 159 boolean createRootAccessors = isRoot(fieldAccess, name); 160 161 int methodAccess = fieldAccess & (~ACC_TRANSIENT); 162 methodAccess &= (~ACC_FINAL); methodAccess &= (~ACC_VOLATILE); 164 methodAccess |= ACC_SYNTHETIC; 165 166 if (createRootAccessors) { 167 createRootGetter(methodAccess, name, desc); 168 } else if (createInstrumentedAccessors) { 169 if (!ByteCodeUtil.isPrimitive(Type.getType(desc))) { 170 createInstrumentedGetter(methodAccess, fieldAccess, name, desc); 171 } else { 172 createPlainGetter(methodAccess, fieldAccess, name, desc); 173 } 174 } else if (createPlainAccessors) { 175 createPlainGetter(methodAccess, fieldAccess, name, desc); 176 } 177 178 if (createInstrumentedAccessors || createRootAccessors) { 179 createInstrumentedSetter(methodAccess, fieldAccess, name, desc); 180 } else if (createPlainAccessors) { 181 createPlainSetter(methodAccess, fieldAccess, name, desc); 182 } 183 } 184 185 private boolean isPrimitive(Type t) { 186 return ByteCodeUtil.isPrimitive(t); 187 } 188 189 protected MethodVisitor basicVisitMethod(int access, String name, final String desc, String signature, 190 final String [] exceptions) { 191 String originalName = name; 192 193 try { 194 physicalClassLogger.logVisitMethodBegin(access, name, desc, signature, exceptions); 195 196 if (name.startsWith(ByteCodeUtil.TC_METHOD_PREFIX) || doNotInstrument.contains(name + desc) 197 || getTransparencyClassSpec().doNotInstrument(name)) { 198 if (!getTransparencyClassSpec().hasCustomMethodAdapter(access, name, desc, exceptions)) { 199 physicalClassLogger.logVisitMethodIgnoring(name, desc); 200 return cv.visitMethod(access, name, desc, signature, exceptions); 201 } 202 } 203 204 LockDefinition[] locks = getTransparencyClassSpec().lockDefinitionsFor(access, name, desc, exceptions); 205 LockDefinition ld = getTransparencyClassSpec().getAutolockDefinition(locks); 206 boolean isAutolock = (ld != null); 207 int lockLevel = -1; 208 if (isAutolock) { 209 lockLevel = ld.getLockLevelAsInt(); 210 if (instrumentationLogger.lockInsertion()) { 211 instrumentationLogger.autolockInserted(this.spec.getClassNameDots(), name, desc, ld); 212 } 213 } 214 boolean isLockMethod = isAutolock && Modifier.isSynchronized(access) && !Modifier.isStatic(access); 215 physicalClassLogger.logVisitMethodCheckIsLockMethod(); 216 217 if (!isLockMethod || spec.isClassAdaptable()) { 218 LockDefinition namedLockDefinition = getTransparencyClassSpec().getNonAutoLockDefinition(locks); 220 isLockMethod = (namedLockDefinition != null); 221 } 222 223 if (isLockMethod && (!name.equals("<init>"))) { 226 physicalClassLogger.logVisitMethodCreateLockMethod(name); 227 Assert.assertNotNull(locks); 229 Assert.eval(locks.length > 0 || isLockMethod); 230 createLockMethod(access, name, desc, signature, exceptions, locks); 231 232 logCustomerLockMethod(name, desc, locks); 233 name = ByteCodeUtil.METHOD_RENAME_PREFIX + name; 234 access |= ACC_PRIVATE; 235 access &= (~ACC_PUBLIC); 236 access &= (~ACC_PROTECTED); 237 } else { 238 physicalClassLogger.logVisitMethodNotALockMethod(access, this.spec.getClassNameDots(), name, desc, exceptions); 239 } 240 MethodVisitor mv = null; 241 242 boolean hasCustomMethodAdapter = getTransparencyClassSpec().hasCustomMethodAdapter(access, originalName, desc, 243 exceptions); 244 if (hasCustomMethodAdapter) { 245 MethodAdapter ma = getTransparencyClassSpec().customMethodAdapterFor(spec.getManagerHelper(), access, name, 246 originalName, desc, signature, exceptions, 247 instrumentationLogger); 248 mv = ma.adapt(cv); 249 250 if (!ma.doesOriginalNeedAdapting()) return mv; 251 } 252 253 if (mv == null) { 254 mv = cv.visitMethod(access, name, desc, signature, exceptions); 255 } 256 257 return mv == null ? null : new TransparencyCodeAdapter(spec, isAutolock, lockLevel, mv, access, originalName, 258 name, desc, signature, exceptions); 259 } catch (RuntimeException e) { 260 handleInstrumentationException(e); 261 throw e; 262 } catch (Error e) { 263 handleInstrumentationException(e); 264 throw e; 265 } 266 } 267 268 275 private void logCustomerLockMethod(String name, final String desc, LockDefinition[] locks) { 276 if (instrumentationLogger.lockInsertion()) { 277 instrumentationLogger.lockInserted(this.spec.getClassNameDots(), name, desc, locks); 278 } 279 } 280 281 private void createLockMethod(int access, String name, String desc, String signature, final String [] exceptions, 282 LockDefinition[] locks) { 283 try { 284 physicalClassLogger.logCreateLockMethodBegin(access, name, desc, signature, exceptions, locks); 285 doNotInstrument.add(name + desc); 286 Type returnType = Type.getReturnType(desc); 287 if (returnType.getSort() == Type.VOID) { 288 createLockMethodVoid(access, name, desc, signature, exceptions, locks); 289 } else { 290 createLockMethodReturn(access, name, desc, signature, exceptions, locks, returnType); 291 } 292 } catch (RuntimeException e) { 293 handleInstrumentationException(e); 294 throw e; 295 } catch (Error e) { 296 handleInstrumentationException(e); 297 throw e; 298 } 299 } 300 301 304 private void createLockMethodVoid(int access, String name, String desc, String signature, final String [] exceptions, 305 LockDefinition[] locks) { 306 try { 307 int localVariableOffset = ByteCodeUtil.getLocalVariableOffset(access); 308 309 physicalClassLogger.logCreateLockMethodVoidBegin(access, name, desc, signature, exceptions, locks); 310 MethodVisitor c = cv.visitMethod(access & (~Modifier.SYNCHRONIZED), name, desc, signature, exceptions); 311 callTCBeginWithLocks(access, name, desc, locks, c); 312 Label l0 = new Label(); 313 c.visitLabel(l0); 314 callRenamedMethod(access, name, desc, c); 315 Label l1 = new Label(); 317 c.visitJumpInsn(GOTO, l1); 318 Label l2 = new Label(); 319 c.visitLabel(l2); 320 c.visitVarInsn(ASTORE, 1 + localVariableOffset); 321 Label l3 = new Label(); 322 c.visitJumpInsn(JSR, l3); 323 c.visitVarInsn(ALOAD, 1 + localVariableOffset); 324 c.visitInsn(ATHROW); 325 c.visitLabel(l3); 326 c.visitVarInsn(ASTORE, 0 + localVariableOffset); 327 callTCCommit(access, name, desc, locks, c); 328 c.visitVarInsn(RET, 0 + localVariableOffset); 329 c.visitLabel(l1); 330 c.visitJumpInsn(JSR, l3); 331 Label l4 = new Label(); 332 c.visitLabel(l4); 333 c.visitInsn(RETURN); 334 c.visitTryCatchBlock(l0, l2, l2, null); 335 c.visitTryCatchBlock(l1, l4, l2, null); 336 c.visitMaxs(0, 0); 337 } catch (RuntimeException e) { 338 handleInstrumentationException(e); 339 } catch (Error e) { 340 handleInstrumentationException(e); 341 throw e; 342 } 343 } 344 345 private void handleInstrumentationException(RuntimeException e) { 346 if (e instanceof DefinitionException) { 348 logger.fatal(e.getLocalizedMessage()); 349 } else { 350 logger.fatal(e); 351 } 352 logger.fatal("Calling System.exit(1)"); 353 System.exit(1); 354 } 355 356 private void callRenamedMethod(int callingMethodModifier, String name, String desc, MethodVisitor c) { 357 ByteCodeUtil.prepareStackForMethodCall(callingMethodModifier, desc, c); 359 if (Modifier.isStatic(callingMethodModifier)) { 360 c.visitMethodInsn(INVOKESTATIC, spec.getClassNameSlashes(), ByteCodeUtil.METHOD_RENAME_PREFIX + name, desc); 361 } else { 362 c.visitMethodInsn(INVOKESPECIAL, spec.getClassNameSlashes(), ByteCodeUtil.METHOD_RENAME_PREFIX + name, desc); 363 } 364 } 365 366 369 private void createLockMethodReturn(int access, String name, String desc, String signature, 370 final String [] exceptions, LockDefinition[] locks, Type returnType) { 371 try { 372 physicalClassLogger.logCreateLockMethodReturnBegin(access, name, desc, signature, exceptions, locks); 373 int localVariableOffset = ByteCodeUtil.getLocalVariableOffset(access); 374 MethodVisitor c = cv.visitMethod(access & (~Modifier.SYNCHRONIZED), name, desc, signature, exceptions); 375 376 callTCBeginWithLocks(access, name, desc, locks, c); 377 Label l0 = new Label(); 378 c.visitLabel(l0); 379 callRenamedMethod(access, name, desc, c); 380 c.visitVarInsn(returnType.getOpcode(ISTORE), 2 + localVariableOffset); 381 Label l1 = new Label(); 382 c.visitJumpInsn(JSR, l1); 383 Label l2 = new Label(); 384 c.visitLabel(l2); 385 c.visitVarInsn(returnType.getOpcode(ILOAD), 2 + localVariableOffset); 386 c.visitInsn(returnType.getOpcode(IRETURN)); 387 Label l3 = new Label(); 388 c.visitLabel(l3); 389 c.visitVarInsn(ASTORE, 1 + localVariableOffset); 390 c.visitJumpInsn(JSR, l1); 391 c.visitVarInsn(ALOAD, 1 + localVariableOffset); 392 c.visitInsn(ATHROW); 393 c.visitLabel(l1); 394 c.visitVarInsn(ASTORE, 0 + localVariableOffset); 395 callTCCommit(access, name, desc, locks, c); 396 c.visitVarInsn(RET, 0 + localVariableOffset); 397 c.visitTryCatchBlock(l0, l2, l3, null); 398 c.visitMaxs(0, 0); 399 } catch (RuntimeException e) { 400 handleInstrumentationException(e); 401 } catch (Error e) { 402 handleInstrumentationException(e); 403 throw e; 404 } 405 406 } 407 408 private void callTCBeginWithLocks(int access, String name, String desc, LockDefinition[] locks, MethodVisitor c) { 409 physicalClassLogger.logCallTCBeginWithLocksStart(access, name, desc, locks, c); 410 for (int i = 0; i < locks.length; i++) { 411 LockDefinition lock = locks[i]; 412 if (lock.isAutolock() && spec.isClassPortable()) { 413 physicalClassLogger.logCallTCBeginWithLocksAutolock(); 414 if (Modifier.isSynchronized(access) && !Modifier.isStatic(access)) { 415 physicalClassLogger.logCallTCBeginWithLocksAutolockSynchronized(name, desc); 416 callTCMonitorEnter(access, locks[i], c); 417 } else { 418 physicalClassLogger.logCallTCBeginWithLocksAutolockNotSynchronized(name, desc); 419 } 420 } else if (!lock.isAutolock()) { 421 physicalClassLogger.logCallTCBeginWithLocksNoAutolock(lock); 422 callTCBeginWithLock(lock, c); 423 } 424 } 425 } 426 427 private void callTCCommit(int access, String name, String desc, LockDefinition[] locks, MethodVisitor c) { 428 physicalClassLogger.logCallTCCommitBegin(access, name, desc, locks, c); 429 for (int i = 0; i < locks.length; i++) { 430 LockDefinition lock = locks[i]; 431 if (lock.isAutolock() && spec.isClassPortable()) { 432 if (Modifier.isSynchronized(access) && !Modifier.isStatic(access)) { 433 callTCMonitorExit(access, c); 434 } 435 } else if (!lock.isAutolock()) { 436 c.visitLdcInsn(ByteCodeUtil.generateNamedLockName(lock.getLockName())); 437 spec.getManagerHelper().callManagerMethod("commitLock", c); 438 } 439 } 440 } 441 442 private void callTCCommitWithLockName(String lockName, MethodVisitor mv) { 443 mv.visitLdcInsn(lockName); 444 spec.getManagerHelper().callManagerMethod("commitLock", mv); 445 } 446 447 private void callTCBeginWithLock(LockDefinition lock, MethodVisitor c) { 448 c.visitLdcInsn(ByteCodeUtil.generateNamedLockName(lock.getLockName())); 449 c.visitLdcInsn(new Integer (lock.getLockLevelAsInt())); 450 spec.getManagerHelper().callManagerMethod("beginLock", c); 451 } 452 453 private void callTCBeginWithLockName(String lockName, int lockLevel, MethodVisitor mv) { 454 mv.visitLdcInsn(lockName); 455 mv.visitLdcInsn(new Integer (lockLevel)); 456 spec.getManagerHelper().callManagerMethod("beginLock", mv); 457 } 458 459 private void callVolatileBegin(String fieldName, int lockLevel, MethodVisitor mv) { 460 getManaged(mv); 461 mv.visitLdcInsn(fieldName); 462 mv.visitIntInsn(BIPUSH, lockLevel); 463 spec.getManagerHelper().callManagerMethod("beginVolatile", mv); 464 } 465 466 private void callVolatileCommit(String fieldName, MethodVisitor mv) { 467 getManaged(mv); 468 mv.visitLdcInsn(fieldName); 469 spec.getManagerHelper().callManagerMethod("commitVolatile", mv); 470 } 471 472 private void createPlainGetter(int methodAccess, int fieldAccess, String name, String desc) { 473 boolean isVolatile = isVolatile(fieldAccess, name); 474 475 String gDesc = "()" + desc; 476 MethodVisitor gv = this.visitMethod(methodAccess, ByteCodeUtil.fieldGetterMethod(name), gDesc, null, null); 477 Type t = Type.getType(desc); 478 479 Label l4 = new Label(); 480 481 if (isVolatile) { 482 getManaged(gv); 483 gv.visitInsn(DUP); 484 gv.visitVarInsn(ASTORE, 2); 485 gv.visitJumpInsn(IFNULL, l4); 486 487 Label l0 = new Label(); 488 Label l1 = new Label(); 489 Label l2 = new Label(); 490 gv.visitTryCatchBlock(l0, l1, l2, null); 491 gv.visitLabel(l0); 492 493 callVolatileBegin(spec.getClassNameDots() + "." + name, LockLevel.READ, gv); 494 495 Label l6 = new Label(); 496 gv.visitJumpInsn(JSR, l6); 497 gv.visitLabel(l1); 498 ByteCodeUtil.pushThis(gv); 499 gv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(), name, desc); 500 gv.visitInsn(t.getOpcode(IRETURN)); 501 gv.visitLabel(l2); 502 gv.visitVarInsn(ASTORE, 2); 503 gv.visitJumpInsn(JSR, l6); 504 gv.visitVarInsn(ALOAD, 2); 505 gv.visitInsn(ATHROW); 506 gv.visitLabel(l6); 507 gv.visitVarInsn(ASTORE, 1); 508 509 callVolatileCommit(spec.getClassNameDots() + "." + name, gv); 510 gv.visitVarInsn(RET, 1); 511 } 512 513 gv.visitLabel(l4); 514 ByteCodeUtil.pushThis(gv); 515 gv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(), name, desc); 516 gv.visitInsn(t.getOpcode(IRETURN)); 517 518 gv.visitMaxs(0, 0); 519 } 520 521 private void checkReturnObjectType(String fieldName, String rootName, String targetType, int loadVariableNumber, 522 Label matchLabel, MethodVisitor mv) { 523 mv.visitVarInsn(ALOAD, loadVariableNumber); 524 mv.visitTypeInsn(INSTANCEOF, targetType); 525 mv.visitJumpInsn(IFNE, matchLabel); 526 mv.visitTypeInsn(NEW, "java/lang/ClassCastException"); 527 mv.visitInsn(DUP); 528 mv.visitTypeInsn(NEW, "java/lang/StringBuffer"); 529 mv.visitInsn(DUP); 530 mv.visitLdcInsn("The field '"); 531 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V"); 532 mv.visitLdcInsn(fieldName); 533 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", 534 "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 535 mv.visitLdcInsn("' with root name '"); 536 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", 537 "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 538 mv.visitLdcInsn(rootName); 539 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", 540 "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 541 mv.visitLdcInsn("' cannot be assigned to a variable of type "); 542 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", 543 "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 544 mv.visitLdcInsn(targetType); 545 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", 546 "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 547 mv.visitLdcInsn(". This root has a type "); 548 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", 549 "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 550 mv.visitVarInsn(ALOAD, loadVariableNumber); 551 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;"); 552 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;"); 553 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", 554 "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 555 mv.visitLdcInsn(". "); 556 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", 557 "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 558 mv.visitLdcInsn("Perhaps you have the same root name assigned more than once to variables of different types."); 559 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", 560 "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 561 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;"); 562 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ClassCastException", "<init>", "(Ljava/lang/String;)V"); 563 mv.visitInsn(ATHROW); 564 565 } 566 567 private void createRootGetter(int methodAccess, String name, String desc) { 568 Type t = Type.getType(desc); 569 boolean isPrimitive = isPrimitive(t); 570 boolean isDSOFinal = isRootDSOFinal(name, isPrimitive); 571 572 String rootName = rootNameFor(spec.getClassNameSlashes(), name); 573 String targetType = isPrimitive ? ByteCodeUtil.sortToWrapperName(t.getSort()) : convertToCheckCastDesc(desc); 574 575 boolean isStatic = Modifier.isStatic(methodAccess); 576 577 Label l1 = new Label(); 578 Label l3 = new Label(); 579 Label l5 = new Label(); 580 Label l6 = new Label(); 581 Label l7 = new Label(); 582 Label l8 = new Label(); 583 584 try { 585 MethodVisitor mv = cv.visitMethod(methodAccess, ByteCodeUtil.fieldGetterMethod(name), "()" + desc, null, null); 586 587 if (isDSOFinal) { 588 callGetFieldInsn(isStatic, name, desc, mv); 589 if (isPrimitive) { 590 addPrimitiveTypeZeroCompare(mv, t, l1); 591 } else { 592 mv.visitJumpInsn(IFNONNULL, l1); 593 } 594 } 595 596 callTCBeginWithLockName(rootName, LockLevel.WRITE, mv); 597 598 mv.visitLabel(l3); 599 mv.visitLdcInsn(rootName); 600 spec.getManagerHelper().callManagerMethod("lookupRoot", mv); 601 mv.visitVarInsn(ASTORE, 1); 602 603 mv.visitVarInsn(ALOAD, 1); 604 mv.visitJumpInsn(IFNULL, l5); 605 606 checkReturnObjectType(name, rootName, targetType, 1, l6, mv); 607 608 mv.visitLabel(l6); 609 callPutFieldInsn(isStatic, t, 1, name, desc, mv); 610 mv.visitJumpInsn(GOTO, l5); 611 612 mv.visitLabel(l7); 613 mv.visitVarInsn(ASTORE, 3); 614 mv.visitJumpInsn(JSR, l8); 615 mv.visitVarInsn(ALOAD, 3); 616 mv.visitInsn(ATHROW); 617 618 mv.visitLabel(l8); 619 mv.visitVarInsn(ASTORE, 2); 620 callTCCommitWithLockName(rootName, mv); 621 mv.visitVarInsn(RET, 2); 622 623 mv.visitLabel(l5); 624 mv.visitJumpInsn(JSR, l8); 625 626 mv.visitLabel(l1); 627 callGetFieldInsn(isStatic, name, desc, mv); 628 mv.visitInsn(t.getOpcode(IRETURN)); 629 mv.visitTryCatchBlock(l3, l7, l7, null); 630 mv.visitMaxs(0, 0); 631 } catch (RuntimeException e) { 632 handleInstrumentationException(e); 633 } catch (Error e) { 634 handleInstrumentationException(e); 635 throw e; 636 } 637 } 638 639 private boolean isVolatile(int access, String fieldName) { 640 return getTransparencyClassSpec().isVolatile(access, fieldName); 641 } 642 643 private void createInstrumentedGetter(int methodAccess, int fieldAccess, String name, String desc) { 644 try { 645 Assert.eval(!getTransparencyClassSpec().isLogical()); 646 boolean isVolatile = isVolatile(fieldAccess, name); 647 648 String gDesc = "()" + desc; 649 MethodVisitor gv = this.visitMethod(methodAccess, ByteCodeUtil.fieldGetterMethod(name), gDesc, null, null); 650 Type t = Type.getType(desc); 651 652 getManaged(gv); 653 gv.visitInsn(DUP); 654 gv.visitVarInsn(ASTORE, 3); 655 656 Label l0 = new Label(); 657 gv.visitJumpInsn(IFNULL, l0); 658 659 if (isVolatile) { 660 callVolatileBegin(spec.getClassNameDots() + '.' + name, LockLevel.READ, gv); 661 } 662 663 gv.visitVarInsn(ALOAD, 3); 664 gv.visitMethodInsn(INVOKEINTERFACE, "com/tc/object/TCObject", "getResolveLock", "()Ljava/lang/Object;"); 665 gv.visitInsn(DUP); 666 gv.visitVarInsn(ASTORE, 2); 667 gv.visitInsn(MONITORENTER); 668 669 Label l1 = new Label(); 670 gv.visitLabel(l1); 671 672 gv.visitVarInsn(ALOAD, 0); 673 gv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(), name, desc); 674 Label l5 = new Label(); 675 gv.visitJumpInsn(IFNONNULL, l5); 676 gv.visitVarInsn(ALOAD, 3); 677 gv.visitLdcInsn(spec.getClassNameDots() + '.' + name); 678 gv.visitMethodInsn(INVOKEINTERFACE, "com/tc/object/TCObject", "resolveReference", "(Ljava/lang/String;)V"); 679 gv.visitLabel(l5); 680 681 Label l2 = new Label(); 682 683 gv.visitVarInsn(ALOAD, 0); 684 gv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(), name, desc); 685 gv.visitVarInsn(ALOAD, 2); 686 687 gv.visitInsn(MONITOREXIT); 688 if (isVolatile) { 689 callVolatileCommit(spec.getClassNameDots() + "." + name, gv); 690 } 691 gv.visitInsn(ARETURN); 692 gv.visitJumpInsn(GOTO, l0); 693 694 gv.visitLabel(l2); 695 gv.visitVarInsn(ALOAD, 2); 696 697 gv.visitInsn(MONITOREXIT); 698 if (isVolatile) { 699 callVolatileCommit(spec.getClassNameDots() + "." + name, gv); 700 } 701 gv.visitInsn(ATHROW); 702 703 gv.visitLabel(l0); 704 gv.visitVarInsn(ALOAD, 0); 705 gv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(), name, desc); 706 gv.visitInsn(t.getOpcode(IRETURN)); 707 708 gv.visitTryCatchBlock(l1, l2, l2, null); 709 710 gv.visitMaxs(0, 0); 711 } catch (RuntimeException e) { 712 handleInstrumentationException(e); 713 } catch (Error e) { 714 handleInstrumentationException(e); 715 throw e; 716 } 717 } 718 719 private void getManaged(MethodVisitor mv) { 720 mv.visitVarInsn(ALOAD, 0); 721 mv.visitMethodInsn(INVOKEVIRTUAL, spec.getClassNameSlashes(), MANAGED_METHOD, "()" + MANAGED_FIELD_TYPE); 722 } 723 724 private void createPlainSetter(int methodAccess, int fieldAccess, String name, String desc) { 725 boolean isVolatile = isVolatile(fieldAccess, name); 726 727 String sDesc = "(" + desc + ")V"; 728 MethodVisitor scv = cv.visitMethod(methodAccess, ByteCodeUtil.fieldSetterMethod(name), sDesc, null, null); 729 Type t = Type.getType(desc); 730 731 Label l4 = new Label(); 732 733 if (isVolatile) { 734 getManaged(scv); 735 scv.visitInsn(DUP); 736 scv.visitVarInsn(ASTORE, 2); 737 scv.visitJumpInsn(IFNULL, l4); 738 739 Label l0 = new Label(); 740 Label l1 = new Label(); 741 Label l2 = new Label(); 742 scv.visitTryCatchBlock(l0, l1, l2, null); 743 scv.visitLabel(l0); 744 745 callVolatileBegin(spec.getClassNameDots() + "." + name, LockLevel.WRITE, scv); 746 747 Label l6 = new Label(); 748 scv.visitJumpInsn(JSR, l6); 749 scv.visitLabel(l1); 750 ByteCodeUtil.pushThis(scv); 751 scv.visitVarInsn(t.getOpcode(ILOAD), 1); 752 753 scv.visitFieldInsn(PUTFIELD, spec.getClassNameSlashes(), name, desc); 754 scv.visitInsn(RETURN); 755 scv.visitLabel(l2); 756 scv.visitVarInsn(ASTORE, 2); 757 scv.visitJumpInsn(JSR, l6); 758 scv.visitVarInsn(ALOAD, 2); 759 scv.visitInsn(ATHROW); 760 scv.visitLabel(l6); 761 scv.visitVarInsn(ASTORE, 1); 762 callVolatileCommit(spec.getClassNameDots() + "." + name, scv); 763 764 scv.visitVarInsn(RET, 1); 765 } 766 767 scv.visitLabel(l4); 768 ByteCodeUtil.pushThis(scv); 769 scv.visitVarInsn(t.getOpcode(ILOAD), 1); 770 771 scv.visitFieldInsn(PUTFIELD, spec.getClassNameSlashes(), name, desc); 772 scv.visitInsn(RETURN); 773 scv.visitMaxs(0, 0); 774 } 775 776 private void createInstrumentedSetter(int methodAccess, int fieldAccess, String name, String desc) { 777 try { 778 Type t = Type.getType(desc); 779 if (isRoot(methodAccess, name)) { 780 createObjectSetter(methodAccess, fieldAccess, name, desc); 781 } 782 else if (((t.getSort() == Type.OBJECT) || (t.getSort() == Type.ARRAY)) && !isPrimitive(t)) { 784 createObjectSetter(methodAccess, fieldAccess, name, desc); 785 } else { 786 createLiteralSetter(methodAccess, fieldAccess, name, desc); 787 } 788 } catch (RuntimeException e) { 789 handleInstrumentationException(e); 790 } catch (Error e) { 791 handleInstrumentationException(e); 792 throw e; 793 } 794 } 795 796 private void createObjectSetter(int methodAccess, int fieldAccess, String name, String desc) { 797 try { 798 if (isRoot(methodAccess, name)) { 799 boolean isStaticRoot = Modifier.isStatic(methodAccess); 800 if (instrumentationLogger.rootInsertion()) { 801 instrumentationLogger.rootInserted(spec.getClassNameDots(), name, desc, isStaticRoot); 802 } 803 804 createRootSetter(methodAccess, name, desc, isStaticRoot); 805 } else { 806 createObjectFieldSetter(methodAccess, fieldAccess, name, desc); 807 } 808 } catch (RuntimeException e) { 809 handleInstrumentationException(e); 810 } catch (Error e) { 811 handleInstrumentationException(e); 812 throw e; 813 } 814 } 815 816 private boolean isRootDSOFinal(String name, boolean isPrimitive) { 817 return spec.getTransparencyClassSpec().isRootDSOFinal(name, isPrimitive); 818 } 819 820 private void createRootSetter(int methodAccess, String name, String desc, boolean isStatic) { 821 Type t = Type.getType(desc); 822 boolean isPrimitive = isPrimitive(t); 823 boolean isDSOFinal = isRootDSOFinal(name, isPrimitive); 824 825 try { 826 String sDesc = "(" + desc + ")V"; 827 String targetType = isPrimitive ? ByteCodeUtil.sortToWrapperName(t.getSort()) : convertToCheckCastDesc(desc); 828 MethodVisitor scv = cv.visitMethod(methodAccess, ByteCodeUtil.fieldSetterMethod(name), sDesc, null, null); 829 830 Label tryStart = new Label(); 831 Label end = new Label(); 832 Label normalExit = new Label(); 833 Label finallyStart = new Label(); 834 Label exceptionHandler = new Label(); 835 836 final int rootInstance = isStatic ? 0 : 1; 837 838 if (!isPrimitive) { 839 scv.visitVarInsn(ALOAD, rootInstance); 840 scv.visitJumpInsn(IFNULL, end); } 842 843 String rootName = rootNameFor(spec.getClassNameSlashes(), name); 844 callTCBeginWithLockName(rootName, LockLevel.WRITE, scv); 845 846 scv.visitLabel(tryStart); 847 848 scv.visitLdcInsn(rootName); 849 if (isPrimitive) { 850 ByteCodeUtil.addTypeSpecificParameterLoad(scv, t, rootInstance); 851 } else { 852 scv.visitVarInsn(ALOAD, rootInstance); 853 } 854 if (isDSOFinal) { 855 spec.getManagerHelper().callManagerMethod("lookupOrCreateRoot", scv); 856 } else { 857 spec.getManagerHelper().callManagerMethod("createOrReplaceRoot", scv); 858 } 859 860 int localVar = rootInstance + 1; 861 scv.visitVarInsn(ASTORE, localVar); 862 863 Label l0 = new Label(); 864 checkReturnObjectType(name, rootName, targetType, localVar, l0, scv); 865 866 scv.visitLabel(l0); 867 callPutFieldInsn(isStatic, t, localVar, name, desc, scv); 868 scv.visitJumpInsn(GOTO, normalExit); 869 870 scv.visitLabel(exceptionHandler); 871 scv.visitVarInsn(ASTORE, 3); 872 scv.visitJumpInsn(JSR, finallyStart); 873 scv.visitVarInsn(ALOAD, 3); 874 scv.visitInsn(ATHROW); 875 876 scv.visitLabel(finallyStart); 877 scv.visitVarInsn(ASTORE, 2); 878 callTCCommitWithLockName(rootName, scv); 879 scv.visitVarInsn(RET, 2); 880 881 scv.visitLabel(normalExit); 882 scv.visitJumpInsn(JSR, finallyStart); 883 scv.visitLabel(end); 884 scv.visitInsn(RETURN); 885 scv.visitTryCatchBlock(tryStart, exceptionHandler, exceptionHandler, null); 886 scv.visitMaxs(0, 0); 887 } catch (RuntimeException e) { 888 handleInstrumentationException(e); 889 } catch (Error e) { 890 handleInstrumentationException(e); 891 throw e; 892 } 893 } 894 895 private void callGetFieldInsn(boolean isStatic, String name, String desc, MethodVisitor mv) { 896 int getInsn = isStatic ? GETSTATIC : GETFIELD; 897 898 if (!isStatic) ByteCodeUtil.pushThis(mv); 899 mv.visitFieldInsn(getInsn, spec.getClassNameSlashes(), name, desc); 900 } 901 902 private void callPutFieldInsn(boolean isStatic, Type targetType, int localVar, String name, String desc, 903 MethodVisitor mv) { 904 int putInsn = isStatic ? PUTSTATIC : PUTFIELD; 905 906 if (!isStatic) ByteCodeUtil.pushThis(mv); 907 mv.visitVarInsn(ALOAD, localVar); 908 909 if (isPrimitive(targetType)) { 910 mv.visitTypeInsn(CHECKCAST, ByteCodeUtil.sortToWrapperName(targetType.getSort())); 911 mv.visitMethodInsn(INVOKEVIRTUAL, ByteCodeUtil.sortToWrapperName(targetType.getSort()), ByteCodeUtil 912 .sortToPrimitiveMethodName(targetType.getSort()), "()" + desc); 913 } else { 914 mv.visitTypeInsn(CHECKCAST, convertToCheckCastDesc(desc)); 915 } 916 917 mv.visitFieldInsn(putInsn, spec.getClassNameSlashes(), name, desc); 918 } 919 920 private void generateCodeForVolatileTransactionBegin(Label l1, Label l2, Label l3, Label l4, String fieldName, 921 int lockLevel, MethodVisitor scv) { 922 scv.visitTryCatchBlock(l4, l1, l1, null); 923 scv.visitTryCatchBlock(l2, l3, l1, null); 924 scv.visitLabel(l4); 925 callVolatileBegin(fieldName, lockLevel, scv); 926 } 927 928 private void generateCodeForVolativeTransactionCommit(Label l1, Label l2, MethodVisitor scv, int newVar1, 929 int newVar2, String fieldName) { 930 scv.visitJumpInsn(GOTO, l2); 931 scv.visitLabel(l1); 932 scv.visitVarInsn(ASTORE, newVar2); 933 Label l5 = new Label(); 934 scv.visitJumpInsn(JSR, l5); 935 scv.visitVarInsn(ALOAD, newVar2); 936 scv.visitInsn(ATHROW); 937 scv.visitLabel(l5); 938 scv.visitVarInsn(ASTORE, newVar1); 939 callVolatileCommit(fieldName, scv); 940 scv.visitVarInsn(RET, newVar1); 941 scv.visitLabel(l2); 942 scv.visitJumpInsn(JSR, l5); 943 } 944 945 private void createObjectFieldSetter(int methodAccess, int fieldAccess, String name, String desc) { 946 try { 947 boolean isVolatile = isVolatile(fieldAccess, name); 948 Label l1 = new Label(); 949 Label l2 = new Label(); 950 Label l4 = new Label(); 951 952 String sDesc = "(" + desc + ")V"; 954 MethodVisitor scv = cv.visitMethod(methodAccess, ByteCodeUtil.fieldSetterMethod(name), sDesc, null, null); 955 getManaged(scv); 956 scv.visitInsn(DUP); 957 scv.visitVarInsn(ASTORE, 2); 958 Label l0 = new Label(); 959 scv.visitJumpInsn(IFNULL, l0); 960 961 if (isVolatile) { 962 generateCodeForVolatileTransactionBegin(l1, l2, l0, l4, spec.getClassNameDots() + "." + name, LockLevel.WRITE, 963 scv); 964 } 965 966 scv.visitVarInsn(ALOAD, 2); 967 scv.visitLdcInsn(spec.getClassNameDots()); 968 scv.visitLdcInsn(spec.getClassNameDots() + "." + name); 969 scv.visitVarInsn(ALOAD, 1); 970 scv.visitInsn(ICONST_M1); 971 scv.visitMethodInsn(INVOKEINTERFACE, "com/tc/object/TCObject", "objectFieldChanged", 972 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;I)V"); 973 974 if (isVolatile) { 975 generateCodeForVolativeTransactionCommit(l1, l2, scv, 3, 4, spec.getClassNameDots() + "." + name); 976 } 977 978 scv.visitLabel(l0); 979 scv.visitVarInsn(ALOAD, 0); 980 scv.visitVarInsn(ALOAD, 1); 981 scv.visitFieldInsn(PUTFIELD, spec.getClassNameSlashes(), name, desc); 982 scv.visitInsn(RETURN); 983 scv.visitMaxs(0, 0); 984 } catch (RuntimeException e) { 985 handleInstrumentationException(e); 986 } catch (Error e) { 987 handleInstrumentationException(e); 988 throw e; 989 } 990 } 991 992 private void createLiteralSetter(int methodAccess, int fieldAccess, String name, String desc) { 993 try { 994 boolean isVolatile = isVolatile(fieldAccess, name); 996 997 Label l1 = new Label(); 998 Label l2 = new Label(); 999 Label l4 = new Label(); 1000 1001 String sDesc = "(" + desc + ")V"; 1002 Type t = Type.getType(desc); 1003 1004 MethodVisitor mv = cv.visitMethod(methodAccess, ByteCodeUtil.fieldSetterMethod(name), sDesc, null, null); 1005 getManaged(mv); 1006 mv.visitInsn(DUP); 1007 mv.visitVarInsn(ASTORE, 1 + t.getSize()); 1008 Label l0 = new Label(); 1009 mv.visitJumpInsn(IFNULL, l0); 1010 1011 if (isVolatile) { 1012 generateCodeForVolatileTransactionBegin(l1, l2, l0, l4, spec.getClassNameDots() + "." + name, LockLevel.WRITE, 1013 mv); 1014 } 1015 1016 mv.visitVarInsn(ALOAD, 1 + t.getSize()); 1017 mv.visitLdcInsn(spec.getClassNameDots()); 1018 mv.visitLdcInsn(spec.getClassNameDots() + "." + name); 1019 mv.visitVarInsn(t.getOpcode(ILOAD), 1); 1020 mv.visitInsn(ICONST_M1); 1021 String method = ByteCodeUtil.codeToName(desc) + "FieldChanged"; 1022 mv.visitMethodInsn(INVOKEINTERFACE, "com/tc/object/TCObject", method, "(Ljava/lang/String;Ljava/lang/String;" 1023 + desc + "I)V"); 1024 1025 if (isVolatile) { 1026 generateCodeForVolativeTransactionCommit(l1, l2, mv, 2 + t.getSize(), 3 + t.getSize(), spec.getClassNameDots() 1027 + "." + name); 1028 } 1029 1030 mv.visitLabel(l0); 1031 mv.visitVarInsn(ALOAD, 0); 1032 mv.visitVarInsn(t.getOpcode(ILOAD), 1); 1033 mv.visitFieldInsn(PUTFIELD, spec.getClassNameSlashes(), name, desc); 1034 mv.visitInsn(RETURN); 1035 mv.visitMaxs(0, 0); 1036 } catch (RuntimeException e) { 1037 handleInstrumentationException(e); 1038 } catch (Error e) { 1039 handleInstrumentationException(e); 1040 throw e; 1041 } 1042 } 1043 1044 private void callTCMonitorExit(int callingMethodModifier, MethodVisitor c) { 1045 Assert.eval("Can't call tc monitorenter from a static method.", !Modifier.isStatic(callingMethodModifier)); 1046 ByteCodeUtil.pushThis(c); 1047 spec.getManagerHelper().callManagerMethod("monitorExit", c); 1048 } 1049 1050 private void callTCMonitorEnter(int callingMethodModifier, LockDefinition def, MethodVisitor c) { 1051 Assert.eval("Can't call tc monitorexit from a static method.", !Modifier.isStatic(callingMethodModifier)); 1052 ByteCodeUtil.pushThis(c); 1053 c.visitLdcInsn(new Integer (def.getLockLevelAsInt())); 1054 spec.getManagerHelper().callManagerMethod("monitorEnter", c); 1055 } 1056 1057 private void addPrimitiveTypeZeroCompare(MethodVisitor mv, Type type, Label notZeroLabel) { 1058 switch (type.getSort()) { 1059 case Type.LONG: 1060 mv.visitInsn(LCONST_0); 1061 mv.visitInsn(LCMP); 1062 mv.visitJumpInsn(IFNE, notZeroLabel); 1063 break; 1064 case Type.DOUBLE: 1065 mv.visitInsn(DCONST_0); 1066 mv.visitInsn(DCMPL); 1067 mv.visitJumpInsn(IFNE, notZeroLabel); 1068 break; 1069 case Type.FLOAT: 1070 mv.visitInsn(FCONST_0); 1071 mv.visitInsn(FCMPL); 1072 mv.visitJumpInsn(IFNE, notZeroLabel); 1073 break; 1074 default: 1075 mv.visitJumpInsn(IFNE, notZeroLabel); 1076 } 1077 } 1078} 1079 | Popular Tags |