From d2b36f09072e03370ee02b063fcc4a1f0e6cb2ee Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Fri, 6 Sep 2024 12:37:48 +0000 Subject: [PATCH] 8339642: Reduce overheads in InvokerBytecodeGenerator Reviewed-by: liach --- .../lang/invoke/InvokerBytecodeGenerator.java | 62 ++++++++++--------- .../classes/java/lang/invoke/LambdaForm.java | 26 +++----- 2 files changed, 43 insertions(+), 45 deletions(-) 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 7e58a862211..806d3339f5f 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -57,6 +57,8 @@ import static java.lang.invoke.LambdaForm.BasicType.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; +import static jdk.internal.constant.ConstantUtils.concat; +import static jdk.internal.constant.ConstantUtils.validateInternalClassName; /** * Code generation backend for LambdaForm. @@ -67,6 +69,7 @@ class InvokerBytecodeGenerator { /** Define class names for convenience. */ private static final ClassDesc CD_CasesHolder = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$CasesHolder;"); private static final ClassDesc CD_DirectMethodHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/DirectMethodHandle;"); + private static final ClassDesc CD_MemberName = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MemberName;"); private static final ClassDesc CD_MethodHandleImpl = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl;"); private static final ClassDesc CD_LambdaForm = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;"); private static final ClassDesc CD_LambdaForm_Name = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Name;"); @@ -126,7 +129,8 @@ class InvokerBytecodeGenerator { } this.name = name; this.className = CLASS_PREFIX.concat(name); - this.classDesc = ClassDesc.ofInternalName(className); + validateInternalClassName(name); + this.classDesc = ReferenceClassDescImpl.ofValidated(concat("L", className, ";")); this.lambdaForm = lambdaForm; this.invokerName = invokerName; this.invokerType = invokerType; @@ -142,8 +146,8 @@ class InvokerBytecodeGenerator { // Create an array to map name indexes to locals indexes. localsMap[0] = 0; // localsMap has at least one element for (int i = 1, index = 0; i < localsMap.length; i++) { - Wrapper w = Wrapper.forBasicType(mt.parameterType(i - 1)); - index += w.stackSlots(); + Class cl = mt.parameterType(i - 1); + index += (cl == long.class || cl == double.class) ? 2 : 1; localsMap[i] = index; } } @@ -223,6 +227,7 @@ class InvokerBytecodeGenerator { // unique static variable name String name; + List classData = this.classData; if (dumper().isEnabled()) { Class c = arg.getClass(); while (c.isArray()) { @@ -232,8 +237,7 @@ class InvokerBytecodeGenerator { } else { name = "_D_" + classData.size(); } - ClassData cd = new ClassData(name, desc, arg); - classData.add(cd); + classData.add(new ClassData(name, desc, arg)); return name; } @@ -292,15 +296,16 @@ class InvokerBytecodeGenerator { */ private Object classDataValues() { final List cd = classData; - return switch (cd.size()) { + int size = cd.size(); + return switch (size) { case 0 -> null; // special case (classData is not used by ) case 1 -> cd.get(0).value; // special case (single object) case 2 -> List.of(cd.get(0).value, cd.get(1).value); case 3 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value); case 4 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value, cd.get(3).value); default -> { - Object[] data = new Object[classData.size()]; - for (int i = 0; i < classData.size(); i++) { + Object[] data = new Object[size]; + for (int i = 0; i < size; i++) { data[i] = classData.get(i).value; } yield List.of(data); @@ -316,18 +321,17 @@ class InvokerBytecodeGenerator { if (classData.isEmpty()) return; - for (ClassData p : classData) { - // add the static field - clb.withField(p.name, p.desc, ACC_STATIC | ACC_FINAL); - } - clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, new Consumer<>() { @Override public void accept(CodeBuilder cob) { cob.loadConstant(classDesc) .invokestatic(CD_MethodHandles, "classData", MTD_Object_Class); - if (classData.size() == 1) { + int size = classData.size(); + if (size == 1) { ClassData p = classData.get(0); + // add the static field + clb.withField(p.name, p.desc, ACC_STATIC | ACC_FINAL); + cob.checkcast(p.desc) .putstatic(classDesc, p.name, p.desc); } else { @@ -335,7 +339,10 @@ class InvokerBytecodeGenerator { .astore(0); int index = 0; var listGet = cob.constantPool().interfaceMethodRefEntry(CD_List, "get", MTD_Object_int); - for (ClassData p : classData) { + for (int i = 0; i < size; i++) { + ClassData p = classData.get(i); + // add the static field + clb.withField(p.name, p.desc, ACC_STATIC | ACC_FINAL); // initialize the static field cob.aload(0) .loadConstant(index++) @@ -538,6 +545,11 @@ class InvokerBytecodeGenerator { static final Annotation INJECTEDPROFILE = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/InjectedProfile;")); static final Annotation LF_COMPILED = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Compiled;")); + // 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_FORCEINLINE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, FORCEINLINE); + /** * Generate an invoker method for the passed {@link LambdaForm}. */ @@ -558,21 +570,11 @@ class InvokerBytecodeGenerator { @Override public void accept(MethodBuilder mb) { - List annotations = new ArrayList<>(3); - - // Suppress this method in backtraces displayed to the user. - annotations.add(HIDDEN); - - // Mark this method as a compiled LambdaForm - annotations.add(LF_COMPILED); - if (lambdaForm.forceInline) { - // Force inlining of this invoker method. - annotations.add(FORCEINLINE); + mb.accept(LF_FORCEINLINE_ANNOTATIONS); } else { - annotations.add(DONTINLINE); + mb.accept(LF_DONTINLINE_ANNOTATIONS); } - mb.accept(RuntimeVisibleAnnotationsAttribute.of(annotations)); classData(lambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled. @@ -1674,10 +1676,12 @@ class InvokerBytecodeGenerator { static ClassDesc classDesc(Class cls) { // assert(VerifyAccess.isTypeVisible(cls, Object.class)) : cls.getName(); - return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor() - : cls == MethodHandle.class ? CD_MethodHandle + return cls == MethodHandle.class ? CD_MethodHandle : cls == DirectMethodHandle.class ? CD_DirectMethodHandle : cls == Object.class ? CD_Object + : cls == MemberName.class ? CD_MemberName + : cls == MethodType.class ? CD_MethodType + : cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor() : ReferenceClassDescImpl.ofValidated(cls.descriptorString()); } diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java index 342cbbe77e5..0132cc6edf5 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java @@ -1555,6 +1555,7 @@ class LambdaForm { * Return -1 if the name is not used. */ int lastUseIndex(Name n) { + Object[] arguments = this.arguments; if (arguments == null) return -1; for (int i = arguments.length; --i >= 0; ) { if (arguments[i] == n) return i; @@ -1562,21 +1563,6 @@ class LambdaForm { return -1; } - /** Return the number of occurrences of n in the argument array. - * Return 0 if the name is not used. - */ - int useCount(Name n) { - int count = 0; - if (arguments != null) { - for (Object argument : arguments) { - if (argument == n) { - count++; - } - } - } - return count; - } - public boolean equals(Name that) { if (this == that) return true; if (isParam()) @@ -1618,8 +1604,16 @@ class LambdaForm { int useCount(Name n) { int count = (result == n.index) ? 1 : 0; int i = Math.max(n.index + 1, arity); + Name[] names = this.names; while (i < names.length) { - count += names[i++].useCount(n); + Object[] arguments = names[i++].arguments; + if (arguments != null) { + for (Object argument : arguments) { + if (argument == n) { + count++; + } + } + } } return count; }