Skip to content

Commit 6ff9ec5

Browse files
Move the InvokeGeneric appendix to the constant pool
This ensure the call-site is not relinked if we use a different bytecode node (e.g., continuations).
1 parent 2c18cce commit 6ff9ec5

File tree

7 files changed

+79
-32
lines changed

7 files changed

+79
-32
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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
import com.oracle.truffle.api.nodes.ExplodeLoop;
6464
import com.oracle.truffle.api.source.Source;
6565
import com.oracle.truffle.api.source.SourceSection;
66-
import com.oracle.truffle.espresso.EspressoLanguage;
6766
import com.oracle.truffle.espresso.EspressoOptions;
6867
import com.oracle.truffle.espresso.analysis.frame.EspressoFrameDescriptor;
6968
import com.oracle.truffle.espresso.analysis.frame.FrameAnalysis;
@@ -102,6 +101,7 @@
102101
import com.oracle.truffle.espresso.meta.ModifiersProvider;
103102
import com.oracle.truffle.espresso.nodes.EspressoRootNode;
104103
import com.oracle.truffle.espresso.nodes.interop.AbstractLookupNode;
104+
import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode.MethodHandleInvoker;
105105
import com.oracle.truffle.espresso.nodes.methodhandle.MethodHandleIntrinsicNode;
106106
import com.oracle.truffle.espresso.runtime.Attribute;
107107
import com.oracle.truffle.espresso.runtime.EspressoContext;
@@ -831,9 +831,9 @@ public Method createIntrinsic(Symbol<Signature> polymorphicRawSignature) {
831831
return new Method(declaringKlass.getKlassVersion(), getLinkedMethod(), polymorphicRawSignature, getRuntimeConstantPool(), flags);
832832
}
833833

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

839839
public Method forceSplit() {

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
@@ -313,6 +313,7 @@
313313
import com.oracle.truffle.espresso.classfile.attributes.BootstrapMethodsAttribute;
314314
import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableAttribute;
315315
import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant;
316+
import com.oracle.truffle.espresso.classfile.constantpool.ClassMethodRefConstant;
316317
import com.oracle.truffle.espresso.classfile.constantpool.DoubleConstant;
317318
import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant;
318319
import com.oracle.truffle.espresso.classfile.constantpool.FloatConstant;
@@ -338,6 +339,7 @@
338339
import com.oracle.truffle.espresso.meta.JavaKind;
339340
import com.oracle.truffle.espresso.meta.Meta;
340341
import com.oracle.truffle.espresso.nodes.helper.EspressoReferenceArrayStoreNode;
342+
import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode.MethodHandleInvoker;
341343
import com.oracle.truffle.espresso.nodes.quick.BaseQuickNode;
342344
import com.oracle.truffle.espresso.nodes.quick.CheckCastQuickNode;
343345
import com.oracle.truffle.espresso.nodes.quick.InstanceOfQuickNode;
@@ -2488,7 +2490,12 @@ private InvokeQuickNode dispatchQuickened(int top, int curBCI, char cpi, int opc
24882490

24892491
InvokeQuickNode invoke;
24902492
if (resolved.isPolySignatureIntrinsic()) {
2491-
invoke = new InvokeHandleNode(resolved, getDeclaringKlass(), top, curBCI);
2493+
MethodHandleInvoker invoker = null;
2494+
if ((resolvedOpCode == INVOKEVIRTUAL || resolvedOpCode == INVOKESPECIAL) && (getConstantPool().resolvedMethodRefAt(getDeclaringKlass(), cpi) instanceof ClassMethodRefConstant methodRef)) {
2495+
// There might be an invoker if it's an InvokeGeneric
2496+
invoker = methodRef.invoker();
2497+
}
2498+
invoke = new InvokeHandleNode(resolved, invoker, top, curBCI);
24922499
} else {
24932500
// @formatter:off
24942501
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

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/MethodHandleIntrinsics.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,18 @@
2626
import java.util.concurrent.ConcurrentHashMap;
2727

2828
import com.oracle.truffle.api.CompilerAsserts;
29-
import com.oracle.truffle.espresso.EspressoLanguage;
3029
import com.oracle.truffle.espresso.descriptors.Symbol;
3130
import com.oracle.truffle.espresso.descriptors.Symbol.Name;
3231
import com.oracle.truffle.espresso.descriptors.Symbol.Signature;
3332
import com.oracle.truffle.espresso.descriptors.Symbol.Type;
3433
import com.oracle.truffle.espresso.descriptors.Types;
3534
import com.oracle.truffle.espresso.impl.Klass;
3635
import com.oracle.truffle.espresso.impl.Method;
37-
import com.oracle.truffle.espresso.impl.ObjectKlass;
3836
import com.oracle.truffle.espresso.meta.EspressoError;
3937
import com.oracle.truffle.espresso.meta.Meta;
4038
import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeBasicNodeGen;
4139
import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode;
40+
import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode.MethodHandleInvoker;
4241
import com.oracle.truffle.espresso.nodes.methodhandle.MHLinkToNativeNode;
4342
import com.oracle.truffle.espresso.nodes.methodhandle.MHLinkToNodeGen;
4443
import com.oracle.truffle.espresso.nodes.methodhandle.MethodHandleIntrinsicNode;
@@ -49,18 +48,17 @@
4948
* espresso Method instances every time a new signature is seen. This is the only place that keeps
5049
* track of these, as the dummy methods are not present in klasses, since they are merely internal
5150
* constructs.
52-
*
51+
* <p>
5352
* Since the whole method handle machinery is a pretty opaque black box, here is a quick summary of
5453
* what's happening under espresso's hood.
55-
*
54+
*
5655
* <li>Each time a {@link java.lang.invoke.MethodHandle} PolymorphicSignature method is resolved
5756
* with a signature that was never seen before by the context, espresso creates a dummy placeholder
5857
* method and keeps track of it.
5958
* <li>When a call site needs to link against a polymorphic signatures, it obtains the dummy method.
60-
* It then calls
61-
* {@link Method#spawnIntrinsicNode(EspressoLanguage, Meta, ObjectKlass, Symbol, Symbol)} which
62-
* gives a truffle node implementing the behavior of the MethodHandle intrinsics (ie: extracting the
63-
* call target from the arguments, appending an appendix to the erguments, etc...)
59+
* It then calls {@link Method#spawnIntrinsicNode(MethodHandleInvoker)} which gives a truffle node
60+
* implementing the behavior of the MethodHandle intrinsics (ie: extracting the call target from the
61+
* arguments, appending an appendix to the arguments, etc...)
6462
* <li>This node is then fed to a {@link InvokeHandleNode} whose role is exactly like the other
6563
* invoke nodes: extracting arguments from the stack and passing it to its child.
6664
*/
@@ -72,11 +70,12 @@ public final class MethodHandleIntrinsics {
7270
this.intrinsics = new ConcurrentHashMap<>();
7371
}
7472

75-
public static MethodHandleIntrinsicNode createIntrinsicNode(EspressoLanguage language, Meta meta, Method method, ObjectKlass accessingKlass, Symbol<Name> methodName, Symbol<Signature> signature) {
73+
public static MethodHandleIntrinsicNode createIntrinsicNode(Meta meta, Method method, MethodHandleInvoker invoker) {
7674
PolySigIntrinsics id = getId(method);
75+
assert (invoker != null) == (id == PolySigIntrinsics.InvokeGeneric);
7776
return switch (id) {
7877
case InvokeBasic -> MHInvokeBasicNodeGen.create(method);
79-
case InvokeGeneric -> MHInvokeGenericNode.create(language, meta, accessingKlass, method, methodName, signature);
78+
case InvokeGeneric -> MHInvokeGenericNode.create(method, invoker);
8079
case LinkToVirtual, LinkToStatic, LinkToSpecial, LinkToInterface -> MHLinkToNodeGen.create(method, id);
8180
case LinkToNative -> MHLinkToNativeNode.create(method, meta);
8281
case None -> throw EspressoError.shouldNotReachHere();
@@ -216,7 +215,7 @@ public enum PolySigIntrinsics {
216215
/**
217216
* Indicates that the given ID represent a static polymorphic signature method. As of Java
218217
* 11, there exists only 4 such methods.
219-
*
218+
*
220219
* @see "java.lang.invoke.MethodHandle.linkToInterface(Object...)"
221220
* @see "java.lang.invoke.MethodHandle.linkToSpecial(Object...)"
222221
* @see "java.lang.invoke.MethodHandle.linkToStatic(Object...)"

0 commit comments

Comments
 (0)