Search in sources :

Example 1 with FilterDelegate

use of org.lanternpowered.server.event.filter.delegate.FilterDelegate in project LanternServer by LanternPowered.

the class FilterGenerator method generateClass.

byte[] generateClass(String name, Method method) {
    name = name.replace('.', '/');
    final Parameter[] params = method.getParameters();
    final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
    MethodVisitor mv;
    cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, name, null, "java/lang/Object", new String[] { Type.getInternalName(EventFilter.class) });
    SubtypeFilterDelegate sfilter = null;
    final List<FilterDelegate> additional = new ArrayList<>();
    boolean cancellation = false;
    for (Annotation anno : method.getAnnotations()) {
        Object obj = filterFromAnnotation(anno.annotationType());
        if (obj == null) {
            continue;
        }
        if (obj instanceof SubtypeFilter) {
            if (sfilter != null) {
                throw new IllegalStateException("Cannot have both @Include and @Exclude annotations present at once");
            }
            sfilter = ((SubtypeFilter) obj).getDelegate(anno);
        } else if (obj instanceof EventTypeFilter) {
            final EventTypeFilter etf = (EventTypeFilter) obj;
            additional.add(etf.getDelegate(anno));
            if (etf == EventTypeFilter.CANCELLATION) {
                cancellation = true;
            }
        }
    }
    if (!cancellation && Cancellable.class.isAssignableFrom(method.getParameterTypes()[0])) {
        additional.add(new CancellationEventFilterDelegate(Tristate.FALSE));
    }
    if (sfilter != null) {
        sfilter.createFields(cw);
    }
    {
        mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
        if (sfilter != null) {
            sfilter.writeCtor(name, cw, mv);
        }
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    {
        mv = cw.visitMethod(ACC_PUBLIC, "filter", "(" + Type.getDescriptor(Event.class) + ")[Ljava/lang/Object;", null, null);
        mv.visitCode();
        // index of the next available local variable
        int local = 2;
        if (sfilter != null) {
            local = sfilter.write(name, cw, mv, method, local);
        }
        for (FilterDelegate eventFilter : additional) {
            local = eventFilter.write(name, cw, mv, method, local);
        }
        // local var indices of the parameters values
        final int[] plocals = new int[params.length - 1];
        for (int i = 1; i < params.length; i++) {
            final Parameter param = params[i];
            ParameterFilterSourceDelegate source = null;
            final List<ParameterFilterDelegate> paramFilters = new ArrayList<>();
            for (Annotation anno : param.getAnnotations()) {
                Object obj = filterFromAnnotation(anno.annotationType());
                if (obj == null) {
                    continue;
                }
                if (obj instanceof ParameterSource) {
                    if (source != null) {
                        throw new IllegalStateException("Cannot have multiple parameter filter source annotations (for " + param.getName() + ")");
                    }
                    source = ((ParameterSource) obj).getDelegate(anno);
                } else if (obj instanceof ParameterFilter) {
                    paramFilters.add(((ParameterFilter) obj).getDelegate(anno));
                }
            }
            if (source == null) {
                throw new IllegalStateException("Cannot have additional parameters filters without a source (for " + param.getName() + ")");
            }
            if (source instanceof AllCauseFilterSourceDelegate && !paramFilters.isEmpty()) {
                // TODO until better handling for filtering arrays is added
                throw new IllegalStateException("Cannot have additional parameters filters without an array source (for " + param.getName() + ")");
            }
            final Tuple<Integer, Integer> localState = source.write(cw, mv, method, param, local);
            local = localState.getFirst();
            plocals[i - 1] = localState.getSecond();
            for (ParameterFilterDelegate paramFilter : paramFilters) {
                paramFilter.write(cw, mv, method, param, plocals[i - 1]);
            }
        }
        // create the return array
        if (params.length == 1) {
            mv.visitInsn(ICONST_1);
        } else {
            mv.visitIntInsn(BIPUSH, params.length);
        }
        mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
        // load the event into the array
        mv.visitInsn(DUP);
        mv.visitInsn(ICONST_0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitInsn(AASTORE);
        // load all the params into the array
        for (int i = 1; i < params.length; i++) {
            mv.visitInsn(DUP);
            mv.visitIntInsn(BIPUSH, i);
            Type paramType = Type.getType(params[i].getType());
            mv.visitVarInsn(paramType.getOpcode(ILOAD), plocals[i - 1]);
            GeneratorUtils.visitBoxingMethod(mv, paramType);
            mv.visitInsn(AASTORE);
        }
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    cw.visitEnd();
    final byte[] data = cw.toByteArray();
    if (FILTER_DEBUG) {
        final Path outDir = Paths.get(".sponge.debug.out");
        final Path outFile = outDir.resolve(name + ".class");
        if (!Files.exists(outFile.getParent())) {
            try {
                Files.createDirectories(outFile.getParent());
            } catch (IOException e) {
                Lantern.getLogger().warn("Unable to create the filter debug directory.", e);
            }
        }
        try (final OutputStream out = Files.newOutputStream(outFile)) {
            out.write(data);
        } catch (IOException e) {
            Lantern.getLogger().warn("Unable to create the filter debug class.", e);
        }
    }
    return data;
}
Also used : CancellationEventFilterDelegate(org.lanternpowered.server.event.filter.delegate.CancellationEventFilterDelegate) Cancellable(org.spongepowered.api.event.Cancellable) OutputStream(java.io.OutputStream) ArrayList(java.util.ArrayList) ParameterFilterDelegate(org.lanternpowered.server.event.filter.delegate.ParameterFilterDelegate) MethodVisitor(org.objectweb.asm.MethodVisitor) List(java.util.List) ArrayList(java.util.ArrayList) Path(java.nio.file.Path) FilterDelegate(org.lanternpowered.server.event.filter.delegate.FilterDelegate) IncludeSubtypeFilterDelegate(org.lanternpowered.server.event.filter.delegate.IncludeSubtypeFilterDelegate) CancellationEventFilterDelegate(org.lanternpowered.server.event.filter.delegate.CancellationEventFilterDelegate) SubtypeFilterDelegate(org.lanternpowered.server.event.filter.delegate.SubtypeFilterDelegate) SupportsDataFilterDelegate(org.lanternpowered.server.event.filter.delegate.SupportsDataFilterDelegate) ParameterFilterDelegate(org.lanternpowered.server.event.filter.delegate.ParameterFilterDelegate) HasDataFilterDelegate(org.lanternpowered.server.event.filter.delegate.HasDataFilterDelegate) ExcludeSubtypeFilterDelegate(org.lanternpowered.server.event.filter.delegate.ExcludeSubtypeFilterDelegate) ParameterFilterSourceDelegate(org.lanternpowered.server.event.filter.delegate.ParameterFilterSourceDelegate) AllCauseFilterSourceDelegate(org.lanternpowered.server.event.filter.delegate.AllCauseFilterSourceDelegate) IOException(java.io.IOException) ClassWriter(org.objectweb.asm.ClassWriter) Annotation(java.lang.annotation.Annotation) IncludeSubtypeFilterDelegate(org.lanternpowered.server.event.filter.delegate.IncludeSubtypeFilterDelegate) SubtypeFilterDelegate(org.lanternpowered.server.event.filter.delegate.SubtypeFilterDelegate) ExcludeSubtypeFilterDelegate(org.lanternpowered.server.event.filter.delegate.ExcludeSubtypeFilterDelegate) Type(org.objectweb.asm.Type) Parameter(java.lang.reflect.Parameter) Event(org.spongepowered.api.event.Event) Tuple(org.spongepowered.api.util.Tuple)

Aggregations

IOException (java.io.IOException)1 OutputStream (java.io.OutputStream)1 Annotation (java.lang.annotation.Annotation)1 Parameter (java.lang.reflect.Parameter)1 Path (java.nio.file.Path)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 AllCauseFilterSourceDelegate (org.lanternpowered.server.event.filter.delegate.AllCauseFilterSourceDelegate)1 CancellationEventFilterDelegate (org.lanternpowered.server.event.filter.delegate.CancellationEventFilterDelegate)1 ExcludeSubtypeFilterDelegate (org.lanternpowered.server.event.filter.delegate.ExcludeSubtypeFilterDelegate)1 FilterDelegate (org.lanternpowered.server.event.filter.delegate.FilterDelegate)1 HasDataFilterDelegate (org.lanternpowered.server.event.filter.delegate.HasDataFilterDelegate)1 IncludeSubtypeFilterDelegate (org.lanternpowered.server.event.filter.delegate.IncludeSubtypeFilterDelegate)1 ParameterFilterDelegate (org.lanternpowered.server.event.filter.delegate.ParameterFilterDelegate)1 ParameterFilterSourceDelegate (org.lanternpowered.server.event.filter.delegate.ParameterFilterSourceDelegate)1 SubtypeFilterDelegate (org.lanternpowered.server.event.filter.delegate.SubtypeFilterDelegate)1 SupportsDataFilterDelegate (org.lanternpowered.server.event.filter.delegate.SupportsDataFilterDelegate)1 ClassWriter (org.objectweb.asm.ClassWriter)1 MethodVisitor (org.objectweb.asm.MethodVisitor)1 Type (org.objectweb.asm.Type)1