diff --git a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java index 1ed7c422c9857..8f934d6d67c95 100644 --- a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java +++ b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java @@ -27,6 +27,7 @@ import java.lang.classfile.*; import java.lang.classfile.attribute.ExceptionsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.classfile.attribute.SourceFileAttribute; import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; @@ -68,6 +69,9 @@ abstract class ClassSpecializer.SpeciesDat private static final ClassDesc CD_LambdaForm = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;"); private static final ClassDesc CD_BoundMethodHandle = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/BoundMethodHandle;"); + private static final RuntimeVisibleAnnotationsAttribute STABLE_ANNOTATION = RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(ConstantUtils.referenceClassDesc(Stable.class)) + ); private final Class topClass; private final Class keyType; @@ -615,7 +619,7 @@ Class generateConcreteSpeciesCode(String className, ClassSpecialize byte[] generateConcreteSpeciesCodeFile(String className0, ClassSpecializer.SpeciesData speciesData) { final ClassDesc classDesc = ClassDesc.of(className0); final ClassDesc superClassDesc = classDesc(speciesData.deriveSuperClass()); - return ClassFile.of().build(classDesc, new Consumer() { + return ClassFile.of().build(classDesc, new Consumer<>() { @Override public void accept(ClassBuilder clb) { clb.withFlags(ACC_FINAL | ACC_SUPER) @@ -623,7 +627,13 @@ public void accept(ClassBuilder clb) { .with(SourceFileAttribute.of(classDesc.displayName())) // emit static types and BMH_SPECIES fields - .withField(sdFieldName, CD_SPECIES_DATA, ACC_STATIC); + .withField(sdFieldName, CD_SPECIES_DATA, new Consumer<>() { + @Override + public void accept(FieldBuilder fb) { + fb.withFlags(ACC_STATIC) + .with(STABLE_ANNOTATION); + } + }); // handy holder for dealing with groups of typed values (ctor arguments and fields) class Var { diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index ec131d67f2b75..ffd368f47c1c0 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -526,7 +526,9 @@ private boolean checkActualReceiver(CodeBuilder cob) { // Suppress method in backtraces displayed to the user, mark this method as // a compiled LambdaForm, then either force or prohibit inlining. public static final RuntimeVisibleAnnotationsAttribute LF_DONTINLINE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, DONTINLINE); + public static final RuntimeVisibleAnnotationsAttribute LF_DONTINLINE_PROFILE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, DONTINLINE, INJECTEDPROFILE); public static final RuntimeVisibleAnnotationsAttribute LF_FORCEINLINE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, FORCEINLINE); + public static final RuntimeVisibleAnnotationsAttribute LF_FORCEINLINE_PROFILE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, FORCEINLINE, INJECTEDPROFILE); /** * Generate an invoker method for the passed {@link LambdaForm}. @@ -586,7 +588,11 @@ public void accept(CodeBuilder cob) { if (PROFILE_GWT) { assert(name.arguments[0] instanceof Name n && n.refersTo(MethodHandleImpl.class, "profileBoolean")); - mb.with(RuntimeVisibleAnnotationsAttribute.of(List.of(INJECTEDPROFILE))); + if (lambdaForm.forceInline) { + mb.with(LF_FORCEINLINE_PROFILE_ANNOTATIONS); + } else { + mb.with(LF_DONTINLINE_PROFILE_ANNOTATIONS); + } } onStack = emitSelectAlternative(cob, name, lambdaForm.names[i+1]); i++; // skip MH.invokeBasic of the selectAlternative result