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

cn.nukkit.plugin.js.compiler.DelegateCompiler Maven / Gradle / Ivy

There is a newer version: 1.20.40-r1
Show newest version
package cn.nukkit.plugin.js.compiler;

import cn.nukkit.utils.StringUtils;
import org.objectweb.asm.*;
import org.objectweb.asm.Type;

import java.lang.ref.WeakReference;
import java.lang.reflect.*;
import java.util.Objects;

import static org.objectweb.asm.Opcodes.*;

@SuppressWarnings({"DuplicatedCode", "ClassCanBeRecord"})
public final class DelegateCompiler {
    private final JClassBuilder builder;

    public DelegateCompiler(JClassBuilder builder) {
        this.builder = builder;
    }

    public byte[] compile() {
        ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        classWriter.visit(V17, ACC_PUBLIC | ACC_SUPER, builder.getClassInternalName(), null,
                builder.getSuperClass().asmType().getInternalName(), builder.getAllInterfaceClasses().stream()
                        .map(e -> e.asmType().getInternalName()).toArray(String[]::new));
        compileBasicStaticFields(classWriter);
        compileConstructorIniter(classWriter);
        compileJSCaller(classWriter);
        builder.getAllConstructors().forEach(e -> compileConstructor(classWriter, e));
        builder.getAllSuperFields().forEach(e -> compileSuperField(classWriter, e));
        builder.getAllSuperMethods().forEach(e -> compileSuperMethod(classWriter, e));
        builder.getAllMethods().forEach(e -> compileMethod(classWriter, e));
        return classWriter.toByteArray();
    }

    public Class compileToClass(ClassLoader classLoader) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        return loadClass(classLoader, compile());
    }

    public void compileSuperField(ClassWriter classWriter, JSuperField jSuperField) {
        var asmType = jSuperField.asmType();
        Field field = null;
        var clazz = builder.superJavaClassObj;
        while (clazz != null && clazz != Object.class) {
            try {
                field = clazz.getDeclaredField(jSuperField.name());
                break;
            } catch (NoSuchFieldException e) {
                clazz = clazz.getSuperclass();
            }
        }
        // 编译Getter
        if (field != null && (Modifier.isPublic(field.getModifiers()) || Modifier.isProtected(field.getModifiers()))){
            var methodType = Type.getMethodType(asmType);
            var methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "get" + StringUtils.capitalize(jSuperField.name()), methodType.getDescriptor(), null, null);
            methodVisitor.visitCode();
            var label0 = new Label();
            methodVisitor.visitLabel(label0);
            methodVisitor.visitVarInsn(ALOAD, 0);
            methodVisitor.visitFieldInsn(GETFIELD, builder.getClassInternalName(), jSuperField.name(), asmType.getDescriptor());
            methodVisitor.visitInsn(asmType.getOpcode(IRETURN));
            var label1 = new Label();
            methodVisitor.visitLabel(label1);
            methodVisitor.visitLocalVariable("this", builder.getClassDescriptor(), null, label0, label1, 0);
            methodVisitor.visitMaxs(0, 0);
            methodVisitor.visitEnd();
        }
        if (field != null && !Modifier.isFinal(field.getModifiers()) && (Modifier.isPublic(field.getModifiers()) || Modifier.isProtected(field.getModifiers()))) {
            var methodType = Type.getMethodType(Type.VOID_TYPE, asmType);
            var methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "set" + StringUtils.capitalize(jSuperField.name()), methodType.getDescriptor(), null, null);
            methodVisitor.visitCode();
            var label0 = new Label();
            methodVisitor.visitLabel(label0);
            methodVisitor.visitVarInsn(ALOAD, 0);
            methodVisitor.visitVarInsn(asmType.getOpcode(ILOAD), 1);
            methodVisitor.visitFieldInsn(PUTFIELD, builder.getClassInternalName(), jSuperField.name(), asmType.getDescriptor());
            var label1 = new Label();
            methodVisitor.visitLabel(label1);
            methodVisitor.visitInsn(RETURN);
            var label2 = new Label();
            methodVisitor.visitLabel(label2);
            methodVisitor.visitLocalVariable("this", builder.getClassDescriptor(), null, label0, label2, 0);
            methodVisitor.visitMaxs(0, 0);
            methodVisitor.visitEnd();
        }
    }

    public void compileMethod(ClassWriter classWriter, JMethod jMethod) {
        var returnAsmType = jMethod.returnAsmType();
        var argAsmTypes = jMethod.argAsmTypes();
        var methodType = Type.getMethodType(returnAsmType, argAsmTypes);
        var methodVisitor = classWriter.visitMethod(ACC_PUBLIC, jMethod.methodName(), methodType.getDescriptor(), null, null);
        methodVisitor.visitCode();
        var label0 = new Label();
        methodVisitor.visitLabel(label0);
        methodVisitor.visitLdcInsn(jMethod.methodName());
        methodVisitor.visitLdcInsn(argAsmTypes.length + 1);
        methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/Object");
        {
            methodVisitor.visitInsn(DUP);
            methodVisitor.visitInsn(ICONST_0);
            methodVisitor.visitVarInsn(ALOAD, 0);
            methodVisitor.visitInsn(AASTORE);
        }
        for (int i = 0, len = argAsmTypes.length; i < len; i++) {
            methodVisitor.visitInsn(DUP);
            methodVisitor.visitLdcInsn(i + 1);
            var argType = argAsmTypes[i];
            var argSort = argType.getSort();
            methodVisitor.visitVarInsn(argType.getOpcode(ILOAD), i + 1);
            if (argSort != Type.OBJECT && argSort != Type.ARRAY) {
                box(methodVisitor, argType.getClassName());
            }
            methodVisitor.visitInsn(AASTORE);
        }
        methodVisitor.visitMethodInsn(INVOKESTATIC, builder.getClassInternalName(), "__callJS__", "(Ljava/lang/String;[Ljava/lang/Object;)Lorg/graalvm/polyglot/Value;", false);
        var sort = returnAsmType.getSort();
        if (sort == Type.VOID) {
            methodVisitor.visitInsn(POP);
            methodVisitor.visitInsn(RETURN);
        } else if (sort == Type.ARRAY || sort == Type.OBJECT) {
            methodVisitor.visitLdcInsn(returnAsmType);
            methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "as", "(Ljava/lang/Class;)Ljava/lang/Object;", false);
            methodVisitor.visitTypeInsn(CHECKCAST, returnAsmType.getInternalName());
            methodVisitor.visitInsn(ARETURN);
        } else {
            var boxInternalName = internalNameOfPrimitive(returnAsmType.getClassName());
            methodVisitor.visitFieldInsn(GETSTATIC, boxInternalName, "TYPE", "Ljava/lang/Class;");
            methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "as", "(Ljava/lang/Class;)Ljava/lang/Object;", false);
            methodVisitor.visitTypeInsn(CHECKCAST, boxInternalName);
            unBox(methodVisitor, boxInternalName);
            methodVisitor.visitInsn(returnAsmType.getOpcode(IRETURN));
        }
        var label1 = new Label();
        methodVisitor.visitLabel(label1);
        methodVisitor.visitLocalVariable("this", builder.getClassDescriptor(), null, label0, label1, 0);
        methodVisitor.visitMaxs(0, 0);
        methodVisitor.visitEnd();
    }

    public void compileSuperMethod(ClassWriter classWriter, JSuperMethod jSuperMethod) {
        var returnAsmType = jSuperMethod.returnAsmType();
        var argAsmTypes = jSuperMethod.argAsmTypes();
        var methodType = Type.getMethodType(returnAsmType, argAsmTypes);
        var methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "__super__" + jSuperMethod.methodName(), methodType.getDescriptor(), null, null);
        methodVisitor.visitCode();
        var label0 = new Label();
        methodVisitor.visitLabel(label0);
        methodVisitor.visitVarInsn(ALOAD, 0);
        for (int i = 0, len = argAsmTypes.length; i < len; i++) {
            methodVisitor.visitVarInsn(argAsmTypes[i].getOpcode(ILOAD), i + 1);
        }
        methodVisitor.visitMethodInsn(INVOKESPECIAL, builder.getSuperClass().asmType().getInternalName(), jSuperMethod.methodName(), methodType.getDescriptor(), false);
        methodVisitor.visitInsn(returnAsmType.getOpcode(IRETURN));
        var label1 = new Label();
        methodVisitor.visitLabel(label1);
        methodVisitor.visitLocalVariable("this", builder.getClassDescriptor(), null, label0, label1, 0);
        methodVisitor.visitMaxs(0, 0);
        methodVisitor.visitEnd();
    }

    public void compileConstructor(ClassWriter classWriter, JConstructor jConstructor) {
        var constructorType = Type.getMethodType(Type.VOID_TYPE, jConstructor.argAsmTypes());
        var superType = Type.getMethodType(Type.VOID_TYPE, jConstructor.superAsmTypes());
        var methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "", constructorType.getDescriptor(), null, null);
        methodVisitor.visitCode();
        // 调用初始化静态函数
        var label1 = new Label();
        methodVisitor.visitLabel(label1);
        methodVisitor.visitLdcInsn(jConstructor.superDelegateName());
        methodVisitor.visitLdcInsn(jConstructor.argTypes().length);
        methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/Object");
        var argAsmTypes = jConstructor.argAsmTypes();
        for (int i = 0, len = jConstructor.argTypes().length; i < len; i++) {
            methodVisitor.visitInsn(DUP);
            methodVisitor.visitLdcInsn(i);
            var argType = argAsmTypes[i];
            var argSort = argType.getSort();
            methodVisitor.visitVarInsn(argType.getOpcode(ILOAD), 1 + i);
            if (argSort != Type.OBJECT && argSort != Type.ARRAY) {
                box(methodVisitor, argType.getClassName());
            }
            methodVisitor.visitInsn(AASTORE);
        }
        methodVisitor.visitMethodInsn(INVOKESTATIC, builder.getClassInternalName(), "__initJSConstructor__", "(Ljava/lang/String;[Ljava/lang/Object;)V", false);
        // 调用super
        var label2 = new Label();
        methodVisitor.visitLabel(label2);
        methodVisitor.visitVarInsn(ALOAD, 0); // 把this先堆到栈顶
        var superAsmTypes = jConstructor.superAsmTypes();
        for (int i = 0, len = superAsmTypes.length; i < len; i++) {
            methodVisitor.visitFieldInsn(GETSTATIC, builder.getClassInternalName(), "cons", "[Lorg/graalvm/polyglot/Value;");
            methodVisitor.visitLdcInsn(i);
            methodVisitor.visitInsn(AALOAD);
            var argType = superAsmTypes[i];
            if (argType.getSort() == Type.OBJECT || argType.getSort() == Type.ARRAY) {
                methodVisitor.visitLdcInsn(superAsmTypes[i]);
                methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "as", "(Ljava/lang/Class;)Ljava/lang/Object;", false);
                methodVisitor.visitTypeInsn(CHECKCAST, superAsmTypes[i].getInternalName());
            } else {
                var boxInternalName = internalNameOfPrimitive(argType.getClassName());
                methodVisitor.visitFieldInsn(GETSTATIC, boxInternalName, "TYPE", "Ljava/lang/Class;");
                methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "as", "(Ljava/lang/Class;)Ljava/lang/Object;", false);
                methodVisitor.visitTypeInsn(CHECKCAST, boxInternalName);
                unBox(methodVisitor, boxInternalName);
            }
        }
        methodVisitor.visitMethodInsn(INVOKESPECIAL, builder.getSuperClass().asmType().getInternalName(), "", superType.getDescriptor(), false);
        // 清理cons临时静态变量
        var label3 = new Label();
        methodVisitor.visitLabel(label3);
        methodVisitor.visitInsn(ACONST_NULL);
        methodVisitor.visitFieldInsn(PUTSTATIC, builder.getClassInternalName(), "cons", "[Lorg/graalvm/polyglot/Value;");
        // 调用主构造代理函数
        if (jConstructor.constructorDelegateName() != null && !"".equals(jConstructor.constructorDelegateName())) {
            var label4 = new Label();
            methodVisitor.visitLabel(label4);
            methodVisitor.visitLdcInsn(jConstructor.constructorDelegateName());
            argAsmTypes = jConstructor.argAsmTypes();
            methodVisitor.visitLdcInsn(argAsmTypes.length + 1);
            methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/Object");
            {
                methodVisitor.visitInsn(DUP);
                methodVisitor.visitInsn(ICONST_0);
                methodVisitor.visitVarInsn(ALOAD, 0);
                methodVisitor.visitInsn(AASTORE);
            }
            for (int i = 0, len = argAsmTypes.length; i < len; i++) {
                methodVisitor.visitInsn(DUP);
                methodVisitor.visitLdcInsn(i + 1);
                var argType = argAsmTypes[i];
                var argSort = argType.getSort();
                methodVisitor.visitVarInsn(argType.getOpcode(ILOAD), i + 1);
                if (argSort != Type.OBJECT && argSort != Type.ARRAY) {
                    box(methodVisitor, argType.getClassName());
                }
                methodVisitor.visitInsn(AASTORE);
            }
            methodVisitor.visitMethodInsn(INVOKESTATIC, builder.getClassInternalName(), "__callJS__", "(Ljava/lang/String;[Ljava/lang/Object;)Lorg/graalvm/polyglot/Value;", false);
            methodVisitor.visitInsn(POP);
            methodVisitor.visitInsn(RETURN);
        } else {
            methodVisitor.visitInsn(RETURN);
        }
        var label5 = new Label();
        methodVisitor.visitLabel(label5);
        methodVisitor.visitLocalVariable("this", builder.getClassDescriptor(), null, label1, label5, 0);
        methodVisitor.visitMaxs(0, 0);
        methodVisitor.visitEnd();
    }

    public void compileBasicStaticFields(ClassWriter classWriter) {
        var fieldVisitor = classWriter.visitField(ACC_PUBLIC | ACC_STATIC, "context", "Lorg/graalvm/polyglot/Context;", null, null);
        fieldVisitor.visitEnd(); // static content
        fieldVisitor = classWriter.visitField(ACC_PUBLIC | ACC_STATIC, "delegate", "Lorg/graalvm/polyglot/Value;", null, null);
        fieldVisitor.visitEnd(); // static delegate
        fieldVisitor = classWriter.visitField(ACC_PRIVATE | ACC_STATIC, "cons", "[Lorg/graalvm/polyglot/Value;", null, null);
        fieldVisitor.visitEnd(); // static cons
    }

    public void compileConstructorIniter(ClassWriter classWriter) {
        var methodVisitor = classWriter.visitMethod(ACC_PRIVATE | ACC_STATIC, "__initJSConstructor__", "(Ljava/lang/String;[Ljava/lang/Object;)V", null, null);
        methodVisitor.visitCode();
        var label0 = new Label();
        var label1 = new Label();
        var label2 = new Label();
        methodVisitor.visitTryCatchBlock(label0, label1, label2, null);
        var label3 = new Label();
        var label4 = new Label();
        methodVisitor.visitTryCatchBlock(label3, label4, label2, null);
        var label5 = new Label();
        methodVisitor.visitTryCatchBlock(label2, label5, label2, null);
        var label6 = new Label();
        methodVisitor.visitLabel(label6);
        methodVisitor.visitFieldInsn(GETSTATIC, builder.getClassInternalName(), "context", "Lorg/graalvm/polyglot/Context;");
        methodVisitor.visitInsn(DUP);
        methodVisitor.visitVarInsn(ASTORE, 2);
        methodVisitor.visitInsn(MONITORENTER);
        methodVisitor.visitLabel(label0);
        methodVisitor.visitFieldInsn(GETSTATIC, builder.getClassInternalName(), "delegate", "Lorg/graalvm/polyglot/Value;");
        methodVisitor.visitVarInsn(ALOAD, 0);
        methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "getMember", "(Ljava/lang/String;)Lorg/graalvm/polyglot/Value;", false);
        methodVisitor.visitVarInsn(ALOAD, 1);
        methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "execute", "([Ljava/lang/Object;)Lorg/graalvm/polyglot/Value;", false);
        methodVisitor.visitVarInsn(ASTORE, 3);
        var label7 = new Label();
        methodVisitor.visitLabel(label7);
        methodVisitor.visitVarInsn(ALOAD, 3);
        methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "isNull", "()Z", false);
        methodVisitor.visitJumpInsn(IFEQ, label3);
        methodVisitor.visitVarInsn(ALOAD, 2);
        methodVisitor.visitInsn(MONITOREXIT);
        methodVisitor.visitLabel(label1);
        methodVisitor.visitInsn(RETURN);
        methodVisitor.visitLabel(label3);
        methodVisitor.visitFrame(Opcodes.F_APPEND, 2, new Object[]{"java/lang/Object", "org/graalvm/polyglot/Value"}, 0, null);
        methodVisitor.visitVarInsn(ALOAD, 3);
        methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "hasArrayElements", "()Z", false);
        var label8 = new Label();
        methodVisitor.visitJumpInsn(IFEQ, label8);
        var label9 = new Label();
        methodVisitor.visitLabel(label9);
        methodVisitor.visitVarInsn(ALOAD, 3);
        methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "getArraySize", "()J", false);
        methodVisitor.visitInsn(L2I);
        methodVisitor.visitTypeInsn(ANEWARRAY, "org/graalvm/polyglot/Value");
        methodVisitor.visitFieldInsn(PUTSTATIC, builder.getClassInternalName(), "cons", "[Lorg/graalvm/polyglot/Value;");
        var label10 = new Label();
        methodVisitor.visitLabel(label10);
        methodVisitor.visitInsn(ICONST_0);
        methodVisitor.visitVarInsn(ISTORE, 4);
        var label11 = new Label();
        methodVisitor.visitLabel(label11);
        methodVisitor.visitFieldInsn(GETSTATIC, builder.getClassInternalName(), "cons", "[Lorg/graalvm/polyglot/Value;");
        methodVisitor.visitInsn(ARRAYLENGTH);
        methodVisitor.visitVarInsn(ISTORE, 5);
        var label12 = new Label();
        methodVisitor.visitLabel(label12);
        methodVisitor.visitVarInsn(ILOAD, 4);
        methodVisitor.visitVarInsn(ILOAD, 5);
        var label13 = new Label();
        methodVisitor.visitJumpInsn(IF_ICMPGE, label13);
        var label14 = new Label();
        methodVisitor.visitLabel(label14);
        methodVisitor.visitFieldInsn(GETSTATIC, builder.getClassInternalName(), "cons", "[Lorg/graalvm/polyglot/Value;");
        methodVisitor.visitVarInsn(ILOAD, 4);
        methodVisitor.visitVarInsn(ALOAD, 3);
        methodVisitor.visitVarInsn(ILOAD, 4);
        methodVisitor.visitInsn(I2L);
        methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "getArrayElement", "(J)Lorg/graalvm/polyglot/Value;", false);
        methodVisitor.visitInsn(AASTORE);
        var label15 = new Label();
        methodVisitor.visitLabel(label15);
        methodVisitor.visitIincInsn(4, 1);
        methodVisitor.visitJumpInsn(GOTO, label12);
        methodVisitor.visitLabel(label13);
        var label16 = new Label();
        methodVisitor.visitJumpInsn(GOTO, label16);
        methodVisitor.visitLabel(label8);
        methodVisitor.visitInsn(ICONST_1);
        methodVisitor.visitTypeInsn(ANEWARRAY, "org/graalvm/polyglot/Value");
        methodVisitor.visitInsn(DUP);
        methodVisitor.visitInsn(ICONST_0);
        methodVisitor.visitVarInsn(ALOAD, 3);
        methodVisitor.visitInsn(AASTORE);
        methodVisitor.visitFieldInsn(PUTSTATIC, builder.getClassInternalName(), "cons", "[Lorg/graalvm/polyglot/Value;");
        methodVisitor.visitLabel(label16);
        methodVisitor.visitVarInsn(ALOAD, 2);
        methodVisitor.visitInsn(MONITOREXIT);
        methodVisitor.visitLabel(label4);
        var label17 = new Label();
        methodVisitor.visitJumpInsn(GOTO, label17);
        methodVisitor.visitLabel(label2);
        methodVisitor.visitVarInsn(ASTORE, 6);
        methodVisitor.visitVarInsn(ALOAD, 2);
        methodVisitor.visitInsn(MONITOREXIT);
        methodVisitor.visitLabel(label5);
        methodVisitor.visitVarInsn(ALOAD, 6);
        methodVisitor.visitInsn(ATHROW);
        methodVisitor.visitLabel(label17);
        methodVisitor.visitInsn(RETURN);
        var label18 = new Label();
        methodVisitor.visitLabel(label18);
        // 加上局部变量名称,免得某些反编译器暴毙
        methodVisitor.visitLocalVariable("i", "I", null, label11, label13, 4);
        methodVisitor.visitLocalVariable("len", "I", null, label12, label13, 5);
        methodVisitor.visitLocalVariable("tmp", "Lorg/graalvm/polyglot/Value;", null, label7, label16, 3);
        methodVisitor.visitLocalVariable("delegateName", "Ljava/lang/String;", null, label6, label18, 0);
        methodVisitor.visitLocalVariable("args", "[Ljava/lang/Object;", null, label6, label18, 1);
        methodVisitor.visitMaxs(0, 0);
        methodVisitor.visitEnd();
    }

    public void compileJSCaller(ClassWriter classWriter) {
        var methodVisitor = classWriter.visitMethod(ACC_PRIVATE | ACC_STATIC, "__callJS__", "(Ljava/lang/String;[Ljava/lang/Object;)Lorg/graalvm/polyglot/Value;", null, null);
        methodVisitor.visitCode();
        var label0 = new Label();
        var label1 = new Label();
        var label2 = new Label();
        methodVisitor.visitTryCatchBlock(label0, label1, label2, null);
        var label3 = new Label();
        var label4 = new Label();
        methodVisitor.visitTryCatchBlock(label3, label4, label2, null);
        var label5 = new Label();
        methodVisitor.visitTryCatchBlock(label2, label5, label2, null);
        var label6 = new Label();
        methodVisitor.visitLabel(label6);
        methodVisitor.visitFieldInsn(GETSTATIC, builder.getClassInternalName(), "context", "Lorg/graalvm/polyglot/Context;");
        methodVisitor.visitInsn(DUP);
        methodVisitor.visitVarInsn(ASTORE, 2);
        methodVisitor.visitInsn(MONITORENTER);
        methodVisitor.visitLabel(label0);
        methodVisitor.visitFieldInsn(GETSTATIC, builder.getClassInternalName(), "delegate", "Lorg/graalvm/polyglot/Value;");
        methodVisitor.visitVarInsn(ALOAD, 0);
        methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "getMember", "(Ljava/lang/String;)Lorg/graalvm/polyglot/Value;", false);
        methodVisitor.visitVarInsn(ASTORE, 3);
        var label7 = new Label();
        methodVisitor.visitLabel(label7);
        methodVisitor.visitVarInsn(ALOAD, 3);
        methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "canExecute", "()Z", false);
        methodVisitor.visitJumpInsn(IFEQ, label3);
        var label8 = new Label();
        methodVisitor.visitLabel(label8);
        methodVisitor.visitVarInsn(ALOAD, 3);
        methodVisitor.visitVarInsn(ALOAD, 1);
        methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "org/graalvm/polyglot/Value", "execute", "([Ljava/lang/Object;)Lorg/graalvm/polyglot/Value;", false);
        methodVisitor.visitVarInsn(ALOAD, 2);
        methodVisitor.visitInsn(MONITOREXIT);
        methodVisitor.visitLabel(label1);
        methodVisitor.visitInsn(ARETURN);
        methodVisitor.visitLabel(label3);
        methodVisitor.visitInsn(ACONST_NULL);
        methodVisitor.visitMethodInsn(INVOKESTATIC, "org/graalvm/polyglot/Value", "asValue", "(Ljava/lang/Object;)Lorg/graalvm/polyglot/Value;", false);
        methodVisitor.visitVarInsn(ALOAD, 2);
        methodVisitor.visitInsn(MONITOREXIT);
        methodVisitor.visitLabel(label4);
        methodVisitor.visitInsn(ARETURN);
        methodVisitor.visitLabel(label2);
        methodVisitor.visitVarInsn(ASTORE, 4);
        methodVisitor.visitVarInsn(ALOAD, 2);
        methodVisitor.visitInsn(MONITOREXIT);
        methodVisitor.visitLabel(label5);
        methodVisitor.visitVarInsn(ALOAD, 4);
        methodVisitor.visitInsn(ATHROW);
        var label9 = new Label();
        methodVisitor.visitLabel(label9);
        methodVisitor.visitLocalVariable("func", "Lorg/graalvm/polyglot/Value;", null, label7, label2, 3);
        methodVisitor.visitLocalVariable("delegateName", "Ljava/lang/String;", null, label6, label9, 0);
        methodVisitor.visitLocalVariable("args", "[Ljava/lang/Object;", null, label6, label9, 1);
        methodVisitor.visitMaxs(0, 0);
        methodVisitor.visitEnd();
    }

    private String internalNameOfPrimitive(String primitiveType) {
        return switch (primitiveType) {
            case "boolean" -> "java/lang/Boolean";
            case "byte" -> "java/lang/Byte";
            case "char" -> "java/lang/Character";
            case "short" -> "java/lang/Short";
            case "int" -> "java/lang/Integer";
            case "long" -> "java/lang/Long";
            case "float" -> "java/lang/Float";
            case "double" -> "java/lang/Double";
            default -> null;
        };
    }

    private String primitiveOfClass(String internalName) {
        return switch (internalName) {
            case "java/lang/Boolean" -> "boolean";
            case "java/lang/Byte" -> "byte";
            case "java/lang/Character" -> "char";
            case "java/lang/Short" -> "short";
            case "java/lang/Integer" -> "int";
            case "java/lang/Long" -> "long";
            case "java/lang/Float" -> "float";
            case "java/lang/Double" -> "double";
            default -> null;
        };
    }

    private void unBox(MethodVisitor methodVisitor, String boxType) {
        switch (boxType) {
            case "java/lang/Boolean" -> methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
            case "java/lang/Byte" -> methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
            case "java/lang/Short" -> methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
            case "java/lang/Character" -> methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
            case "java/lang/Integer" -> methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
            case "java/lang/Long" -> methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
            case "java/lang/Float" -> methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
            case "java/lang/Double" -> methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
        }
    }

    private void box(MethodVisitor methodVisitor, String primitiveType) {
        switch (primitiveType) {
            case "boolean" -> methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
            case "byte" -> methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
            case "char" -> methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
            case "short" -> methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
            case "int" -> methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
            case "long" -> methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
            case "float" -> methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
            case "double" -> methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
        }
    }

    private static WeakReference defineClassMethodRef = new WeakReference<>(null);

    @SuppressWarnings("DuplicatedCode")
    private Class loadClass(ClassLoader loader, byte[] b) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InaccessibleObjectException {
        Class clazz;
        java.lang.reflect.Method method;
        if (defineClassMethodRef.get() == null) {
            var cls = Class.forName("java.lang.ClassLoader");
            method = cls.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
            defineClassMethodRef = new WeakReference<>(method);
        } else {
            method = defineClassMethodRef.get();
        }
        Objects.requireNonNull(method).setAccessible(true);
        try {
            var args = new Object[]{builder.getClassName(), b, 0, b.length};
            clazz = (Class) method.invoke(loader, args);
        } finally {
            method.setAccessible(false);
        }
        return clazz;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy