/*
* Copyright (c) 2013, 2017, 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 org.graalvm.compiler.nodes.java.LoadFieldNode;
import com.oracle.graal.pointsto.BigBang;
import com.oracle.graal.pointsto.flow.context.object.AnalysisObject;
import com.oracle.graal.pointsto.typestate.TypeState;
import jdk.vm.ci.code.BytecodePosition;
Implements a field load operation type flow.
/**
* Implements a field load operation type flow.
*/
public abstract class LoadFieldTypeFlow extends AccessFieldTypeFlow {
protected LoadFieldTypeFlow(LoadFieldNode node) {
super(node);
}
protected LoadFieldTypeFlow(MethodFlowsGraph methodFlows, LoadFieldTypeFlow original) {
super(original, methodFlows);
}
public static class LoadStaticFieldTypeFlow extends LoadFieldTypeFlow {
private final FieldTypeFlow fieldFlow;
LoadStaticFieldTypeFlow(LoadFieldNode node, FieldTypeFlow fieldFlow) {
super(node);
this.fieldFlow = fieldFlow;
/*
* The original static load cannot be added as a use to the static field, even using the
* non-state-transfering method, because whenever the field is updated would also update
* the load. We only want that update in the clone.
*/
}
LoadStaticFieldTypeFlow(MethodFlowsGraph methodFlows, LoadStaticFieldTypeFlow original) {
super(methodFlows, original);
fieldFlow = original.fieldFlow;
}
@Override
public TypeFlow<BytecodePosition> copy(BigBang bb, MethodFlowsGraph methodFlows) {
return new LoadStaticFieldTypeFlow(methodFlows, this);
}
@Override
public void initClone(BigBang bb) {
fieldFlow.addUse(bb, this);
}
@Override
public String toString() {
return "LoadStaticFieldTypeFlow<" + getState() + ">";
}
}
The type state of the load instance field flow reflects the type state of the field on the
receiver objects that triggered this load operation.
/**
* The type state of the load instance field flow reflects the type state of the field on the
* receiver objects that triggered this load operation.
*/
public static class LoadInstanceFieldTypeFlow extends LoadFieldTypeFlow {
The flow of the receiver object. The load flow is registered as an observer of the
receiver object.
/**
* The flow of the receiver object. The load flow is registered as an observer of the
* receiver object.
*/
private TypeFlow<?> objectFlow;
LoadInstanceFieldTypeFlow(LoadFieldNode node, TypeFlow<?> objectFlow) {
super(node);
this.objectFlow = objectFlow;
}
LoadInstanceFieldTypeFlow(BigBang bb, MethodFlowsGraph methodFlows, LoadInstanceFieldTypeFlow original) {
super(methodFlows, original);
this.objectFlow = methodFlows.lookupCloneOf(bb, original.objectFlow);
}
@Override
public LoadFieldTypeFlow copy(BigBang bb, MethodFlowsGraph methodFlows) {
return new LoadInstanceFieldTypeFlow(bb, methodFlows, this);
}
Return the receiver object flow. /** Return the receiver object flow. */
@Override
public TypeFlow<?> receiver() {
return objectFlow;
}
@Override
public void setObserved(TypeFlow<?> newObjectFlow) {
this.objectFlow = newObjectFlow;
}
@Override
public void onObservedUpdate(BigBang bb) {
/* Only a clone should be updated */
assert this.isClone();
/*
* The state of the receiver object of the load operation has changed. Link the new heap
* sensitive field flows.
*/
TypeState objectState = objectFlow.getState();
if (objectState.isUnknown()) {
bb.reportIllegalUnknownUse(graphRef.getMethod(), source, "Illegal: Field loading from UnknownTypeState objects. Field: " + field);
return;
}
objectState = filterObjectState(bb, objectState);
/* Iterate over the receiver objects. */
for (AnalysisObject object : objectState.objects()) {
/* Get the field flow corresponding to the receiver object. */
FieldTypeFlow fieldFlow = object.getInstanceFieldFlow(bb, this.method(), field, false);
/* Add the load field flow as a use to the heap sensitive field flow. */
fieldFlow.addUse(bb, this);
}
}
@Override
public void onObservedSaturated(BigBang bb, TypeFlow<?> observed) {
assert this.isClone();
/* When receiver flow saturates start observing the flow of the field declaring type. */
replaceObservedWith(bb, field.getDeclaringClass());
}
@Override
public String toString() {
return "LoadInstanceFieldTypeFlow<" + getState() + ">";
}
}
}