Skip to content

Commit

Permalink
Merge branch '6.1' into 6.2
Browse files Browse the repository at this point in the history
# Conflicts:
#	loader/build.xml
#	loader/pom.xml
  • Loading branch information
michaeloffner committed Aug 13, 2024
2 parents 7a8fb96 + cc16117 commit 25e832f
Show file tree
Hide file tree
Showing 12 changed files with 383 additions and 136 deletions.
20 changes: 20 additions & 0 deletions core/src/main/java/lucee/commons/io/ModeUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

import java.io.IOException;

import lucee.commons.io.log.Log;
import lucee.commons.io.log.LogUtil;

public final class ModeUtil {

public static final int PERM_READ = 04;
Expand Down Expand Up @@ -66,6 +69,23 @@ private static int _toOctalMode(String strMode) {
return mode;
}

/**
* Extracts the permission bits from the mode value. Logs a message if the file type bits are
* removed and logging is enabled.
*
* @param mode The mode value that includes file type and permission bits.
* @param log If true, log a message if file type bits are removed.
* @return The permission bits (e.g., 0700).
*/
public static int extractPermissions(int mode, boolean log) {
int permissionBits = mode & 07777;

if (log && (mode != permissionBits)) {
LogUtil.log(Log.LEVEL_WARN, "mode", "File type bits removed from mode: original=" + toStringMode(mode) + ", extracted=" + toStringMode(permissionBits));
}
return permissionBits;
}

/**
* translate an octal mode value (73) to a string representation ("111")
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;

import lucee.commons.io.IOUtil;
import lucee.commons.io.ModeUtil;
import lucee.commons.io.SystemUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.ResourceProvider;
Expand Down Expand Up @@ -221,7 +222,9 @@ private static void extractTar(Resource tarFile, Resource targetDir) throws IOEx
}
target.setLastModified(entry.getModTime().getTime());
mode = entry.getMode();
if (mode > 0) target.setMode(mode);
if (mode > 0) {
target.setMode(ModeUtil.extractPermissions(mode, false));
}
// tis.closeEntry() ;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,8 +439,9 @@ public static int getMode(Path path) {

@Override
public void setMode(int mode) throws IOException {
// TODO unter windows mit setReadable usw.
// TODO for windows do it with help of NIO functions
if (!SystemUtil.isUnix()) return;
mode = ModeUtil.extractPermissions(mode, true); // we only need the permission part
provider.lock(this);
try {
// print.ln(ModeUtil.toStringMode(mode));
Expand Down
8 changes: 3 additions & 5 deletions core/src/main/java/lucee/runtime/config/ConfigImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -3932,15 +3932,13 @@ public LogEngine getLogEngine() {
}

protected void setCachedAfterTimeRange(TimeSpan ts) {
this.cachedAfterTimeRange = ts;
if (ts != null && ts.getMillis() > 0) {
this.cachedAfterTimeRange = ts;
}
}

@Override
public TimeSpan getCachedAfterTimeRange() {
TimeSpan tmp = this.cachedAfterTimeRange;
if (tmp != null && tmp.getMillis() <= 0) {
this.cachedAfterTimeRange = null;
}
return this.cachedAfterTimeRange;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,9 @@ private Pair<FunctionMember, Object> getResult() throws PageException {
try {
result = DynamicInvoker.getInstance(null).createInstance(clazz, methodName, args);
}
catch (Exception e) {
throw Caster.toPageException(e);
catch (Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
throw Caster.toPageException(t);
}
}
return result;
Expand Down
25 changes: 16 additions & 9 deletions core/src/main/java/lucee/runtime/tag/TagHandlerPool.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,14 @@ public TagHandlerPool(ConfigWeb config) {
*/
public Tag use(String className, String tagBundleName, String tagBundleVersion, Identification id) throws PageException {
Queue<Tag> queue = getQueue(toId(className, tagBundleName, tagBundleVersion));
Tag tag = queue.poll();
Tag tag = null;
synchronized (queue) {
tag = queue.poll();
}
if (tag != null) return tag;
return loadTag(className, tagBundleName, tagBundleVersion, id);
}

private String toId(String className, String tagBundleName, String tagBundleVersion) {
if (tagBundleName == null && tagBundleVersion == null) return className;
if (tagBundleVersion == null) return className + ":" + tagBundleName;
return className + ":" + tagBundleName + ":" + tagBundleVersion;
}

/**
* free a tag for reusing
*
Expand All @@ -74,13 +71,23 @@ private String toId(String className, String tagBundleName, String tagBundleVers
public void reuse(Tag tag) {
tag.release();
Queue<Tag> queue = getQueue(tag.getClass().getName());
queue.add(tag);
synchronized (queue) {
queue.add(tag);
}
}

public void reuse(Tag tag, String bundleName, String bundleVersion) {
tag.release();
Queue<Tag> queue = getQueue(toId(tag.getClass().getName(), bundleName, bundleVersion));
queue.add(tag);
synchronized (queue) {
queue.add(tag);
}
}

private String toId(String className, String tagBundleName, String tagBundleVersion) {
if (tagBundleName == null && tagBundleVersion == null) return className;
if (tagBundleVersion == null) return className + ":" + tagBundleName;
return className + ":" + tagBundleName + ":" + tagBundleVersion;
}

private Tag loadTag(String className, String tagBundleName, String tagBundleVersion, Identification id) throws PageException {
Expand Down
224 changes: 108 additions & 116 deletions core/src/main/java/lucee/transformer/dynamic/DynamicInvoker.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<FunctionMember, Object> createInstance(Class<?> clazz, Key methodName, Object[] arguments) throws NoSuchMethodException, IOException, ClassNotFoundException,
UnmodifiableClassException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, PageException {
public Pair<FunctionMember, Object> createInstance(Class<?> clazz, Key methodName, Object[] arguments) throws NoSuchMethodException, IOException, UnmodifiableClassException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, PageException {
// observe(clazz, methodName);
// double start = SystemUtil.millis();

Expand Down Expand Up @@ -181,129 +181,121 @@ public Pair<FunctionMember, Object> 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<FunctionMember, Object>(fm, loader.loadInstance(className));
/*
* } finally { hasMatchCount++; hasMatchTotal += (SystemUtil.millis() - start); print.e("has match("
* + hasMatchCount + "):" + Caster.toString(hasMatchTotal / hasMatchCount)); start =
* SystemUtil.millis(); }
*/
}
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<Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;>;", "java/lang/Object",
new String[] { "java/util/function/BiFunction" });
// Constructor
mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0); // Load "this"
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, abstractClassPath, "<init>", "()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)) {

}
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()));
DynamicClassLoader loader = getCL(clazz);
if (loader.hasClass(className)) {
try {
return new Pair<FunctionMember, Object>(fm, loader.loadInstance(className));

}
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<Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;>;", "java/lang/Object",
new String[] { "java/util/function/BiFunction" });
// Constructor
mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0); // Load "this"
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, abstractClassPath, "<init>", "()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(), "<init>", 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(), "<init>", 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<FunctionMember, Object>(fm, result);
cw.visitEnd();
byte[] barr = cw.toByteArray();
Object result = loader.loadInstance(className, barr);
return new Pair<FunctionMember, Object>(fm, result);
}
}

private static void observe(Class<?> clazz, Key methodName) {
Expand Down
2 changes: 1 addition & 1 deletion loader/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<project default="core" basedir="." name="Lucee"
xmlns:resolver="antlib:org.apache.maven.resolver.ant">

<property name="version" value="6.2.0.43-SNAPSHOT"/>
<property name="version" value="6.2.0.44-SNAPSHOT"/>

<taskdef uri="antlib:org.apache.maven.resolver.ant" resource="org/apache/maven/resolver/ant/antlib.xml">
<classpath>
Expand Down
Loading

0 comments on commit 25e832f

Please sign in to comment.