Skip to content

Commit

Permalink
[GR-43361] [GR-50205] Whole-Program Sparse Conditional Constant Propa…
Browse files Browse the repository at this point in the history
…gation

PullRequest: graal/18609
  • Loading branch information
d-kozak committed Oct 5, 2024
2 parents ee62612 + 9a73d5d commit c9658c9
Show file tree
Hide file tree
Showing 52 changed files with 2,295 additions and 321 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,15 @@ public AnalysisObjectScanningObserver(BigBang bb) {

@Override
public boolean forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue, ScanReason reason) {
if (!field.isWritten()) {
return field.registerAsWritten(reason);
}
var changed = false;
if (fieldValue.isNonNull()) {
FieldTypeFlow fieldTypeFlow = getFieldTypeFlow(field, receiver);
return fieldTypeFlow.addState(getAnalysis(), TypeState.anyPrimitiveState());
changed = fieldTypeFlow.addState(getAnalysis(), TypeState.anyPrimitiveState());
}
return false;
if (!field.isWritten()) {
changed |= field.registerAsWritten(reason);
}
return changed;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ public abstract class PointsToAnalysis extends AbstractAnalysisEngine {
* immediately represented as {@link com.oracle.graal.pointsto.flow.AnyPrimitiveSourceTypeFlow}.
*/
private final boolean trackPrimitiveValues;
private final AnalysisType longType;
private final AnalysisType voidType;
private final boolean usePredicates;
private AnyPrimitiveSourceTypeFlow anyPrimitiveSourceTypeFlow;

protected final boolean trackTypeFlowInputs;
Expand All @@ -121,10 +124,15 @@ public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM
ClassInclusionPolicy classInclusionPolicy) {
super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection, classInclusionPolicy);
this.typeFlowTimer = timerCollection.createTimer("(typeflow)");
this.trackPrimitiveValues = PointstoOptions.TrackPrimitiveValues.getValue(options);
this.anyPrimitiveSourceTypeFlow = new AnyPrimitiveSourceTypeFlow(null, null);

this.objectType = metaAccess.lookupJavaType(Object.class);
this.longType = metaAccess.lookupJavaType(long.class);
this.voidType = metaAccess.lookupJavaType(void.class);

this.trackPrimitiveValues = PointstoOptions.TrackPrimitiveValues.getValue(options);
this.usePredicates = PointstoOptions.UsePredicates.getValue(options);
this.anyPrimitiveSourceTypeFlow = new AnyPrimitiveSourceTypeFlow(null, longType);
this.anyPrimitiveSourceTypeFlow.enableFlow(null);
/*
* Make sure the all-instantiated type flow is created early. We do not have any
* instantiated types yet, so the state is empty at first.
Expand Down Expand Up @@ -270,6 +278,14 @@ public AnalysisType getObjectType() {
return universe.objectType();
}

public AnalysisType getLongType() {
return longType;
}

public AnalysisType getVoidType() {
return voidType;
}

public AnalysisType getObjectArrayType() {
return metaAccess.lookupJavaType(Object[].class);
}
Expand Down Expand Up @@ -538,6 +554,10 @@ public boolean trackPrimitiveValues() {
return trackPrimitiveValues;
}

public boolean usePredicates() {
return usePredicates;
}

public interface TypeFlowRunnable extends DebugContextRunnable {
TypeFlow<?> getTypeFlow();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public class PointstoOptions {
@Option(help = "Track primitive values using the infrastructure of points-to analysis.")//
public static final OptionKey<Boolean> TrackPrimitiveValues = new OptionKey<>(false);

@Option(help = "Use predicates in points-to analysis.")//
public static final OptionKey<Boolean> UsePredicates = new OptionKey<>(false);

@Option(help = "Use experimental Reachability Analysis instead of points-to.")//
public static final OptionKey<Boolean> UseExperimentalReachabilityAnalysis = new OptionKey<>(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ protected AbstractSpecialInvokeTypeFlow(PointsToAnalysis bb, MethodFlowsGraph me
super(bb, methodFlows, original);
}

@Override
protected void onFlowEnabled(PointsToAnalysis bb) {
bb.postTask(() -> onObservedUpdate(bb));
}

@Override
public boolean addState(PointsToAnalysis bb, TypeState add, boolean postFlow) {
throw AnalysisError.shouldNotReachHere("The SpecialInvokeTypeFlow should not be updated directly.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,6 @@ protected AbstractStaticInvokeTypeFlow(PointsToAnalysis bb, MethodFlowsGraph met
super(bb, methodFlows, original);
}

@Override
public void initFlow(PointsToAnalysis bb) {
/* Trigger the update for static invokes, there is no receiver to trigger it. */
bb.postFlow(this);
}

@Override
public boolean needsInitialization() {
return true;
}

@Override
public String toString() {
return "StaticInvoke<" + targetMethod.format("%h.%n") + ">" + ":" + getState();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ public final boolean isDirectInvoke() {
return false;
}

@Override
protected void onFlowEnabled(PointsToAnalysis bb) {
bb.postTask(() -> onObservedUpdate(bb));
}

@Override
public boolean addState(PointsToAnalysis bb, TypeState add, boolean postFlow) {
throw AnalysisError.shouldNotReachHere("The VirtualInvokeTypeFlow should not be updated directly.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
* of the all assignable types. This flow is used for uses that need to be notified when a sub-type
* of a specific type is marked as instantiated, e.g., a saturated field access type flow needs to
* be notified when a sub-type of its declared type is marked as instantiated.
*
* <p>
* Note this flow should only be instantiated within AnalysisType. When needed, this flow should be
* retrieved via calling {@link AnalysisType#getTypeFlow}.
*/
public final class AllInstantiatedTypeFlow extends TypeFlow<AnalysisType> {
public final class AllInstantiatedTypeFlow extends TypeFlow<AnalysisType> implements GlobalFlow {

public AllInstantiatedTypeFlow(AnalysisType declaredType, boolean canBeNull) {
super(declaredType, declaredType, canBeNull);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.graal.pointsto.flow;

import com.oracle.graal.pointsto.typestate.TypeState;

import jdk.vm.ci.code.BytecodePosition;

/**
* Always-enabled global flow that is used as a predicate before any other suitable flow is
* available.
*/
public class AlwaysEnabledPredicateFlow extends TypeFlow<BytecodePosition> implements GlobalFlow {

public AlwaysEnabledPredicateFlow() {
/* We use any primitive state here just to make sure the state is always non-empty. */
super(TypeState.anyPrimitiveState());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,47 @@
*/
package com.oracle.graal.pointsto.flow;

import com.oracle.graal.pointsto.PointsToAnalysis;
import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.graal.pointsto.typestate.TypeState;

import jdk.vm.ci.code.BytecodePosition;

/**
* Produces AnyPrimitive state that leads to immediate saturation of all uses. Used to represent any
* operation that is not modeled by the analysis.
* operation on primitives that is not explicitly modeled by the analysis.
* </p>
* This flow can be either global (source == null) or local (source != null).
*/
public final class AnyPrimitiveSourceTypeFlow extends TypeFlow<BytecodePosition> implements PrimitiveFlow {

public AnyPrimitiveSourceTypeFlow(BytecodePosition source, AnalysisType type) {
super(source, type, TypeState.anyPrimitiveState());
}

private AnyPrimitiveSourceTypeFlow(MethodFlowsGraph methodFlows, AnyPrimitiveSourceTypeFlow original) {
super(original, methodFlows, TypeState.anyPrimitiveState());
}

@Override
public TypeFlow<BytecodePosition> copy(PointsToAnalysis bb, MethodFlowsGraph methodFlows) {
assert isLocal() : "Global flow should never be cloned: " + this;
return new AnyPrimitiveSourceTypeFlow(methodFlows, this);
}

private boolean isLocal() {
return source != null;
}

@Override
public boolean canSaturate() {
/*
* AnyPrimitiveSourceTypeFlow can be used as a global flow that should always propagate
* values. The global version can be identified be having source == null, and it should
* never saturate.
*
* The local versions of this flow have a concrete bytecode position and can saturate.
*/
return isLocal();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
/**
* This class is used to model the elements type flow for array objects.
*/
public class ArrayElementsTypeFlow extends TypeFlow<AnalysisType> {
public class ArrayElementsTypeFlow extends TypeFlow<AnalysisType> implements GlobalFlow {

/** The array object. */
private final AnalysisObject object;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.graal.pointsto.flow;

import com.oracle.graal.pointsto.PointsToAnalysis;
import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.graal.pointsto.typestate.TypeState;
import com.oracle.graal.pointsto.util.AnalysisError;

import jdk.vm.ci.code.BytecodePosition;

/**
* This flow represents a boolean check, i.e. a null check, type check, or primitive check that
* converts its inputs into boolean values. Instances of this class are used as conditions for
* {@link ConditionalFlow}.
*/
public abstract class BooleanCheckTypeFlow extends TypeFlow<BytecodePosition> {

public BooleanCheckTypeFlow(BytecodePosition position, AnalysisType declaredType) {
super(position, declaredType);
}

protected BooleanCheckTypeFlow(BooleanCheckTypeFlow original, MethodFlowsGraph methodFlows) {
super(original, methodFlows);
}

protected static TypeState convertToBoolean(boolean canBeTrue, boolean canBeFalse) {
if (canBeTrue && canBeFalse) {
return TypeState.anyPrimitiveState();
} else if (canBeTrue) {
return TypeState.forBoolean(true);
} else if (canBeFalse) {
return TypeState.forBoolean(false);
}
return TypeState.forEmpty();
}

protected static TypeState convertToBoolean(TypeState trueState, TypeState falseState) {
return convertToBoolean(trueState.isNotEmpty(), falseState.isNotEmpty());
}

@Override
public void addPredicated(PointsToAnalysis bb, TypeFlow<?> predicatedFlow) {
AnalysisError.shouldNotReachHere(getClass() + " shouldn't act as a predicate.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.graal.pointsto.flow;

import com.oracle.graal.pointsto.PointsToAnalysis;
import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.graal.pointsto.typestate.TypeState;

import jdk.vm.ci.code.BytecodePosition;

/**
* This flow represents a type check used by {@link ConditionalFlow}.
*/
public class BooleanInstanceOfCheckTypeFlow extends BooleanCheckTypeFlow {
private final AnalysisType checkedType;
private final boolean isExact;
private final boolean includeNull;

public BooleanInstanceOfCheckTypeFlow(BytecodePosition position, AnalysisType checkedType, boolean isExact, boolean includeNull, AnalysisType longType) {
super(position, longType);
this.checkedType = checkedType;
this.isExact = isExact;
this.includeNull = includeNull;
}

private BooleanInstanceOfCheckTypeFlow(MethodFlowsGraph methodFlows, BooleanInstanceOfCheckTypeFlow original) {
super(original, methodFlows);
this.checkedType = original.checkedType;
this.isExact = original.isExact;
this.includeNull = original.includeNull;
}

@Override
public TypeFlow<BytecodePosition> copy(PointsToAnalysis bb, MethodFlowsGraph methodFlows) {
return new BooleanInstanceOfCheckTypeFlow(methodFlows, this);
}

@Override
public TypeState filter(PointsToAnalysis bb, TypeState update) {
TypeState canBeTrue;
TypeState canBeFalse;
if (isExact) {
canBeTrue = TypeState.forIntersection(bb, update, TypeState.forExactType(bb, checkedType, includeNull));
canBeFalse = TypeState.forSubtraction(bb, update, TypeState.forExactType(bb, checkedType, includeNull));
} else {
canBeTrue = TypeState.forIntersection(bb, update, checkedType.getAssignableTypes(includeNull));
canBeFalse = TypeState.forSubtraction(bb, update, checkedType.getAssignableTypes(includeNull));
}
return convertToBoolean(canBeTrue, canBeFalse);
}
}
Loading

0 comments on commit c9658c9

Please sign in to comment.