Skip to content

Commit 5dece06

Browse files
Setup the ability to interpret polymorphic signature intrinsics
* Polymorphic signature method instantiations have an "intrinsic" field set denoting which kind of intrinsic type it is. * The interpreter can dispatch to `IntrinsicRoot.execute` for intrinsics. * Stack walking knows about this interpeter method * The special interpreter methods should be marked as `@NeverInline` and don't need to be added as root. * Add support in the interpreter for `invokeBasic`
1 parent eda9426 commit 5dece06

File tree

9 files changed

+264
-44
lines changed

9 files changed

+264
-44
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/interpreter/InterpreterSupport.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,14 @@ public static InterpreterSupport singleton() {
6464
return ImageSingletons.lookup(InterpreterSupport.class);
6565
}
6666

67-
/*
68-
* Check if a given argument matches the inner class Interpreter.Root (holder of the interpreter
69-
* dispatch loop).
67+
/**
68+
* Check if a given frame should be processed by {@link #getInterpretedMethodFrameInfo}.
7069
*/
71-
public abstract boolean isInterpreterRoot(Class<?> clazz);
70+
public abstract boolean isInterpreterRoot(FrameInfoQueryResult frameInfo);
7271

7372
/**
74-
* Transforms an interpreter (root) frame into a frame of the interpreted method. The passed
75-
* frame must be an interpreter root e.g. {@code isInterpreterRoot(frameInfo.getSourceClass())}
76-
* otherwise a fatal exception is thrown.
73+
* Transforms an interpreter (root) frame into a frame of the interpreted method. An error is
74+
* thrown if the passed frame is not an {@link #isInterpreterRoot interpreter root}.
7775
*
7876
* @param frameInfo interpreter root frame
7977
* @param sp stack pointer of the interpreter frame
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core.methodhandles;
26+
27+
import java.lang.invoke.MethodHandle;
28+
29+
import com.oracle.svm.core.SubstrateUtil;
30+
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
31+
32+
public final class MethodHandleInterpreterUtils {
33+
private MethodHandleInterpreterUtils() {
34+
}
35+
36+
public static Target_java_lang_invoke_MemberName extractVMEntry(MethodHandle handle) {
37+
Target_java_lang_invoke_LambdaForm lform = SubstrateUtil.cast(handle, Target_java_lang_invoke_MethodHandle.class).internalForm();
38+
return lform.vmentry;
39+
}
40+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaStackFrameVisitor.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,9 @@ protected boolean visitDeoptimizedFrame(Pointer originalSP, CodePointer deoptStu
5959
return true;
6060
}
6161

62-
private static FrameSourceInfo interpreterToInterpretedMethodFrame(FrameInfoQueryResult frameInfo, Pointer sp) {
63-
InterpreterSupport interpreter = InterpreterSupport.singleton();
64-
VMError.guarantee(interpreter.isInterpreterRoot(frameInfo.getSourceClass()));
65-
return interpreter.getInterpretedMethodFrameInfo(frameInfo, sp);
66-
}
67-
6862
protected final boolean dispatchPossiblyInterpretedFrame(FrameInfoQueryResult frameInfo, Pointer sp) {
69-
if (InterpreterSupport.isEnabled() && InterpreterSupport.singleton().isInterpreterRoot(frameInfo.getSourceClass())) {
70-
return visitFrame(interpreterToInterpretedMethodFrame(frameInfo, sp), sp);
63+
if (InterpreterSupport.isEnabled() && InterpreterSupport.singleton().isInterpreterRoot(frameInfo)) {
64+
return visitFrame(InterpreterSupport.singleton().getInterpretedMethodFrameInfo(frameInfo, sp), sp);
7165
} else {
7266
return visitFrame(frameInfo, sp);
7367
}

substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaMethod.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131
import static com.oracle.svm.espresso.classfile.Constants.ACC_SYNTHETIC;
3232
import static com.oracle.svm.espresso.classfile.Constants.ACC_VARARGS;
3333
import static com.oracle.svm.interpreter.metadata.Bytecodes.BREAKPOINT;
34+
import static com.oracle.svm.interpreter.metadata.CremaMethodAccess.toJVMCI;
3435

3536
import java.lang.annotation.Annotation;
37+
import java.lang.reflect.Executable;
3638
import java.lang.reflect.Modifier;
3739
import java.lang.reflect.Type;
3840
import java.util.HashSet;
@@ -45,6 +47,7 @@
4547
import com.oracle.svm.core.FunctionPointerHolder;
4648
import com.oracle.svm.core.hub.RuntimeClassLoading;
4749
import com.oracle.svm.core.hub.registry.SymbolsSupport;
50+
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
4851
import com.oracle.svm.core.meta.MethodPointer;
4952
import com.oracle.svm.core.util.VMError;
5053
import com.oracle.svm.espresso.classfile.Constants;
@@ -739,4 +742,8 @@ public final void reprofile() {
739742
}
740743

741744
// endregion Unimplemented methods
745+
746+
public static InterpreterResolvedJavaMethod fromMemberName(Target_java_lang_invoke_MemberName memberName) {
747+
return toJVMCI((Executable) memberName.reflectAccess);
748+
}
742749
}

substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/Interpreter.java

Lines changed: 150 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,15 @@
266266

267267
import java.lang.invoke.MethodHandle;
268268
import java.lang.invoke.MethodType;
269+
import java.util.Objects;
269270

271+
import com.oracle.svm.core.NeverInline;
272+
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
270273
import com.oracle.svm.core.jdk.InternalVMMethod;
274+
import com.oracle.svm.core.methodhandles.MethodHandleInterpreterUtils;
271275
import com.oracle.svm.core.util.VMError;
272276
import com.oracle.svm.espresso.classfile.ConstantPool;
277+
import com.oracle.svm.espresso.shared.meta.SignaturePolymorphicIntrinsic;
273278
import com.oracle.svm.interpreter.debug.DebuggerEvents;
274279
import com.oracle.svm.interpreter.debug.EventKind;
275280
import com.oracle.svm.interpreter.debug.SteppingControl;
@@ -364,7 +369,7 @@ public static Object execute(InterpreterResolvedJavaMethod method, InterpreterFr
364369
public static Object execute(InterpreterResolvedJavaMethod method, Object[] args, boolean forceStayInInterpreter) {
365370
InterpreterFrame frame = EspressoFrame.allocate(method.getMaxLocals(), method.getMaxStackSize(), args);
366371

367-
InterpreterUtil.guarantee(!method.isNative(), "trying to interpret native method %s", method);
372+
InterpreterUtil.guarantee(!method.isNative() || method.getSignaturePolymorphicIntrinsic() != null, "trying to interpret native method %s", method);
368373

369374
initializeFrame(frame, method);
370375
return execute0(method, frame, forceStayInInterpreter);
@@ -379,8 +384,13 @@ private static Object execute0(InterpreterResolvedJavaMethod method, Interpreter
379384
assert lockTarget != null;
380385
InterpreterToVM.monitorEnter(frame, nullCheck(lockTarget));
381386
}
382-
int startTop = startingStackOffset(method.getMaxLocals());
383-
return Root.executeBodyFromBCI(frame, method, 0, startTop, stayInInterpreter);
387+
SignaturePolymorphicIntrinsic intrinsic = method.getSignaturePolymorphicIntrinsic();
388+
if (intrinsic != null) {
389+
return IntrinsicRoot.execute(frame, method, intrinsic, stayInInterpreter);
390+
} else {
391+
int startTop = startingStackOffset(method.getMaxLocals());
392+
return Root.executeBodyFromBCI(frame, method, 0, startTop, stayInInterpreter);
393+
}
384394
} finally {
385395
InterpreterToVM.releaseInterpreterFrameLocks(frame);
386396
}
@@ -467,8 +477,144 @@ private static void traceInterpreterException(InterpreterResolvedJavaMethod meth
467477
.string("/top=").unsigned(top).newline();
468478
}
469479

470-
public static final class Root {
480+
private static void traceIntrinsicEnter(InterpreterResolvedJavaMethod method, int indent, SignaturePolymorphicIntrinsic intrinsic) {
481+
/* arguments to Log methods might have side-effects */
482+
if (!InterpreterOptions.InterpreterTraceSupport.getValue()) {
483+
return;
484+
}
485+
486+
setLogIndent(indent + 2);
487+
traceInterpreter(" ".repeat(indent)) //
488+
.string("[interp] Intrinsic Entered ") //
489+
.string(method.getDeclaringClass().getName()) //
490+
.string("::") //
491+
.string(method.getName()) //
492+
.string(method.getSignature().toMethodDescriptor()) //
493+
.string(" with iid=").string(intrinsic.name()) //
494+
.newline();
495+
}
496+
497+
private static void traceInvokeBasic(InterpreterResolvedJavaMethod target, int indent) {
498+
/* arguments to Log methods might have side-effects */
499+
if (!InterpreterOptions.InterpreterTraceSupport.getValue()) {
500+
return;
501+
}
502+
503+
traceInterpreter(" ".repeat(indent)) //
504+
.string("invokeBasic target=") //
505+
.string(target.getDeclaringClass().getName()) //
506+
.string("::") //
507+
.string(target.getName()) //
508+
.string(target.getSignature().toMethodDescriptor()) //
509+
.newline();
510+
}
471511

512+
private static void traceLinkTo(InterpreterResolvedJavaMethod target, SignaturePolymorphicIntrinsic intrinsic, int indent) {
513+
/* arguments to Log methods might have side-effects */
514+
if (!InterpreterOptions.InterpreterTraceSupport.getValue()) {
515+
return;
516+
}
517+
518+
traceInterpreter(" ".repeat(indent)) //
519+
.string(intrinsic.name())
520+
.string(" target=") //
521+
.string(target.getDeclaringClass().getName()) //
522+
.string("::") //
523+
.string(target.getName()) //
524+
.string(target.getSignature().toMethodDescriptor()) //
525+
.newline();
526+
}
527+
528+
public static final class IntrinsicRoot {
529+
@NeverInline("needed far stack walking")
530+
public static Object execute(InterpreterFrame frame, InterpreterResolvedJavaMethod method, SignaturePolymorphicIntrinsic intrinsic, boolean forceStayInInterpreter) {
531+
int indent = getLogIndent();
532+
traceIntrinsicEnter(method, indent, intrinsic);
533+
return switch (intrinsic) {
534+
case InvokeBasic -> {
535+
MethodHandle mh = (MethodHandle) EspressoFrame.getThis(frame);
536+
Target_java_lang_invoke_MemberName vmentry = MethodHandleInterpreterUtils.extractVMEntry(mh);
537+
InterpreterResolvedJavaMethod target = InterpreterResolvedJavaMethod.fromMemberName(vmentry);
538+
Object[] calleeArgs = frame.getArguments();
539+
// This should integrate with the debugger GR-70801
540+
boolean preferStayInInterpreter = forceStayInInterpreter;
541+
traceInvokeBasic(target, indent);
542+
try {
543+
yield InterpreterToVM.dispatchInvocation(target, calleeArgs, false, forceStayInInterpreter, preferStayInInterpreter, false);
544+
} catch (SemanticJavaException e) {
545+
throw uncheckedThrow(e.getCause());
546+
}
547+
}
548+
case LinkToStatic, LinkToSpecial, LinkToVirtual, LinkToInterface -> {
549+
InterpreterResolvedJavaMethod resolutionSeed = getLinkToTarget(frame);
550+
InterpreterUnresolvedSignature signature = resolutionSeed.getSignature();
551+
Object[] basicArgs = unbasic(frame, signature, false);
552+
// This should integrate with the debugger GR-70801
553+
boolean preferStayInInterpreter = forceStayInInterpreter;
554+
traceLinkTo(resolutionSeed, intrinsic, indent);
555+
try {
556+
boolean isInvokeInterface = intrinsic == SignaturePolymorphicIntrinsic.LinkToInterface;
557+
boolean isVirtual = isInvokeInterface || intrinsic == SignaturePolymorphicIntrinsic.LinkToVirtual;
558+
Object result = InterpreterToVM.dispatchInvocation(resolutionSeed, basicArgs, isVirtual, forceStayInInterpreter, preferStayInInterpreter, isInvokeInterface);
559+
yield rebasic(result, signature.getReturnKind());
560+
} catch (SemanticJavaException e) {
561+
throw uncheckedThrow(e.getCause());
562+
}
563+
}
564+
default -> throw VMError.shouldNotReachHere(Objects.toString(intrinsic));
565+
};
566+
}
567+
}
568+
569+
private static InterpreterResolvedJavaMethod getLinkToTarget(InterpreterFrame frame) {
570+
Object[] arguments = frame.getArguments();
571+
Target_java_lang_invoke_MemberName memberName = (Target_java_lang_invoke_MemberName) arguments[arguments.length - 1];
572+
return InterpreterResolvedJavaMethod.fromMemberName(memberName);
573+
}
574+
575+
private static Object[] unbasic(InterpreterFrame frame, InterpreterUnresolvedSignature targetSig, boolean inclReceiver) {
576+
Object[] arguments = frame.getArguments();
577+
int parameterCount = targetSig.getParameterCount(inclReceiver);
578+
Object[] res = new Object[parameterCount];
579+
int start = 0;
580+
if (inclReceiver) {
581+
res[start++] = arguments[0];
582+
}
583+
for (int i = start; i < parameterCount; i++) {
584+
JavaKind kind = targetSig.getParameterKind(i - start);
585+
res[i] = unbasic(arguments[i], kind);
586+
}
587+
return res;
588+
}
589+
590+
// Transforms ints to sub-words
591+
public static Object unbasic(Object arg, JavaKind kind) {
592+
return switch (kind) {
593+
case Boolean -> (int) arg != 0;
594+
case Byte -> (byte) (int) arg;
595+
case Char -> (char) (int) arg;
596+
case Short -> (short) (int) arg;
597+
default -> arg;
598+
};
599+
}
600+
601+
private static Object rebasic(Object value, JavaKind returnType) {
602+
// @formatter:off
603+
return switch (returnType) {
604+
case Boolean -> stackIntToBoolean((int) value);
605+
case Byte -> (byte) value;
606+
case Short -> (short) value;
607+
case Char -> (char) value;
608+
case Int, Long, Float, Double, Object
609+
-> value;
610+
case Void -> null; // void
611+
default -> throw VMError.shouldNotReachHereAtRuntime();
612+
};
613+
// @formatter:on
614+
}
615+
616+
public static final class Root {
617+
@NeverInline("needed far stack walking")
472618
private static Object executeBodyFromBCI(InterpreterFrame frame, InterpreterResolvedJavaMethod method, int startBCI, int startTop,
473619
boolean forceStayInInterpreter) {
474620
int curBCI = startBCI;

substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/InterpreterFeature.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,20 +200,26 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
200200
BuildTimeInterpreterUniverse.freshSingletonInstance();
201201
AnalysisMethod interpreterRoot = accessImpl.getMetaAccess().lookupJavaType(Interpreter.Root.class).getDeclaredMethods(false)[0];
202202

203-
accessImpl.registerAsRoot(interpreterRoot, true, "interpreter main loop");
204203
LocalVariableTable interpreterVariableTable = interpreterRoot.getLocalVariableTable();
205-
int interpretedMethodSlot = findLocalSlotByName("method", interpreterVariableTable.getLocalsAt(0)); // parameter
204+
int interpreterMethodSlot = findLocalSlotByName("method", interpreterVariableTable.getLocalsAt(0)); // parameter
206205
int interpreterFrameSlot = findLocalSlotByName("frame", interpreterVariableTable.getLocalsAt(0)); // parameter
207206
// Local variable, search all locals.
208207
int bciSlot = findLocalSlotByName("curBCI", interpreterVariableTable.getLocals());
209208

210-
ImageSingletons.add(InterpreterSupport.class, new InterpreterSupportImpl(bciSlot, interpretedMethodSlot, interpreterFrameSlot));
209+
AnalysisMethod intrinsicRoot = accessImpl.getMetaAccess().lookupJavaType(Interpreter.IntrinsicRoot.class).getDeclaredMethods(false)[0];
210+
211+
LocalVariableTable intrinsicVariableTable = intrinsicRoot.getLocalVariableTable();
212+
int intrinsicMethodSlot = findLocalSlotByName("method", intrinsicVariableTable.getLocalsAt(0)); // parameter
213+
int intrinsicFrameSlot = findLocalSlotByName("frame", intrinsicVariableTable.getLocalsAt(0)); // parameter
214+
215+
ImageSingletons.add(InterpreterSupport.class, new InterpreterSupportImpl(bciSlot, interpreterMethodSlot, interpreterFrameSlot, intrinsicMethodSlot, intrinsicFrameSlot));
211216
ImageSingletons.add(InterpreterDirectivesSupport.class, new InterpreterDirectivesSupportImpl());
212217
ImageSingletons.add(InterpreterMethodPointerHolder.class, new InterpreterMethodPointerHolder());
213218

214219
// Locals must be available at runtime to retrieve BCI, interpreted method and interpreter
215220
// frame.
216221
SubstrateCompilationDirectives.singleton().registerFrameInformationRequired(interpreterRoot);
222+
SubstrateCompilationDirectives.singleton().registerFrameInformationRequired(intrinsicRoot);
217223

218224
Method leaveMethod = ReflectionUtil.lookupMethod(InterpreterStubSection.class, "leaveInterpreterStub", CFunctionPointer.class, Pointer.class, long.class, long.class);
219225
leaveStub = accessImpl.getMetaAccess().lookupJavaMethod(leaveMethod);

0 commit comments

Comments
 (0)