From 1405644a17e454f613d14da04ba8d762e3ee7036 Mon Sep 17 00:00:00 2001 From: michaeloffner Date: Fri, 9 Aug 2024 20:16:29 +0200 Subject: [PATCH] LDEV-5038 - sync class creation --- .../transformer/dynamic/DynamicInvoker.java | 223 +++++++++--------- loader/build.xml | 2 +- loader/pom.xml | 2 +- 3 files changed, 110 insertions(+), 117 deletions(-) diff --git a/core/src/main/java/lucee/transformer/dynamic/DynamicInvoker.java b/core/src/main/java/lucee/transformer/dynamic/DynamicInvoker.java index 872f2360a3..bf937278b6 100644 --- a/core/src/main/java/lucee/transformer/dynamic/DynamicInvoker.java +++ b/core/src/main/java/lucee/transformer/dynamic/DynamicInvoker.java @@ -139,8 +139,8 @@ public Clazz getClazz(Class clazz, boolean useReflection) { * private static int loadClassCount = 0; private static int getMatchCount = 0; private static int * hasMatchCount = 0; private static int create1Count = 0; private static int create2Count = 0; */ - public Pair createInstance(Class clazz, Key methodName, Object[] arguments) throws NoSuchMethodException, IOException, ClassNotFoundException, - UnmodifiableClassException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, PageException { + public Pair createInstance(Class clazz, Key methodName, Object[] arguments) throws NoSuchMethodException, IOException, UnmodifiableClassException, + InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, PageException { // observe(clazz, methodName); // double start = SystemUtil.millis(); @@ -181,128 +181,121 @@ public Pair createInstance(Class clazz, Key methodNam String classPath = Clazz.getPackagePrefix() + sbClassPath.toString();// StringUtil.replace(sbClassPath.toString(), "javae/lang/", "java_lang/", false); String className = classPath.replace('/', '.'); - DynamicClassLoader loader = getCL(clazz); - if (loader.hasClass(className)) { - try { - return new Pair(fm, loader.loadInstance(className)); - } - catch (Exception e) { - // simply ignore when fail - } - } - Class[] parameterClasses = fm.getArgumentClasses(); - - ClassWriter cw = ASMUtil.getClassWriter(); - MethodVisitor mv; - String abstractClassPath = "java/lang/Object"; - cw.visit(ASMUtil.getJavaVersionForBytecodeGeneration(), Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, classPath, - "Ljava/lang/Object;Ljava/util/function/BiFunction;", "java/lang/Object", - new String[] { "java/util/function/BiFunction" }); - // Constructor - mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(Opcodes.ALOAD, 0); // Load "this" - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, abstractClassPath, "", "()V", false); // Call the constructor of super class (Object) - mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(1, 1); // Compute automatically - mv.visitEnd(); - - // Dynamic invoke method - // public abstract Object invoke(PageContext pc, Object[] args) throws PageException; - mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null); - mv.visitCode(); - boolean isStatic = true; - if (isConstr) { - mv.visitTypeInsn(Opcodes.NEW, Type.getType(clazz).getInternalName()); - mv.visitInsn(Opcodes.DUP); // Duplicate the top operand stack value + synchronized (SystemUtil.createToken("dyninvoc", className)) { + + DynamicClassLoader loader = getCL(clazz); + if (loader.hasClass(className)) { + try { + return new Pair(fm, loader.loadInstance(className)); - } - else { - isStatic = fm.isStatic(); - if (!isStatic) { - // Load the instance to call the method on - mv.visitVarInsn(Opcodes.ALOAD, 1); // Load the first method argument (instance) - if (!fm.getDeclaringProviderClassWithSameAccess().equals(Object.class)) { // Only cast if clazz is not java.lang.Object - mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(fm.getDeclaringProviderClassWithSameAccess())); + } + catch (Exception e) { + // simply ignore when fail } } - } - // Assuming no arguments are needed for the invoked method, i.e., toString() - // For methods that require arguments, you would need to manipulate the args array appropriately - // here - - // print.e(Type.getInternalName(clazz)); - - StringBuilder methodDesc = new StringBuilder(); - String del = "("; - if (fm.getArgumentCount() > 0) { - // Load method arguments from the args array - Type[] args = fm.getArgumentTypes(); - // TODO if args!=arguments throw ! - for (int i = 0; i < args.length; i++) { - - methodDesc.append(del).append(args[i].getDescriptor()); - del = ""; - - mv.visitVarInsn(Opcodes.ALOAD, 2); // Load the args array - mv.visitTypeInsn(Opcodes.CHECKCAST, "[Ljava/lang/Object;"); // Cast it to Object[] - - mv.visitIntInsn(Opcodes.BIPUSH, i); // Index of the argument in the array - mv.visitInsn(Opcodes.AALOAD); // Load the argument from the array - - // Cast or unbox the argument as necessary - // TOOD Caster.castTo(null, clazz, methodDesc) - Class argType = parameterClasses[i]; // TODO get the class from args - if (argType.isPrimitive()) { - Type type = Type.getType(argType); - Class wrapperType = Reflector.toReferenceClass(argType); - mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(wrapperType)); // Cast to wrapper type - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(wrapperType), type.getClassName() + "Value", "()" + type.getDescriptor(), false); // Unbox + Class[] parameterClasses = fm.getArgumentClasses(); + + ClassWriter cw = ASMUtil.getClassWriter(); + MethodVisitor mv; + String abstractClassPath = "java/lang/Object"; + cw.visit(ASMUtil.getJavaVersionForBytecodeGeneration(), Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, classPath, + "Ljava/lang/Object;Ljava/util/function/BiFunction;", "java/lang/Object", + new String[] { "java/util/function/BiFunction" }); + // Constructor + mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(Opcodes.ALOAD, 0); // Load "this" + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, abstractClassPath, "", "()V", false); // Call the constructor of super class (Object) + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(1, 1); // Compute automatically + mv.visitEnd(); + + // Dynamic invoke method + // public abstract Object invoke(PageContext pc, Object[] args) throws PageException; + mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null); + mv.visitCode(); + boolean isStatic = true; + if (isConstr) { + mv.visitTypeInsn(Opcodes.NEW, Type.getType(clazz).getInternalName()); + mv.visitInsn(Opcodes.DUP); // Duplicate the top operand stack value + + } + else { + isStatic = fm.isStatic(); + if (!isStatic) { + // Load the instance to call the method on + mv.visitVarInsn(Opcodes.ALOAD, 1); // Load the first method argument (instance) + if (!fm.getDeclaringProviderClassWithSameAccess().equals(Object.class)) { // Only cast if clazz is not java.lang.Object + mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(fm.getDeclaringProviderClassWithSameAccess())); + } } - else { - mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(argType)); // Cast to correct type + } + // Assuming no arguments are needed for the invoked method, i.e., toString() + // For methods that require arguments, you would need to manipulate the args array appropriately + // here + + // print.e(Type.getInternalName(clazz)); + + StringBuilder methodDesc = new StringBuilder(); + String del = "("; + if (fm.getArgumentCount() > 0) { + // Load method arguments from the args array + Type[] args = fm.getArgumentTypes(); + // TODO if args!=arguments throw ! + for (int i = 0; i < args.length; i++) { + + methodDesc.append(del).append(args[i].getDescriptor()); + del = ""; + + mv.visitVarInsn(Opcodes.ALOAD, 2); // Load the args array + mv.visitTypeInsn(Opcodes.CHECKCAST, "[Ljava/lang/Object;"); // Cast it to Object[] + + mv.visitIntInsn(Opcodes.BIPUSH, i); // Index of the argument in the array + mv.visitInsn(Opcodes.AALOAD); // Load the argument from the array + + // Cast or unbox the argument as necessary + // TOOD Caster.castTo(null, clazz, methodDesc) + Class argType = parameterClasses[i]; // TODO get the class from args + if (argType.isPrimitive()) { + Type type = Type.getType(argType); + Class wrapperType = Reflector.toReferenceClass(argType); + mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(wrapperType)); // Cast to wrapper type + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(wrapperType), type.getClassName() + "Value", "()" + type.getDescriptor(), false); // Unbox + } + else { + mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(argType)); // Cast to correct type + } } } - } - else { - methodDesc.append('('); - } - Type rt = isConstr ? Type.getType(clazz) : method.getReturnType(); - methodDesc.append(')').append(isConstr ? Types.VOID : rt.getDescriptor()); - if (isConstr) { - // Create a new instance of java/lang/String - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, rt.getInternalName(), "", methodDesc.toString(), false); // Call the constructor of String - } - else { - mv.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : (fm.getDeclaringProviderClassWithSameAccess().isInterface() ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL), - Type.getInternalName(fm.getDeclaringProviderClassWithSameAccess()), method.getName(), methodDesc.toString(), - fm.getDeclaringProviderClassWithSameAccess().isInterface()); - - } + else { + methodDesc.append('('); + } + Type rt = isConstr ? Type.getType(clazz) : method.getReturnType(); + methodDesc.append(')').append(isConstr ? Types.VOID : rt.getDescriptor()); + if (isConstr) { + // Create a new instance of java/lang/String + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, rt.getInternalName(), "", methodDesc.toString(), false); // Call the constructor of String + } + else { + mv.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : (fm.getDeclaringProviderClassWithSameAccess().isInterface() ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL), + Type.getInternalName(fm.getDeclaringProviderClassWithSameAccess()), method.getName(), methodDesc.toString(), + fm.getDeclaringProviderClassWithSameAccess().isInterface()); - boxIfPrimitive(mv, rt); - // method on the - // instance - mv.visitInsn(Opcodes.ARETURN); // Return the result of the method call - if (isConstr) mv.visitMaxs(2, 1); - else mv.visitMaxs(1, 3); // Compute automatically - mv.visitEnd(); + } - cw.visitEnd(); - byte[] barr = cw.toByteArray(); + boxIfPrimitive(mv, rt); + // method on the + // instance + mv.visitInsn(Opcodes.ARETURN); // Return the result of the method call + if (isConstr) mv.visitMaxs(2, 1); + else mv.visitMaxs(1, 3); // Compute automatically + mv.visitEnd(); - /* - * { create1Count++; create1Total += (SystemUtil.millis() - start); print.e("create 1(" + - * create1Count + "):" + Caster.toString(create1Total / create1Count)); start = SystemUtil.millis(); - * } - */ - Object result = loader.loadInstance(className, barr); - /* - * { create2Count++; create2Total += (SystemUtil.millis() - start); print.e("create 2(" + - * create2Count + "):" + Caster.toString(create2Total / create2Count)); start = SystemUtil.millis(); - * } - */ - return new Pair(fm, result); + cw.visitEnd(); + byte[] barr = cw.toByteArray(); + Object result = loader.loadInstance(className, barr); + return new Pair(fm, result); + } } private static void observe(Class clazz, Key methodName) { diff --git a/loader/build.xml b/loader/build.xml index e66e9c42a0..df51bad273 100644 --- a/loader/build.xml +++ b/loader/build.xml @@ -2,7 +2,7 @@ - + diff --git a/loader/pom.xml b/loader/pom.xml index 88fda9a380..2b173194c6 100644 --- a/loader/pom.xml +++ b/loader/pom.xml @@ -3,7 +3,7 @@ org.lucee lucee - 6.1.1.57-SNAPSHOT + 6.1.1.58-SNAPSHOT jar Lucee Loader Build