From a45aa19c1c4300ef2091cde23dfe432e957b67dc Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Thu, 8 Dec 2022 16:09:46 -0800 Subject: [PATCH] Do more constant folding before analysis --- .../StandardGraphBuilderPlugins.java | 28 +++++++ .../pointsto/phases/InlineBeforeAnalysis.java | 2 +- .../phases/InlineBeforeAnalysisPolicy.java | 11 ++- .../svm/core/jdk/JavaLangSubstitutions.java | 73 ++++++++++++++++++- .../ameta/AnalysisConstantFieldProvider.java | 7 +- .../InlineBeforeAnalysisPolicyImpl.java | 7 +- 6 files changed, 120 insertions(+), 8 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java index 977e043c529c..3cfcfb40ca2f 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java @@ -702,6 +702,34 @@ private static void registerUnsafePlugins0(Registration r, boolean sunMiscUnsafe r.register(new CacheWritebackPlugin(true, "writebackPreSync0", Receiver.class)); r.register(new CacheWritebackPlugin(false, "writebackPostSync0", Receiver.class)); } + + r.register(new InvocationPlugin("arrayBaseOffset", Receiver.class, Class.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode arrayClass) { + return handleArrayBaseOffsetOrIndexScale(b, unsafe, arrayClass, true); + } + }); + r.register(new InvocationPlugin("arrayIndexScale", Receiver.class, Class.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode arrayClass) { + return handleArrayBaseOffsetOrIndexScale(b, unsafe, arrayClass, false); + } + }); + } + + private static boolean handleArrayBaseOffsetOrIndexScale(GraphBuilderContext b, Receiver unsafe, ValueNode arrayClass, boolean arrayBaseOffset) { + var arrayClassConstant = arrayClass.asJavaConstant(); + if (arrayClassConstant != null && arrayClassConstant.isNonNull()) { + var arrayType = b.getConstantReflection().asJavaType(arrayClassConstant); + if (arrayType != null && arrayType.isArray()) { + unsafe.get(); + var elementKind = b.getMetaAccessExtensionProvider().getStorageKind(arrayType.getComponentType()); + int result = arrayBaseOffset ? b.getMetaAccess().getArrayBaseOffset(elementKind) : b.getMetaAccess().getArrayIndexScale(elementKind); + b.addPush(JavaKind.Int, ConstantNode.forInt(result)); + return true; + } + } + return false; } private static void registerIntegerLongPlugins(InvocationPlugins plugins, JavaKind kind) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java index 5224f602b273..5e34e845823f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java @@ -158,7 +158,7 @@ class InlineBeforeAnalysisMethodScope extends PEMethodScope { super(AnalysisParsedGraph.HOST_ARCHITECTURE, graph, bb.getProviders(), null, bb.getProviders().getGraphBuilderPlugins().getInvocationPlugins(), new InlineInvokePlugin[]{new InlineBeforeAnalysisInlineInvokePlugin(policy)}, - null, null, null, null, + null, policy.nodePlugins, null, null, new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), true, false); this.bb = bb; this.policy = policy; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java index ef75af619b2a..df5aed5cb37e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java @@ -24,11 +24,13 @@ */ package com.oracle.graal.pointsto.phases; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; + +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -44,7 +46,7 @@ @SuppressWarnings("unused") public class InlineBeforeAnalysisPolicy { - public static final InlineBeforeAnalysisPolicy NO_INLINING = new InlineBeforeAnalysisPolicy<>(); + public static final InlineBeforeAnalysisPolicy NO_INLINING = new InlineBeforeAnalysisPolicy<>(new NodePlugin[0]); /** * A place for policy implementations to store per-callee information like the number of nodes @@ -53,7 +55,10 @@ public class InlineBeforeAnalysisPolicy Character.MAX_LOW_SURROGATE)) { + return StringHelper.simpleSplit(SubstrateUtil.cast(this, String.class), limit, ch); + } + return Pattern.compile(regex).split(SubstrateUtil.cast(this, String.class), limit); + } +} + +final class StringHelper { + static String[] simpleSplit(String that, int limit, char ch) { + int off = 0; + int next = 0; + boolean limited = limit > 0; + ArrayList list = new ArrayList<>(); + while ((next = that.indexOf(ch, off)) != -1) { + if (!limited || list.size() < limit - 1) { + list.add(that.substring(off, next)); + off = next + 1; + } else { // last one + // assert (list.size() == limit - 1); + int last = that.length(); + list.add(that.substring(off, last)); + off = last; + break; + } + } + // If no match was found, return this + if (off == 0) { + return new String[]{that}; + } + // Add remaining segment + if (!limited || list.size() < limit) { + list.add(that.substring(off, that.length())); + } + // Construct result + int resultSize = list.size(); + if (limit == 0) { + while (resultSize > 0 && list.get(resultSize - 1).isEmpty()) { + resultSize--; + } + } + String[] result = new String[resultSize]; + return list.subList(0, resultSize).toArray(result); + } } @TargetClass(className = "java.lang.StringLatin1") diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java index 0e932aa27df8..b9f36cbb6cd1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java @@ -63,7 +63,12 @@ public T readConstantField(ResolvedJavaField field, ConstantFieldTool ana if (readableField.allowConstantFolding() && readableField.isValueAvailable()) { JavaConstant fieldValue = readableField.readValue(metaAccess, universe.toHosted(analysisTool.getReceiver())); if (fieldValue != null) { - foldedValue = analysisTool.foldConstant(constantReflection.interceptValue(metaAccess, f, universe.lookup(fieldValue))); + JavaConstant interceptedValue = constantReflection.interceptValue(metaAccess, f, universe.lookup(fieldValue)); + if (isStableField(field, analysisTool) && isStableFieldValueConstant(field, interceptedValue, analysisTool)) { + foldedValue = foldStableArray(interceptedValue, field, analysisTool); + } else { + foldedValue = analysisTool.foldConstant(interceptedValue); + } } } } else { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java index 7e9ae670188c..9289b49e05a2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java @@ -42,6 +42,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.extended.ValueAnchorNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; import org.graalvm.compiler.nodes.java.AbstractNewObjectNode; import org.graalvm.compiler.nodes.java.NewArrayNode; import org.graalvm.compiler.nodes.spi.ValueProxy; @@ -50,18 +51,19 @@ import org.graalvm.compiler.nodes.virtual.VirtualArrayNode; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.compiler.options.Option; +import org.graalvm.nativeimage.AnnotationAccess; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; -import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.SVMHost; import jdk.vm.ci.meta.ResolvedJavaMethod; -import org.graalvm.nativeimage.AnnotationAccess; /** * The defaults for node limits are very conservative. Only small methods should be inlined. The @@ -114,6 +116,7 @@ public String toString() { } public InlineBeforeAnalysisPolicyImpl(SVMHost hostVM) { + super(new NodePlugin[]{new ConstantFoldLoadFieldPlugin(ParsingReason.PointsToAnalysis)}); this.hostVM = hostVM; }