private void installFieldRequests(final Shadow.Kind kind, final RequestContext context) {
    // No point in tracking cflow state in these, since get()/set() joinpoints
    // never contain any other joinpoints.
    if (advice.getKind().isCflow()) {
      return;
    }

    // TODO-RS: Optimize for the exact field match case

    // Copy the state to make sure the class prepare callback
    // reads the right state.
    forAllWovenClasses(
        new Callback<ClassMirror>() {
          public ClassMirror handle(ClassMirror klass) {
            ReferenceType type = (ReferenceType) world.resolve(klass);
            for (ResolvedMember field : type.getDeclaredFields()) {
              boolean matches = true;
              for (PatternNode targetPattern : context.targetFilters) {
                if (targetPattern instanceof SignaturePattern) {
                  if (!(((SignaturePattern) targetPattern).matches(field, world, false))) {
                    matches = false;
                    break;
                  }
                }
              }
              if (matches) {
                FieldMirrorMember member = (FieldMirrorMember) field;
                MirrorEventRequest request;
                FieldMirror fieldMirror = member.getField();
                if (advice.getKind() == AdviceKind.Around) {
                  if (kind.bit == Shadow.FieldSetBit) {
                    request =
                        manager.createFieldMirrorSetHandlerRequest(
                            fieldMirror.getDeclaringClass().getClassName(), fieldMirror.getName());
                  } else {
                    request =
                        manager.createFieldMirrorGetHandlerRequest(
                            fieldMirror.getDeclaringClass().getClassName(), fieldMirror.getName());
                  }
                } else if (advice.getKind() == AdviceKind.Before) {
                  if (kind.bit == Shadow.FieldSetBit) {
                    request =
                        manager.createFieldMirrorSetRequest(
                            fieldMirror.getDeclaringClass().getClassName(), fieldMirror.getName());
                  } else {
                    request =
                        manager.createFieldMirrorGetRequest(
                            fieldMirror.getDeclaringClass().getClassName(), fieldMirror.getName());
                  }
                } else {
                  throw new IllegalArgumentException("After advice on field get/set not supported");
                }
                addFiltersAndInstall(request, context.targetFilters, kind, context);
              }
            }

            return klass;
          };
        });
  }
 private void forAllWovenClasses(final Callback<ClassMirror> callback) {
   // TODO: reuse ShadowMunger.match() by faking a shadow
   final TypePattern scoped = world.getAspectScope(advice.getDeclaringType());
   world
       .vm
       .dispatch()
       .forAllClasses(
           new Callback<ClassMirror>() {
             public ClassMirror handle(ClassMirror klass) {
               if (scoped == null
                   || scoped.matches(world.resolve(klass), TypePattern.STATIC).alwaysTrue()) {
                 return callback.handle(klass);
               } else {
                 return klass;
               }
             }
           });
 }
 public static void installCallback(MirrorWorld world, Advice advice) {
   PointcutMirrorRequestExtractor extractor = new PointcutMirrorRequestExtractor(world, advice);
   Pointcut dnf = new PointcutRewriter().rewrite(advice.getPointcut());
   extractor.visit(dnf, null, new RequestContext());
 }
  private void installSynchronizationRequests(
      final Shadow.Kind kind, final RequestContext context) {
    // No point in tracking cflow state in these, since lock()/unlock() joinpoints
    // never contain any other joinpoints.
    if (advice.getKind().isCflow()) {
      return;
    }

    // TODO-RS: This isn't perfect, since I'm only supporting execution() shadows
    // at the moment, which implies that only after: lock() and before: unlock() work.
    // Realistically it doesn't matter unless the code queries the thread state in very specific
    // ways.
    forAllWovenClasses(
        new Callback<ClassMirror>() {
          public ClassMirror handle(ClassMirror klass) {
            ReferenceType type = (ReferenceType) world.resolve(klass);

            // These are handled in two parts:
            // 1. Delegate to handling the pointcut call(synchronized * *.*(..)), to
            //    catch all synchronized methods.
            for (ResolvedMember method : type.getDeclaredMethods()) {
              if (Modifier.isSynchronized(method.getModifiers())) {
                MethodMirrorMember member = (MethodMirrorMember) method;
                MirrorEventRequest request;
                MethodMirror methodMirror = (MethodMirror) member.getMethod();

                if (advice.getKind() == AdviceKind.Before && kind == Shadow.SynchronizationLock) {
                  MethodMirrorEntryRequest mmer = manager.createMethodMirrorEntryRequest();
                  mmer.setMethodFilter(
                      methodMirror.getDeclaringClass().getClassName(),
                      methodMirror.getName(),
                      methodMirror.getParameterTypeNames());
                  request = mmer;
                } else if (advice.getKind().isAfter() && kind == Shadow.SynchronizationUnlock) {
                  MethodMirrorExitRequest mmer = manager.createMethodMirrorExitRequest();
                  mmer.setMethodFilter(
                      methodMirror.getDeclaringClass().getClassName(),
                      methodMirror.getName(),
                      methodMirror.getParameterTypeNames());
                  request = mmer;
                } else {
                  throw new IllegalArgumentException(
                      "Unsupported lock()/unlock() advice kind: " + advice);
                }
                addFiltersAndInstall(request, context.thisFilters, kind, context);
              }
            }

            // 2. Search through the bytecode for MONITORENTER/EXIT instructions,
            //    and create breakpoints for each.
            try {
              Map<MethodMirror, Method> bcelMethods = null;
              for (MethodMirror methodMirror : klass.getDeclaredMethods(false)) {
                int modifiers = methodMirror.getModifiers();
                if (Modifier.isNative(modifiers)
                    || Modifier.isAbstract(modifiers)
                    || (modifiers & Opcodes.ACC_BRIDGE) != 0) {
                  continue;
                }

                byte[] bytecode;
                try {
                  bytecode = methodMirror.getBytecode();
                } catch (UnsupportedOperationException e) {
                  if (bcelMethods == null) {
                    bcelMethods = new HashMap<MethodMirror, Method>();
                    JavaClass bcelClass =
                        new ClassParser(new ByteArrayInputStream(klass.getBytecode()), "").parse();
                    for (Method method : bcelClass.getMethods()) {
                      try {
                        String name = method.getName();
                        if (!name.equals("<init>")) {
                          MethodMirror thisMirror =
                              Reflection.getDeclaredMethod(
                                  klass, name, Type.getMethodType(method.getSignature()));
                          bcelMethods.put(thisMirror, method);
                        }
                      } catch (NoSuchMethodException e1) {
                        throw new RuntimeException(e1);
                      }
                    }
                  }
                  bytecode = bcelMethods.get(methodMirror).getCode().getCode();
                }

                InstructionList insnList = new InstructionList(bytecode);
                for (InstructionHandle handle : insnList.getInstructionHandles()) {
                  short opcode = handle.getInstruction().getOpcode();
                  if ((kind == Shadow.SynchronizationLock && opcode == Opcodes.MONITORENTER)
                      || (kind == Shadow.SynchronizationUnlock && opcode == Opcodes.MONITOREXIT)) {
                    int offset = handle.getPosition();
                    installMonitorRequests(kind, methodMirror, offset);
                  }
                }
              }

            } catch (ClassFormatException | IOException | SecurityException e) {
              throw new RuntimeException(e);
            }

            return klass;
          };
        });
  }
 private void installRequest(RequestContext context) {
   AdviceKind adviceKind = advice.getKind();
   for (final Shadow.Kind kind : Shadow.toSet(context.kinds)) {
     switch (kind.bit) {
       case (Shadow.MethodExecutionBit):
       case (Shadow.MethodCallBit):
         // If there are no filters at all, it's much more efficient to create single request
         if (context.thisFilters.isEmpty()) {
           if (adviceKind == AdviceKind.Before || adviceKind.isCflow()) {
             addFiltersAndInstall(
                 manager.createMethodMirrorHandlerRequest(), context.thisFilters, kind, context);
           }
           if (adviceKind.isAfter()) {
             addFiltersAndInstall(
                 manager.createMethodMirrorHandlerRequest(), context.thisFilters, kind, context);
           }
           if (adviceKind == AdviceKind.Around) {
             addFiltersAndInstall(
                 manager.createMethodMirrorHandlerRequest(), context.thisFilters, kind, context);
           }
         } else {
           installMethodRequests(kind, context);
         }
         break;
       case (Shadow.ConstructorExecutionBit):
       case (Shadow.ConstructorCallBit):
         if (adviceKind == AdviceKind.Before || adviceKind.isCflow()) {
           addFiltersAndInstall(
               manager.createConstructorMirrorHandlerRequest(),
               context.thisFilters,
               kind,
               context);
         }
         if (adviceKind.isAfter()) {
           addFiltersAndInstall(
               manager.createConstructorMirrorHandlerRequest(),
               context.thisFilters,
               kind,
               context);
         }
         if (adviceKind == AdviceKind.Around) {
           addFiltersAndInstall(
               manager.createConstructorMirrorHandlerRequest(),
               context.thisFilters,
               kind,
               context);
         }
         break;
       case (Shadow.FieldSetBit):
       case (Shadow.FieldGetBit):
         installFieldRequests(kind, context);
         break;
       case Shadow.SynchronizationLockBit:
       case Shadow.SynchronizationUnlockBit:
         installSynchronizationRequests(kind, context);
         break;
       case Shadow.AdviceExecutionBit:
       case Shadow.InitializationBit:
       case Shadow.PreInitializationBit:
       case Shadow.ExceptionHandlerBit:
         world.showMessage(IMessage.WARNING, "Unsupported pointcut kind: " + kind, null, null);
         break;
     }
   }
 }