Skip to content

Commit 8ed6c1d

Browse files
committedMar 7, 2025
8350607: Consolidate MethodHandles::zero into MethodHandles::constant
Reviewed-by: jrose, redestad, jvernee
1 parent f6a8db2 commit 8ed6c1d

10 files changed

+144
-175
lines changed
 

‎src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java

+34-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -62,10 +62,42 @@ LambdaFormEditor editor() {
6262
return form.editor();
6363
}
6464

65-
static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
65+
static BoundMethodHandle bindSingleL(MethodType type, LambdaForm form, Object x) {
6666
return Species_L.make(type, form, x);
6767
}
6868

69+
static BoundMethodHandle bindSingleI(MethodType type, LambdaForm form, int x) {
70+
try {
71+
return (BoundMethodHandle) SimpleMethodHandle.BMH_SPECIES.extendWith(I_TYPE).factory().invokeBasic(type, form, x);
72+
} catch (Throwable ex) {
73+
throw uncaughtException(ex);
74+
}
75+
}
76+
77+
static BoundMethodHandle bindSingleJ(MethodType type, LambdaForm form, long x) {
78+
try {
79+
return (BoundMethodHandle) SimpleMethodHandle.BMH_SPECIES.extendWith(J_TYPE).factory().invokeBasic(type, form, x);
80+
} catch (Throwable ex) {
81+
throw uncaughtException(ex);
82+
}
83+
}
84+
85+
static BoundMethodHandle bindSingleF(MethodType type, LambdaForm form, float x) {
86+
try {
87+
return (BoundMethodHandle) SimpleMethodHandle.BMH_SPECIES.extendWith(F_TYPE).factory().invokeBasic(type, form, x);
88+
} catch (Throwable ex) {
89+
throw uncaughtException(ex);
90+
}
91+
}
92+
93+
static BoundMethodHandle bindSingleD(MethodType type, LambdaForm form, double x) {
94+
try {
95+
return (BoundMethodHandle) SimpleMethodHandle.BMH_SPECIES.extendWith(D_TYPE).factory().invokeBasic(type, form, x);
96+
} catch (Throwable ex) {
97+
throw uncaughtException(ex);
98+
}
99+
}
100+
69101
@Override // there is a default binder in the super class, for 'L' types only
70102
/*non-public*/
71103
BoundMethodHandle bindArgumentL(int pos, Object value) {

‎src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -378,13 +378,7 @@ static byte[] generateBasicFormsClassBytes(String className) {
378378
ArrayList<String> names = new ArrayList<>();
379379
HashSet<String> dedupSet = new HashSet<>();
380380
for (LambdaForm.BasicType type : LambdaForm.BasicType.values()) {
381-
LambdaForm zero = LambdaForm.zeroForm(type);
382-
String name = zero.kind.defaultLambdaName
383-
+ "_" + zero.returnType().basicTypeChar();
384-
if (dedupSet.add(name)) {
385-
names.add(name);
386-
forms.add(zero);
387-
}
381+
String name;
388382

389383
LambdaForm identity = LambdaForm.identityForm(type);
390384
name = identity.kind.defaultLambdaName
@@ -393,6 +387,16 @@ static byte[] generateBasicFormsClassBytes(String className) {
393387
names.add(name);
394388
forms.add(identity);
395389
}
390+
391+
if (type != V_TYPE) {
392+
LambdaForm constant = LambdaForm.constantForm(type);
393+
name = constant.kind.defaultLambdaName
394+
+ "_" + constant.returnType().basicTypeChar();
395+
if (dedupSet.add(name)) {
396+
names.add(name);
397+
forms.add(constant);
398+
}
399+
}
396400
}
397401
return generateCodeBytesForLFs(className,
398402
names.toArray(new String[0]),

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

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -457,8 +457,8 @@ private static MemberName lookupPregenerated(LambdaForm form, MethodType invoker
457457
return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
458458
}
459459
case DELEGATE: return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
460-
case ZERO: // fall-through
461-
case IDENTITY: {
460+
case IDENTITY: // fall-through
461+
case CONSTANT: {
462462
name = name + "_" + form.returnType().basicTypeChar();
463463
return resolveFrom(name, invokerType, LambdaForm.Holder.class);
464464
}
@@ -631,10 +631,6 @@ public void accept(CodeBuilder cob) {
631631
assert(name.arguments.length == 1);
632632
emitPushArguments(cob, name, 0);
633633
continue;
634-
case ZERO:
635-
assert(name.arguments.length == 0);
636-
cob.loadConstant((ConstantDesc)name.type.basicTypeWrapper().zero());
637-
continue;
638634
case NONE:
639635
// no intrinsic associated
640636
break;

‎src/java.base/share/classes/java/lang/invoke/Invokers.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -145,7 +145,7 @@ private MethodHandle makeExactOrGeneralInvoker(boolean isExact) {
145145
MethodType invokerType = mtype.invokerType();
146146
int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER);
147147
LambdaForm lform = invokeHandleForm(mtype, false, which);
148-
MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
148+
MethodHandle invoker = BoundMethodHandle.bindSingleL(invokerType, lform, mtype);
149149
String whichName = (isExact ? "invokeExact" : "invoke");
150150
invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype), false);
151151
assert(checkInvoker(invoker));
@@ -159,7 +159,7 @@ private MethodHandle makeVarHandleMethodInvoker(VarHandle.AccessMode ak, boolean
159159

160160
LambdaForm lform = varHandleMethodInvokerHandleForm(mtype, isExact);
161161
VarHandle.AccessDescriptor ad = new VarHandle.AccessDescriptor(mtype, ak.at.ordinal(), ak.ordinal());
162-
MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, ad);
162+
MethodHandle invoker = BoundMethodHandle.bindSingleL(invokerType, lform, ad);
163163

164164
invoker = invoker.withInternalMemberName(MemberName.makeVarHandleMethodInvoke(ak.methodName(), mtype), false);
165165
assert(checkVarHandleInvoker(invoker));

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

+27-95
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -245,8 +245,8 @@ private static boolean checkBasicType() {
245245

246246
enum Kind {
247247
GENERIC("invoke"),
248-
ZERO("zero"),
249248
IDENTITY("identity"),
249+
CONSTANT("constant"),
250250
BOUND_REINVOKER("BMH.reinvoke", "reinvoke"),
251251
REINVOKER("MH.reinvoke", "reinvoke"),
252252
DELEGATE("MH.delegate", "delegate"),
@@ -372,31 +372,13 @@ static LambdaForm create(int arity, Name[] names, boolean forceInline, Kind kind
372372
}
373373

374374
private static LambdaForm createBlankForType(MethodType mt) {
375-
// Make a blank lambda form, which returns a constant zero or null.
375+
// Make a dummy blank lambda form.
376376
// It is used as a template for managing the invocation of similar forms that are non-empty.
377377
// Called only from getPreparedForm.
378-
int arity = mt.parameterCount();
379-
int result = (mt.returnType() == void.class || mt.returnType() == Void.class) ? VOID_RESULT : arity;
380-
Name[] names = buildEmptyNames(arity, mt, result == VOID_RESULT);
381-
boolean canInterpret = normalizeNames(arity, names);
382-
LambdaForm form = new LambdaForm(arity, result, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, names, Kind.ZERO);
383-
assert(form.nameRefsAreLegal() && form.isEmpty() && isValidSignature(form.basicTypeSignature()));
384-
if (!canInterpret) {
385-
form.compileToBytecode();
386-
}
378+
LambdaForm form = new LambdaForm(0, 0, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, new Name[0], Kind.GENERIC);
387379
return form;
388380
}
389381

390-
private static Name[] buildEmptyNames(int arity, MethodType mt, boolean isVoid) {
391-
Name[] names = arguments(isVoid ? 0 : 1, mt);
392-
if (!isVoid) {
393-
Name zero = new Name(constantZero(basicType(mt.returnType())));
394-
names[arity] = zero.withIndex(arity);
395-
}
396-
assert(namesOK(arity, names));
397-
return names;
398-
}
399-
400382
private static int fixResult(int result, Name[] names) {
401383
if (result == LAST_RESULT)
402384
result = names.length - 1; // might still be void
@@ -1011,15 +993,6 @@ private boolean resultCheck(Object[] argumentValues, Object result) {
1011993
return true;
1012994
}
1013995

1014-
private boolean isEmpty() {
1015-
if (result < 0)
1016-
return (names.length == arity);
1017-
else if (result == arity && names.length == arity + 1)
1018-
return names[arity].isConstantZero();
1019-
else
1020-
return false;
1021-
}
1022-
1023996
public String toString() {
1024997
return debugString(-1);
1025998
}
@@ -1251,10 +1224,6 @@ public boolean isIdentity() {
12511224
return this.equals(identity(returnType()));
12521225
}
12531226

1254-
public boolean isConstantZero() {
1255-
return this.equals(constantZero(returnType()));
1256-
}
1257-
12581227
public MethodHandleImpl.Intrinsic intrinsicName() {
12591228
return resolvedHandle != null
12601229
? resolvedHandle.intrinsicName()
@@ -1453,9 +1422,6 @@ void internArguments() {
14531422
boolean isParam() {
14541423
return function == null;
14551424
}
1456-
boolean isConstantZero() {
1457-
return !isParam() && arguments.length == 0 && function.isConstantZero();
1458-
}
14591425

14601426
boolean refersTo(Class<?> declaringClass, String methodName) {
14611427
return function != null &&
@@ -1662,50 +1628,45 @@ static LambdaForm identityForm(BasicType type) {
16621628
if (form != null) {
16631629
return form;
16641630
}
1665-
createFormsFor(type);
1631+
createIdentityForm(type);
16661632
return LF_identity[ord];
16671633
}
16681634

1669-
static LambdaForm zeroForm(BasicType type) {
1670-
int ord = type.ordinal();
1671-
LambdaForm form = LF_zero[ord];
1672-
if (form != null) {
1673-
return form;
1674-
}
1675-
createFormsFor(type);
1676-
return LF_zero[ord];
1677-
}
1678-
16791635
static NamedFunction identity(BasicType type) {
16801636
int ord = type.ordinal();
16811637
NamedFunction function = NF_identity[ord];
16821638
if (function != null) {
16831639
return function;
16841640
}
1685-
createFormsFor(type);
1641+
createIdentityForm(type);
16861642
return NF_identity[ord];
16871643
}
16881644

1689-
static NamedFunction constantZero(BasicType type) {
1690-
int ord = type.ordinal();
1691-
NamedFunction function = NF_zero[ord];
1692-
if (function != null) {
1693-
return function;
1694-
}
1695-
createFormsFor(type);
1696-
return NF_zero[ord];
1645+
static LambdaForm constantForm(BasicType type) {
1646+
assert type != null && type != V_TYPE : type;
1647+
var cached = LF_constant[type.ordinal()];
1648+
if (cached != null)
1649+
return cached;
1650+
return createConstantForm(type);
1651+
}
1652+
1653+
private static LambdaForm createConstantForm(BasicType type) {
1654+
UNSAFE.ensureClassInitialized(BoundMethodHandle.class); // defend access to SimpleMethodHandle
1655+
var species = SimpleMethodHandle.BMH_SPECIES.extendWith(type);
1656+
var carrier = argument(0, L_TYPE).withConstraint(species); // BMH bound with data
1657+
Name[] constNames = new Name[] { carrier, new Name(species.getterFunction(0), carrier) };
1658+
return LF_constant[type.ordinal()] = create(1, constNames, Kind.CONSTANT);
16971659
}
16981660

16991661
private static final @Stable LambdaForm[] LF_identity = new LambdaForm[TYPE_LIMIT];
1700-
private static final @Stable LambdaForm[] LF_zero = new LambdaForm[TYPE_LIMIT];
17011662
private static final @Stable NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
1702-
private static final @Stable NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
1663+
private static final @Stable LambdaForm[] LF_constant = new LambdaForm[ARG_TYPE_LIMIT]; // no void
17031664

1704-
private static final Object createFormsLock = new Object();
1705-
private static void createFormsFor(BasicType type) {
1665+
private static final Object createIdentityFormLock = new Object();
1666+
private static void createIdentityForm(BasicType type) {
17061667
// Avoid racy initialization during bootstrap
17071668
UNSAFE.ensureClassInitialized(BoundMethodHandle.class);
1708-
synchronized (createFormsLock) {
1669+
synchronized (createIdentityFormLock) {
17091670
final int ord = type.ordinal();
17101671
LambdaForm idForm = LF_identity[ord];
17111672
if (idForm != null) {
@@ -1714,27 +1675,18 @@ private static void createFormsFor(BasicType type) {
17141675
char btChar = type.basicTypeChar();
17151676
boolean isVoid = (type == V_TYPE);
17161677
Class<?> btClass = type.btClass;
1717-
MethodType zeType = MethodType.methodType(btClass);
1718-
MethodType idType = (isVoid) ? zeType : MethodType.methodType(btClass, btClass);
1678+
MethodType idType = (isVoid) ? MethodType.methodType(btClass) : MethodType.methodType(btClass, btClass);
17191679

17201680
// Look up symbolic names. It might not be necessary to have these,
17211681
// but if we need to emit direct references to bytecodes, it helps.
1722-
// Zero is built from a call to an identity function with a constant zero input.
17231682
MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
1724-
MemberName zeMem = null;
17251683
try {
17261684
idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, LM_TRUSTED, NoSuchMethodException.class);
1727-
if (!isVoid) {
1728-
zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
1729-
zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, LM_TRUSTED, NoSuchMethodException.class);
1730-
}
17311685
} catch (IllegalAccessException|NoSuchMethodException ex) {
17321686
throw newInternalError(ex);
17331687
}
17341688

17351689
NamedFunction idFun;
1736-
LambdaForm zeForm;
1737-
NamedFunction zeFun;
17381690

17391691
// Create the LFs and NamedFunctions. Precompiling LFs to byte code is needed to break circular
17401692
// bootstrap dependency on this method in case we're interpreting LFs
@@ -1743,32 +1695,18 @@ private static void createFormsFor(BasicType type) {
17431695
idForm = LambdaForm.create(1, idNames, VOID_RESULT, Kind.IDENTITY);
17441696
idForm.compileToBytecode();
17451697
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
1746-
1747-
zeForm = idForm;
1748-
zeFun = idFun;
17491698
} else {
17501699
Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
17511700
idForm = LambdaForm.create(2, idNames, 1, Kind.IDENTITY);
17521701
idForm.compileToBytecode();
1753-
idFun = new NamedFunction(idMem, MethodHandleImpl.makeIntrinsic(SimpleMethodHandle.make(idMem.getInvocationType(), idForm),
1702+
idFun = new NamedFunction(idMem, MethodHandleImpl.makeIntrinsic(idMem.getInvocationType(), idForm,
17541703
MethodHandleImpl.Intrinsic.IDENTITY));
1755-
1756-
Object zeValue = Wrapper.forBasicType(btChar).zero();
1757-
Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
1758-
zeForm = LambdaForm.create(1, zeNames, 1, Kind.ZERO);
1759-
zeForm.compileToBytecode();
1760-
zeFun = new NamedFunction(zeMem, MethodHandleImpl.makeIntrinsic(SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm),
1761-
MethodHandleImpl.Intrinsic.ZERO));
17621704
}
17631705

1764-
LF_zero[ord] = zeForm;
1765-
NF_zero[ord] = zeFun;
17661706
LF_identity[ord] = idForm;
17671707
NF_identity[ord] = idFun;
17681708

17691709
assert(idFun.isIdentity());
1770-
assert(zeFun.isConstantZero());
1771-
assert(new Name(zeFun).isConstantZero());
17721710
}
17731711
}
17741712

@@ -1779,12 +1717,6 @@ private static void createFormsFor(BasicType type) {
17791717
private static double identity_D(double x) { return x; }
17801718
private static Object identity_L(Object x) { return x; }
17811719
private static void identity_V() { return; }
1782-
private static int zero_I() { return 0; }
1783-
private static long zero_J() { return 0; }
1784-
private static float zero_F() { return 0; }
1785-
private static double zero_D() { return 0; }
1786-
private static Object zero_L() { return null; }
1787-
17881720
/**
17891721
* Internal marker for byte-compiled LambdaForms.
17901722
*/
@@ -1814,7 +1746,7 @@ private static void createFormsFor(BasicType type) {
18141746
UNSAFE.ensureClassInitialized(Holder.class);
18151747
}
18161748

1817-
/* Placeholder class for zero and identity forms generated ahead of time */
1749+
/* Placeholder class for identity and constant forms generated ahead of time */
18181750
final class Holder {}
18191751

18201752
// The following hack is necessary in order to suppress TRACE_INTERPRETER

‎src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -969,7 +969,7 @@ LambdaForm filterReturnForm(BasicType newType, boolean constantZero) {
969969
if (newType == V_TYPE)
970970
callFilter = null;
971971
else
972-
callFilter = new Name(constantZero(newType));
972+
callFilter = new Name(LambdaForm.identity(newType), newType.btWrapper.zero());
973973
} else {
974974
BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
975975
BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);

1 commit comments

Comments
 (1)

openjdk-notifier[bot] commented on Mar 7, 2025

@openjdk-notifier[bot]
Please sign in to comment.