Skip to content

Commit d5a5d12

Browse files
[GR-55548] [GR-55549] Improve method handle support in espresso.
PullRequest: graal/18327
2 parents 569ae85 + 6ff9ec5 commit d5a5d12

File tree

7 files changed

+101
-39
lines changed

7 files changed

+101
-39
lines changed

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/RuntimeConstantPool.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant;
3030
import com.oracle.truffle.espresso.classfile.constantpool.FieldRefConstant;
3131
import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant;
32+
import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant;
3233
import com.oracle.truffle.espresso.classfile.constantpool.NeedsFreshResolutionException;
3334
import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant;
3435
import com.oracle.truffle.espresso.classfile.constantpool.Resolvable;
@@ -174,6 +175,11 @@ public Method resolvedMethodAt(ObjectKlass accessingKlass, int index) {
174175
return (Method) resolved.value();
175176
}
176177

178+
public MethodRefConstant resolvedMethodRefAt(ObjectKlass accessingKlass, int index) {
179+
Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "method");
180+
return (MethodRefConstant) resolved;
181+
}
182+
177183
public Method resolvedMethodAtNoCache(ObjectKlass accessingKlass, int index) {
178184
CompilerAsserts.neverPartOfCompilation();
179185
Resolvable.ResolvedConstant resolved = resolvedAtNoCache(accessingKlass, index, "method");

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/ClassMethodRefConstant.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.oracle.truffle.espresso.impl.ObjectKlass;
3737
import com.oracle.truffle.espresso.meta.EspressoError;
3838
import com.oracle.truffle.espresso.meta.Meta;
39+
import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode;
3940
import com.oracle.truffle.espresso.runtime.EspressoContext;
4041

4142
public interface ClassMethodRefConstant extends MethodRefConstant {
@@ -49,6 +50,10 @@ default Tag tag() {
4950
return Tag.METHOD_REF;
5051
}
5152

53+
default MHInvokeGenericNode.MethodHandleInvoker invoker() {
54+
return null;
55+
}
56+
5257
final class Indexes extends MethodRefConstant.Indexes implements ClassMethodRefConstant, Resolvable {
5358
Indexes(int classIndex, int nameAndTypeIndex) {
5459
super(classIndex, nameAndTypeIndex);
@@ -188,6 +193,9 @@ public ResolvedConstant resolve(RuntimeConstantPool pool, int thisIndex, ObjectK
188193

189194
if (!method.isPolySignatureIntrinsic()) {
190195
method.checkLoadingConstraints(accessingKlass.getDefiningClassLoader(), method.getDeclaringKlass().getDefiningClassLoader());
196+
} else if (method.isInvokeIntrinsic()) {
197+
MHInvokeGenericNode.MethodHandleInvoker invoker = MHInvokeGenericNode.linkMethod(meta.getLanguage(), meta, accessingKlass, method, name, signature);
198+
return new ResolvedWithInvoker(method, invoker);
191199
}
192200

193201
return new Resolved(method);
@@ -211,31 +219,52 @@ public void validate(ConstantPool pool) {
211219
}
212220
}
213221

214-
final class Resolved implements InterfaceMethodRefConstant, Resolvable.ResolvedConstant {
222+
class Resolved implements ClassMethodRefConstant, Resolvable.ResolvedConstant {
215223
private final Method resolved;
216224

217225
Resolved(Method resolved) {
218226
this.resolved = Objects.requireNonNull(resolved);
219227
}
220228

221229
@Override
222-
public Method value() {
230+
public final Method value() {
223231
return resolved;
224232
}
225233

226234
@Override
227-
public Symbol<Name> getHolderKlassName(ConstantPool pool) {
235+
public final Symbol<Name> getHolderKlassName(ConstantPool pool) {
228236
throw EspressoError.shouldNotReachHere("Method already resolved");
229237
}
230238

231239
@Override
232-
public Symbol<Name> getName(ConstantPool pool) {
240+
public final Symbol<Name> getName(ConstantPool pool) {
233241
return resolved.getName();
234242
}
235243

236244
@Override
237-
public Symbol<? extends Descriptor> getDescriptor(ConstantPool pool) {
245+
public final Symbol<? extends Descriptor> getDescriptor(ConstantPool pool) {
238246
return resolved.getRawSignature();
239247
}
240248
}
249+
250+
/**
251+
* This is used for
252+
* {@link com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics.PolySigIntrinsics#InvokeGeneric}
253+
* polymorphic signature methods. The invoker object contains the method and appendix that
254+
* should be used to implement the intrinsic's behaviour. This is provided by the JDK
255+
* ({@code MethodHandleNatives.linkMethod}).
256+
*/
257+
final class ResolvedWithInvoker extends Resolved {
258+
private final MHInvokeGenericNode.MethodHandleInvoker invoker;
259+
260+
ResolvedWithInvoker(Method resolved, MHInvokeGenericNode.MethodHandleInvoker invoker) {
261+
super(resolved);
262+
this.invoker = Objects.requireNonNull(invoker);
263+
}
264+
265+
@Override
266+
public MHInvokeGenericNode.MethodHandleInvoker invoker() {
267+
return invoker;
268+
}
269+
}
241270
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,13 @@
2929
import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTSTATIC;
3030
import static com.oracle.truffle.espresso.bytecode.Bytecodes.RETURN;
3131
import static com.oracle.truffle.espresso.classfile.Constants.ACC_CALLER_SENSITIVE;
32+
import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINAL;
3233
import static com.oracle.truffle.espresso.classfile.Constants.ACC_FORCE_INLINE;
3334
import static com.oracle.truffle.espresso.classfile.Constants.ACC_HIDDEN;
3435
import static com.oracle.truffle.espresso.classfile.Constants.ACC_NATIVE;
3536
import static com.oracle.truffle.espresso.classfile.Constants.ACC_SCOPED;
37+
import static com.oracle.truffle.espresso.classfile.Constants.ACC_STATIC;
38+
import static com.oracle.truffle.espresso.classfile.Constants.ACC_SYNTHETIC;
3639
import static com.oracle.truffle.espresso.classfile.Constants.ACC_VARARGS;
3740
import static com.oracle.truffle.espresso.classfile.Constants.REF_invokeInterface;
3841
import static com.oracle.truffle.espresso.classfile.Constants.REF_invokeSpecial;
@@ -60,7 +63,6 @@
6063
import com.oracle.truffle.api.nodes.ExplodeLoop;
6164
import com.oracle.truffle.api.source.Source;
6265
import com.oracle.truffle.api.source.SourceSection;
63-
import com.oracle.truffle.espresso.EspressoLanguage;
6466
import com.oracle.truffle.espresso.EspressoOptions;
6567
import com.oracle.truffle.espresso.analysis.frame.EspressoFrameDescriptor;
6668
import com.oracle.truffle.espresso.analysis.frame.FrameAnalysis;
@@ -99,6 +101,7 @@
99101
import com.oracle.truffle.espresso.meta.ModifiersProvider;
100102
import com.oracle.truffle.espresso.nodes.EspressoRootNode;
101103
import com.oracle.truffle.espresso.nodes.interop.AbstractLookupNode;
104+
import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode.MethodHandleInvoker;
102105
import com.oracle.truffle.espresso.nodes.methodhandle.MethodHandleIntrinsicNode;
103106
import com.oracle.truffle.espresso.runtime.Attribute;
104107
import com.oracle.truffle.espresso.runtime.EspressoContext;
@@ -128,9 +131,8 @@ public final class Method extends Member<Signature> implements TruffleObject, Co
128131
private final Method proxy;
129132
private String genericSignature;
130133

131-
// always null unless the raw signature exposed for this method should be
132-
// different from the one in the linkedKlass
133134
private final Symbol<Signature> rawSignature;
135+
private final int rawFlags;
134136

135137
// the parts of the method that can change when it's redefined
136138
// are encapsulated within the methodVersion
@@ -148,6 +150,7 @@ public final class Method extends Member<Signature> implements TruffleObject, Co
148150

149151
private Method(Method method, CodeAttribute split) {
150152
this.rawSignature = method.rawSignature;
153+
this.rawFlags = method.rawFlags;
151154
this.declaringKlass = method.declaringKlass;
152155
this.methodVersion = new MethodVersion(method.getMethodVersion().klassVersion, method.getRuntimeConstantPool(), method.getLinkedMethod(),
153156
method.getMethodVersion().poisonPill, split);
@@ -166,12 +169,13 @@ private Method(Method method, CodeAttribute split) {
166169
}
167170

168171
Method(ObjectKlass.KlassVersion klassVersion, LinkedMethod linkedMethod, RuntimeConstantPool pool) {
169-
this(klassVersion, linkedMethod, linkedMethod.getRawSignature(), pool);
172+
this(klassVersion, linkedMethod, linkedMethod.getRawSignature(), pool, linkedMethod.getFlags());
170173
}
171174

172-
Method(ObjectKlass.KlassVersion klassVersion, LinkedMethod linkedMethod, Symbol<Signature> rawSignature, RuntimeConstantPool pool) {
175+
Method(ObjectKlass.KlassVersion klassVersion, LinkedMethod linkedMethod, Symbol<Signature> rawSignature, RuntimeConstantPool pool, int rawFlags) {
173176
this.declaringKlass = klassVersion.getKlass();
174177
this.rawSignature = rawSignature;
178+
this.rawFlags = rawFlags;
175179
this.methodVersion = new MethodVersion(klassVersion, pool, linkedMethod, false, (CodeAttribute) linkedMethod.getAttribute(CodeAttribute.NAME));
176180

177181
try {
@@ -522,7 +526,7 @@ public boolean isClassInitializer() {
522526

523527
@Override
524528
public int getModifiers() {
525-
return getMethodVersion().getModifiers();
529+
return rawFlags;
526530
}
527531

528532
public boolean isCallerSensitive() {
@@ -813,12 +817,23 @@ public int getCatchLocation(int bci, StaticObject ex) {
813817
// Spawns a placeholder method for MH intrinsics
814818
public Method createIntrinsic(Symbol<Signature> polymorphicRawSignature) {
815819
assert isPolySignatureIntrinsic();
816-
return new Method(declaringKlass.getKlassVersion(), getLinkedMethod(), polymorphicRawSignature, getRuntimeConstantPool());
820+
int flags;
821+
MethodHandleIntrinsics.PolySigIntrinsics iid = MethodHandleIntrinsics.getId(this);
822+
if (iid == MethodHandleIntrinsics.PolySigIntrinsics.InvokeGeneric) {
823+
flags = getModifiers() & ~ACC_VARARGS;
824+
} else {
825+
flags = ACC_NATIVE | ACC_SYNTHETIC | ACC_FINAL;
826+
if (iid.isStaticPolymorphicSignature()) {
827+
flags |= ACC_STATIC;
828+
}
829+
}
830+
assert Modifier.isNative(flags);
831+
return new Method(declaringKlass.getKlassVersion(), getLinkedMethod(), polymorphicRawSignature, getRuntimeConstantPool(), flags);
817832
}
818833

819-
public MethodHandleIntrinsicNode spawnIntrinsicNode(EspressoLanguage language, Meta meta, ObjectKlass accessingKlass, Symbol<Name> mname, Symbol<Signature> signature) {
834+
public MethodHandleIntrinsicNode spawnIntrinsicNode(MethodHandleInvoker invoker) {
820835
assert isPolySignatureIntrinsic();
821-
return MethodHandleIntrinsics.createIntrinsicNode(language, meta, this, accessingKlass, mname, signature);
836+
return MethodHandleIntrinsics.createIntrinsicNode(getMeta(), this, invoker);
822837
}
823838

824839
public Method forceSplit() {
@@ -1543,7 +1558,7 @@ public String getGenericSignatureAsString() {
15431558

15441559
@Override
15451560
public int getModifiers() {
1546-
return linkedMethod.getFlags();
1561+
return getMethod().getModifiers();
15471562
}
15481563

15491564
@Override

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@
314314
import com.oracle.truffle.espresso.classfile.attributes.BootstrapMethodsAttribute;
315315
import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableAttribute;
316316
import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant;
317+
import com.oracle.truffle.espresso.classfile.constantpool.ClassMethodRefConstant;
317318
import com.oracle.truffle.espresso.classfile.constantpool.DoubleConstant;
318319
import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant;
319320
import com.oracle.truffle.espresso.classfile.constantpool.FloatConstant;
@@ -339,6 +340,7 @@
339340
import com.oracle.truffle.espresso.meta.JavaKind;
340341
import com.oracle.truffle.espresso.meta.Meta;
341342
import com.oracle.truffle.espresso.nodes.helper.EspressoReferenceArrayStoreNode;
343+
import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode.MethodHandleInvoker;
342344
import com.oracle.truffle.espresso.nodes.quick.BaseQuickNode;
343345
import com.oracle.truffle.espresso.nodes.quick.CheckCastQuickNode;
344346
import com.oracle.truffle.espresso.nodes.quick.InstanceOfQuickNode;
@@ -2501,7 +2503,12 @@ private InvokeQuickNode dispatchQuickened(int top, int curBCI, char cpi, int opc
25012503

25022504
InvokeQuickNode invoke;
25032505
if (resolved.isPolySignatureIntrinsic()) {
2504-
invoke = new InvokeHandleNode(resolved, getDeclaringKlass(), top, curBCI);
2506+
MethodHandleInvoker invoker = null;
2507+
if ((resolvedOpCode == INVOKEVIRTUAL || resolvedOpCode == INVOKESPECIAL) && (getConstantPool().resolvedMethodRefAt(getDeclaringKlass(), cpi) instanceof ClassMethodRefConstant methodRef)) {
2508+
// There might be an invoker if it's an InvokeGeneric
2509+
invoker = methodRef.invoker();
2510+
}
2511+
invoke = new InvokeHandleNode(resolved, invoker, top, curBCI);
25052512
} else {
25062513
// @formatter:off
25072514
switch (resolvedOpCode) {

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHInvokeGenericNode.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,16 @@ public class MHInvokeGenericNode extends MethodHandleIntrinsicNode {
4848
private final boolean unbasic;
4949
@Child private DirectCallNode callNode;
5050

51-
public MHInvokeGenericNode(Method method, StaticObject memberName, StaticObject appendix) {
51+
public MHInvokeGenericNode(Method method, MethodHandleInvoker invoker) {
5252
super(method);
53-
this.appendix = appendix;
54-
Method target = (Method) method.getMeta().HIDDEN_VMTARGET.getHiddenObject(memberName);
53+
this.appendix = invoker.appendix;
5554
// Call the invoker java code spun for us.
5655
if (method.getContext().getEspressoEnv().SplitMethodHandles) {
57-
this.callNode = DirectCallNode.create(target.forceSplit().getCallTarget());
56+
this.callNode = DirectCallNode.create(invoker.method.forceSplit().getCallTarget());
5857
} else {
59-
this.callNode = DirectCallNode.create(target.getCallTarget());
58+
this.callNode = DirectCallNode.create(invoker.method.getCallTarget());
6059
}
61-
this.unbasic = target.getReturnKind() != method.getReturnKind();
60+
this.unbasic = invoker.unbasic;
6261
}
6362

6463
@Override
@@ -69,7 +68,14 @@ public Object call(Object[] args) {
6968
return callNode.call(args);
7069
}
7170

72-
public static MHInvokeGenericNode create(EspressoLanguage language, Meta meta, ObjectKlass accessingKlass, Method method, Symbol<Name> methodName, Symbol<Signature> signature) {
71+
public static MHInvokeGenericNode create(Method method, MethodHandleInvoker invoker) {
72+
return new MHInvokeGenericNode(method, invoker);
73+
}
74+
75+
public record MethodHandleInvoker(Method method, StaticObject appendix, boolean unbasic) {
76+
}
77+
78+
public static MethodHandleInvoker linkMethod(EspressoLanguage language, Meta meta, ObjectKlass accessingKlass, Method method, Symbol<Name> methodName, Symbol<Signature> signature) {
7379
ObjectKlass callerKlass = accessingKlass == null ? meta.java_lang_Object : accessingKlass;
7480
StaticObject appendixBox = StaticObject.createArray(meta.java_lang_Object_array, new StaticObject[1], meta.getContext());
7581
// Ask java code to spin an invoker for us.
@@ -79,7 +85,8 @@ public static MHInvokeGenericNode create(EspressoLanguage language, Meta meta, O
7985
method.getDeclaringKlass().mirror(), meta.toGuestString(methodName), meta.toGuestString(signature),
8086
appendixBox);
8187
StaticObject appendix = appendixBox.get(language, 0);
82-
return new MHInvokeGenericNode(method, memberName, appendix);
88+
Method target = (Method) method.getMeta().HIDDEN_VMTARGET.getHiddenObject(memberName);
89+
return new MethodHandleInvoker(target, appendix, target.getReturnKind() != method.getReturnKind());
8390
}
8491

8592
@Override

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeHandleNode.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,20 @@
2424

2525
import com.oracle.truffle.api.frame.VirtualFrame;
2626
import com.oracle.truffle.espresso.impl.Method;
27-
import com.oracle.truffle.espresso.impl.ObjectKlass;
2827
import com.oracle.truffle.espresso.nodes.EspressoFrame;
28+
import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode.MethodHandleInvoker;
2929
import com.oracle.truffle.espresso.nodes.methodhandle.MethodHandleIntrinsicNode;
3030
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
3131

3232
public final class InvokeHandleNode extends InvokeQuickNode {
33-
3433
@Child private MethodHandleIntrinsicNode intrinsic;
3534
private final boolean hasReceiver;
3635
private final int argCount;
3736

38-
public InvokeHandleNode(Method method, ObjectKlass accessingKlass, int top, int curBCI) {
37+
public InvokeHandleNode(Method method, MethodHandleInvoker invoker, int top, int curBCI) {
3938
super(method, top, curBCI);
4039
this.hasReceiver = !method.isStatic();
41-
this.intrinsic = insert(method.spawnIntrinsicNode(getLanguage(), getContext().getMeta(), accessingKlass, method.getName(), method.getRawSignature()));
40+
this.intrinsic = insert(method.spawnIntrinsicNode(invoker));
4241
this.argCount = method.getParameterCount() + (method.isStatic() ? 0 : 1) + (method.isInvokeIntrinsic() ? 1 : 0);
4342
}
4443

0 commit comments

Comments
 (0)