Skip to content

Commit 5398fa4

Browse files
committed
Execute potentially dangerous bootstrap methods at run time instead of build time
1 parent 4f7bad0 commit 5398fa4

File tree

9 files changed

+1086
-108
lines changed

9 files changed

+1086
-108
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,7 +1792,7 @@ private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int o
17921792

17931793
}
17941794

1795-
boolean hasReceiver = (opcode == INVOKEDYNAMIC) ? false : !target.isStatic();
1795+
boolean hasReceiver = opcode != INVOKEDYNAMIC && !target.isStatic();
17961796
ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver));
17971797
if (hasReceiver) {
17981798
appendInvoke(InvokeKind.Virtual, target, args, null);
@@ -2089,12 +2089,7 @@ private static boolean checkPartialIntrinsicExit(ValueNode[] originalArgs, Value
20892089
protected Invoke createNonInlinedInvoke(ExceptionEdgeAction exceptionEdge, int invokeBci, ValueNode[] invokeArgs, ResolvedJavaMethod targetMethod,
20902090
InvokeKind invokeKind, JavaKind resultType, JavaType returnType, JavaTypeProfile profile) {
20912091

2092-
StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false);
2093-
if (returnStamp == null) {
2094-
returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
2095-
}
2096-
2097-
MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, invokeArgs, returnStamp, profile));
2092+
MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, invokeArgs, returnType, profile));
20982093
Invoke invoke = createNonInlinedInvoke(exceptionEdge, invokeBci, callTarget, resultType);
20992094

21002095
for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
@@ -2105,11 +2100,14 @@ protected Invoke createNonInlinedInvoke(ExceptionEdgeAction exceptionEdge, int i
21052100
}
21062101

21072102
protected Invoke createNonInlinedInvoke(ExceptionEdgeAction exceptionEdge, int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
2103+
Invoke invoke;
21082104
if (exceptionEdge == ExceptionEdgeAction.OMIT) {
2109-
return createInvoke(invokeBci, callTarget, resultType);
2105+
invoke = append(createInvoke(invokeBci, callTarget, resultType));
21102106
} else {
2111-
return createInvokeWithException(invokeBci, callTarget, resultType, exceptionEdge);
2107+
invoke = append(createInvokeWithException(invokeBci, callTarget, resultType, exceptionEdge));
21122108
}
2109+
invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
2110+
return invoke;
21132111
}
21142112

21152113
/**
@@ -2675,14 +2673,22 @@ private ValueNode processCalleeReturn(ResolvedJavaMethod targetMethod, InliningS
26752673
return null;
26762674
}
26772675

2676+
public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, JavaType returnType, JavaTypeProfile profile) {
2677+
StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false);
2678+
if (returnStamp == null) {
2679+
returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
2680+
}
2681+
2682+
return createMethodCallTarget(invokeKind, targetMethod, args, returnStamp, profile);
2683+
}
2684+
26782685
public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, JavaTypeProfile profile) {
26792686
return new MethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, profile);
26802687
}
26812688

26822689
protected InvokeNode createInvoke(int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
2683-
InvokeNode invoke = append(new InvokeNode(callTarget, invokeBci));
2690+
InvokeNode invoke = new InvokeNode(callTarget, invokeBci);
26842691
frameState.pushReturn(resultType, invoke);
2685-
invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
26862692
return invoke;
26872693
}
26882694

@@ -2696,9 +2702,8 @@ protected InvokeWithExceptionNode createInvokeWithException(int invokeBci, CallT
26962702
}
26972703

26982704
AbstractBeginNode exceptionEdge = handleException(null, bci(), exceptionEdgeAction == ExceptionEdgeAction.INCLUDE_AND_DEOPTIMIZE);
2699-
InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, invokeBci));
2705+
InvokeWithExceptionNode invoke = new InvokeWithExceptionNode(callTarget, exceptionEdge, invokeBci);
27002706
frameState.pushReturn(resultType, invoke);
2701-
invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
27022707
return invoke;
27032708
}
27042709

@@ -3939,7 +3944,7 @@ public BailoutException bailout(String string) {
39393944
throw GraphUtil.createBailoutException(string, bailout, elements);
39403945
}
39413946

3942-
private FrameState createFrameState(int bci, StateSplit forStateSplit) {
3947+
protected FrameState createFrameState(int bci, StateSplit forStateSplit) {
39433948
assert !(forStateSplit instanceof BytecodeExceptionNode) : Assertions.errorMessageContext("forStateSplit", forStateSplit);
39443949
if (currentBlock != null && bci > currentBlock.getEndBci()) {
39453950
frameState.clearNonLiveLocals(currentBlock, liveness, false);
@@ -4023,19 +4028,24 @@ public void storeLocal(JavaKind kind, int index) {
40234028

40244029
protected void genLoadConstant(int cpi, int opcode) {
40254030
Object con = lookupConstant(cpi, opcode, false);
4031+
genLoadConstantHelper(con, opcode);
4032+
}
4033+
4034+
protected void genLoadConstantHelper(Object con, int opcode) {
40264035
if (con == null) {
40274036
handleUnresolvedLoadConstant(null);
4028-
} else if (con instanceof JavaType) {
4037+
} else if (con instanceof JavaType type) {
40294038
// this is a load of class constant which might be unresolved
4030-
JavaType type = (JavaType) con;
40314039
if (typeIsResolved(type)) {
4040+
assert opcode != LDC2_W : "Type cannot use two slots";
40324041
frameState.push(JavaKind.Object, appendConstant(getConstantReflection().asJavaClass((ResolvedJavaType) type)));
40334042
} else {
40344043
handleUnresolvedLoadConstant(type);
40354044
}
4036-
} else if (con instanceof JavaConstant) {
4037-
JavaConstant constant = (JavaConstant) con;
4038-
frameState.push(constant.getJavaKind(), appendConstant(constant));
4045+
} else if (con instanceof JavaConstant constant) {
4046+
JavaKind javaKind = constant.getJavaKind();
4047+
assert (opcode == LDC2_W) == javaKind.needsTwoSlots() : "Constant required incorrect number of slots: needsTwoSlots is " + javaKind.needsTwoSlots();
4048+
frameState.push(javaKind, appendConstant(constant));
40394049
} else if (!(con instanceof Throwable)) {
40404050
/**
40414051
* We use the exceptional return value of {@link #lookupConstant(int, int)} as sentinel
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Copyright (c) 2023, 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 jdk.graal.compiler.serviceprovider;
26+
27+
import java.lang.reflect.Method;
28+
import java.util.List;
29+
30+
import jdk.graal.compiler.core.common.BootstrapMethodIntrospection;
31+
import jdk.graal.compiler.debug.GraalError;
32+
import jdk.vm.ci.meta.JavaConstant;
33+
import jdk.vm.ci.meta.ResolvedJavaMethod;
34+
35+
public class BootstrapMethodIntrospectionImpl implements BootstrapMethodIntrospection {
36+
private final Object wrapped;
37+
38+
/**
39+
* The interface jdk.vm.ci.meta.ConstantPool.BootstrapMethodInvocation was introduced in JVMCI
40+
* 22.1.
41+
*/
42+
private static final Class<?> bsmClass;
43+
private static final Method bsmGetMethod;
44+
private static final Method bsmIsInvokeDynamic;
45+
private static final Method bsmGetName;
46+
private static final Method bsmGetType;
47+
private static final Method bsmGetStaticArguments;
48+
49+
static {
50+
Class<?> bootstrapMethodClass = null;
51+
try {
52+
bootstrapMethodClass = Class.forName("jdk.vm.ci.meta.ConstantPool$BootstrapMethodInvocation");
53+
} catch (ClassNotFoundException e) {
54+
}
55+
bsmClass = bootstrapMethodClass;
56+
57+
Method bootstrapMethodGetMethod = null;
58+
Method bootstrapMethodIsInvokeDynamic = null;
59+
Method bootstrapMethodGetName = null;
60+
Method bootstrapMethodGetType = null;
61+
Method bootstrapMethodGetStaticArguments = null;
62+
63+
try {
64+
bootstrapMethodGetMethod = bsmClass == null ? null : bsmClass.getMethod("getMethod");
65+
} catch (NoSuchMethodException e) {
66+
}
67+
68+
try {
69+
bootstrapMethodIsInvokeDynamic = bsmClass == null ? null : bsmClass.getMethod("isInvokeDynamic");
70+
} catch (NoSuchMethodException e) {
71+
}
72+
73+
try {
74+
bootstrapMethodGetName = bsmClass == null ? null : bsmClass.getMethod("getName");
75+
} catch (NoSuchMethodException e) {
76+
}
77+
78+
try {
79+
bootstrapMethodGetType = bsmClass == null ? null : bsmClass.getMethod("getType");
80+
} catch (NoSuchMethodException e) {
81+
}
82+
83+
try {
84+
bootstrapMethodGetStaticArguments = bsmClass == null ? null : bsmClass.getMethod("getStaticArguments");
85+
} catch (NoSuchMethodException e) {
86+
}
87+
88+
bsmGetMethod = bootstrapMethodGetMethod;
89+
bsmIsInvokeDynamic = bootstrapMethodIsInvokeDynamic;
90+
bsmGetName = bootstrapMethodGetName;
91+
bsmGetType = bootstrapMethodGetType;
92+
bsmGetStaticArguments = bootstrapMethodGetStaticArguments;
93+
94+
}
95+
96+
public BootstrapMethodIntrospectionImpl(Object wrapped) {
97+
this.wrapped = wrapped;
98+
}
99+
100+
@Override
101+
public ResolvedJavaMethod getMethod() {
102+
try {
103+
return (ResolvedJavaMethod) bsmGetMethod.invoke(wrapped);
104+
} catch (Throwable t) {
105+
throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport
106+
}
107+
}
108+
109+
@Override
110+
public boolean isInvokeDynamic() {
111+
try {
112+
return (boolean) bsmIsInvokeDynamic.invoke(wrapped);
113+
} catch (Throwable t) {
114+
throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport
115+
}
116+
}
117+
118+
@Override
119+
public String getName() {
120+
try {
121+
return (String) bsmGetName.invoke(wrapped);
122+
} catch (Throwable t) {
123+
throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport
124+
}
125+
}
126+
127+
@Override
128+
public JavaConstant getType() {
129+
try {
130+
return (JavaConstant) bsmGetType.invoke(wrapped);
131+
} catch (Throwable t) {
132+
throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport
133+
}
134+
}
135+
136+
@SuppressWarnings("unchecked")
137+
@Override
138+
public List<JavaConstant> getStaticArguments() {
139+
try {
140+
return (List<JavaConstant>) bsmGetStaticArguments.invoke(wrapped);
141+
} catch (Throwable t) {
142+
throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport
143+
}
144+
}
145+
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.util.ServiceConfigurationError;
4141
import java.util.ServiceLoader;
4242

43+
import jdk.graal.compiler.core.common.BootstrapMethodIntrospection;
4344
import jdk.graal.compiler.debug.GraalError;
4445
import jdk.vm.ci.meta.ConstantPool;
4546
import jdk.vm.ci.meta.EncodedSpeculationReason;
@@ -61,10 +62,12 @@ public final class GraalServices {
6162

6263
private static final Method constantPoolLookupMethodWithCaller;
6364
private static final Method constantPoolLookupConstantWithResolve;
65+
private static final Method constantPoolLookupBootstrapMethodInvocation;
6466

6567
static {
6668
Method lookupMethodWithCaller = null;
6769
Method lookupConstantWithResolve = null;
70+
Method lookupBootstrapMethodInvocation = null;
6871

6972
try {
7073
lookupMethodWithCaller = ConstantPool.class.getDeclaredMethod("lookupMethod", Integer.TYPE, Integer.TYPE, ResolvedJavaMethod.class);
@@ -76,8 +79,14 @@ public final class GraalServices {
7679
} catch (NoSuchMethodException e) {
7780
}
7881

82+
try {
83+
lookupBootstrapMethodInvocation = ConstantPool.class.getDeclaredMethod("lookupBootstrapMethodInvocation", Integer.TYPE, Integer.TYPE);
84+
} catch (NoSuchMethodException e) {
85+
}
86+
7987
constantPoolLookupMethodWithCaller = lookupMethodWithCaller;
8088
constantPoolLookupConstantWithResolve = lookupConstantWithResolve;
89+
constantPoolLookupBootstrapMethodInvocation = lookupBootstrapMethodInvocation;
8190
}
8291

8392
private GraalServices() {
@@ -478,6 +487,22 @@ public static Object lookupConstant(ConstantPool constantPool, int cpi, boolean
478487
return constantPool.lookupConstant(cpi);
479488
}
480489

490+
public static BootstrapMethodIntrospection lookupBootstrapMethodIntrospection(ConstantPool constantPool, int cpi, int opcode) {
491+
if (constantPoolLookupBootstrapMethodInvocation != null) {
492+
try {
493+
Object bootstrapMethodInvocation = constantPoolLookupBootstrapMethodInvocation.invoke(constantPool, cpi, opcode);
494+
if (bootstrapMethodInvocation != null) {
495+
return new BootstrapMethodIntrospectionImpl(bootstrapMethodInvocation);
496+
}
497+
} catch (InvocationTargetException e) {
498+
throw rethrow(e.getCause());
499+
} catch (IllegalAccessException e) {
500+
throw GraalError.shouldNotReachHere(e, "The method lookupBootstrapMethodInvocation should be accessible");
501+
}
502+
}
503+
return null;
504+
}
505+
481506
@SuppressWarnings("unchecked")
482507
static <E extends Throwable> RuntimeException rethrow(Throwable ex) throws E {
483508
throw (E) ex;

0 commit comments

Comments
 (0)