1 8 package org.codehaus.aspectwerkz.transform.inlining.weaver; 9 10 import org.objectweb.asm.ClassAdapter; 11 import org.objectweb.asm.ClassVisitor; 12 import org.objectweb.asm.CodeVisitor; 13 import org.objectweb.asm.Attribute; 14 import org.objectweb.asm.Constants; 15 import org.objectweb.asm.CodeAdapter; 16 import org.objectweb.asm.Label; 17 import org.codehaus.aspectwerkz.definition.SystemDefinition; 18 import org.codehaus.aspectwerkz.expression.ExpressionContext; 19 import org.codehaus.aspectwerkz.expression.PointcutType; 20 import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType; 21 import org.codehaus.aspectwerkz.reflect.ClassInfo; 22 import org.codehaus.aspectwerkz.reflect.ConstructorInfo; 23 import org.codehaus.aspectwerkz.reflect.MemberInfo; 24 import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo; 25 import org.codehaus.aspectwerkz.transform.Context; 26 import org.codehaus.aspectwerkz.transform.TransformationUtil; 27 import org.codehaus.aspectwerkz.transform.TransformationConstants; 28 import org.codehaus.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler; 29 import org.codehaus.aspectwerkz.transform.inlining.ContextImpl; 30 import org.codehaus.aspectwerkz.transform.inlining.AsmHelper; 31 import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint; 32 import org.codehaus.aspectwerkz.annotation.instrumentation.asm.AsmAnnotationHelper; 33 34 import java.lang.reflect.Modifier ; 35 import java.util.Iterator ; 36 import java.util.List ; 37 import java.util.Stack ; 38 import java.util.Set ; 39 40 import gnu.trove.TLongObjectHashMap; 41 import gnu.trove.TIntObjectHashMap; 42 43 59 public class ConstructorCallVisitor extends ClassAdapter implements TransformationConstants { 60 61 private final static TIntObjectHashMap EMPTY_INTHASHMAP = new TIntObjectHashMap(0); 62 63 private final ContextImpl m_ctx; 64 private final ClassLoader m_loader; 65 private final ClassInfo m_callerClassInfo; 66 67 72 private final TLongObjectHashMap m_newInvocationsByCallerMemberHash; 73 74 private Label m_lastLabelForLineNumber = EmittedJoinPoint.NO_LINE_NUMBER; 75 76 84 public ConstructorCallVisitor(final ClassVisitor cv, 85 final ClassLoader loader, 86 final ClassInfo classInfo, 87 final Context ctx, 88 final TLongObjectHashMap newInvocationsByCallerMemberHash) { 89 super(cv); 90 m_loader = loader; 91 m_callerClassInfo = classInfo; 92 m_ctx = (ContextImpl) ctx; 93 m_newInvocationsByCallerMemberHash = newInvocationsByCallerMemberHash; 94 } 95 96 106 public CodeVisitor visitMethod(final int access, 107 final String name, 108 final String desc, 109 final String [] exceptions, 110 final Attribute attrs) { 111 112 if (name.startsWith(WRAPPER_METHOD_PREFIX) || 113 Modifier.isNative(access) || 114 Modifier.isAbstract(access)) { 115 return super.visitMethod(access, name, desc, exceptions, attrs); 116 } 117 118 CodeVisitor mv = cv.visitMethod(access, name, desc, exceptions, attrs); 119 return mv == null ? null : new ReplaceNewInstructionCodeAdapter( 120 mv, 121 m_loader, 122 m_callerClassInfo, 123 m_ctx.getClassName(), 124 name, 125 desc, 126 (TIntObjectHashMap) m_newInvocationsByCallerMemberHash.get(getMemberHash(name, desc)) 127 ); 128 } 129 130 131 141 public class ReplaceNewInstructionCodeAdapter extends CodeAdapter { 142 143 private final ClassLoader m_loader; 144 private final ClassInfo m_callerClassInfo; 145 private final String m_callerClassName; 146 private final String m_callerMethodName; 147 private final String m_callerMethodDesc; 148 private final MemberInfo m_callerMemberInfo; 149 150 153 private final TIntObjectHashMap m_newInvocations; 154 155 158 private int m_newInvocationIndex = -1; 159 160 166 private final Stack m_newInvocationStructStack = new Stack (); 167 168 171 private boolean m_skipNextDup = false; 172 173 183 public ReplaceNewInstructionCodeAdapter(final CodeVisitor ca, 184 final ClassLoader loader, 185 final ClassInfo callerClassInfo, 186 final String callerClassName, 187 final String callerMethodName, 188 final String callerMethodDesc, 189 final TIntObjectHashMap newInvocations) { 190 super(ca); 191 m_loader = loader; 192 m_callerClassInfo = callerClassInfo; 193 m_callerClassName = callerClassName; 194 m_callerMethodName = callerMethodName; 195 m_callerMethodDesc = callerMethodDesc; 196 m_newInvocations = (newInvocations != null) ? newInvocations : EMPTY_INTHASHMAP; 197 198 if (CLINIT_METHOD_NAME.equals(m_callerMethodName)) { 199 m_callerMemberInfo = m_callerClassInfo.staticInitializer(); 200 } else if (INIT_METHOD_NAME.equals(m_callerMethodName)) { 201 final int hash = AsmHelper.calculateConstructorHash(m_callerMethodDesc); 202 m_callerMemberInfo = m_callerClassInfo.getConstructor(hash); 203 } else { 204 final int hash = AsmHelper.calculateMethodHash(m_callerMethodName, m_callerMethodDesc); 205 m_callerMemberInfo = m_callerClassInfo.getMethod(hash); 206 } 207 if (m_callerMemberInfo == null) { 208 System.err.println( 209 "AW::WARNING " + 210 "metadata structure could not be build for method [" 211 + m_callerClassInfo.getName().replace('/', '.') 212 + '.' + m_callerMethodName + ':' + m_callerMethodDesc + ']' 213 ); 214 } 215 } 216 217 222 public void visitLabel(Label label) { 223 m_lastLabelForLineNumber = label; 224 super.visitLabel(label); 225 } 226 227 233 public void visitTypeInsn(int opcode, String desc) { 234 if (m_callerMemberInfo == null) { 235 return; 236 } 237 238 if (opcode == NEW) { 239 m_newInvocationIndex++; 240 NewInvocationStruct newInvocationStruct = (NewInvocationStruct) m_newInvocations.get( 242 m_newInvocationIndex 243 ); 244 if (newInvocationStruct == null) { 245 super.visitTypeInsn(opcode, desc); return; 247 } 248 String calleeClassName = newInvocationStruct.className; 249 String calleeMethodName = INIT_METHOD_NAME; 250 String calleeMethodDesc = newInvocationStruct.ctorDesc; 251 int joinPointHash = AsmHelper.calculateMethodHash(calleeMethodName, calleeMethodDesc); 252 ClassInfo classInfo = AsmClassInfo.getClassInfo(calleeClassName, m_loader); 253 ConstructorInfo calleeConstructorInfo = classInfo.getConstructor(joinPointHash); 254 if (calleeConstructorInfo == null) { 255 super.visitTypeInsn(opcode, desc); System.err.println( 257 "AW::WARNING " + 258 "metadata structure could not be build for method [" 259 + classInfo.getName().replace('/', '.') 260 + '.' + calleeMethodName + ':' + calleeMethodDesc + ']' 261 ); 262 return; 263 } 264 265 ExpressionContext ctx = new ExpressionContext( 267 PointcutType.CALL, calleeConstructorInfo, m_callerMemberInfo 268 ); 269 if (constructorFilter(m_ctx.getDefinitions(), ctx, calleeConstructorInfo)) { 270 m_newInvocationStructStack.push(null); 272 super.visitTypeInsn(opcode, desc); 273 } else { 274 newInvocationStruct.constructorInfo = calleeConstructorInfo; 276 newInvocationStruct.joinPointHash = joinPointHash; 277 m_newInvocationStructStack.push(newInvocationStruct); 278 m_skipNextDup = true; 280 } 282 } else { 283 super.visitTypeInsn(opcode, desc); 285 } 286 } 287 288 293 public void visitInsn(int opcode) { 294 if ((opcode == DUP || opcode == DUP_X1) && m_skipNextDup) { 295 ; if (opcode == DUP_X1) 298 super.visitInsn(DUP); 299 } else { 300 super.visitInsn(opcode); 301 } 302 m_skipNextDup = false; 303 } 304 305 313 public void visitMethodInsn(final int opcode, 314 final String calleeClassName, 315 final String calleeConstructorName, 316 final String calleeConstructorDesc) { 317 318 if (m_callerMemberInfo == null) { 319 super.visitMethodInsn(opcode, calleeClassName, calleeConstructorName, calleeConstructorDesc); 320 return; 321 } 322 323 if (!INIT_METHOD_NAME.equals(calleeConstructorName) || 324 calleeClassName.endsWith(AbstractJoinPointCompiler.JOIN_POINT_CLASS_SUFFIX)) { 325 super.visitMethodInsn(opcode, calleeClassName, calleeConstructorName, calleeConstructorDesc); 326 return; 327 } 328 329 if (m_newInvocationStructStack.isEmpty()) { 331 super.visitMethodInsn(opcode, calleeClassName, calleeConstructorName, calleeConstructorDesc); 333 return; 334 } 335 336 NewInvocationStruct struct = (NewInvocationStruct) m_newInvocationStructStack.pop(); 337 if (struct == null) { 338 super.visitMethodInsn(opcode, calleeClassName, calleeConstructorName, calleeConstructorDesc); 340 } else { 341 m_ctx.markAsAdvised(); 342 343 String joinPointClassName = TransformationUtil.getJoinPointClassName( 344 m_callerClassName, 345 m_callerMethodName, 346 m_callerMethodDesc, 347 calleeClassName, 348 JoinPointType.CONSTRUCTOR_CALL_INT, 349 struct.joinPointHash 350 ); 351 352 if (Modifier.isStatic(m_callerMemberInfo.getModifiers())) { 355 visitInsn(ACONST_NULL); 356 } else { 357 visitVarInsn(ALOAD, 0); 358 } 359 360 super.visitMethodInsn( 362 INVOKESTATIC, 363 joinPointClassName, 364 INVOKE_METHOD_NAME, 365 TransformationUtil.getInvokeSignatureForConstructorCallJoinPoints( 366 calleeConstructorDesc, 367 m_callerClassName, 368 calleeClassName 369 ) 370 ); 371 372 m_ctx.addEmittedJoinPoint( 374 new EmittedJoinPoint( 375 JoinPointType.CONSTRUCTOR_CALL_INT, 376 m_callerClassName, 377 m_callerMethodName, 378 m_callerMethodDesc, 379 m_callerMemberInfo.getModifiers(), 380 calleeClassName, 381 calleeConstructorName, 382 calleeConstructorDesc, 383 struct.constructorInfo.getModifiers(), 384 struct.joinPointHash, 385 joinPointClassName, 386 m_lastLabelForLineNumber 387 ) 388 ); 389 } 390 } 391 392 400 public boolean constructorFilter(final Set definitions, 401 final ExpressionContext ctx, 402 final ConstructorInfo calleeConstructorInfo) { 403 for (Iterator it = definitions.iterator(); it.hasNext();) { 404 if (((SystemDefinition) it.next()).hasPointcut(ctx)) { 405 return false; 406 } else { 407 continue; 408 } 409 } 410 return true; 411 } 412 } 413 414 private static int getMemberHash(String name, String desc) { 415 int hash = 29; 416 hash = (29 * hash) + name.hashCode(); 417 return (29 * hash) + desc.hashCode(); 418 } 419 420 431 public static class LookaheadNewDupInvokeSpecialInstructionClassAdapter 432 extends AsmAnnotationHelper.NullClassAdapter { 433 434 private String m_callerMemberName; 435 436 public TLongObjectHashMap m_newInvocationsByCallerMemberHash; 438 439 public LookaheadNewDupInvokeSpecialInstructionClassAdapter(TLongObjectHashMap newInvocations) { 440 m_newInvocationsByCallerMemberHash = newInvocations; 441 } 442 443 public CodeVisitor visitMethod(final int access, 444 final String name, 445 final String desc, 446 final String [] exceptions, 447 final Attribute attrs) { 448 if (name.startsWith(WRAPPER_METHOD_PREFIX) || 449 Modifier.isNative(access) || 450 Modifier.isAbstract(access)) { 451 ; } 453 454 m_callerMemberName = name; 455 456 TIntObjectHashMap newInvocations = new TIntObjectHashMap(5); 457 m_newInvocationsByCallerMemberHash.put(getMemberHash(name, desc), newInvocations); 458 return new LookaheadNewDupInvokeSpecialInstructionCodeAdapter( 459 super.visitMethod(access, name, desc, exceptions, attrs), 460 newInvocations, 461 m_callerMemberName 462 ); 463 } 464 } 465 466 public static class LookaheadNewDupInvokeSpecialInstructionCodeAdapter 467 extends AfterObjectInitializationCodeAdapter { 468 469 private TIntObjectHashMap m_newInvocations; 470 471 private Stack m_newIndexStack = new Stack (); 472 private int m_newIndex = -1; 473 474 477 public LookaheadNewDupInvokeSpecialInstructionCodeAdapter(CodeVisitor cv, TIntObjectHashMap newInvocations, 478 final String callerMemberName) { 479 super(cv, callerMemberName); 480 m_newInvocations = newInvocations; 481 } 482 483 public void visitTypeInsn(int opcode, String desc) { 484 super.visitTypeInsn(opcode, desc); 486 if (opcode == NEW) { 487 m_newIndex++; 488 m_newIndexStack.push(new Integer (m_newIndex)); 489 } 490 } 491 492 public void visitMethodInsn(final int opcode, 493 final String calleeClassName, 494 final String calleeMethodName, 495 final String calleeMethodDesc) { 496 super.visitMethodInsn(opcode, calleeClassName, calleeMethodName, calleeMethodDesc); 498 499 if (INIT_METHOD_NAME.equals(calleeMethodName) && opcode == INVOKESPECIAL) { 500 if (!m_isObjectInitialized) { 501 if (!m_newIndexStack.isEmpty()) { 503 m_newIndexStack.pop(); 504 } 505 } else { 506 if (!m_newIndexStack.isEmpty()) { 507 int index = ((Integer ) m_newIndexStack.pop()).intValue(); 508 NewInvocationStruct newInvocationStruct = new NewInvocationStruct(); 509 newInvocationStruct.className = calleeClassName; 510 newInvocationStruct.ctorDesc = calleeMethodDesc; 511 m_newInvocations.put(index, newInvocationStruct); 513 } 514 } 515 } 516 } 517 } 518 519 private static class NewInvocationStruct { 520 public String className; 521 public String ctorDesc; 522 public ConstructorInfo constructorInfo = null; 523 public int joinPointHash = -1; 524 } 525 526 } | Popular Tags |