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; } } }