Skip to content

Commit d2b36f0

Browse files
committed
8339642: Reduce overheads in InvokerBytecodeGenerator
Reviewed-by: liach
1 parent cb00333 commit d2b36f0

File tree

2 files changed

+43
-45
lines changed

2 files changed

+43
-45
lines changed

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
import static java.lang.invoke.MethodHandleNatives.Constants.*;
5858
import static java.lang.invoke.MethodHandleStatics.*;
5959
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
60+
import static jdk.internal.constant.ConstantUtils.concat;
61+
import static jdk.internal.constant.ConstantUtils.validateInternalClassName;
6062

6163
/**
6264
* Code generation backend for LambdaForm.
@@ -67,6 +69,7 @@ class InvokerBytecodeGenerator {
6769
/** Define class names for convenience. */
6870
private static final ClassDesc CD_CasesHolder = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$CasesHolder;");
6971
private static final ClassDesc CD_DirectMethodHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/DirectMethodHandle;");
72+
private static final ClassDesc CD_MemberName = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MemberName;");
7073
private static final ClassDesc CD_MethodHandleImpl = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl;");
7174
private static final ClassDesc CD_LambdaForm = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;");
7275
private static final ClassDesc CD_LambdaForm_Name = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Name;");
@@ -126,7 +129,8 @@ private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
126129
}
127130
this.name = name;
128131
this.className = CLASS_PREFIX.concat(name);
129-
this.classDesc = ClassDesc.ofInternalName(className);
132+
validateInternalClassName(name);
133+
this.classDesc = ReferenceClassDescImpl.ofValidated(concat("L", className, ";"));
130134
this.lambdaForm = lambdaForm;
131135
this.invokerName = invokerName;
132136
this.invokerType = invokerType;
@@ -142,8 +146,8 @@ private InvokerBytecodeGenerator(String name, String invokerName, MethodType inv
142146
// Create an array to map name indexes to locals indexes.
143147
localsMap[0] = 0; // localsMap has at least one element
144148
for (int i = 1, index = 0; i < localsMap.length; i++) {
145-
Wrapper w = Wrapper.forBasicType(mt.parameterType(i - 1));
146-
index += w.stackSlots();
149+
Class<?> cl = mt.parameterType(i - 1);
150+
index += (cl == long.class || cl == double.class) ? 2 : 1;
147151
localsMap[i] = index;
148152
}
149153
}
@@ -223,6 +227,7 @@ String classData(Object arg) {
223227

224228
// unique static variable name
225229
String name;
230+
List<ClassData> classData = this.classData;
226231
if (dumper().isEnabled()) {
227232
Class<?> c = arg.getClass();
228233
while (c.isArray()) {
@@ -232,8 +237,7 @@ String classData(Object arg) {
232237
} else {
233238
name = "_D_" + classData.size();
234239
}
235-
ClassData cd = new ClassData(name, desc, arg);
236-
classData.add(cd);
240+
classData.add(new ClassData(name, desc, arg));
237241
return name;
238242
}
239243

@@ -292,15 +296,16 @@ private void methodSetup(ClassBuilder clb, Consumer<? super MethodBuilder> confi
292296
*/
293297
private Object classDataValues() {
294298
final List<ClassData> cd = classData;
295-
return switch (cd.size()) {
299+
int size = cd.size();
300+
return switch (size) {
296301
case 0 -> null; // special case (classData is not used by <clinit>)
297302
case 1 -> cd.get(0).value; // special case (single object)
298303
case 2 -> List.of(cd.get(0).value, cd.get(1).value);
299304
case 3 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value);
300305
case 4 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value, cd.get(3).value);
301306
default -> {
302-
Object[] data = new Object[classData.size()];
303-
for (int i = 0; i < classData.size(); i++) {
307+
Object[] data = new Object[size];
308+
for (int i = 0; i < size; i++) {
304309
data[i] = classData.get(i).value;
305310
}
306311
yield List.of(data);
@@ -316,26 +321,28 @@ static void clinit(ClassBuilder clb, ClassDesc classDesc, List<ClassData> classD
316321
if (classData.isEmpty())
317322
return;
318323

319-
for (ClassData p : classData) {
320-
// add the static field
321-
clb.withField(p.name, p.desc, ACC_STATIC | ACC_FINAL);
322-
}
323-
324324
clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, new Consumer<>() {
325325
@Override
326326
public void accept(CodeBuilder cob) {
327327
cob.loadConstant(classDesc)
328328
.invokestatic(CD_MethodHandles, "classData", MTD_Object_Class);
329-
if (classData.size() == 1) {
329+
int size = classData.size();
330+
if (size == 1) {
330331
ClassData p = classData.get(0);
332+
// add the static field
333+
clb.withField(p.name, p.desc, ACC_STATIC | ACC_FINAL);
334+
331335
cob.checkcast(p.desc)
332336
.putstatic(classDesc, p.name, p.desc);
333337
} else {
334338
cob.checkcast(CD_List)
335339
.astore(0);
336340
int index = 0;
337341
var listGet = cob.constantPool().interfaceMethodRefEntry(CD_List, "get", MTD_Object_int);
338-
for (ClassData p : classData) {
342+
for (int i = 0; i < size; i++) {
343+
ClassData p = classData.get(i);
344+
// add the static field
345+
clb.withField(p.name, p.desc, ACC_STATIC | ACC_FINAL);
339346
// initialize the static field
340347
cob.aload(0)
341348
.loadConstant(index++)
@@ -538,6 +545,11 @@ private boolean checkActualReceiver(CodeBuilder cob) {
538545
static final Annotation INJECTEDPROFILE = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/InjectedProfile;"));
539546
static final Annotation LF_COMPILED = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Compiled;"));
540547

548+
// Suppress method in backtraces displayed to the user, mark this method as
549+
// a compiled LambdaForm, then either force or prohibit inlining.
550+
public static final RuntimeVisibleAnnotationsAttribute LF_DONTINLINE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, DONTINLINE);
551+
public static final RuntimeVisibleAnnotationsAttribute LF_FORCEINLINE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, FORCEINLINE);
552+
541553
/**
542554
* Generate an invoker method for the passed {@link LambdaForm}.
543555
*/
@@ -558,21 +570,11 @@ void addMethod(ClassBuilder clb) {
558570
@Override
559571
public void accept(MethodBuilder mb) {
560572

561-
List<Annotation> annotations = new ArrayList<>(3);
562-
563-
// Suppress this method in backtraces displayed to the user.
564-
annotations.add(HIDDEN);
565-
566-
// Mark this method as a compiled LambdaForm
567-
annotations.add(LF_COMPILED);
568-
569573
if (lambdaForm.forceInline) {
570-
// Force inlining of this invoker method.
571-
annotations.add(FORCEINLINE);
574+
mb.accept(LF_FORCEINLINE_ANNOTATIONS);
572575
} else {
573-
annotations.add(DONTINLINE);
576+
mb.accept(LF_DONTINLINE_ANNOTATIONS);
574577
}
575-
mb.accept(RuntimeVisibleAnnotationsAttribute.of(annotations));
576578

577579
classData(lambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled.
578580

@@ -1674,10 +1676,12 @@ public void accept(CodeBuilder cob) {
16741676

16751677
static ClassDesc classDesc(Class<?> cls) {
16761678
// assert(VerifyAccess.isTypeVisible(cls, Object.class)) : cls.getName();
1677-
return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor()
1678-
: cls == MethodHandle.class ? CD_MethodHandle
1679+
return cls == MethodHandle.class ? CD_MethodHandle
16791680
: cls == DirectMethodHandle.class ? CD_DirectMethodHandle
16801681
: cls == Object.class ? CD_Object
1682+
: cls == MemberName.class ? CD_MemberName
1683+
: cls == MethodType.class ? CD_MethodType
1684+
: cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor()
16811685
: ReferenceClassDescImpl.ofValidated(cls.descriptorString());
16821686
}
16831687

src/java.base/share/classes/java/lang/invoke/LambdaForm.java

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,28 +1555,14 @@ private static boolean typesMatch(BasicType parameterType, Object object) {
15551555
* Return -1 if the name is not used.
15561556
*/
15571557
int lastUseIndex(Name n) {
1558+
Object[] arguments = this.arguments;
15581559
if (arguments == null) return -1;
15591560
for (int i = arguments.length; --i >= 0; ) {
15601561
if (arguments[i] == n) return i;
15611562
}
15621563
return -1;
15631564
}
15641565

1565-
/** Return the number of occurrences of n in the argument array.
1566-
* Return 0 if the name is not used.
1567-
*/
1568-
int useCount(Name n) {
1569-
int count = 0;
1570-
if (arguments != null) {
1571-
for (Object argument : arguments) {
1572-
if (argument == n) {
1573-
count++;
1574-
}
1575-
}
1576-
}
1577-
return count;
1578-
}
1579-
15801566
public boolean equals(Name that) {
15811567
if (this == that) return true;
15821568
if (isParam())
@@ -1618,8 +1604,16 @@ int lastUseIndex(Name n) {
16181604
int useCount(Name n) {
16191605
int count = (result == n.index) ? 1 : 0;
16201606
int i = Math.max(n.index + 1, arity);
1607+
Name[] names = this.names;
16211608
while (i < names.length) {
1622-
count += names[i++].useCount(n);
1609+
Object[] arguments = names[i++].arguments;
1610+
if (arguments != null) {
1611+
for (Object argument : arguments) {
1612+
if (argument == n) {
1613+
count++;
1614+
}
1615+
}
1616+
}
16231617
}
16241618
return count;
16251619
}

0 commit comments

Comments
 (0)