Search in sources :

Example 1 with ParameterFilterDelegate

use of org.spongepowered.common.event.filter.delegate.ParameterFilterDelegate in project SpongeCommon by SpongePowered.

the class FilterGenerator method generateClass.

public byte[] generateClass(String name, Method method) {
    name = name.replace('.', '/');
    Parameter[] params = method.getParameters();
    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;
    List<FilterDelegate> additional = Lists.newArrayList();
    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) {
            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
        int[] plocals = new int[params.length - 1];
        for (int i = 1; i < params.length; i++) {
            Parameter param = params[i];
            ParameterFilterSourceDelegate source = null;
            List<ParameterFilterDelegate> paramFilters = Lists.newArrayList();
            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() + ")");
            }
            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();
    byte[] data = cw.toByteArray();
    if (FILTER_DEBUG) {
        File outDir = new File(".sponge.debug.out");
        File outFile = new File(outDir, name + ".class");
        if (!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }
        try (FileOutputStream out = new FileOutputStream(outFile)) {
            out.write(data);
        } catch (IOException ignored) {
            ignored.printStackTrace();
        }
    }
    return data;
}
Also used : CancellationEventFilterDelegate(org.spongepowered.common.event.filter.delegate.CancellationEventFilterDelegate) Cancellable(org.spongepowered.api.event.Cancellable) ParameterFilterDelegate(org.spongepowered.common.event.filter.delegate.ParameterFilterDelegate) MethodVisitor(org.objectweb.asm.MethodVisitor) List(java.util.List) SubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.SubtypeFilterDelegate) SupportsDataFilterDelegate(org.spongepowered.common.event.filter.delegate.SupportsDataFilterDelegate) IncludeSubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.IncludeSubtypeFilterDelegate) FilterDelegate(org.spongepowered.common.event.filter.delegate.FilterDelegate) ParameterFilterDelegate(org.spongepowered.common.event.filter.delegate.ParameterFilterDelegate) HasDataFilterDelegate(org.spongepowered.common.event.filter.delegate.HasDataFilterDelegate) ExcludeSubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.ExcludeSubtypeFilterDelegate) CancellationEventFilterDelegate(org.spongepowered.common.event.filter.delegate.CancellationEventFilterDelegate) ParameterFilterSourceDelegate(org.spongepowered.common.event.filter.delegate.ParameterFilterSourceDelegate) AllCauseFilterSourceDelegate(org.spongepowered.common.event.filter.delegate.AllCauseFilterSourceDelegate) IOException(java.io.IOException) ClassWriter(org.objectweb.asm.ClassWriter) Annotation(java.lang.annotation.Annotation) SubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.SubtypeFilterDelegate) IncludeSubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.IncludeSubtypeFilterDelegate) ExcludeSubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.ExcludeSubtypeFilterDelegate) Type(org.objectweb.asm.Type) FileOutputStream(java.io.FileOutputStream) Parameter(java.lang.reflect.Parameter) Event(org.spongepowered.api.event.Event) File(java.io.File) Tuple(org.spongepowered.api.util.Tuple)

Aggregations

File (java.io.File)1 FileOutputStream (java.io.FileOutputStream)1 IOException (java.io.IOException)1 Annotation (java.lang.annotation.Annotation)1 Parameter (java.lang.reflect.Parameter)1 List (java.util.List)1 ClassWriter (org.objectweb.asm.ClassWriter)1 MethodVisitor (org.objectweb.asm.MethodVisitor)1 Type (org.objectweb.asm.Type)1 Cancellable (org.spongepowered.api.event.Cancellable)1 Event (org.spongepowered.api.event.Event)1 Tuple (org.spongepowered.api.util.Tuple)1 AllCauseFilterSourceDelegate (org.spongepowered.common.event.filter.delegate.AllCauseFilterSourceDelegate)1 CancellationEventFilterDelegate (org.spongepowered.common.event.filter.delegate.CancellationEventFilterDelegate)1 ExcludeSubtypeFilterDelegate (org.spongepowered.common.event.filter.delegate.ExcludeSubtypeFilterDelegate)1 FilterDelegate (org.spongepowered.common.event.filter.delegate.FilterDelegate)1 HasDataFilterDelegate (org.spongepowered.common.event.filter.delegate.HasDataFilterDelegate)1 IncludeSubtypeFilterDelegate (org.spongepowered.common.event.filter.delegate.IncludeSubtypeFilterDelegate)1 ParameterFilterDelegate (org.spongepowered.common.event.filter.delegate.ParameterFilterDelegate)1 ParameterFilterSourceDelegate (org.spongepowered.common.event.filter.delegate.ParameterFilterSourceDelegate)1