From 9b120a51491d132aaa533aeee5513f9b7e9ef1f3 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 6 Feb 2023 12:04:59 +0100 Subject: [PATCH 1/3] Cache multiMethodAnalysisPolicy. --- .../src/com/oracle/svm/hosted/SVMHost.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index bac7be76cc7d..a98b6de62cee 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -163,6 +163,7 @@ public class SVMHost extends HostVM { private final ConcurrentMap analysisTrivialMethods = new ConcurrentHashMap<>(); private final Set finalFieldsInitializedOutsideOfConstructor = ConcurrentHashMap.newKeySet(); + private final MultiMethodAnalysisPolicy multiMethodAnalysisPolicy; public SVMHost(OptionValues options, ClassLoader classLoader, ClassInitializationSupport classInitializationSupport, UnsafeAutomaticSubstitutionProcessor automaticSubstitutions, Platform platform) { @@ -173,6 +174,13 @@ public SVMHost(OptionValues options, ClassLoader classLoader, ClassInitializatio this.automaticSubstitutions = automaticSubstitutions; this.platform = platform; this.linkAtBuildTimeSupport = LinkAtBuildTimeSupport.singleton(); + if (ImageSingletons.contains(MultiMethodAnalysisPolicy.class)) { + multiMethodAnalysisPolicy = ImageSingletons.lookup(MultiMethodAnalysisPolicy.class); + } else { + /* Install the default so no other policy can be installed. */ + ImageSingletons.add(HostVM.MultiMethodAnalysisPolicy.class, DEFAULT_MULTIMETHOD_ANALYSIS_POLICY); + multiMethodAnalysisPolicy = DEFAULT_MULTIMETHOD_ANALYSIS_POLICY; + } } private static Map> setupForbiddenTypes(OptionValues options) { @@ -847,11 +855,7 @@ public StructuredGraph.AllowAssumptions allowAssumptions(AnalysisMethod method) @Override public MultiMethodAnalysisPolicy getMultiMethodAnalysisPolicy() { - if (ImageSingletons.contains(MultiMethodAnalysisPolicy.class)) { - return ImageSingletons.lookup(MultiMethodAnalysisPolicy.class); - } else { - return super.getMultiMethodAnalysisPolicy(); - } + return multiMethodAnalysisPolicy; } @Override From 593c9eac79c9e81aeef2922b104fe10758d83dcc Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 6 Feb 2023 13:04:25 +0100 Subject: [PATCH 2/3] Cache points-to options. --- .../oracle/graal/pointsto/AnalysisPolicy.java | 21 +++++++++++++++ .../pointsto/flow/ArrayCopyTypeFlow.java | 3 +-- .../BytecodeSensitiveAnalysisPolicy.java | 27 +++++++++---------- .../AllocationContextSensitiveObject.java | 3 +-- .../ContextSensitiveAnalysisObject.java | 9 +++---- .../pointsto/typestate/TypeStateUtils.java | 5 ++-- 6 files changed, 42 insertions(+), 26 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisPolicy.java index 718901195ee9..52d94d4d8889 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisPolicy.java @@ -64,6 +64,10 @@ public abstract class AnalysisPolicy { protected final boolean relaxTypeFlowConstraints; protected final boolean removeSaturatedTypeFlows; protected final int typeFlowSaturationCutoff; + protected final boolean allocationSiteSensitiveHeap; + protected final int maxHeapContextDepth; + protected final boolean limitObjectArrayLength; + protected final int maxObjectSetSize; public AnalysisPolicy(OptionValues options) { this.options = options; @@ -72,6 +76,11 @@ public AnalysisPolicy(OptionValues options) { relaxTypeFlowConstraints = PointstoOptions.RelaxTypeFlowStateConstraints.getValue(options); removeSaturatedTypeFlows = PointstoOptions.RemoveSaturatedTypeFlows.getValue(options); typeFlowSaturationCutoff = PointstoOptions.TypeFlowSaturationCutoff.getValue(options); + allocationSiteSensitiveHeap = PointstoOptions.AllocationSiteSensitiveHeap.getValue(options); + maxHeapContextDepth = PointstoOptions.MaxHeapContextDepth.getValue(options); + limitObjectArrayLength = PointstoOptions.LimitObjectArrayLength.getValue(options); + maxObjectSetSize = PointstoOptions.MaxObjectSetSize.getValue(options); + } public abstract boolean isContextSensitiveAnalysis(); @@ -92,6 +101,18 @@ public int typeFlowSaturationCutoff() { return typeFlowSaturationCutoff; } + public boolean allocationSiteSensitiveHeap() { + return allocationSiteSensitiveHeap; + } + + public boolean limitObjectArrayLength() { + return limitObjectArrayLength; + } + + public int maxObjectSetSize() { + return maxObjectSetSize; + } + public abstract MethodTypeFlow createMethodTypeFlow(PointsToAnalysisMethod method); /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java index 52d655151ac9..c3243cb20d58 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java @@ -25,7 +25,6 @@ package com.oracle.graal.pointsto.flow; import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.context.object.AnalysisObject; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.typestate.TypeState; @@ -84,7 +83,7 @@ public void onObservedUpdate(PointsToAnalysis bb) { * applications. So we optimize it as much as possible: We compute the delta of added source * and destination types, to avoid re-processing the same elements over and over. */ - if (lastSrc == null || lastDst == null || PointstoOptions.AllocationSiteSensitiveHeap.getValue(bb.getOptions())) { + if (lastSrc == null || lastDst == null || bb.analysisPolicy().allocationSiteSensitiveHeap()) { /* * No previous state available, process the full type states. We also need to do that * when using the allocation site context, because TypeState.forSubtraction does not diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/bytecode/BytecodeSensitiveAnalysisPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/bytecode/BytecodeSensitiveAnalysisPolicy.java index 518eaf681a36..e303ad94dabb 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/bytecode/BytecodeSensitiveAnalysisPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/bytecode/BytecodeSensitiveAnalysisPolicy.java @@ -35,7 +35,6 @@ import com.oracle.graal.pointsto.AnalysisPolicy; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.AbstractSpecialInvokeTypeFlow; import com.oracle.graal.pointsto.flow.AbstractStaticInvokeTypeFlow; import com.oracle.graal.pointsto.flow.AbstractVirtualInvokeTypeFlow; @@ -79,7 +78,7 @@ import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.JavaConstant; -public class BytecodeSensitiveAnalysisPolicy extends AnalysisPolicy { +public final class BytecodeSensitiveAnalysisPolicy extends AnalysisPolicy { private final BytecodeAnalysisContextPolicy contextPolicy; @@ -143,7 +142,7 @@ public boolean isContextSensitiveAllocation(PointsToAnalysis bb, AnalysisType ty @Override public AnalysisObject createHeapObject(PointsToAnalysis bb, AnalysisType type, BytecodePosition allocationSite, AnalysisContext allocationContext) { - assert PointstoOptions.AllocationSiteSensitiveHeap.getValue(options); + assert allocationSiteSensitiveHeap; if (isContextSensitiveAllocation(bb, type, allocationContext)) { return new AllocationContextSensitiveObject(bb, type, allocationSite, allocationContext); } else { @@ -268,7 +267,7 @@ public void linkClonedObjects(PointsToAnalysis bb, TypeFlow inputFlow, CloneT @Override public FieldTypeStore createFieldTypeStore(PointsToAnalysis bb, AnalysisObject object, AnalysisField field, AnalysisUniverse universe) { - assert PointstoOptions.AllocationSiteSensitiveHeap.getValue(options); + assert allocationSiteSensitiveHeap; if (object.isContextInsensitiveObject()) { /* * Write flow is context-sensitive and read flow is context-insensitive. This split is @@ -296,7 +295,7 @@ public FieldTypeStore createFieldTypeStore(PointsToAnalysis bb, AnalysisObject o @Override public ArrayElementsTypeStore createArrayElementsTypeStore(AnalysisObject object, AnalysisUniverse universe) { - assert PointstoOptions.AllocationSiteSensitiveHeap.getValue(options); + assert allocationSiteSensitiveHeap; if (object.type().isArray()) { if (aliasArrayTypeFlows) { /* Alias all array type flows using the elements type flow model of Object type. */ @@ -345,7 +344,7 @@ public MethodFlowsGraphInfo staticRootMethodGraph(PointsToAnalysis bb, PointsToA @Override public AnalysisContext allocationContext(PointsToAnalysis bb, MethodFlowsGraph callerGraph) { - return contextPolicy.allocationContext((BytecodeAnalysisContext) ((MethodFlowsGraphClone) callerGraph).context(), PointstoOptions.MaxHeapContextDepth.getValue(bb.getOptions())); + return contextPolicy.allocationContext((BytecodeAnalysisContext) ((MethodFlowsGraphClone) callerGraph).context(), maxHeapContextDepth); } @Override @@ -595,7 +594,7 @@ public TypeState doUnion(PointsToAnalysis bb, MultiTypeState state1, MultiTypeSt return doUnion0(bb, s1, s2, resultCanBeNull); } - private static TypeState doUnion0(PointsToAnalysis bb, ContextSensitiveMultiTypeState s1, ContextSensitiveMultiTypeState s2, boolean resultCanBeNull) { + private TypeState doUnion0(PointsToAnalysis bb, ContextSensitiveMultiTypeState s1, ContextSensitiveMultiTypeState s2, boolean resultCanBeNull) { /* Speculate that s1 and s2 are distinct sets. */ @@ -631,8 +630,8 @@ private static TypeState doUnion0(PointsToAnalysis bb, ContextSensitiveMultiType return doUnion1(bb, s1, s2, resultCanBeNull); } - private static TypeState doUnion1(PointsToAnalysis bb, ContextSensitiveMultiTypeState s1, ContextSensitiveMultiTypeState s2, boolean resultCanBeNull) { - if (PointstoOptions.AllocationSiteSensitiveHeap.getValue(bb.getOptions())) { + private TypeState doUnion1(PointsToAnalysis bb, ContextSensitiveMultiTypeState s1, ContextSensitiveMultiTypeState s2, boolean resultCanBeNull) { + if (allocationSiteSensitiveHeap) { return allocationSensitiveSpeculativeUnion1(bb, s1, s2, resultCanBeNull); } else { return allocationInsensitiveSpeculativeUnion1(bb, s1, s2, resultCanBeNull); @@ -642,7 +641,7 @@ private static TypeState doUnion1(PointsToAnalysis bb, ContextSensitiveMultiType /** * Optimization that gives 1.5-3x in performance for the (typeflow) phase. */ - private static TypeState allocationInsensitiveSpeculativeUnion1(PointsToAnalysis bb, ContextSensitiveMultiTypeState s1, ContextSensitiveMultiTypeState s2, boolean resultCanBeNull) { + private TypeState allocationInsensitiveSpeculativeUnion1(PointsToAnalysis bb, ContextSensitiveMultiTypeState s1, ContextSensitiveMultiTypeState s2, boolean resultCanBeNull) { if (s1.bitSet().length() >= s2.bitSet().length()) { long[] bits1 = TypeStateUtils.extractBitSetField(s1.bitSet()); long[] bits2 = TypeStateUtils.extractBitSetField(s2.bitSet()); @@ -664,7 +663,7 @@ private static TypeState allocationInsensitiveSpeculativeUnion1(PointsToAnalysis return doUnion2(bb, s1, s2, resultCanBeNull, 0, 0); } - private static TypeState allocationSensitiveSpeculativeUnion1(PointsToAnalysis bb, ContextSensitiveMultiTypeState s1, ContextSensitiveMultiTypeState s2, boolean resultCanBeNull) { + private TypeState allocationSensitiveSpeculativeUnion1(PointsToAnalysis bb, ContextSensitiveMultiTypeState s1, ContextSensitiveMultiTypeState s2, boolean resultCanBeNull) { int idx1 = 0; int idx2 = 0; AnalysisPolicy analysisPolicy = bb.analysisPolicy(); @@ -701,7 +700,7 @@ private static TypeState allocationSensitiveSpeculativeUnion1(PointsToAnalysis b private static final ThreadLocal> doUnion2TL = new ThreadLocal<>(); private static final ThreadLocal> doUnion2ObjectsTL = new ThreadLocal<>(); - private static TypeState doUnion2(PointsToAnalysis bb, ContextSensitiveMultiTypeState s1, ContextSensitiveMultiTypeState s2, boolean resultCanBeNull, int startId1, int startId2) { + private TypeState doUnion2(PointsToAnalysis bb, ContextSensitiveMultiTypeState s1, ContextSensitiveMultiTypeState s2, boolean resultCanBeNull, int startId1, int startId2) { try (UnsafeArrayListClosable resultObjectsClosable = getTLArrayList(doUnion2TL, s1.objects.length + s2.objects.length)) { UnsafeArrayList resultObjects = resultObjectsClosable.list(); /* Add the beginning of the s1 list that we already walked above. */ @@ -757,7 +756,7 @@ private static TypeState doUnion2(PointsToAnalysis bb, ContextSensitiveMultiType * Check if the union of objects of a type in the overlapping section reached the * limit. The limit, bb.options().maxObjectSetSize(), has a minimum value of 1. */ - if (PointstoOptions.LimitObjectArrayLength.getValue(bb.getOptions()) && unionObjects.size() > PointstoOptions.MaxObjectSetSize.getValue(bb.getOptions())) { + if (limitObjectArrayLength && unionObjects.size() > maxObjectSetSize) { int idxStart = 0; int idxEnd = 0; while (idxEnd < unionObjects.size()) { @@ -772,7 +771,7 @@ private static TypeState doUnion2(PointsToAnalysis bb, ContextSensitiveMultiType * stride */ int size = idxEnd - idxStart; - if (size > PointstoOptions.MaxObjectSetSize.getValue(bb.getOptions())) { + if (size > maxObjectSetSize) { /* * Object count exceeds the limit. Mark the objects in the stride as * merged. diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/object/AllocationContextSensitiveObject.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/object/AllocationContextSensitiveObject.java index 4d27f6822e1b..dd305a612be5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/object/AllocationContextSensitiveObject.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/object/AllocationContextSensitiveObject.java @@ -25,7 +25,6 @@ package com.oracle.graal.pointsto.flow.context.object; import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.ArrayElementsTypeFlow; import com.oracle.graal.pointsto.flow.context.AnalysisContext; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -73,7 +72,7 @@ public void setAllocatorContext(AnalysisContext allocatorContext) { @Override public ArrayElementsTypeFlow getArrayElementsFlow(PointsToAnalysis bb, boolean isStore) { assert type.isArray(); - assert PointstoOptions.AllocationSiteSensitiveHeap.getValue(bb.getOptions()); + assert bb.analysisPolicy().allocationSiteSensitiveHeap(); if (!arrayElementsTypeStore.writeFlow().getState().canBeNull()) { /* diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/object/ContextSensitiveAnalysisObject.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/object/ContextSensitiveAnalysisObject.java index 73fa01c6b798..9cf95d96957a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/object/ContextSensitiveAnalysisObject.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/object/ContextSensitiveAnalysisObject.java @@ -29,7 +29,6 @@ import java.util.List; import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.ArrayElementsTypeFlow; import com.oracle.graal.pointsto.flow.FieldFilterTypeFlow; import com.oracle.graal.pointsto.flow.FieldTypeFlow; @@ -52,7 +51,7 @@ public class ContextSensitiveAnalysisObject extends AnalysisObject { public ContextSensitiveAnalysisObject(AnalysisUniverse universe, AnalysisType type, AnalysisObjectKind kind) { super(universe, type, kind); - assert PointstoOptions.AllocationSiteSensitiveHeap.getValue(universe.hostVM().options()); + assert universe.analysisPolicy().allocationSiteSensitiveHeap(); } /** The object has been in contact with an context insensitive object in an union operation. */ @@ -121,7 +120,7 @@ protected static void mergeInstanceFieldFlow(PointsToAnalysis bb, FieldTypeStore @Override public ArrayElementsTypeFlow getArrayElementsFlow(PointsToAnalysis bb, boolean isStore) { assert type.isArray(); - assert PointstoOptions.AllocationSiteSensitiveHeap.getValue(bb.getOptions()); + assert bb.analysisPolicy().allocationSiteSensitiveHeap(); return isStore ? arrayElementsTypeStore.writeFlow() : arrayElementsTypeStore.readFlow(); } @@ -129,7 +128,7 @@ public ArrayElementsTypeFlow getArrayElementsFlow(PointsToAnalysis bb, boolean i /** Returns the filter field flow corresponding to an unsafe accessed field. */ @Override public FieldFilterTypeFlow getInstanceFieldFilterFlow(PointsToAnalysis bb, TypeFlow objectFlow, BytecodePosition context, AnalysisField field) { - assert !Modifier.isStatic(field.getModifiers()) && field.isUnsafeAccessed() && PointstoOptions.AllocationSiteSensitiveHeap.getValue(bb.getOptions()); + assert !Modifier.isStatic(field.getModifiers()) && field.isUnsafeAccessed() && bb.analysisPolicy().allocationSiteSensitiveHeap(); FieldTypeStore fieldTypeStore = getInstanceFieldTypeStore(bb, objectFlow, context, field); @@ -146,7 +145,7 @@ public FieldFilterTypeFlow getInstanceFieldFilterFlow(PointsToAnalysis bb, TypeF @Override public FieldTypeFlow getInstanceFieldFlow(PointsToAnalysis bb, TypeFlow objectFlow, BytecodePosition context, AnalysisField field, boolean isStore) { - assert !Modifier.isStatic(field.getModifiers()) && PointstoOptions.AllocationSiteSensitiveHeap.getValue(bb.getOptions()); + assert !Modifier.isStatic(field.getModifiers()) && bb.analysisPolicy().allocationSiteSensitiveHeap(); FieldTypeStore fieldTypeStore = getInstanceFieldTypeStore(bb, objectFlow, context, field); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java index e97680f9854b..196ff0568ee0 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java @@ -34,7 +34,6 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.context.object.AnalysisObject; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.util.ReflectionUtil; @@ -226,7 +225,7 @@ private static AnalysisObject[] arraysUnion(PointsToAnalysis bb, AnalysisObject[ private static AnalysisObject[] checkUnionSize(PointsToAnalysis bb, AnalysisObject[] oa1, AnalysisObject[] oa2, AnalysisObject[] result) { assert result.length >= 2; - if (PointstoOptions.LimitObjectArrayLength.getValue(bb.getOptions()) && (result.length > PointstoOptions.MaxObjectSetSize.getValue(bb.getOptions()))) { + if (bb.analysisPolicy().limitObjectArrayLength() && (result.length > bb.analysisPolicy().maxObjectSetSize())) { AnalysisObject rObj = result[0].type().getContextInsensitiveAnalysisObject(); bb.analysisPolicy().noteMerge(bb, oa1); bb.analysisPolicy().noteMerge(bb, oa2); @@ -324,7 +323,7 @@ private static AnalysisObject[] arraysIntersection(PointsToAnalysis bb, Analysis * If the LimitObjectArrayLength is enabled then the result MUST be smaller than * MaxObjectSetSize. */ - assert !PointstoOptions.LimitObjectArrayLength.getValue(bb.getOptions()) || rList.size() <= PointstoOptions.MaxObjectSetSize.getValue(bb.getOptions()); + assert !bb.analysisPolicy().limitObjectArrayLength() || rList.size() <= bb.analysisPolicy().maxObjectSetSize(); if (rList.size() == 0) { return AnalysisObject.EMPTY_ARRAY; From 1b04e6be65eb9b49aa8d1b6148121fddd4432763 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 6 Feb 2023 12:11:55 +0100 Subject: [PATCH 3/3] Fix bitset preallocation size. --- .../pointsto/typestate/TypeStateUtils.java | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java index 196ff0568ee0..ed65fd52bcd7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java @@ -44,10 +44,12 @@ public class TypeStateUtils { private static final MethodHandle bitSetArrayAccess; + private static final MethodHandle wordInUseAccess; private static final MethodHandle trimToSizeAccess; static { try { bitSetArrayAccess = MethodHandles.lookup().unreflectGetter(ReflectionUtil.lookupField(BitSet.class, "words")); + wordInUseAccess = MethodHandles.lookup().unreflectGetter(ReflectionUtil.lookupField(BitSet.class, "wordsInUse")); trimToSizeAccess = MethodHandles.lookup().unreflect(ReflectionUtil.lookupMethod(BitSet.class, "trimToSize")); } catch (IllegalAccessException t) { throw JVMCIError.shouldNotReachHere(t); @@ -71,6 +73,28 @@ public static long[] extractBitSetField(BitSet bitSet) { } } + public static int extractWordsInUseField(BitSet bitSet) { + try { + return (int) wordInUseAccess.invokeExact(bitSet); + } catch (Throwable t) { + throw JVMCIError.shouldNotReachHere(t); + } + } + + public static boolean needsTrim(BitSet bitSet) { + int wordsInUse = extractWordsInUseField(bitSet); + long[] words = extractBitSetField(bitSet); + return wordsInUse != words.length; + } + + public static void trimBitSetToSize(BitSet bs) { + try { + trimToSizeAccess.invokeExact(bs); + } catch (Throwable t) { + throw JVMCIError.shouldNotReachHere(t); + } + } + /** Return true if {@code first} is a superset of {@code second}. */ public static boolean isSuperset(BitSet first, BitSet second) { if (first.length() >= second.length()) { @@ -91,15 +115,6 @@ public static boolean isSuperset(BitSet first, BitSet second) { return false; } - public static void trimBitSetToSize(BitSet bs) { - try { - trimToSizeAccess.invokeExact(bs); - } catch (Throwable t) { - throw JVMCIError.shouldNotReachHere(t); - } - - } - public static AnalysisObject[] concat(AnalysisObject[] oa1, AnalysisObject[] oa2) { int resultSize = oa1.length + oa2.length; @@ -421,7 +436,7 @@ public static BitSet set(BitSet bs1, int bitIndex) { /* Check if the new bit index exceeds the capacity of bs1. */ if (bitIndex > highestSetIndex) { /* Preallocate the bit set to represent bitIndex without expansion. */ - bsr = new BitSet(bitIndex); + bsr = new BitSet(bitIndex + 1); /* First add in the original bits, which will System.arraycopy() bs1 bits into bsr. */ bsr.or(bs1); /* ... then set the new index. */ @@ -432,16 +447,18 @@ public static BitSet set(BitSet bs1, int bitIndex) { bsr = (BitSet) bs1.clone(); bsr.set(bitIndex); } + assert !needsTrim(bsr); return bsr; } /** Create a new bit set with the bits of the inputs IDs set. */ public static BitSet newBitSet(int index1, int index2) { /* Preallocate the result bit set to represent index1 and index2 without any expansion. */ - BitSet typesBitSet = new BitSet(Math.max(index1, index2)); - typesBitSet.set(index1); - typesBitSet.set(index2); - return typesBitSet; + BitSet bs = new BitSet(Math.max(index1, index2) + 1); + bs.set(index1); + bs.set(index2); + assert !needsTrim(bs); + return bs; } public static boolean closeToAllInstantiated(BigBang bb, TypeState state) {