private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
   // Avoid lock contention for known Methods through concurrent access...
   ShadowMatch shadowMatch = this.shadowMatchCache.get(targetMethod);
   if (shadowMatch == null) {
     synchronized (this.shadowMatchCache) {
       // Not found - now check again with full lock...
       PointcutExpression fallbackExpression = null;
       Method methodToMatch = targetMethod;
       shadowMatch = this.shadowMatchCache.get(targetMethod);
       if (shadowMatch == null) {
         try {
           shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
         } catch (ReflectionWorldException ex) {
           // Failed to introspect target method, probably because it has been loaded
           // in a special ClassLoader. Let's try the declaring ClassLoader instead...
           try {
             fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
             if (fallbackExpression != null) {
               shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
             }
           } catch (ReflectionWorldException ex2) {
             fallbackExpression = null;
           }
         }
         if (shadowMatch == null && targetMethod != originalMethod) {
           methodToMatch = originalMethod;
           try {
             shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
           } catch (ReflectionWorldException ex3) {
             // Could neither introspect the target class nor the proxy class ->
             // let's try the original method's declaring class before we give up...
             try {
               fallbackExpression =
                   getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
               if (fallbackExpression != null) {
                 shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
               }
             } catch (ReflectionWorldException ex4) {
               fallbackExpression = null;
             }
           }
         }
         if (shadowMatch == null) {
           shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
         } else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
           shadowMatch =
               new DefensiveShadowMatch(
                   shadowMatch, fallbackExpression.matchesMethodExecution(methodToMatch));
         }
         this.shadowMatchCache.put(targetMethod, shadowMatch);
       }
     }
   }
   return shadowMatch;
 }
 @Override
 public boolean matches(Class<?> targetClass) {
   checkReadyToMatch();
   try {
     try {
       return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
     } catch (ReflectionWorldException ex) {
       logger.debug(
           "PointcutExpression matching rejected target class - trying fallback expression", ex);
       // Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough
       // yet
       PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
       if (fallbackExpression != null) {
         return fallbackExpression.couldMatchJoinPointsInType(targetClass);
       }
     }
   } catch (BCException ex) {
     logger.debug("PointcutExpression matching rejected target class", ex);
   }
   return false;
 }