From c87cbe8459cbdcb3605d8fa28183ba9315cfd287 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Tue, 13 Feb 2024 13:42:30 +0100 Subject: [PATCH 1/4] Add support for jdk.internal.vm.annotation.DontInline This is not respected by the truffle inliner at the moment --- .../truffle/espresso/classfile/ClassfileParser.java | 4 ++++ .../oracle/truffle/espresso/classfile/Constants.java | 1 + .../oracle/truffle/espresso/descriptors/Symbol.java | 2 ++ .../src/com/oracle/truffle/espresso/impl/Method.java | 10 ++++++++-- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java index 552fad828055..c077b50f6275 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java @@ -26,6 +26,7 @@ import static com.oracle.truffle.espresso.classfile.Constants.ACC_ABSTRACT; import static com.oracle.truffle.espresso.classfile.Constants.ACC_ANNOTATION; import static com.oracle.truffle.espresso.classfile.Constants.ACC_CALLER_SENSITIVE; +import static com.oracle.truffle.espresso.classfile.Constants.ACC_DONT_INLINE; import static com.oracle.truffle.espresso.classfile.Constants.ACC_ENUM; import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINAL; import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINALIZER; @@ -837,6 +838,9 @@ private ParserMethod parseMethod(boolean isInterface) { } else if (Type.java_lang_invoke_ForceInline.equals(annotType) || Type.jdk_internal_vm_annotation_ForceInline.equals(annotType)) { methodFlags |= ACC_FORCE_INLINE; + } else if (Type.java_lang_invoke_DontInline.equals(annotType) || + Type.jdk_internal_vm_annotation_DontInline.equals(annotType)) { + methodFlags |= ACC_DONT_INLINE; } else if (Type.jdk_internal_misc_ScopedMemoryAccess$Scoped.equals(annotType)) { methodFlags |= ACC_SCOPED; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java index ec9496057346..e7103c389cb9 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java @@ -56,6 +56,7 @@ public final class Constants { public static final int ACC_CALLER_SENSITIVE = 0x00080000; public static final int ACC_HIDDEN = 0x00100000; public static final int ACC_SCOPED = 0x00200000; + public static final int ACC_DONT_INLINE = 0x00400000; public static final int ACC_IS_HIDDEN_CLASS = 0x04000000; public static final int FIELD_ID_TYPE = 0x01000000; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java index f2a5716c7f93..1b2e2aecd21c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java @@ -908,6 +908,8 @@ public static void ensureInitialized() { public static final Symbol jdk_internal_reflect_CallerSensitive = StaticSymbols.putType("Ljdk/internal/reflect/CallerSensitive;"); public static final Symbol java_lang_invoke_ForceInline = StaticSymbols.putType("Ljava/lang/invoke/ForceInline;"); public static final Symbol jdk_internal_vm_annotation_ForceInline = StaticSymbols.putType("Ljdk/internal/vm/annotation/ForceInline;"); + public static final Symbol java_lang_invoke_DontInline = StaticSymbols.putType("Ljava/lang/invoke/DontInline;"); + public static final Symbol jdk_internal_vm_annotation_DontInline = StaticSymbols.putType("Ljdk/internal/vm/annotation/DontInline;"); // ScopedMemoryAccess public static final Symbol jdk_internal_misc_ScopedMemoryAccess$Scoped = StaticSymbols.putType("Ljdk/internal/misc/ScopedMemoryAccess$Scoped;"); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java index 953215b51ddf..497f65b2aea7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java @@ -29,6 +29,7 @@ import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTSTATIC; import static com.oracle.truffle.espresso.bytecode.Bytecodes.RETURN; import static com.oracle.truffle.espresso.classfile.Constants.ACC_CALLER_SENSITIVE; +import static com.oracle.truffle.espresso.classfile.Constants.ACC_DONT_INLINE; import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINAL; import static com.oracle.truffle.espresso.classfile.Constants.ACC_FORCE_INLINE; import static com.oracle.truffle.espresso.classfile.Constants.ACC_HIDDEN; @@ -571,6 +572,11 @@ public boolean isForceInline() { return (getModifiers() & ACC_FORCE_INLINE) != 0 && StaticObject.isNull(getDeclaringKlass().getDefiningClassLoader()); } + public boolean isDontInline() { + // Respect in truffle compilations when that's possible (GR-57507) + return (getModifiers() & ACC_DONT_INLINE) != 0; + } + public boolean isHidden() { return (getModifiers() & ACC_HIDDEN) != 0; } @@ -743,7 +749,7 @@ public boolean isPolySignatureIntrinsic() { } public boolean isInlinableGetter() { - if (!getSubstitutions().hasSubstitutionFor(this)) { + if (!getSubstitutions().hasSubstitutionFor(this) && !isDontInline()) { if (getParameterCount() == 0 && !isAbstract() && !isNative() && !isSynchronized()) { return hasGetterBytecodes(); } @@ -766,7 +772,7 @@ private boolean hasGetterBytecodes() { } public boolean isInlinableSetter() { - if (!getSubstitutions().hasSubstitutionFor(this)) { + if (!getSubstitutions().hasSubstitutionFor(this) && !isDontInline()) { if (getParameterCount() == 1 && !isAbstract() && !isNative() && !isSynchronized()) { return hasSetterBytecodes(); } From 26279ecd18e55e2320f193aee4ccc693da257b62 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Thu, 25 Jul 2024 10:55:19 +0200 Subject: [PATCH 2/4] Refactor VM annotation parsing --- .../espresso/classfile/ClassfileParser.java | 97 ++++++++++++------- 1 file changed, 63 insertions(+), 34 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java index c077b50f6275..1c5be7c07686 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java @@ -632,6 +632,18 @@ boolean supports(int annotation) { } } + private enum AnnotationLocation { + Method, + Field, + Class + } + + private record RuntimeVisibleAnnotationsAttribute(Attribute attribute, int flags) { + private RuntimeVisibleAnnotationsAttribute { + Objects.requireNonNull(attribute); + } + } + private class CommonAttributeParser { final InfoType infoType; @@ -696,6 +708,54 @@ Attribute parseCommonAttribute(Symbol attributeName, int attributeSize) { } return null; } + + RuntimeVisibleAnnotationsAttribute parseRuntimeVisibleAnnotations(int attributeSize, AnnotationLocation location) { + assert infoType.supports(RUNTIME_VISIBLE_ANNOTATIONS); + if (runtimeVisibleAnnotations != null) { + throw ConstantPool.classFormatError("Duplicate RuntimeVisibleAnnotations attribute"); + } + + // Check for special internal annotations + byte[] data = stream.readByteArray(attributeSize); + ClassfileStream subStream = new ClassfileStream(data, classfile); + int flags = 0; + if (location == AnnotationLocation.Method) { + flags = parseMethodVMAnnotations(subStream); + } + + Attribute attribute = new Attribute(Name.RuntimeVisibleAnnotations, data); + runtimeVisibleAnnotations = attribute; + return new RuntimeVisibleAnnotationsAttribute(attribute, flags); + } + + private int parseMethodVMAnnotations(ClassfileStream subStream) { + int flags = 0; + int count = subStream.readU2(); + for (int j = 0; j < count; j++) { + int typeIndex = parseAnnotation(subStream); + Utf8Constant constant = pool.utf8At(typeIndex, "annotation type"); + // Validation of the type is done at runtime by guest java code. + Symbol annotType = constant.value(); + if (Type.java_lang_invoke_LambdaForm$Compiled.equals(annotType)) { + flags |= ACC_LAMBDA_FORM_COMPILED; + } else if (Type.java_lang_invoke_LambdaForm$Hidden.equals(annotType) || + Type.jdk_internal_vm_annotation_Hidden.equals(annotType)) { + flags |= ACC_HIDDEN; + } else if (Type.sun_reflect_CallerSensitive.equals(annotType) || + Type.jdk_internal_reflect_CallerSensitive.equals(annotType)) { + flags |= ACC_CALLER_SENSITIVE; + } else if (Type.java_lang_invoke_ForceInline.equals(annotType) || + Type.jdk_internal_vm_annotation_ForceInline.equals(annotType)) { + flags |= ACC_FORCE_INLINE; + } else if (Type.java_lang_invoke_DontInline.equals(annotType) || + Type.jdk_internal_vm_annotation_DontInline.equals(annotType)) { + flags |= ACC_DONT_INLINE; + } else if (Type.jdk_internal_misc_ScopedMemoryAccess$Scoped.equals(annotType)) { + flags |= ACC_SCOPED; + } + } + return flags; + } } private ParserMethod parseMethod(boolean isInterface) { @@ -788,7 +848,6 @@ private ParserMethod parseMethod(boolean isInterface) { CodeAttribute codeAttribute = null; Attribute checkedExceptions = null; - Attribute runtimeVisibleAnnotations = null; CommonAttributeParser commonAttributeParser = new CommonAttributeParser(InfoType.Method); MethodParametersAttribute methodParameters = null; @@ -815,37 +874,9 @@ private ParserMethod parseMethod(boolean isInterface) { methodAttributes[i] = checkedExceptions = new Attribute(attributeName, null); } else if (majorVersion >= JAVA_1_5_VERSION) { if (attributeName.equals(Name.RuntimeVisibleAnnotations)) { - if (runtimeVisibleAnnotations != null) { - throw ConstantPool.classFormatError("Duplicate RuntimeVisibleAnnotations attribute"); - } - // Check if java.lang.invoke.LambdaForm.Compiled is present here. - byte[] data = stream.readByteArray(attributeSize); - ClassfileStream subStream = new ClassfileStream(data, this.classfile); - int count = subStream.readU2(); - for (int j = 0; j < count; j++) { - int typeIndex = parseAnnotation(subStream); - Utf8Constant constant = pool.utf8At(typeIndex, "annotation type"); - // Validation of the type is done at runtime by guest java code. - Symbol annotType = constant.value(); - if (Type.java_lang_invoke_LambdaForm$Compiled.equals(annotType)) { - methodFlags |= ACC_LAMBDA_FORM_COMPILED; - } else if (Type.java_lang_invoke_LambdaForm$Hidden.equals(annotType) || - Type.jdk_internal_vm_annotation_Hidden.equals(annotType)) { - methodFlags |= ACC_HIDDEN; - } else if (Type.sun_reflect_CallerSensitive.equals(annotType) || - Type.jdk_internal_reflect_CallerSensitive.equals(annotType)) { - methodFlags |= ACC_CALLER_SENSITIVE; - } else if (Type.java_lang_invoke_ForceInline.equals(annotType) || - Type.jdk_internal_vm_annotation_ForceInline.equals(annotType)) { - methodFlags |= ACC_FORCE_INLINE; - } else if (Type.java_lang_invoke_DontInline.equals(annotType) || - Type.jdk_internal_vm_annotation_DontInline.equals(annotType)) { - methodFlags |= ACC_DONT_INLINE; - } else if (Type.jdk_internal_misc_ScopedMemoryAccess$Scoped.equals(annotType)) { - methodFlags |= ACC_SCOPED; - } - } - methodAttributes[i] = runtimeVisibleAnnotations = new Attribute(attributeName, data); + RuntimeVisibleAnnotationsAttribute annotations = commonAttributeParser.parseRuntimeVisibleAnnotations(attributeSize, AnnotationLocation.Method); + methodFlags |= annotations.flags; + methodAttributes[i] = annotations.attribute; } else if (attributeName.equals(Name.MethodParameters)) { if (methodParameters != null) { throw ConstantPool.classFormatError("Duplicate MethodParameters attribute"); @@ -853,12 +884,10 @@ private ParserMethod parseMethod(boolean isInterface) { methodAttributes[i] = methodParameters = parseMethodParameters(attributeName); } else { Attribute attr = commonAttributeParser.parseCommonAttribute(attributeName, attributeSize); - // stream.skip(attributeSize); methodAttributes[i] = attr == null ? new Attribute(attributeName, stream.readByteArray(attributeSize)) : attr; } } else { - // stream.skip(attributeSize); methodAttributes[i] = new Attribute(attributeName, stream.readByteArray(attributeSize)); } From bca538f0972e21c2106b4fcdec2e1b4472f0e108 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Thu, 25 Jul 2024 11:07:24 +0200 Subject: [PATCH 3/4] Parse Stable annotation --- .../espresso/classfile/ClassfileParser.java | 41 +++++++++++++++---- .../truffle/espresso/classfile/Constants.java | 8 +++- .../truffle/espresso/descriptors/Symbol.java | 1 + .../espresso/impl/LinkedKlassFieldLayout.java | 3 +- .../truffle/espresso/impl/ParserField.java | 13 +++--- 5 files changed, 46 insertions(+), 20 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java index 1c5be7c07686..d39db9df6e5d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java @@ -40,6 +40,7 @@ import static com.oracle.truffle.espresso.classfile.Constants.ACC_PROTECTED; import static com.oracle.truffle.espresso.classfile.Constants.ACC_PUBLIC; import static com.oracle.truffle.espresso.classfile.Constants.ACC_SCOPED; +import static com.oracle.truffle.espresso.classfile.Constants.ACC_STABLE; import static com.oracle.truffle.espresso.classfile.Constants.ACC_STATIC; import static com.oracle.truffle.espresso.classfile.Constants.ACC_STRICT; import static com.oracle.truffle.espresso.classfile.Constants.ACC_SUPER; @@ -461,11 +462,11 @@ private ParserKlass parseClassImpl() { return new ParserKlass(pool, classDefinitionInfo.patchFlags(classFlags), thisKlassName, thisKlassType, superKlass, superInterfaces, methods, fields, attributes, thisKlassIndex); } - public static Symbol getClassName(ClassLoadingEnv env, byte[] bytes) { + public static Symbol getClassName(ClassLoadingEnv env, byte[] bytes) { return new ClassfileParser(env, new ClassfileStream(bytes, null)).getClassName(); } - private Symbol getClassName() { + private Symbol getClassName() { readMagic(); @@ -719,9 +720,11 @@ RuntimeVisibleAnnotationsAttribute parseRuntimeVisibleAnnotations(int attributeS byte[] data = stream.readByteArray(attributeSize); ClassfileStream subStream = new ClassfileStream(data, classfile); int flags = 0; - if (location == AnnotationLocation.Method) { - flags = parseMethodVMAnnotations(subStream); - } + flags = switch (location) { + case Method -> parseMethodVMAnnotations(subStream); + case Field -> parseFieldVMAnnotations(subStream); + case Class -> 0; + }; Attribute attribute = new Attribute(Name.RuntimeVisibleAnnotations, data); runtimeVisibleAnnotations = attribute; @@ -756,6 +759,21 @@ private int parseMethodVMAnnotations(ClassfileStream subStream) { } return flags; } + + private int parseFieldVMAnnotations(ClassfileStream subStream) { + int flags = 0; + int count = subStream.readU2(); + for (int j = 0; j < count; j++) { + int typeIndex = parseAnnotation(subStream); + Utf8Constant constant = pool.utf8At(typeIndex, "annotation type"); + // Validation of the type is done at runtime by guest java code. + Symbol annotType = constant.value(); + if (Type.jdk_internal_vm_annotation_Stable.equals(annotType)) { + flags |= ACC_STABLE; + } + } + return flags; + } } private ParserMethod parseMethod(boolean isInterface) { @@ -885,7 +903,6 @@ private ParserMethod parseMethod(boolean isInterface) { } else { Attribute attr = commonAttributeParser.parseCommonAttribute(attributeName, attributeSize); methodAttributes[i] = attr == null ? new Attribute(attributeName, stream.readByteArray(attributeSize)) : attr; - } } else { methodAttributes[i] = new Attribute(attributeName, stream.readByteArray(attributeSize)); @@ -1640,9 +1657,15 @@ private ParserField parseField(boolean isInterface) { fieldFlags |= ACC_SYNTHETIC; fieldAttributes[i] = new Attribute(attributeName, null); } else if (majorVersion >= JAVA_1_5_VERSION) { - Attribute attr = commonAttributeParser.parseCommonAttribute(attributeName, attributeSize); - // stream.skip(attributeSize); - fieldAttributes[i] = attr == null ? new Attribute(attributeName, stream.readByteArray(attributeSize)) : attr; + if (attributeName.equals(Name.RuntimeVisibleAnnotations)) { + RuntimeVisibleAnnotationsAttribute annotations = commonAttributeParser.parseRuntimeVisibleAnnotations(attributeSize, AnnotationLocation.Field); + fieldFlags |= annotations.flags; + fieldAttributes[i] = annotations.attribute; + } else { + Attribute attr = commonAttributeParser.parseCommonAttribute(attributeName, attributeSize); + // stream.skip(attributeSize); + fieldAttributes[i] = attr == null ? new Attribute(attributeName, stream.readByteArray(attributeSize)) : attr; + } } else { // stream.skip(attributeSize); fieldAttributes[i] = new Attribute(attributeName, stream.readByteArray(attributeSize)); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java index e7103c389cb9..4965e91283d2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java @@ -50,14 +50,18 @@ public final class Constants { public static final int ACC_MODULE = 0x00008000; // Not part of the spec, used internally by the VM. + // Methods public static final int ACC_FINALIZER = 0x00010000; public static final int ACC_FORCE_INLINE = 0x00020000; public static final int ACC_LAMBDA_FORM_COMPILED = 0x00040000; public static final int ACC_CALLER_SENSITIVE = 0x00080000; - public static final int ACC_HIDDEN = 0x00100000; + public static final int ACC_HIDDEN = 0x00100000; // also for fields public static final int ACC_SCOPED = 0x00200000; public static final int ACC_DONT_INLINE = 0x00400000; - public static final int ACC_IS_HIDDEN_CLASS = 0x04000000; + // Classes + public static final int ACC_IS_HIDDEN_CLASS = 0x04000000; // synchronized with JVM_ACC_IS_HIDDEN_CLASS + // Fields + public static final int ACC_STABLE = 0x00010000; public static final int FIELD_ID_TYPE = 0x01000000; public static final int FIELD_ID_OBFUSCATE = 0x02000000; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java index 1b2e2aecd21c..371a8c3a928a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java @@ -904,6 +904,7 @@ public static void ensureInitialized() { public static final Symbol java_lang_invoke_LambdaForm$Compiled = StaticSymbols.putType("Ljava/lang/invoke/LambdaForm$Compiled;"); public static final Symbol java_lang_invoke_LambdaForm$Hidden = StaticSymbols.putType("Ljava/lang/invoke/LambdaForm$Hidden;"); public static final Symbol jdk_internal_vm_annotation_Hidden = StaticSymbols.putType("Ljdk/internal/vm/annotation/Hidden;"); + public static final Symbol jdk_internal_vm_annotation_Stable = StaticSymbols.putType("Ljdk/internal/vm/annotation/Stable;"); public static final Symbol sun_reflect_CallerSensitive = StaticSymbols.putType("Lsun/reflect/CallerSensitive;"); public static final Symbol jdk_internal_reflect_CallerSensitive = StaticSymbols.putType("Ljdk/internal/reflect/CallerSensitive;"); public static final Symbol java_lang_invoke_ForceInline = StaticSymbols.putType("Ljava/lang/invoke/ForceInline;"); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java index 627bff1cd265..bde0330e5736 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.espresso.impl; +import static com.oracle.truffle.espresso.classfile.Constants.ACC_HIDDEN; import static java.util.Map.entry; import java.util.HashSet; @@ -78,7 +79,7 @@ final class LinkedKlassFieldLayout { for (HiddenField hiddenField : fieldCounter.hiddenFieldNames) { if (hiddenField.versionRange.contains(description.javaVersion)) { - ParserField hiddenParserField = new ParserField(ParserField.HIDDEN | hiddenField.additionalFlags, hiddenField.name, hiddenField.type, null); + ParserField hiddenParserField = new ParserField(ACC_HIDDEN | hiddenField.additionalFlags, hiddenField.name, hiddenField.type, null); createAndRegisterLinkedField(parserKlass, hiddenParserField, nextInstanceFieldSlot++, nextInstanceFieldIndex++, idMode, instanceBuilder, instanceFields); } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserField.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserField.java index f2a8809bad50..a1a697898cea 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserField.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserField.java @@ -22,6 +22,10 @@ */ package com.oracle.truffle.espresso.impl; +import static com.oracle.truffle.espresso.classfile.Constants.ACC_HIDDEN; + +import java.lang.reflect.Modifier; + import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.espresso.descriptors.Symbol; import com.oracle.truffle.espresso.descriptors.Symbol.Name; @@ -31,15 +35,8 @@ import com.oracle.truffle.espresso.runtime.Attribute; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; -import java.lang.reflect.Modifier; - -import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINALIZER; - public final class ParserField { - public static final ParserField[] EMPTY_ARRAY = new ParserField[0]; - // re-use the Constants.ACC_FINALIZER flag to mark hidden fields - public static final int HIDDEN = ACC_FINALIZER; /** * This value contains all flags as stored in the VM including internal ones. @@ -78,7 +75,7 @@ public ParserField(int flags, Symbol name, Symbol type, final Attrib } public boolean isHidden() { - return (flags & HIDDEN) != 0; + return (flags & ACC_HIDDEN) != 0; } public boolean isStatic() { From efafec4df4283007a26fda9ab5432726a57c15d0 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 23 Aug 2024 11:05:14 +0200 Subject: [PATCH 4/4] Only parse VM annotations for privileged classes --- .../espresso/classfile/ClassfileParser.java | 29 ++++++++++--------- .../espresso/impl/ClassRegistries.java | 5 ---- .../truffle/espresso/impl/ClassRegistry.java | 19 ++++++++---- .../oracle/truffle/espresso/impl/Method.java | 2 +- .../preinit/DefaultParserKlassProvider.java | 2 +- .../com/oracle/truffle/espresso/vm/VM.java | 2 +- 6 files changed, 31 insertions(+), 28 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java index d39db9df6e5d..d407c84b9b49 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java @@ -165,6 +165,7 @@ public final class ClassfileParser { private final ClassfileStream stream; private final ClassRegistry.ClassDefinitionInfo classDefinitionInfo; + private final boolean loaderIsBootOrPlatform; private Symbol classType; @@ -179,18 +180,19 @@ public final class ClassfileParser { private ImmutableConstantPool pool; - private ClassfileParser(ClassLoadingEnv env, ClassfileStream stream, boolean verifiable, Symbol requestedClassType, ClassRegistry.ClassDefinitionInfo info) { + private ClassfileParser(ClassLoadingEnv env, ClassfileStream stream, boolean verifiable, boolean loaderIsBootOrPlatform, Symbol requestedClassType, ClassRegistry.ClassDefinitionInfo info) { this.requestedClassType = requestedClassType; this.env = env; this.classfile = null; this.stream = Objects.requireNonNull(stream); this.verifiable = verifiable; + this.loaderIsBootOrPlatform = loaderIsBootOrPlatform; this.classDefinitionInfo = info; } // Note: only used for reading the class name from class bytes private ClassfileParser(ClassLoadingEnv env, ClassfileStream stream) { - this(env, stream, false, null, ClassRegistry.ClassDefinitionInfo.EMPTY); + this(env, stream, false, false, null, ClassRegistry.ClassDefinitionInfo.EMPTY); } void handleBadConstant(Tag tag, ClassfileStream s) { @@ -224,15 +226,12 @@ void checkDynamicConstantSupport(Tag tag) { public static ParserKlass parse(ClassLoadingEnv env, ClassfileStream stream, StaticObject loader, Symbol requestedClassName) { boolean verifiable = MethodVerifier.needsVerify(env.getLanguage(), loader); - return parse(env, stream, verifiable, requestedClassName, ClassRegistry.ClassDefinitionInfo.EMPTY); + return parse(env, stream, verifiable, env.loaderIsBootOrPlatform(loader), requestedClassName, ClassRegistry.ClassDefinitionInfo.EMPTY); } - public static ParserKlass parse(ClassLoadingEnv env, ClassfileStream stream, boolean verifiable, Symbol requestedClassName) { - return parse(env, stream, verifiable, requestedClassName, ClassRegistry.ClassDefinitionInfo.EMPTY); - } - - public static ParserKlass parse(ClassLoadingEnv env, ClassfileStream stream, boolean verifiable, Symbol requestedClassType, ClassRegistry.ClassDefinitionInfo info) { - return new ClassfileParser(env, stream, verifiable, requestedClassType, info).parseClass(); + public static ParserKlass parse(ClassLoadingEnv env, ClassfileStream stream, boolean verifiable, boolean loaderIsBootOrPlatform, Symbol requestedClassType, + ClassRegistry.ClassDefinitionInfo info) { + return new ClassfileParser(env, stream, verifiable, loaderIsBootOrPlatform, requestedClassType, info).parseClass(); } private ParserKlass parseClass() { @@ -720,11 +719,13 @@ RuntimeVisibleAnnotationsAttribute parseRuntimeVisibleAnnotations(int attributeS byte[] data = stream.readByteArray(attributeSize); ClassfileStream subStream = new ClassfileStream(data, classfile); int flags = 0; - flags = switch (location) { - case Method -> parseMethodVMAnnotations(subStream); - case Field -> parseFieldVMAnnotations(subStream); - case Class -> 0; - }; + if (loaderIsBootOrPlatform || classDefinitionInfo.forceAllowVMAnnotations()) { + flags = switch (location) { + case Method -> parseMethodVMAnnotations(subStream); + case Field -> parseFieldVMAnnotations(subStream); + case Class -> 0; + }; + } Attribute attribute = new Attribute(Name.RuntimeVisibleAnnotations, data); runtimeVisibleAnnotations = attribute; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java index 315fc59f1787..8739380eb1d0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java @@ -262,11 +262,6 @@ public Klass loadKlass(Symbol type, @JavaType(ClassLoader.class) StaticObj return registry.loadKlass(context, type, protectionDomain); } - @TruffleBoundary - public ObjectKlass defineKlass(Symbol type, byte[] bytes, StaticObject classLoader) throws EspressoClassLoadingException { - return defineKlass(type, bytes, classLoader, ClassRegistry.ClassDefinitionInfo.EMPTY); - } - @TruffleBoundary public ObjectKlass defineKlass(Symbol type, byte[] bytes, StaticObject classLoader, ClassRegistry.ClassDefinitionInfo info) throws EspressoClassLoadingException { assert classLoader != null; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java index ea154a11a164..3575a1914fd0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java @@ -67,21 +67,21 @@ public abstract class ClassRegistry { * registry. */ public static final class ClassDefinitionInfo { - public static final ClassDefinitionInfo EMPTY = new ClassDefinitionInfo(null, null, null, null, null, false, false); + public static final ClassDefinitionInfo EMPTY = new ClassDefinitionInfo(null, null, null, null, null, false, false, false); // Constructor for regular definition, but with a specified protection domain public ClassDefinitionInfo(StaticObject protectionDomain) { - this(protectionDomain, null, null, null, null, false, false); + this(protectionDomain, null, null, null, null, false, false, false); } // Constructor for Unsafe anonymous class definition. public ClassDefinitionInfo(StaticObject protectionDomain, ObjectKlass hostKlass, StaticObject[] patches) { - this(protectionDomain, hostKlass, patches, null, null, false, false); + this(protectionDomain, hostKlass, patches, null, null, false, false, true); } // Constructor for Hidden class definition. - public ClassDefinitionInfo(StaticObject protectionDomain, ObjectKlass dynamicNest, StaticObject classData, boolean isStrongHidden) { - this(protectionDomain, null, null, dynamicNest, classData, true, isStrongHidden); + public ClassDefinitionInfo(StaticObject protectionDomain, ObjectKlass dynamicNest, StaticObject classData, boolean isStrongHidden, boolean forceAllowVMAnnotations) { + this(protectionDomain, null, null, dynamicNest, classData, true, isStrongHidden, forceAllowVMAnnotations); } private ClassDefinitionInfo(StaticObject protectionDomain, @@ -90,7 +90,8 @@ private ClassDefinitionInfo(StaticObject protectionDomain, ObjectKlass dynamicNest, StaticObject classData, boolean isHidden, - boolean isStrongHidden) { + boolean isStrongHidden, + boolean forceAllowVMAnnotations) { // isStrongHidden => isHidden assert !isStrongHidden || isHidden; this.protectionDomain = protectionDomain; @@ -100,6 +101,7 @@ private ClassDefinitionInfo(StaticObject protectionDomain, this.classData = classData; this.isHidden = isHidden; this.isStrongHidden = isStrongHidden; + this.forceAllowVMAnnotations = forceAllowVMAnnotations; assert isAnonymousClass() || patches == null; } @@ -114,6 +116,7 @@ private ClassDefinitionInfo(StaticObject protectionDomain, public final StaticObject classData; public final boolean isHidden; public final boolean isStrongHidden; + public final boolean forceAllowVMAnnotations; public long klassID = -1; public boolean addedToRegistry() { @@ -132,6 +135,10 @@ public boolean isStrongHidden() { return isStrongHidden; } + public boolean forceAllowVMAnnotations() { + return forceAllowVMAnnotations; + } + public int patchFlags(int classFlags) { int flags = classFlags; if (isHidden()) { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java index 497f65b2aea7..4d491dbf5c83 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java @@ -569,7 +569,7 @@ public boolean isCallerSensitive() { * of the boot loader are ignored. */ public boolean isForceInline() { - return (getModifiers() & ACC_FORCE_INLINE) != 0 && StaticObject.isNull(getDeclaringKlass().getDefiningClassLoader()); + return (getModifiers() & ACC_FORCE_INLINE) != 0; } public boolean isDontInline() { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultParserKlassProvider.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultParserKlassProvider.java index f202d3276368..0beca02e070f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultParserKlassProvider.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultParserKlassProvider.java @@ -35,6 +35,6 @@ public final class DefaultParserKlassProvider implements ParserKlassProvider { @Override public ParserKlass getParserKlass(ClassLoadingEnv env, StaticObject loader, Symbol typeOrNull, byte[] bytes, ClassRegistry.ClassDefinitionInfo info) { boolean verifiable = MethodVerifier.needsVerify(env.getLanguage(), loader); - return ClassfileParser.parse(env, new ClassfileStream(bytes, null), verifiable, typeOrNull, info); + return ClassfileParser.parse(env, new ClassfileStream(bytes, null), verifiable, env.loaderIsBootOrPlatform(loader), typeOrNull, info); } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java index 9082ed5bd288..085a3ca3f4be 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java @@ -1895,7 +1895,7 @@ private Symbol namePtrToInternal(TruffleObject namePtr) { try { if (isHidden) { // Special handling - k = getContext().getRegistries().defineKlass(type, bytes, loader, new ClassRegistry.ClassDefinitionInfo(pd, nest, classData, isStrong)); + k = getContext().getRegistries().defineKlass(type, bytes, loader, new ClassRegistry.ClassDefinitionInfo(pd, nest, classData, isStrong, vmAnnotations)); } else { k = getContext().getRegistries().defineKlass(type, bytes, loader, new ClassRegistry.ClassDefinitionInfo(pd)); }