Search in sources :

Example 86 with ClassWriter

use of org.objectweb.asm.ClassWriter in project saral by PaulNoth.

the class ByteCodeGenerator method generateByteCode.

public byte[] generateByteCode(Init compilationUnit) {
    String name = compilationUnit.getScope().getClassName();
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES + ClassWriter.COMPUTE_MAXS);
    cw.visit(CLASS_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, name, null, "java/lang/Object", null);
    InitGenerator initGenerator = new InitGenerator(cw);
    return initGenerator.generate(compilationUnit).toByteArray();
}
Also used : ClassWriter(org.objectweb.asm.ClassWriter)

Example 87 with ClassWriter

use of org.objectweb.asm.ClassWriter 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)

Example 88 with ClassWriter

use of org.objectweb.asm.ClassWriter in project LanternServer by LanternPowered.

the class ClassEventListenerFactory method generateClass.

private static byte[] generateClass(String name, Class<?> handle, Method method, Class<?> eventClass, Class<? extends EventFilter> filter) {
    name = name.replace('.', '/');
    final String handleName = Type.getInternalName(handle);
    final String handleDescriptor = Type.getDescriptor(handle);
    final String filterName = Type.getInternalName(filter);
    String eventDescriptor = "(";
    for (int i = 0; i < method.getParameterCount(); i++) {
        eventDescriptor += Type.getDescriptor(method.getParameterTypes()[i]);
    }
    eventDescriptor += ")V";
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
    MethodVisitor mv;
    FieldVisitor fv;
    cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, name, null, BASE_HANDLER, null);
    {
        fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, "FILTER", "L" + filterName + ";", null, null);
        fv.visitEnd();
    }
    {
        mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
        mv.visitCode();
        mv.visitTypeInsn(NEW, filterName);
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, filterName, "<init>", "()V", false);
        mv.visitFieldInsn(PUTSTATIC, name, "FILTER", "L" + filterName + ";");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    {
        mv = cw.visitMethod(ACC_PUBLIC, "<init>", '(' + handleDescriptor + ")V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(INVOKESPECIAL, BASE_HANDLER, "<init>", "(Ljava/lang/Object;)V", false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    {
        mv = cw.visitMethod(ACC_PUBLIC, "handle", HANDLE_METHOD_DESCRIPTOR, null, new String[] { "java/lang/Exception" });
        mv.visitCode();
        mv.visitFieldInsn(GETSTATIC, name, "FILTER", "L" + filterName + ";");
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(EventFilter.class), "filter", FILTER_DESCRIPTOR, true);
        mv.visitVarInsn(ASTORE, 2);
        mv.visitVarInsn(ALOAD, 2);
        Label l2 = new Label();
        mv.visitJumpInsn(IFNULL, l2);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, name, "handle", "Ljava/lang/Object;");
        mv.visitTypeInsn(CHECKCAST, handleName);
        for (int i = 0; i < method.getParameterCount(); i++) {
            mv.visitVarInsn(ALOAD, 2);
            mv.visitIntInsn(BIPUSH, i);
            mv.visitInsn(AALOAD);
            Type paramType = Type.getType(method.getParameterTypes()[i]);
            GeneratorUtils.visitUnboxingMethod(mv, paramType);
        }
        mv.visitMethodInsn(INVOKEVIRTUAL, handleName, method.getName(), eventDescriptor, false);
        mv.visitLabel(l2);
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    cw.visitEnd();
    return cw.toByteArray();
}
Also used : Type(org.objectweb.asm.Type) Label(org.objectweb.asm.Label) FieldVisitor(org.objectweb.asm.FieldVisitor) ClassWriter(org.objectweb.asm.ClassWriter) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 89 with ClassWriter

use of org.objectweb.asm.ClassWriter in project LanternServer by LanternPowered.

the class InventoryConstructorFactory method generateCarriedClass.

/**
 * Gets the generated class for the target class that
 * also implements {@link CarriedInventory}.
 *
 * @param inventoryType The inventory type
 * @return The carried inventory type
 */
private Class<? extends AbstractInventory> generateCarriedClass(Class<? extends AbstractInventory> inventoryType) {
    final String name = inventoryType.getName() + "$$Carried";
    final String className = name.replace('.', '/');
    // Generate the class bytecode and load it
    final ClassWriter cw = new ClassWriter(0);
    final String superName = Type.getInternalName(inventoryType);
    cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, className, String.format("L%s;L%s<L%s;>;", superName, CARRIED_INVENTORY_NAME, CARRIER_NAME), superName, new String[] { CARRIED_INVENTORY_NAME });
    final FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, CARRIER_REF_FIELD, CARRIER_REFERENCE_DESC, String.format("L%s<L%s;>;", CARRIER_REFERENCE_NAME, CARRIER_NAME), null);
    fv.visitEnd();
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
    mv.visitCode();
    mv.visitVarInsn(ALOAD, 0);
    mv.visitMethodInsn(INVOKESPECIAL, superName, "<init>", "()V", false);
    mv.visitVarInsn(ALOAD, 0);
    mv.visitLdcInsn(Type.getType(CARRIER_DESC));
    mv.visitMethodInsn(INVOKESTATIC, CARRIER_REFERENCE_NAME, "of", String.format("(Ljava/lang/Class;)L%s;", CARRIER_REFERENCE_NAME), true);
    mv.visitFieldInsn(PUTFIELD, className, CARRIER_REF_FIELD, CARRIER_REFERENCE_DESC);
    mv.visitInsn(RETURN);
    mv.visitMaxs(2, 1);
    mv.visitEnd();
    mv = cw.visitMethod(ACC_PROTECTED, "setCarrier", String.format("(L%s;)V", CARRIER_NAME), null, null);
    mv.visitCode();
    mv.visitVarInsn(ALOAD, 0);
    mv.visitVarInsn(ALOAD, 1);
    mv.visitMethodInsn(INVOKESPECIAL, superName, "setCarrier", String.format("(L%s;)V", CARRIER_NAME), false);
    mv.visitVarInsn(ALOAD, 0);
    mv.visitFieldInsn(GETFIELD, className, CARRIER_REF_FIELD, CARRIER_REFERENCE_DESC);
    mv.visitVarInsn(ALOAD, 1);
    mv.visitMethodInsn(INVOKEINTERFACE, CARRIER_REFERENCE_NAME, "set", String.format("(L%s;)V", CARRIER_NAME), true);
    mv.visitInsn(RETURN);
    mv.visitMaxs(2, 2);
    mv.visitEnd();
    mv = cw.visitMethod(ACC_PUBLIC, "getCarrier", "()Ljava/util/Optional;", String.format("()Ljava/util/Optional<L%s;>;", CARRIER_NAME), null);
    mv.visitCode();
    mv.visitVarInsn(ALOAD, 0);
    mv.visitFieldInsn(GETFIELD, className, CARRIER_REF_FIELD, CARRIER_REFERENCE_DESC);
    mv.visitMethodInsn(INVOKEINTERFACE, CARRIER_REFERENCE_NAME, "get", "()Ljava/util/Optional;", true);
    mv.visitInsn(ARETURN);
    mv.visitMaxs(1, 1);
    mv.visitEnd();
    cw.visitEnd();
    return this.classLoader.defineClass(name, cw.toByteArray());
}
Also used : FieldVisitor(org.objectweb.asm.FieldVisitor) ClassWriter(org.objectweb.asm.ClassWriter) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 90 with ClassWriter

use of org.objectweb.asm.ClassWriter in project LanternServer by LanternPowered.

the class FieldAccessFactory method createSetter.

/**
 * Creates a setter {@link BiConsumer} for the given {@link Field}.
 *
 * @param field The field
 * @param <T> The target object type
 * @param <V> The field value type
 * @return The bi consumer
 */
public static <T, V> BiConsumer<T, V> createSetter(Field field) {
    checkNotNull(field, "field");
    field.setAccessible(true);
    boolean isFinal = Modifier.isFinal(field.getModifiers());
    // Better check is somebody changed the final modifier already
    if (!isFinal) {
        final Field[] fields = field.getDeclaringClass().getDeclaredFields();
        boolean isFound = false;
        for (Field field1 : fields) {
            // The same signature, now check if somebody tinkered with the field
            if (field.getName().equals(field1.getName()) && field.getType().equals(field1.getType())) {
                isFinal = Modifier.isFinal(field1.getModifiers());
                isFound = true;
                break;
            }
        }
        if (!isFound) {
            throw new IllegalStateException("Something funky happened with: " + field.getName());
        }
    } else {
        try {
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
    }
    // Final fields don't allow direct access, so MethodHandles will do the trick.
    if (isFinal) {
        try {
            final MethodHandle methodHandle = MethodHandleMagic.trustedLookup().in(field.getDeclaringClass()).unreflectSetter(field).asType(setterMethodType);
            return (a, b) -> {
                try {
                    methodHandle.invokeExact(a, b);
                } catch (Throwable throwable) {
                    throw new IllegalStateException(throwable);
                }
            };
        } catch (IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
    }
    final ClassWriter cw = new ClassWriter(0);
    final String className = field.getName().replace('.', '/') + "$$LanternSetter$" + setterCounter.incrementAndGet();
    cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, className, "Ljava/lang/Object;Ljava/util/function/BiConsumer<Ljava/lang/Object;Ljava/lang/Object;>;", "java/lang/Object", new String[] { "java/util/function/BiConsumer" });
    // Add a empty constructor
    BytecodeUtils.visitEmptyConstructor(cw);
    // Generate the apply method
    final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "accept", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null);
    mv.visitCode();
    final String descriptor = Type.getDescriptor(field.getType());
    final String targetName = Type.getInternalName(field.getDeclaringClass());
    final boolean isStatic = Modifier.isStatic(field.getModifiers());
    if (!isStatic) {
        // Load the target parameter
        mv.visitVarInsn(ALOAD, 1);
        // Cast it
        mv.visitTypeInsn(CHECKCAST, targetName);
    }
    // Load the value parameter
    mv.visitVarInsn(ALOAD, 2);
    // Unbox the values in case they are primitives, otherwise cast
    GeneratorUtils.visitUnboxingMethod(mv, Type.getType(field.getType()));
    // Put the value into the field
    if (isStatic) {
        mv.visitFieldInsn(PUTSTATIC, targetName, field.getName(), descriptor);
    } else {
        mv.visitFieldInsn(PUTFIELD, targetName, field.getName(), descriptor);
    }
    // Return
    mv.visitInsn(RETURN);
    mv.visitMaxs(2, 3);
    mv.visitEnd();
    // Finish class generation
    cw.visitEnd();
    // Define the class and create a function instance
    final MethodHandles.Lookup lookup = MethodHandleMagic.trustedLookup().in(field.getDeclaringClass());
    final Class<?> functionClass = MethodHandleMagic.defineNestmateClass(lookup, cw.toByteArray());
    try {
        return (BiConsumer<T, V>) functionClass.newInstance();
    } catch (Exception e) {
        throw new IllegalStateException("Something went wrong!", e);
    }
}
Also used : ClassWriter(org.objectweb.asm.ClassWriter) MethodHandle(java.lang.invoke.MethodHandle) MethodVisitor(org.objectweb.asm.MethodVisitor) ACC_SUPER(org.objectweb.asm.Opcodes.ACC_SUPER) GETSTATIC(org.objectweb.asm.Opcodes.GETSTATIC) GeneratorUtils(org.spongepowered.api.util.generator.GeneratorUtils) V1_8(org.objectweb.asm.Opcodes.V1_8) Type(org.objectweb.asm.Type) Function(java.util.function.Function) Supplier(java.util.function.Supplier) PUTFIELD(org.objectweb.asm.Opcodes.PUTFIELD) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) BiConsumer(java.util.function.BiConsumer) CHECKCAST(org.objectweb.asm.Opcodes.CHECKCAST) MethodHandles(java.lang.invoke.MethodHandles) Preconditions.checkNotNull(com.google.common.base.Preconditions.checkNotNull) Field(java.lang.reflect.Field) Preconditions.checkState(com.google.common.base.Preconditions.checkState) GETFIELD(org.objectweb.asm.Opcodes.GETFIELD) Consumer(java.util.function.Consumer) MethodType(java.lang.invoke.MethodType) RETURN(org.objectweb.asm.Opcodes.RETURN) ACC_PUBLIC(org.objectweb.asm.Opcodes.ACC_PUBLIC) PUTSTATIC(org.objectweb.asm.Opcodes.PUTSTATIC) Modifier(java.lang.reflect.Modifier) ARETURN(org.objectweb.asm.Opcodes.ARETURN) ALOAD(org.objectweb.asm.Opcodes.ALOAD) ClassWriter(org.objectweb.asm.ClassWriter) MethodVisitor(org.objectweb.asm.MethodVisitor) Field(java.lang.reflect.Field) MethodHandles(java.lang.invoke.MethodHandles) BiConsumer(java.util.function.BiConsumer) MethodHandle(java.lang.invoke.MethodHandle)

Aggregations

ClassWriter (org.objectweb.asm.ClassWriter)502 ClassReader (org.objectweb.asm.ClassReader)285 MethodVisitor (org.objectweb.asm.MethodVisitor)127 Test (org.junit.Test)99 ClassVisitor (org.objectweb.asm.ClassVisitor)88 ClassNode (org.objectweb.asm.tree.ClassNode)70 IOException (java.io.IOException)62 Label (org.objectweb.asm.Label)55 SemanticVersioningClassVisitor (org.apache.aries.versioning.utils.SemanticVersioningClassVisitor)52 HashSet (java.util.HashSet)37 Method (java.lang.reflect.Method)36 Type (org.objectweb.asm.Type)33 BinaryCompatibilityStatus (org.apache.aries.versioning.utils.BinaryCompatibilityStatus)32 File (java.io.File)30 InvocationTargetException (java.lang.reflect.InvocationTargetException)28 FieldVisitor (org.objectweb.asm.FieldVisitor)28 FileOutputStream (java.io.FileOutputStream)27 InputStream (java.io.InputStream)26 MethodNode (org.objectweb.asm.tree.MethodNode)25 OuterClass (com.android.tools.layoutlib.create.dataclass.OuterClass)23