Skip to content

Commit eb792f6

Browse files
committed
Add LambdaSubstrateGraphBuilderPhase to be able to execute some bootstrap method at run time when finding a stable name for a lambda
1 parent 5398fa4 commit eb792f6

File tree

4 files changed

+118
-62
lines changed

4 files changed

+118
-62
lines changed

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,29 @@
2525

2626
package jdk.graal.compiler.hotspot.test;
2727

28+
import static org.junit.Assert.assertEquals;
29+
import static org.junit.Assert.assertNotNull;
30+
import static org.junit.Assert.assertTrue;
31+
import static org.junit.Assert.fail;
32+
2833
import java.math.BigInteger;
2934
import java.util.Collections;
30-
import jdk.vm.ci.meta.ResolvedJavaType;
31-
import jdk.vm.ci.runtime.JVMCI;
35+
36+
import org.junit.Test;
37+
import org.objectweb.asm.Type;
38+
3239
import jdk.graal.compiler.api.runtime.GraalJVMCICompiler;
3340
import jdk.graal.compiler.debug.DebugContext;
3441
import jdk.graal.compiler.debug.DebugContext.Builder;
3542
import jdk.graal.compiler.hotspot.meta.HotSpotJITClassInitializationPlugin;
43+
import jdk.graal.compiler.java.GraphBuilderPhase;
3644
import jdk.graal.compiler.java.LambdaUtils;
3745
import jdk.graal.compiler.options.OptionValues;
46+
import jdk.graal.compiler.phases.OptimisticOptimizations;
3847
import jdk.graal.compiler.phases.util.Providers;
3948
import jdk.graal.compiler.runtime.RuntimeProvider;
40-
import static org.junit.Assert.assertEquals;
41-
import static org.junit.Assert.assertNotNull;
42-
import static org.junit.Assert.assertTrue;
43-
import static org.junit.Assert.fail;
44-
import org.junit.Test;
45-
import org.objectweb.asm.Type;
49+
import jdk.vm.ci.meta.ResolvedJavaType;
50+
import jdk.vm.ci.runtime.JVMCI;
4651

4752
public class LambdaStableNameTest {
4853
private String findStableLambdaName(ResolvedJavaType type) {
@@ -51,7 +56,8 @@ private String findStableLambdaName(ResolvedJavaType type) {
5156
GraalJVMCICompiler compiler = (GraalJVMCICompiler) JVMCI.getRuntime().getCompiler();
5257
Providers providers = compiler.getGraalRuntime().getCapability(RuntimeProvider.class).getHostBackend().getProviders();
5358
final HotSpotJITClassInitializationPlugin initializationPlugin = new HotSpotJITClassInitializationPlugin();
54-
return LambdaUtils.findStableLambdaName(initializationPlugin, providers, type, options, debug, this);
59+
return LambdaUtils.findStableLambdaName(initializationPlugin, providers, type, options, debug, this,
60+
config -> new GraphBuilderPhase.Instance(providers, config, OptimisticOptimizations.NONE, null));
5561
}
5662

5763
@Test

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/LambdaUtils.java

Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,23 @@
2929
import java.security.NoSuchAlgorithmException;
3030
import java.util.Arrays;
3131
import java.util.List;
32+
import java.util.function.Function;
3233
import java.util.regex.Matcher;
3334
import java.util.regex.Pattern;
3435
import java.util.stream.Collectors;
3536
import java.util.stream.StreamSupport;
3637

3738
import jdk.graal.compiler.debug.DebugContext;
38-
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
3939
import jdk.graal.compiler.nodes.Invoke;
4040
import jdk.graal.compiler.nodes.StructuredGraph;
4141
import jdk.graal.compiler.nodes.graphbuilderconf.ClassInitializationPlugin;
4242
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
43-
import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext;
43+
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
4444
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins;
45-
import jdk.graal.compiler.nodes.spi.CoreProviders;
4645
import jdk.graal.compiler.options.OptionValues;
4746
import jdk.graal.compiler.phases.OptimisticOptimizations;
4847
import jdk.graal.compiler.phases.tiers.HighTierContext;
4948
import jdk.graal.compiler.phases.util.Providers;
50-
5149
import jdk.vm.ci.common.JVMCIError;
5250
import jdk.vm.ci.meta.ResolvedJavaMethod;
5351
import jdk.vm.ci.meta.ResolvedJavaType;
@@ -99,7 +97,8 @@ private LambdaUtils() {
9997
* @return stable name for the lambda class
10098
*/
10199
@SuppressWarnings("try")
102-
public static String findStableLambdaName(ClassInitializationPlugin cip, Providers providers, ResolvedJavaType lambdaType, OptionValues options, DebugContext debug, Object ctx)
100+
public static String findStableLambdaName(ClassInitializationPlugin cip, Providers providers, ResolvedJavaType lambdaType, OptionValues options, DebugContext debug, Object ctx,
101+
Function<GraphBuilderConfiguration, GraphBuilderPhase.Instance> graphBuilderSupplier)
103102
throws RuntimeException {
104103
ResolvedJavaMethod[] lambdaProxyMethods = Arrays.stream(lambdaType.getDeclaredMethods(false)).filter(m -> !m.isBridge() && m.isPublic()).toArray(ResolvedJavaMethod[]::new);
105104
/*
@@ -108,7 +107,7 @@ public static String findStableLambdaName(ClassInitializationPlugin cip, Provide
108107
*/
109108
StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(lambdaProxyMethods[0]).build();
110109
try (DebugContext.Scope ignored = debug.scope("Lambda target method analysis", graph, lambdaType, ctx)) {
111-
GraphBuilderPhase lambdaParserPhase = new LambdaGraphBuilder(LambdaUtils.buildLambdaParserConfig(cip));
110+
GraphBuilderPhase.Instance lambdaParserPhase = graphBuilderSupplier.apply(buildLambdaParserConfig(cip));
112111
HighTierContext context = new HighTierContext(providers, null, OptimisticOptimizations.NONE);
113112
lambdaParserPhase.apply(graph, context);
114113
} catch (Throwable e) {
@@ -171,44 +170,4 @@ public static String digest(String value) {
171170
public static String capturingClass(String className) {
172171
return className.split(LambdaUtils.SERIALIZATION_TEST_LAMBDA_CLASS_SPLIT_PATTERN)[0];
173172
}
174-
175-
private static final class LambdaGraphBuilder extends GraphBuilderPhase {
176-
177-
private LambdaGraphBuilder(GraphBuilderConfiguration config) {
178-
super(config);
179-
}
180-
181-
@Override
182-
protected GraphBuilderPhase.Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts,
183-
IntrinsicContext initialIntrinsicContext) {
184-
return new Instance(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext);
185-
}
186-
187-
private static class Instance extends GraphBuilderPhase.Instance {
188-
Instance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
189-
super(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext);
190-
}
191-
192-
@Override
193-
protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) {
194-
return new LambdaBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext);
195-
}
196-
}
197-
}
198-
199-
private static class LambdaBytecodeParser extends BytecodeParser {
200-
201-
LambdaBytecodeParser(GraphBuilderPhase.Instance instance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) {
202-
super(instance, graph, parent, method, entryBCI, intrinsicContext);
203-
}
204-
205-
@Override
206-
protected Object lookupConstant(int cpi, int opcode, boolean allowBootstrapMethodInvocation) {
207-
/*
208-
* Native Image forces bootstrap method invocation at build time until support has been
209-
* added for doing the invocation at runtime (GR-45806)
210-
*/
211-
return super.lookupConstant(cpi, opcode, true);
212-
}
213-
}
214173
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaProxyRenamingSubstitutionProcessor.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,18 @@
2828
import java.util.Set;
2929
import java.util.concurrent.ConcurrentHashMap;
3030

31+
import com.oracle.graal.pointsto.BigBang;
32+
import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor;
33+
import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin;
34+
import com.oracle.graal.pointsto.util.GraalAccess;
35+
3136
import jdk.graal.compiler.debug.DebugContext;
3237
import jdk.graal.compiler.debug.DebugContext.Builder;
3338
import jdk.graal.compiler.java.LambdaUtils;
3439
import jdk.graal.compiler.options.OptionValues;
40+
import jdk.graal.compiler.phases.OptimisticOptimizations;
3541
import jdk.graal.compiler.phases.util.Providers;
3642
import jdk.graal.compiler.printer.GraalDebugHandlersFactory;
37-
38-
import com.oracle.graal.pointsto.BigBang;
39-
import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor;
40-
import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin;
41-
import com.oracle.graal.pointsto.util.GraalAccess;
42-
4343
import jdk.vm.ci.meta.ResolvedJavaType;
4444

4545
/**
@@ -89,7 +89,8 @@ private LambdaSubstitutionType getSubstitution(ResolvedJavaType original) {
8989
DebugContext debug = new Builder(options, new GraalDebugHandlersFactory(bb.getSnippetReflectionProvider())).build();
9090

9191
Providers providers = GraalAccess.getOriginalProviders();
92-
String lambdaTargetName = LambdaUtils.findStableLambdaName(new NoClassInitializationPlugin(), providers, key, options, debug, this);
92+
String lambdaTargetName = LambdaUtils.findStableLambdaName(new NoClassInitializationPlugin(), providers, key, options, debug, this,
93+
config -> new LambdaSubstrateGraphBuilderPhase.LambdaSubstrateGraphBuilderInstance(providers, config, OptimisticOptimizations.NONE, null));
9394
return new LambdaSubstitutionType(key, findUniqueLambdaProxyName(lambdaTargetName));
9495
});
9596
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (c) 2023, 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 com.oracle.svm.hosted.lambda;
26+
27+
import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider;
28+
import com.oracle.svm.core.bootstrap.BootstrapMethodConfiguration;
29+
30+
import jdk.graal.compiler.core.common.BootstrapMethodIntrospection;
31+
import jdk.graal.compiler.java.BytecodeParser;
32+
import jdk.graal.compiler.java.GraphBuilderPhase;
33+
import jdk.graal.compiler.nodes.StructuredGraph;
34+
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
35+
import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext;
36+
import jdk.graal.compiler.nodes.spi.CoreProviders;
37+
import jdk.graal.compiler.phases.OptimisticOptimizations;
38+
import jdk.graal.compiler.serviceprovider.GraalServices;
39+
import jdk.vm.ci.meta.ResolvedJavaMethod;
40+
41+
public class LambdaSubstrateGraphBuilderPhase extends GraphBuilderPhase {
42+
public LambdaSubstrateGraphBuilderPhase(GraphBuilderConfiguration config) {
43+
super(config);
44+
}
45+
46+
@Override
47+
protected Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
48+
return new LambdaSubstrateGraphBuilderInstance(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext);
49+
}
50+
51+
public static class LambdaSubstrateGraphBuilderInstance extends GraphBuilderPhase.Instance {
52+
LambdaSubstrateGraphBuilderInstance(CoreProviders theProviders, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
53+
IntrinsicContext initialIntrinsicContext) {
54+
super(theProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
55+
}
56+
57+
@Override
58+
protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) {
59+
return new LambdaSubstrateBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext);
60+
}
61+
}
62+
63+
public static class LambdaSubstrateBytecodeParser extends BytecodeParser {
64+
protected LambdaSubstrateBytecodeParser(Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI,
65+
IntrinsicContext intrinsicContext) {
66+
super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext);
67+
}
68+
69+
@Override
70+
protected void genLoadConstant(int cpi, int opcode) {
71+
Object con = lookupConstant(cpi, opcode, false);
72+
BootstrapMethodIntrospection bootstrap = GraalServices.lookupBootstrapMethodIntrospection(constantPool, cpi, -1);
73+
if (con == null && bootstrap != null && BootstrapMethodConfiguration.singleton().isCondyTrusted(OriginalMethodProvider.getJavaMethod(bootstrap.getMethod()))) {
74+
/*
75+
* With the current implementation of LambdaUtils#findStableLambdaName, each lambda
76+
* must contain at least one method invocation to compute its name. Looking up the
77+
* constant with allowBootstrapMethodInvocation set to false will produce null if
78+
* the constant is dynamic. Returning it will cause a runtime exception and if the
79+
* lambda starts with the constant lookup, the lambda will contain no method
80+
* invocation. At this stage, the AnalysisBytecodeParser cannot be created, so the
81+
* graph with the bootstrap method call cannot be created. Thus, at the moment,
82+
* allowing those bootstrap method to be executed at build time is the only way to
83+
* obtain correct lambda names.
84+
*/
85+
con = lookupConstant(cpi, opcode, true);
86+
}
87+
genLoadConstantHelper(con, opcode);
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)