1 4 package com.tc.aspectwerkz.transform.inlining.weaver; 5 6 7 import java.lang.reflect.Modifier ; 8 import java.util.Collections ; 9 import java.util.HashMap ; 10 import java.util.Iterator ; 11 import java.util.Map ; 12 import java.util.Set ; 13 import java.util.Stack ; 14 15 import com.tc.asm.ClassAdapter; 16 import com.tc.asm.ClassVisitor; 17 import com.tc.asm.MethodAdapter; 18 import com.tc.asm.MethodVisitor; 19 import com.tc.asm.Label; 20 21 import com.tc.aspectwerkz.definition.SystemDefinition; 22 import com.tc.aspectwerkz.joinpoint.management.JoinPointType; 23 import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo; 24 import com.tc.aspectwerkz.reflect.ClassInfo; 25 import com.tc.aspectwerkz.reflect.MemberInfo; 26 import com.tc.aspectwerkz.reflect.ConstructorInfo; 27 import com.tc.aspectwerkz.transform.InstrumentationContext; 28 import com.tc.aspectwerkz.transform.TransformationConstants; 29 import com.tc.aspectwerkz.transform.TransformationUtil; 30 import com.tc.aspectwerkz.transform.inlining.AsmHelper; 31 import com.tc.aspectwerkz.transform.inlining.AsmNullAdapter; 32 import com.tc.aspectwerkz.transform.inlining.EmittedJoinPoint; 33 import com.tc.aspectwerkz.expression.ExpressionContext; 34 import com.tc.aspectwerkz.expression.PointcutType; 35 36 37 53 public class ConstructorCallVisitor extends ClassAdapter implements TransformationConstants { 54 55 private final static Map EMPTY_INTHASHMAP = Collections.EMPTY_MAP; 56 57 private final InstrumentationContext m_ctx; 58 private final ClassLoader m_loader; 59 private final ClassInfo m_callerClassInfo; 60 61 66 private final Map m_newInvocationsByCallerMemberHash; 67 68 private Label m_lastLabelForLineNumber = EmittedJoinPoint.NO_LINE_NUMBER; 69 70 78 public ConstructorCallVisitor(final ClassVisitor cv, 79 final ClassLoader loader, 80 final ClassInfo classInfo, 81 final InstrumentationContext ctx, 82 final Map newInvocationsByCallerMemberHash) { 83 super(cv); 84 m_loader = loader; 85 m_callerClassInfo = classInfo; 86 m_ctx = ctx; 87 m_newInvocationsByCallerMemberHash = newInvocationsByCallerMemberHash; 88 } 89 90 100 public MethodVisitor visitMethod(final int access, 101 final String name, 102 final String desc, 103 final String signature, 104 final String [] exceptions) { 105 106 if (name.startsWith(WRAPPER_METHOD_PREFIX) || 107 Modifier.isNative(access) || 108 Modifier.isAbstract(access)) { 109 return super.visitMethod(access, name, desc, signature, exceptions); 110 } 111 112 MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); 113 return mv == null ? null : new ReplaceNewInstructionCodeAdapter( 114 mv, 115 m_loader, 116 m_callerClassInfo, 117 m_ctx.getClassName(), 118 name, 119 desc, 120 (Map ) m_newInvocationsByCallerMemberHash.get(getMemberHash(name, desc)) 121 ); 122 } 123 124 125 135 public class ReplaceNewInstructionCodeAdapter extends MethodAdapter { 136 137 private final ClassLoader m_loader; 138 private final ClassInfo m_callerClassInfo; 139 private final String m_callerClassName; 140 private final String m_callerMethodName; 141 private final String m_callerMethodDesc; 142 private final MemberInfo m_callerMemberInfo; 143 144 147 private final Map m_newInvocations; 148 149 152 private int m_newInvocationIndex = -1; 153 154 160 private final Stack m_newInvocationStructStack = new Stack (); 161 162 165 private boolean m_skipNextDup = false; 166 167 177 public ReplaceNewInstructionCodeAdapter(final MethodVisitor ca, 178 final ClassLoader loader, 179 final ClassInfo callerClassInfo, 180 final String callerClassName, 181 final String callerMethodName, 182 final String callerMethodDesc, 183 final Map newInvocations) { 184 super(ca); 185 m_loader = loader; 186 m_callerClassInfo = callerClassInfo; 187 m_callerClassName = callerClassName; 188 m_callerMethodName = callerMethodName; 189 m_callerMethodDesc = callerMethodDesc; 190 m_newInvocations = (newInvocations != null) ? newInvocations : EMPTY_INTHASHMAP; 191 192 if (CLINIT_METHOD_NAME.equals(m_callerMethodName)) { 193 m_callerMemberInfo = m_callerClassInfo.staticInitializer(); 194 } else if (INIT_METHOD_NAME.equals(m_callerMethodName)) { 195 final int hash = AsmHelper.calculateConstructorHash(m_callerMethodDesc); 196 m_callerMemberInfo = m_callerClassInfo.getConstructor(hash); 197 } else { 198 final int hash = AsmHelper.calculateMethodHash(m_callerMethodName, m_callerMethodDesc); 199 m_callerMemberInfo = m_callerClassInfo.getMethod(hash); 200 } 201 if (m_callerMemberInfo == null) { 202 System.err.println( 203 "AW::WARNING " + 204 "metadata structure could not be build for method [" 205 + m_callerClassInfo.getName().replace('/', '.') 206 + '.' + m_callerMethodName + ':' + m_callerMethodDesc + ']' 207 ); 208 } 209 } 210 211 216 public void visitLabel(Label label) { 217 m_lastLabelForLineNumber = label; 218 super.visitLabel(label); 219 } 220 221 227 public void visitTypeInsn(int opcode, String desc) { 228 if (m_callerMemberInfo == null) { 229 return; 230 } 231 232 if (opcode == NEW) { 233 m_newInvocationIndex++; 234 NewInvocationStruct newInvocationStruct = (NewInvocationStruct) m_newInvocations.get(new Integer (m_newInvocationIndex)); 236 if (newInvocationStruct == null) { 237 super.visitTypeInsn(opcode, desc); return; 239 } 240 String calleeClassName = newInvocationStruct.className; 241 String calleeMethodName = INIT_METHOD_NAME; 242 String calleeMethodDesc = newInvocationStruct.ctorDesc; 243 int joinPointHash = AsmHelper.calculateMethodHash(calleeMethodName, calleeMethodDesc); 244 ClassInfo classInfo = AsmClassInfo.getClassInfo(calleeClassName, m_loader); 245 ConstructorInfo calleeConstructorInfo = classInfo.getConstructor(joinPointHash); 246 if (calleeConstructorInfo == null) { 247 super.visitTypeInsn(opcode, desc); System.err.println( 249 "AW::WARNING " + 250 "metadata structure could not be build for method [" 251 + classInfo.getName().replace('/', '.') 252 + '.' + calleeMethodName + ':' + calleeMethodDesc + ']' 253 ); 254 return; 255 } 256 257 ExpressionContext ctx = new ExpressionContext( 259 PointcutType.CALL, calleeConstructorInfo, m_callerMemberInfo 260 ); 261 if (constructorFilter(m_ctx.getDefinitions(), ctx, calleeConstructorInfo)) { 262 m_newInvocationStructStack.push(null); 264 super.visitTypeInsn(opcode, desc); 265 } else { 266 newInvocationStruct.constructorInfo = calleeConstructorInfo; 268 newInvocationStruct.joinPointHash = joinPointHash; 269 m_newInvocationStructStack.push(newInvocationStruct); 270 m_skipNextDup = true; 272 } 274 } else { 275 super.visitTypeInsn(opcode, desc); 277 } 278 } 279 280 285 public void visitInsn(int opcode) { 286 if ((opcode == DUP || opcode == DUP_X1) && m_skipNextDup) { 287 if (opcode == DUP_X1) 290 super.visitInsn(DUP); 291 } else { 292 super.visitInsn(opcode); 293 } 294 m_skipNextDup = false; 295 } 296 297 305 public void visitMethodInsn(final int opcode, 306 final String calleeClassName, 307 final String calleeConstructorName, 308 final String calleeConstructorDesc) { 309 310 if (m_callerMemberInfo == null) { 311 super.visitMethodInsn(opcode, calleeClassName, calleeConstructorName, calleeConstructorDesc); 312 return; 313 } 314 315 if (!INIT_METHOD_NAME.equals(calleeConstructorName) || 316 calleeClassName.endsWith(TransformationConstants.JOIN_POINT_CLASS_SUFFIX)) { 317 super.visitMethodInsn(opcode, calleeClassName, calleeConstructorName, calleeConstructorDesc); 318 return; 319 } 320 321 if (m_newInvocationStructStack.isEmpty()) { 323 super.visitMethodInsn(opcode, calleeClassName, calleeConstructorName, calleeConstructorDesc); 325 return; 326 } 327 328 NewInvocationStruct struct = (NewInvocationStruct) m_newInvocationStructStack.pop(); 329 if (struct == null) { 330 super.visitMethodInsn(opcode, calleeClassName, calleeConstructorName, calleeConstructorDesc); 332 } else { 333 m_ctx.markAsAdvised(); 334 335 String joinPointClassName = TransformationUtil.getJoinPointClassName( 336 m_callerClassName, 337 m_callerMethodName, 338 m_callerMethodDesc, 339 calleeClassName, 340 JoinPointType.CONSTRUCTOR_CALL_INT, 341 struct.joinPointHash 342 ); 343 344 if (Modifier.isStatic(m_callerMemberInfo.getModifiers())) { 347 visitInsn(ACONST_NULL); 348 } else { 349 visitVarInsn(ALOAD, 0); 350 } 351 352 super.visitMethodInsn( 354 INVOKESTATIC, 355 joinPointClassName, 356 INVOKE_METHOD_NAME, 357 TransformationUtil.getInvokeSignatureForConstructorCallJoinPoints( 358 calleeConstructorDesc, 359 m_callerClassName, 360 calleeClassName 361 ) 362 ); 363 364 m_ctx.addEmittedJoinPoint( 366 new EmittedJoinPoint( 367 JoinPointType.CONSTRUCTOR_CALL_INT, 368 m_callerClassName, 369 m_callerMethodName, 370 m_callerMethodDesc, 371 m_callerMemberInfo.getModifiers(), 372 calleeClassName, 373 calleeConstructorName, 374 calleeConstructorDesc, 375 struct.constructorInfo.getModifiers(), 376 struct.joinPointHash, 377 joinPointClassName, 378 m_lastLabelForLineNumber 379 ) 380 ); 381 } 382 } 383 384 392 public boolean constructorFilter(final Set definitions, 393 final ExpressionContext ctx, 394 final ConstructorInfo calleeConstructorInfo) { 395 for (Iterator it = definitions.iterator(); it.hasNext();) { 396 if (((SystemDefinition) it.next()).hasPointcut(ctx)) { 397 return false; 398 } else { 399 continue; 400 } 401 } 402 return true; 403 } 404 } 405 406 private static Integer getMemberHash(String name, String desc) { 407 int hash = 29; 408 hash = (29 * hash) + name.hashCode(); 409 hash = (29 * hash) + desc.hashCode(); 410 return new Integer (hash); 411 } 412 413 424 public static class LookaheadNewDupInvokeSpecialInstructionClassAdapter 425 extends AsmNullAdapter.NullClassAdapter { 426 427 private String m_callerMemberName; 428 429 public Map m_newInvocationsByCallerMemberHash; 431 432 public LookaheadNewDupInvokeSpecialInstructionClassAdapter(Map newInvocations) { 433 m_newInvocationsByCallerMemberHash = newInvocations; 434 } 435 436 public MethodVisitor visitMethod(final int access, 437 final String name, 438 final String desc, 439 final String signature, 440 final String [] exceptions) { 441 if (name.startsWith(WRAPPER_METHOD_PREFIX) || 442 Modifier.isNative(access) || 443 Modifier.isAbstract(access)) { 444 } 446 447 m_callerMemberName = name; 448 449 Map newInvocations = new HashMap (5); 450 m_newInvocationsByCallerMemberHash.put(getMemberHash(name, desc), newInvocations); 451 return new LookaheadNewDupInvokeSpecialInstructionCodeAdapter( 452 super.visitMethod(access, name, desc, signature, exceptions), 453 newInvocations, 454 m_callerMemberName 455 ); 456 } 457 } 458 459 public static class LookaheadNewDupInvokeSpecialInstructionCodeAdapter 460 extends AfterObjectInitializationCodeAdapter { 461 462 private Map m_newInvocations; 463 464 private Stack m_newIndexStack = new Stack (); 465 private int m_newIndex = -1; 466 467 470 public LookaheadNewDupInvokeSpecialInstructionCodeAdapter(MethodVisitor cv, Map newInvocations, 471 final String callerMemberName) { 472 super(cv, callerMemberName); 473 m_newInvocations = newInvocations; 474 } 475 476 public void visitTypeInsn(int opcode, String desc) { 477 super.visitTypeInsn(opcode, desc); 479 if (opcode == NEW) { 480 m_newIndex++; 481 m_newIndexStack.push(new Integer (m_newIndex)); 482 } 483 } 484 485 public void visitMethodInsn(final int opcode, 486 final String calleeClassName, 487 final String calleeMethodName, 488 final String calleeMethodDesc) { 489 super.visitMethodInsn(opcode, calleeClassName, calleeMethodName, calleeMethodDesc); 491 492 if (INIT_METHOD_NAME.equals(calleeMethodName) && opcode == INVOKESPECIAL) { 493 if (!m_isObjectInitialized) { 494 if (!m_newIndexStack.isEmpty()) { 496 m_newIndexStack.pop(); 497 } 498 } else { 499 if (!m_newIndexStack.isEmpty()) { 500 Object index = m_newIndexStack.pop(); 501 NewInvocationStruct newInvocationStruct = new NewInvocationStruct(); 502 newInvocationStruct.className = calleeClassName; 503 newInvocationStruct.ctorDesc = calleeMethodDesc; 504 m_newInvocations.put(index, newInvocationStruct); 506 } 507 } 508 } 509 } 510 } 511 512 private static class NewInvocationStruct { 513 public String className; 514 public String ctorDesc; 515 public ConstructorInfo constructorInfo = null; 516 public int joinPointHash = -1; 517 } 518 519 } | Popular Tags |