All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.mcollovati.quarkus.hilla.deployment.InjectableObjectFactoryFieldUsageRemovalMethodVisitor Maven / Gradle / Ivy

There is a newer version: 24.6.0
Show newest version
/*
 * Copyright 2024 Marco Collovati, Dario Götze
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.mcollovati.quarkus.hilla.deployment;

import java.util.HashMap;
import java.util.ListIterator;
import java.util.Map;
import java.util.function.Predicate;

import io.quarkus.gizmo.Gizmo;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;

final class InjectableObjectFactoryFieldUsageRemovalMethodVisitor extends MethodNode {
    public InjectableObjectFactoryFieldUsageRemovalMethodVisitor(
            MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions) {
        super(Gizmo.ASM_API_VERSION, access, name, descriptor, signature, exceptions);
        this.mv = mv;
    }

    @Override
    public void visitEnd() {
        ListIterator iterator = instructions.iterator();
        Map nodesToReplace = new HashMap<>();

        FieldInsnNode fieldUsage;
        while ((fieldUsage = findFieldUsage(iterator)) != null) {
            if (fieldUsage.getOpcode() == Opcodes.PUTFIELD) {
                /*
                 * L6 LINENUMBER 66 L6 ALOAD 0 LDC
                 * Lorg/atmosphere/inject/Injectable;.class INVOKESTATIC
                 * java/util/ServiceLoader.load
                 * (Ljava/lang/Class;)Ljava/util/ServiceLoader; PUTFIELD
                 * org/atmosphere/inject/InjectableObjectFactory.
                 * injectableServiceLoader : Ljava/util/ServiceLoader;
                 */
                nodesToReplace.put(iterator.previous(), new InsnNode(Opcodes.NOP)); // PUTFIELD
                nodesToReplace.put(iterator.previous(), new InsnNode(Opcodes.NOP)); // INVOKESTATIC
                nodesToReplace.put(iterator.previous(), new InsnNode(Opcodes.NOP)); // LDC
                nodesToReplace.put(iterator.previous(), new InsnNode(Opcodes.NOP)); // ALOAD

                AbstractInsnNode stop = fieldUsage;
                findNextNode(iterator, n -> n == stop);
            } else if (fieldUsage.getOpcode() == Opcodes.GETFIELD) {
                /*
                 * L13 LINENUMBER 86 L13 FRAME FULL
                 * [org/atmosphere/inject/InjectableObjectFactory
                 * org/atmosphere/cpr/AtmosphereConfig java/lang/String] []
                 * ALOAD 0 GETFIELD
                 * org/atmosphere/inject/InjectableObjectFactory.
                 * injectableServiceLoader : Ljava/util/ServiceLoader;
                 * INVOKEVIRTUAL java/util/ServiceLoader.iterator
                 * ()Ljava/util/Iterator; ASTORE 3
                 */
                nodesToReplace.put(
                        iterator.previous(),
                        new MethodInsnNode(
                                Opcodes.INVOKESTATIC,
                                "java/util/ServiceLoader",
                                "load",
                                "(Ljava/lang/Class;)Ljava/util/ServiceLoader;",
                                false)); // GETFIELD
                nodesToReplace.put(
                        iterator.previous(),
                        new LdcInsnNode(Type.getType("Lorg/atmosphere/inject/Injectable;"))); // ALOAD
                AbstractInsnNode stop = fieldUsage;
                findNextNode(iterator, n -> n == stop);
            }
        }
        nodesToReplace.forEach(instructions::set);
        instructions.resetLabels();
        accept(mv);
    }

    private FieldInsnNode findFieldUsage(ListIterator iterator) {
        return (FieldInsnNode) findNextNode(
                iterator, node -> node instanceof FieldInsnNode field && field.name.equals("injectableServiceLoader"));
    }

    private AbstractInsnNode findNextNode(ListIterator iterator, Predicate test) {
        while (iterator.hasNext()) {
            AbstractInsnNode node = iterator.next();
            if (test.test(node)) {
                return node;
            }
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy