Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void initializeMetaData(AnalysisType type) {
public void onTypeInitialized(AnalysisType type) {
AnalysisMethod clinitMethod = type.getClassInitializer();
if (clinitMethod != null && !addedClinits.contains(clinitMethod)) {
addRootMethod(clinitMethod, true).registerAsImplementationInvoked();
addRootMethod(clinitMethod, true).registerAsImplementationInvoked(type);
addedClinits.add(clinitMethod);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,11 @@ public void registerAsUnsafeAccessed(AnalysisField aField, UnsafePartitionKind p
}

public void registerAsInvoked(Executable method, boolean invokeSpecial) {
registerAsInvoked(getMetaAccess().lookupJavaMethod(method), invokeSpecial);
registerAsInvoked(getMetaAccess().lookupJavaMethod(method), invokeSpecial, "registered from standalone feature");
}

public void registerAsInvoked(AnalysisMethod aMethod, boolean invokeSpecial) {
bb.addRootMethod(aMethod, invokeSpecial).registerAsImplementationInvoked();
public void registerAsInvoked(AnalysisMethod aMethod, boolean invokeSpecial, Object reason) {
bb.addRootMethod(aMethod, invokeSpecial).registerAsImplementationInvoked(reason);
}

public void registerUnsafeFieldsRecomputed(Class<?> clazz) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecia
*/
postTask(() -> {
pointsToMethod.registerAsDirectRootMethod();
pointsToMethod.registerAsImplementationInvoked(null);
pointsToMethod.registerAsImplementationInvoked("root method");
MethodFlowsGraph methodFlowsGraph = analysisPolicy.staticRootMethodGraph(this, pointsToMethod);
for (int idx = 0; idx < paramCount; idx++) {
AnalysisType declaredParamType = (AnalysisType) signature.getParameterType(idx, declaringClass);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ public CallSiteSensitiveMethodTypeFlow(OptionValues options, PointsToAnalysisMet
/**
* Add the context, if not already added, and return the method flows clone from that context.
*/
public MethodFlowsGraph addContext(PointsToAnalysis bb, AnalysisContext calleeContext) {
return addContext(bb, calleeContext, null);
}

public MethodFlowsGraph addContext(PointsToAnalysis bb, AnalysisContext calleeContext, InvokeTypeFlow reason) {

/* Ensure that the method is parsed before attempting to clone it. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private synchronized void createFlowsGraph(PointsToAnalysis bb, InvokeTypeFlow r
parsingReason = reason;
try {
MethodTypeFlowBuilder builder = bb.createMethodTypeFlowBuilder(bb, method);
builder.apply();
builder.apply(PointsToAnalysisMethod.unwrapInvokeReason(parsingReason));

returnedParameterIndex = computeReturnedParameterIndex(builder.graph);
bb.numParsedGraphs.incrementAndGet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,10 @@ public MethodTypeFlowBuilder(PointsToAnalysis bb, StructuredGraph graph) {
}

@SuppressWarnings("try")
private boolean parse() {
private boolean parse(Object reason) {
AnalysisParsedGraph analysisParsedGraph = method.ensureGraphParsed(bb);
if (analysisParsedGraph.isIntrinsic()) {
method.registerAsIntrinsicMethod();
method.registerAsIntrinsicMethod(reason);
}

if (analysisParsedGraph.getEncodedGraph() == null) {
Expand Down Expand Up @@ -394,7 +394,7 @@ private static void registerForeignCall(PointsToAnalysis bb, ForeignCallDescript
targetMethod.ifPresent(analysisMethod -> bb.addRootMethod(analysisMethod, true));
}

protected void apply() {
protected void apply(Object reason) {
// assert method.getAnnotation(Fold.class) == null : method;
if (AnnotationAccess.isAnnotationPresent(method, NodeIntrinsic.class)) {
graph.getDebug().log("apply MethodTypeFlow on node intrinsic %s", method);
Expand All @@ -417,7 +417,7 @@ protected void apply() {
return;
}

if (!parse()) {
if (!parse(reason)) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ public AbstractStaticInvokeTypeFlow createStaticInvokeTypeFlow(BytecodePosition

@Override
public MethodFlowsGraph staticRootMethodGraph(PointsToAnalysis bb, PointsToAnalysisMethod pointsToMethod) {
return ((CallSiteSensitiveMethodTypeFlow) pointsToMethod.getTypeFlow()).addContext(bb, contextPolicy.emptyContext());
return ((CallSiteSensitiveMethodTypeFlow) pointsToMethod.getTypeFlow()).addContext(bb, contextPolicy.emptyContext(), null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -80,17 +81,17 @@ public abstract class AnalysisMethod extends AnalysisElement implements WrappedJ
private static final AtomicIntegerFieldUpdater<AnalysisMethod> isDirectRootMethodUpdater = AtomicIntegerFieldUpdater
.newUpdater(AnalysisMethod.class, "isDirectRootMethod");

private static final AtomicIntegerFieldUpdater<AnalysisMethod> isInvokedUpdater = AtomicIntegerFieldUpdater
.newUpdater(AnalysisMethod.class, "isInvoked");
private static final AtomicReferenceFieldUpdater<AnalysisMethod, Object> isInvokedUpdater = AtomicReferenceFieldUpdater
.newUpdater(AnalysisMethod.class, Object.class, "isInvoked");

private static final AtomicIntegerFieldUpdater<AnalysisMethod> isImplementationInvokedUpdater = AtomicIntegerFieldUpdater
.newUpdater(AnalysisMethod.class, "isImplementationInvoked");
private static final AtomicReferenceFieldUpdater<AnalysisMethod, Object> isImplementationInvokedUpdater = AtomicReferenceFieldUpdater
.newUpdater(AnalysisMethod.class, Object.class, "isImplementationInvoked");

private static final AtomicIntegerFieldUpdater<AnalysisMethod> isIntrinsicMethodUpdater = AtomicIntegerFieldUpdater
.newUpdater(AnalysisMethod.class, "isIntrinsicMethod");
private static final AtomicReferenceFieldUpdater<AnalysisMethod, Object> isIntrinsicMethodUpdater = AtomicReferenceFieldUpdater
.newUpdater(AnalysisMethod.class, Object.class, "isIntrinsicMethod");

private static final AtomicIntegerFieldUpdater<AnalysisMethod> isInlinedUpdater = AtomicIntegerFieldUpdater
.newUpdater(AnalysisMethod.class, "isInlined");
private static final AtomicReferenceFieldUpdater<AnalysisMethod, Object> isInlinedUpdater = AtomicReferenceFieldUpdater
.newUpdater(AnalysisMethod.class, Object.class, "isInlined");

public final ResolvedJavaMethod wrapped;

Expand All @@ -108,10 +109,10 @@ public abstract class AnalysisMethod extends AnalysisElement implements WrappedJ
/** Direct (special or static) invoked method registered as root. */
@SuppressWarnings("unused") private volatile int isDirectRootMethod;
private Object entryPointData;
@SuppressWarnings("unused") private volatile int isInvoked;
@SuppressWarnings("unused") private volatile int isImplementationInvoked;
@SuppressWarnings("unused") private volatile int isIntrinsicMethod;
@SuppressWarnings("unused") private volatile int isInlined;
@SuppressWarnings("unused") private volatile Object isInvoked;
@SuppressWarnings("unused") private volatile Object isImplementationInvoked;
@SuppressWarnings("unused") private volatile Object isIntrinsicMethod;
@SuppressWarnings("unused") private volatile Object isInlined;

private final AtomicReference<Object> parsedGraphCacheState = new AtomicReference<>(GRAPH_CACHE_UNPARSED);
private static final Object GRAPH_CACHE_UNPARSED = "unparsed";
Expand Down Expand Up @@ -260,8 +261,9 @@ public int getId() {
* builder plugin}. Such a method is treated similar to an invoked method. For example, method
* resolution must be able to find the method (otherwise the intrinsification would not work).
*/
public void registerAsIntrinsicMethod() {
AtomicUtils.atomicMarkAndRun(this, isIntrinsicMethodUpdater, this::onReachable);
public void registerAsIntrinsicMethod(Object reason) {
assert isValidReason(reason) : "Registering a method as intrinsic needs to provide a valid reason, found: " + reason;
AtomicUtils.atomicSetAndRun(this, reason, isIntrinsicMethodUpdater, this::onReachable);
}

public void registerAsEntryPoint(Object newEntryPointData) {
Expand All @@ -274,11 +276,13 @@ public void registerAsEntryPoint(Object newEntryPointData) {
startTrackInvocations();
}

public boolean registerAsInvoked() {
return AtomicUtils.atomicMark(this, isInvokedUpdater);
public boolean registerAsInvoked(Object reason) {
assert isValidReason(reason) : "Registering a method as invoked needs to provide a valid reason, found: " + reason;
return AtomicUtils.atomicSet(this, reason, isInvokedUpdater);
}

public boolean registerAsImplementationInvoked() {
public boolean registerAsImplementationInvoked(Object reason) {
assert isValidReason(reason) : "Registering a method as implementation invoked needs to provide a valid reason, found: " + reason;
assert !Modifier.isAbstract(getModifiers());

/*
Expand All @@ -290,11 +294,12 @@ public boolean registerAsImplementationInvoked() {
* return before the class gets marked as reachable.
*/
getDeclaringClass().registerAsReachable("declared method " + this.format("%H.%n(%p)") + " is registered as implementation invoked");
return AtomicUtils.atomicMarkAndRun(this, isImplementationInvokedUpdater, this::onReachable);
return AtomicUtils.atomicSetAndRun(this, reason, isImplementationInvokedUpdater, this::onReachable);
}

public void registerAsInlined() {
AtomicUtils.atomicMarkAndRun(this, isInlinedUpdater, this::onReachable);
public void registerAsInlined(Object reason) {
assert isValidReason(reason) : "Registering a method as inlined needs to provide a valid reason, found: " + reason;
AtomicUtils.atomicSetAndRun(this, reason, isInlinedUpdater, this::onReachable);
}

/** Get the set of all callers for this method, as inferred by the static analysis. */
Expand Down Expand Up @@ -324,7 +329,7 @@ public boolean isIntrinsicMethod() {
* as invoked also makes the declaring class reachable.
*
* Class is always marked as reachable regardless of the success of the atomic mark, same reason
* as in {@link AnalysisMethod#registerAsImplementationInvoked()}.
* as in {@link AnalysisMethod#registerAsImplementationInvoked(Object)}.
*/
public boolean registerAsVirtualRootMethod() {
getDeclaringClass().registerAsReachable("declared method " + this.format("%H.%n(%p)") + " is registered as virtual root");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;

import com.oracle.graal.pointsto.PointsToAnalysis;
Expand All @@ -48,8 +48,8 @@
public class PointsToAnalysisMethod extends AnalysisMethod {
private MethodTypeFlow typeFlow;

private ConcurrentMap<InvokeTypeFlow, Object> invokedBy;
private ConcurrentMap<InvokeTypeFlow, Object> implementationInvokedBy;
private Set<InvokeTypeFlow> invokedBy;
private Set<InvokeTypeFlow> implementationInvokedBy;
/**
* Unique, per method, context insensitive invoke. The context insensitive invoke uses the
* receiver type of the method, i.e., its declaring-class. Therefore, this invoke will link with
Expand All @@ -66,35 +66,55 @@ public class PointsToAnalysisMethod extends AnalysisMethod {
@Override
public void startTrackInvocations() {
if (invokedBy == null) {
invokedBy = new ConcurrentHashMap<>();
invokedBy = ConcurrentHashMap.newKeySet();
}
if (implementationInvokedBy == null) {
implementationInvokedBy = new ConcurrentHashMap<>();
implementationInvokedBy = ConcurrentHashMap.newKeySet();
}
}

public MethodTypeFlow getTypeFlow() {
return typeFlow;
}

public boolean registerAsInvoked(InvokeTypeFlow invoke) {
if (invokedBy != null && invoke != null) {
invokedBy.put(invoke, Boolean.TRUE);
@Override
public boolean registerAsInvoked(Object reason) {
assert reason instanceof InvokeTypeFlow || reason instanceof String;
if (invokedBy != null && reason instanceof InvokeTypeFlow) {
invokedBy.add((InvokeTypeFlow) reason);
}
return super.registerAsInvoked(unwrapInvokeReason(reason));
}

@Override
public boolean registerAsImplementationInvoked(Object reason) {
assert reason instanceof InvokeTypeFlow || reason instanceof String;
if (implementationInvokedBy != null && reason instanceof InvokeTypeFlow) {
implementationInvokedBy.add((InvokeTypeFlow) reason);
}
return super.registerAsInvoked();
return super.registerAsImplementationInvoked(unwrapInvokeReason(reason));
}

public boolean registerAsImplementationInvoked(InvokeTypeFlow invoke) {
if (implementationInvokedBy != null && invoke != null) {
implementationInvokedBy.put(invoke, Boolean.TRUE);
/**
* In general the reason for a method invocation is an {@link InvokeTypeFlow}. Special and
* virtual root methods have the corresponding context-insensitive invoke reason set. Static
* root method doesn't have any reason set.
*/
public static Object unwrapInvokeReason(Object reason) {
if (reason == null) {
return "static root method";
}
if (reason instanceof InvokeTypeFlow) {
BytecodePosition source = ((InvokeTypeFlow) reason).getSource();
return source != null ? source : "root method";
}
return super.registerAsImplementationInvoked();
return reason;
}

@Override
public List<BytecodePosition> getInvokeLocations() {
List<BytecodePosition> locations = new ArrayList<>();
for (InvokeTypeFlow invoke : implementationInvokedBy.keySet()) {
for (InvokeTypeFlow invoke : implementationInvokedBy) {
if (InvokeTypeFlow.isContextInsensitiveVirtualInvoke(invoke)) {
locations.addAll(((AbstractVirtualInvokeTypeFlow) invoke).getInvokeLocations());
} else if (invoke.getSource() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import java.util.Deque;
import java.util.concurrent.ConcurrentHashMap;

import com.oracle.graal.pointsto.BigBang;
import org.graalvm.compiler.bytecode.BytecodeProvider;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
Expand All @@ -52,6 +51,7 @@
import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
import org.graalvm.compiler.replacements.PEGraphDecoder;

import com.oracle.graal.pointsto.BigBang;
import com.oracle.graal.pointsto.flow.AnalysisParsedGraph;
import com.oracle.graal.pointsto.meta.AnalysisMethod;
import com.oracle.svm.util.ClassUtil;
Expand Down Expand Up @@ -278,7 +278,9 @@ protected void finishInlining(MethodScope is) {
if (callerScope.policyScope != null) {
policy.commitCalleeScope(callerScope.policyScope, inlineScope.policyScope);
}
((AnalysisMethod) invokeData.callTarget.targetMethod()).registerAsInlined();
Object reason = graph.currentNodeSourcePosition() != null ? graph.currentNodeSourcePosition() : graph.method();

((AnalysisMethod) invokeData.callTarget.targetMethod()).registerAsInlined(reason);

super.finishInlining(inlineScope);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.lang.reflect.Modifier;
import java.util.Optional;

import jdk.vm.ci.code.BytecodePosition;
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
import org.graalvm.compiler.core.common.spi.ForeignCallSignature;
import org.graalvm.compiler.graph.Node;
Expand Down Expand Up @@ -135,13 +136,14 @@ private static void analyzeStructuredGraph(ReachabilityAnalysisEngine bb, Reacha
if (targetMethod == null || AnnotationAccess.isAnnotationPresent(targetMethod, Node.NodeIntrinsic.class)) {
continue;
}
BytecodePosition reason = AbstractAnalysisEngine.sourcePosition(node.asNode());
if (method != null) {
method.addInvoke(new ReachabilityInvokeInfo(targetMethod, AbstractAnalysisEngine.sourcePosition(node.asNode()), kind.isDirect()));
method.addInvoke(new ReachabilityInvokeInfo(targetMethod, reason, kind.isDirect()));
}
if (kind.isDirect()) {
bb.markMethodImplementationInvoked(targetMethod);
bb.markMethodImplementationInvoked(targetMethod, reason);
} else {
bb.markMethodInvoked(targetMethod);
bb.markMethodInvoked(targetMethod, reason);
}
} else if (n instanceof FrameState) {
FrameState node = (FrameState) n;
Expand All @@ -159,10 +161,11 @@ private static void analyzeStructuredGraph(ReachabilityAnalysisEngine bb, Reacha
} else if (n instanceof MacroInvokable) {
MacroInvokable node = (MacroInvokable) n;
ReachabilityAnalysisMethod targetMethod = (ReachabilityAnalysisMethod) node.getTargetMethod();
BytecodePosition reason = AbstractAnalysisEngine.syntheticSourcePosition(node.asNode(), method);
if (node.getInvokeKind().isDirect()) {
bb.markMethodImplementationInvoked(targetMethod);
bb.markMethodImplementationInvoked(targetMethod, reason);
} else {
bb.markMethodInvoked(targetMethod);
bb.markMethodInvoked(targetMethod, reason);
}
} else if (n instanceof ForeignCall) {
handleForeignCall(bb, ((ForeignCall) n).getDescriptor());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ public void processGraph(ReachabilityAnalysisEngine bb, StructuredGraph graph) {
*/
private static void processSummary(ReachabilityAnalysisEngine bb, ReachabilityAnalysisMethod method, MethodSummary summary) {
for (AnalysisMethod invokedMethod : summary.invokedMethods) {
bb.markMethodInvoked((ReachabilityAnalysisMethod) invokedMethod);
bb.markMethodInvoked((ReachabilityAnalysisMethod) invokedMethod, method);
}
for (AnalysisMethod invokedMethod : summary.implementationInvokedMethods) {
bb.markMethodImplementationInvoked((ReachabilityAnalysisMethod) invokedMethod);
bb.markMethodImplementationInvoked((ReachabilityAnalysisMethod) invokedMethod, method);
}
for (AnalysisType type : summary.accessedTypes) {
bb.registerTypeAsReachable(type, method);
Expand Down
Loading