diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk index 4484cffe21..1ac3426ac5 100644 --- a/make/InitSupport.gmk +++ b/make/InitSupport.gmk @@ -424,7 +424,7 @@ else # $(HAS_SPEC)=true $(if $(filter all, $(LOG_REPORT)), \ $(GREP) -v -e "^Note: including file:" < $(logfile) || true $(NEWLINE) \ , \ - ($(GREP) -v -e "^Note: including file:" < $(logfile) || true) | $(HEAD) -n 15 $(NEWLINE) \ + ($(GREP) -v -e "^Note: including file:" < $(logfile) || true) | $(HEAD) -n 1500 $(NEWLINE) \ if test `$(WC) -l < $(logfile)` -gt 15; then \ $(ECHO) " ... (rest of output omitted)" ; \ fi $(NEWLINE) \ diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 3d8a6470f0..fd0d638d9c 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -425,7 +425,7 @@ const size_t minimumSymbolTableSize = 1024; diagnostic(bool, BytecodeVerificationRemote, true, \ "Enable the Java bytecode verifier for remote classes") \ \ - diagnostic(bool, BytecodeVerificationLocal, false, \ + diagnostic(bool, BytecodeVerificationLocal, trueInDebug, \ "Enable the Java bytecode verifier for local classes") \ \ develop(bool, ForceFloatExceptions, trueInDebug, \ diff --git a/src/java.base/share/classes/java/lang/Scoped.java b/src/java.base/share/classes/java/lang/Scoped.java index c2ed36ed6e..431ee5d74a 100644 --- a/src/java.base/share/classes/java/lang/Scoped.java +++ b/src/java.base/share/classes/java/lang/Scoped.java @@ -72,17 +72,6 @@ public abstract class Scoped { return Thread.currentThread().scopedMap(); } - /** - * TBD - * @param aMap a map - * @return a map - */ - public static Object replaceScopedMap(Object aMap) { - Object result = Thread.currentThread().replaceScopedMap(aMap); - Thread.setScopedCache(null); - return result; - } - @ForceInline @SuppressWarnings("unchecked") // one map has entries for all types static final Object getObject(int hash, Scoped key) { @@ -137,6 +126,20 @@ public abstract class Scoped { return (Scoped) writeClass(klass, generateKey(), caller, Scoped.class); } + /** + * TBD + * + * @param TBD + * @param klass TBD + * @return TBD + */ + @SuppressWarnings("unchecked") // one map has entries for all types + @CallerSensitive + public static Scoped inheritableForType(Class klass) { + Class caller = Reflection.getCallerClass(); + return (Scoped) writeClass(klass, generateKey(), caller, InheritableScoped.class); + } + /** * TBD * @@ -332,6 +335,26 @@ public abstract class Scoped { } } + // Support for scope inheritance + + /** + * TBD + * + * @return TBD + */ + public boolean shouldInherit() { + return false; + } + + static abstract class InheritableScoped extends Scoped { + InheritableScoped() { + super(); + } + public final boolean shouldInherit() { + return true; + } + } + private static class Cache { static final int INDEX_BITS = SCOPED_CACHE_SHIFT; @@ -413,6 +436,38 @@ public abstract class Scoped { } } + /** + * TBD + * + * @return TBD + */ + public static Object collectInheritableValues() { + ScopedMap map = Thread.currentThread().maybeScopedMap(); + return map != null ? map.collectInheritableValues() : null; + } + + /** + * TBD + * + * @param obj TBD + * @return TBD + */ + public static Object bindValues(Object obj) { + return obj != null + ? Thread.currentThread().scopedMap().bindInheritableValues(obj) + : null; + } + + /** + * TBD + * + * @param obj TBD + */ + public static void releaseValues(Object obj) { + if (obj != null) { + Thread.currentThread().scopedMap().releaseInheritableValues(obj); + } + } } abstract class ScopedFinal extends Scoped { diff --git a/src/java.base/share/classes/java/lang/ScopedMap.java b/src/java.base/share/classes/java/lang/ScopedMap.java index bf202d191c..583b432e6b 100644 --- a/src/java.base/share/classes/java/lang/ScopedMap.java +++ b/src/java.base/share/classes/java/lang/ScopedMap.java @@ -178,4 +178,45 @@ class ScopedMap { tab = newTable; return true; } + + Object[] collectInheritableValues() { + var result = new Object[this.size * 2]; + int cursor = 0; + int remaining = this.size; + for (int i = 0; remaining > 0; i += 2) { + var key = (Scoped)tab[i]; + if (key != null) { + if (key.shouldInherit()) { + result[cursor++] = key; + result[cursor++] = tab[i + 1]; + } + remaining--; + } + } + + if (cursor < tab.length) { + var tmp = new Object[cursor]; + System.arraycopy(result, 0, tmp, 0, cursor); + result = tmp; + } + + return result; + } + + @SuppressWarnings("unchecked") // one map has entries for all types + ScopedBinding[] bindInheritableValues(Object o) { + Object[] theTable = (Object[])o; + ScopedBinding[] result = new ScopedBinding[theTable.length / 2]; + int cursor = 0; + for (int i = 0; i < theTable.length; i += 2) { + result[cursor++] = ((Scoped)theTable[i]).bind(theTable[i + 1]); + } + return result; + } + + void releaseInheritableValues(Object obj) { + for (ScopedBinding b : (ScopedBinding[])obj) { + b.close(); + } + } } \ No newline at end of file diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index 73dce7681f..e579184083 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -314,24 +314,8 @@ public class Thread implements Runnable { return map; } - final ScopedMap mutableScopedMap() { - var map = scopedMap; - if (map == null) { - map = scopedMap = new ScopedMap(); - } - map.copyOnWrite = true; - return map; - } - - /** - * TBD - * @param map a map - * @return a map - */ - public final Object replaceScopedMap(Object map) { - ScopedMap result = scopedMap; - scopedMap = (ScopedMap)map; - return result; + final ScopedMap maybeScopedMap() { + return scopedMap; } // end Scoped support diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 4ca0a8e923..1c8b3967e0 100644 --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -91,6 +91,8 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; private static final boolean disableEagerInitialization; + private static final boolean shouldInheritScopedValues; + static { try { final String dumpProxyClassesKey = "jdk.internal.lambda.dumpProxyClasses"; @@ -99,6 +101,10 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization"; disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey); + + final String inheritScopedValuesKey = "jdk.internal.lambda.inheritScopedValues"; + final String shouldInherit = GetPropertyAction.privilegedGetProperty(inheritScopedValuesKey); + shouldInheritScopedValues = (null == shouldInherit) || (shouldInherit.equals("true")); } catch (Throwable t) { t.printStackTrace(); throw t; @@ -303,7 +309,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; // Forward the SAM method MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName, samMethodType.toMethodDescriptorString(), null, null); - mv.visitAnnotation(DESCR_HIDDEN, true); + // mv.visitAnnotation(DESCR_HIDDEN, true); new ForwardingMethodGenerator(mv).generate(samMethodType); // Forward the bridges @@ -311,7 +317,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; for (MethodType mt : additionalBridges) { mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName, mt.toMethodDescriptorString(), null, null); - mv.visitAnnotation(DESCR_HIDDEN, true); + // qmv.visitAnnotation(DESCR_HIDDEN, true); new ForwardingMethodGenerator(mv).generate(mt); } } @@ -368,6 +374,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; * Generate the constructor for the class */ private void generateConstructor() { + boolean inheritScopedValues = shouldInheritScopedValues && VM.isBooted(); // Generate constructor MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR, constructorType.toMethodDescriptorString(), null, null); @@ -383,11 +390,13 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; lvIndex += getParameterSize(argType); ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]); } - if (VM.isBooted()) { + if (inheritScopedValues) { ctor.visitVarInsn(ALOAD, 0); // ctor.visitMethodInsn(INVOKESTATIC, "java/lang/Scoped", "replaceScopedMap", "(Ljava/lang/Object;)Ljava/lang/Object;", // false); - ctor.visitMethodInsn(INVOKESTATIC, "java/lang/Scoped", "getScopedMap", "()Ljava/lang/Object;", + // ctor.visitMethodInsn(INVOKESTATIC, "java/lang/Scoped", "getScopedMap", "()Ljava/lang/Object;", + // false); + ctor.visitMethodInsn(INVOKESTATIC, "java/lang/Scoped", "collectInheritableValues", "()Ljava/lang/Object;", false); ctor.visitFieldInsn(PUTFIELD, lambdaClassName, "Scoped$$scopedMap", "Ljava/lang/Object;"); @@ -469,6 +478,12 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; mv.visitEnd(); } + private Label mark(MethodVisitor mv) { + Label label = new Label(); + mv.visitLabel(label); + return label; + } + /** * This class generates a method body which calls the lambda implementation * method, converting arguments, as needed. @@ -482,6 +497,11 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; void generate(MethodType methodType) { visitCode(); + boolean inheritScopedValues = shouldInheritScopedValues && VM.isBooted(); + + // Catch anything thrown in the called method + Label start, end, handler; + if (implKind == MethodHandleInfo.REF_newInvokeSpecial) { visitTypeInsn(NEW, implMethodClassName); visitInsn(DUP); @@ -493,25 +513,33 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; convertArgumentTypes(methodType); - if (VM.isBooted()) { + // System.err.println("Type: " + lambdaClassName + " methodType.parameterCount: " + methodType.parameterCount()); + + int scopedMapLocalSlot = methodType.parameterCount() + 1; + + if (inheritScopedValues) { visitVarInsn(ALOAD, 0); - visitFieldInsn(GETFIELD, lambdaClassName, "Scoped$$mutableScopedMap", + visitFieldInsn(GETFIELD, lambdaClassName, "Scoped$$scopedMap", "Ljava/lang/Object;"); - visitMethodInsn(INVOKESTATIC, "java/lang/Scoped", "replaceScopedMap", "(Ljava/lang/Object;)Ljava/lang/Object;", + visitMethodInsn(INVOKESTATIC, "java/lang/Scoped", "bindValues", "(Ljava/lang/Object;)Ljava/lang/Object;", false); - visitVarInsn(ASTORE, 1); + visitVarInsn(ASTORE, scopedMapLocalSlot); } + start = mark(mv); + // Invoke the method we want to forward to visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc, implClass.isInterface()); - if (VM.isBooted()) { - visitVarInsn(ALOAD, 1); - visitMethodInsn(INVOKESTATIC, "java/lang/Scoped", "replaceScopedMap", "(Ljava/lang/Object;)Ljava/lang/Object;", + end = mark(mv); + + if (inheritScopedValues) { + visitVarInsn(ALOAD, scopedMapLocalSlot); + visitMethodInsn(INVOKESTATIC, "java/lang/Scoped", "releaseValues", "(Ljava/lang/Object;)V", false); - visitInsn(POP); + // visitInsn(POP); } // Convert the return value (if any) and return it @@ -521,6 +549,27 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; Class samReturnClass = methodType.returnType(); convertType(implReturnClass, samReturnClass, samReturnClass); visitInsn(getReturnOpcode(samReturnClass)); + + // Exception handler to restore the Scoped map + if (inheritScopedValues) { + handler = mark(mv); + Object[] stack = {"java/lang/Throwable"}; + Object[] locals = new Object[methodType.parameterCount() + 2]; + locals[0] = lambdaClassName; + for (int i = 1; i < locals.length; i++) { + locals[i] = TOP; + } + locals[scopedMapLocalSlot] = "java/lang/Object"; + mv.visitFrame(F_FULL, locals.length, locals, stack.length, stack); + visitVarInsn(ALOAD, scopedMapLocalSlot); + visitMethodInsn(INVOKESTATIC, "java/lang/Scoped", "releaseValues", "(Ljava/lang/Object;)V", + false); + // visitInsn(POP); + mv.visitTryCatchBlock(start, end, handler, null); + mv.visitInsn(ATHROW); + // visitInsn(getReturnOpcode(samReturnClass)); + } + // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored visitMaxs(-1, -1); visitEnd(); diff --git a/src/java.base/share/classes/java/lang/invoke/ProxyClassesDumper.java b/src/java.base/share/classes/java/lang/invoke/ProxyClassesDumper.java index e2eef6f8c4..e8963b0e11 100644 --- a/src/java.base/share/classes/java/lang/invoke/ProxyClassesDumper.java +++ b/src/java.base/share/classes/java/lang/invoke/ProxyClassesDumper.java @@ -57,10 +57,10 @@ final class ProxyClassesDumper { private final Path dumpDir; public static ProxyClassesDumper getInstance(String path) { - System.out.println("path for dumper: " + path); - if (null == path) { - return null; - } + // if (null == path) { + // path = "/tmp"; + // System.err.println("Dumping to /tmp"); + // } try { path = path.trim(); final Path dir = Path.of(path.isEmpty() ? "." : path);