use of org.graalvm.compiler.nodes.ConstantNode in project graal by oracle.
the class MethodTypeFlowBuilder method apply.
protected void apply() {
// assert method.getAnnotation(Fold.class) == null : method;
if (method.getAnnotation(NodeIntrinsic.class) != null) {
graph.getDebug().log("apply MethodTypeFlow on node intrinsic %s", method);
AnalysisType returnType = (AnalysisType) method.getSignature().getReturnType(method.getDeclaringClass());
if (returnType.getJavaKind() == JavaKind.Object) {
/*
* This is a method used in a snippet, so most likely the return value does not
* matter at all. However, some methods return an object, and the snippet continues
* to work with the object. So pretend that this method returns an object of the
* exact return type.
*/
TypeFlow<?> returnTypeFlow = methodFlow.getResultFlow().getDeclaredType().getTypeFlow(this.bb, true);
returnTypeFlow = new ProxyTypeFlow(null, returnTypeFlow);
FormalReturnTypeFlow resultFlow = new FormalReturnTypeFlow(null, returnType, method);
returnTypeFlow.addOriginalUse(this.bb, resultFlow);
methodFlow.addMiscEntry(returnTypeFlow);
methodFlow.setResult(resultFlow);
}
return;
}
if (!parse()) {
return;
}
this.bb.getUnsupportedFeatures().checkMethod(method, graph);
processedNodes = new NodeBitMap(graph);
TypeFlowsOfNodes typeFlows = new TypeFlowsOfNodes();
for (Node n : graph.getNodes()) {
if (n instanceof ParameterNode) {
ParameterNode node = (ParameterNode) n;
if (node.getStackKind() == JavaKind.Object) {
TypeFlowBuilder<?> paramBuilder = TypeFlowBuilder.create(bb, node, FormalParamTypeFlow.class, () -> {
boolean isStatic = Modifier.isStatic(method.getModifiers());
int index = node.index();
FormalParamTypeFlow parameter;
if (!isStatic && index == 0) {
AnalysisType paramType = method.getDeclaringClass();
parameter = new FormalReceiverTypeFlow(node, paramType, method);
} else {
int offset = isStatic ? 0 : 1;
AnalysisType paramType = (AnalysisType) method.getSignature().getParameterType(index - offset, method.getDeclaringClass());
parameter = new FormalParamTypeFlow(node, paramType, method, index);
}
methodFlow.setParameter(index, parameter);
return parameter;
});
typeFlowGraphBuilder.checkFormalParameterBuilder(paramBuilder);
typeFlows.add(node, paramBuilder);
}
} else if (n instanceof BoxNode) {
BoxNode node = (BoxNode) n;
Object key = uniqueKey(node);
BytecodeLocation boxSite = bb.analysisPolicy().createAllocationSite(bb, key, methodFlow.getMethod());
AnalysisType type = (AnalysisType) StampTool.typeOrNull(node);
TypeFlowBuilder<?> boxBuilder = TypeFlowBuilder.create(bb, node, BoxTypeFlow.class, () -> {
BoxTypeFlow boxFlow = new BoxTypeFlow(node, type, boxSite);
methodFlow.addAllocation(boxFlow);
return boxFlow;
});
typeFlows.add(node, boxBuilder);
}
for (Node input : n.inputs()) {
/*
* TODO change the handling of constants so that the SourceTypeFlow is created on
* demand, with the optimization that only one SourceTypeFlow is created ever for
* every distinct object (using, e.g., caching in a global IdentityHashMap).
*/
if (input instanceof ConstantNode && !typeFlows.contains((ConstantNode) input)) {
ConstantNode node = (ConstantNode) input;
if (node.asJavaConstant().isNull()) {
TypeFlowBuilder<SourceTypeFlow> sourceBuilder = TypeFlowBuilder.create(bb, node, SourceTypeFlow.class, () -> {
SourceTypeFlow constantSource = new SourceTypeFlow(node, TypeState.forNull());
methodFlow.addSource(constantSource);
return constantSource;
});
typeFlows.add(node, sourceBuilder);
} else if (node.asJavaConstant().getJavaKind() == JavaKind.Object) {
/*
* TODO a SubstrateObjectConstant wrapping a PrimitiveConstant has kind
* equals to Object. Do we care about the effective value of these primitive
* constants in the analysis?
*/
assert StampTool.isExactType(node);
AnalysisType type = (AnalysisType) StampTool.typeOrNull(node);
assert type.isInstantiated();
TypeFlowBuilder<SourceTypeFlow> sourceBuilder = TypeFlowBuilder.create(bb, node, SourceTypeFlow.class, () -> {
SourceTypeFlow constantSource = new SourceTypeFlow(node, TypeState.forConstant(this.bb, node.asJavaConstant(), type));
methodFlow.addSource(constantSource);
return constantSource;
});
typeFlows.add(node, sourceBuilder);
}
}
}
}
// Propagate the type flows through the method's graph
new NodeIterator(graph.start(), typeFlows).apply();
/* Prune the method graph. Eliminate nodes with no uses. */
typeFlowGraphBuilder.build();
/*
* Make sure that all existing InstanceOfNodes are registered even when only used as an
* input of a conditional.
*/
for (Node n : graph.getNodes()) {
if (n instanceof InstanceOfNode) {
InstanceOfNode instanceOf = (InstanceOfNode) n;
markFieldsUsedInComparison(instanceOf.getValue());
} else if (n instanceof ObjectEqualsNode) {
ObjectEqualsNode compareNode = (ObjectEqualsNode) n;
markFieldsUsedInComparison(compareNode.getX());
markFieldsUsedInComparison(compareNode.getY());
}
}
}
use of org.graalvm.compiler.nodes.ConstantNode in project graal by oracle.
the class XorNode method create.
public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
BinaryOp<Xor> op = ArithmeticOpTable.forStamp(x.stamp(view)).getXor();
Stamp stamp = op.foldStamp(x.stamp(view), y.stamp(view));
ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp, view);
if (tryConstantFold != null) {
return tryConstantFold;
}
return canonical(null, op, stamp, x, y, view);
}
use of org.graalvm.compiler.nodes.ConstantNode in project graal by oracle.
the class SubNode method create.
public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
BinaryOp<Sub> op = ArithmeticOpTable.forStamp(x.stamp(view)).getSub();
Stamp stamp = op.foldStamp(x.stamp(view), y.stamp(view));
ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp, view);
if (tryConstantFold != null) {
return tryConstantFold;
}
return canonical(null, op, stamp, x, y, view);
}
use of org.graalvm.compiler.nodes.ConstantNode in project graal by oracle.
the class IntegerSwitchNode method tryOptimizeEnumSwitch.
/**
* For switch statements on enum values, the Java compiler has to generate complicated code:
* because {@link Enum#ordinal()} can change when recompiling an enum, it cannot be used
* directly as the value that is switched on. An intermediate int[] array, which is initialized
* once at run time based on the actual {@link Enum#ordinal()} values, is used.
*
* The {@link ConstantFieldProvider} of Graal already detects the int[] arrays and marks them as
* {@link ConstantNode#isDefaultStable() stable}, i.e., the array elements are constant. The
* code in this method detects array loads from such a stable array and re-wires the switch to
* use the keys from the array elements, so that the array load is unnecessary.
*/
private boolean tryOptimizeEnumSwitch(SimplifierTool tool) {
if (!(value() instanceof LoadIndexedNode)) {
/* Not the switch pattern we are looking for. */
return false;
}
LoadIndexedNode loadIndexed = (LoadIndexedNode) value();
if (loadIndexed.usages().count() > 1) {
/*
* The array load is necessary for other reasons too, so there is no benefit optimizing
* the switch.
*/
return false;
}
assert loadIndexed.usages().first() == this;
ValueNode newValue = loadIndexed.index();
JavaConstant arrayConstant = loadIndexed.array().asJavaConstant();
if (arrayConstant == null || ((ConstantNode) loadIndexed.array()).getStableDimension() != 1 || !((ConstantNode) loadIndexed.array()).isDefaultStable()) {
/*
* The array is a constant that we can optimize. We require the array elements to be
* constant too, since we put them as literal constants into the switch keys.
*/
return false;
}
Integer optionalArrayLength = tool.getConstantReflection().readArrayLength(arrayConstant);
if (optionalArrayLength == null) {
/* Loading a constant value can be denied by the VM. */
return false;
}
int arrayLength = optionalArrayLength;
Map<Integer, List<Integer>> reverseArrayMapping = new HashMap<>();
for (int i = 0; i < arrayLength; i++) {
JavaConstant elementConstant = tool.getConstantReflection().readArrayElement(arrayConstant, i);
if (elementConstant == null || elementConstant.getJavaKind() != JavaKind.Int) {
/* Loading a constant value can be denied by the VM. */
return false;
}
int element = elementConstant.asInt();
/*
* The value loaded from the array is the old switch key, the index into the array is
* the new switch key. We build a mapping from the old switch key to new keys.
*/
reverseArrayMapping.computeIfAbsent(element, e -> new ArrayList<>()).add(i);
}
/* Build high-level representation of new switch keys. */
List<KeyData> newKeyDatas = new ArrayList<>(arrayLength);
ArrayList<AbstractBeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
for (int i = 0; i < keys.length; i++) {
List<Integer> newKeys = reverseArrayMapping.get(keys[i]);
if (newKeys == null || newKeys.size() == 0) {
/* The switch case is unreachable, we can ignore it. */
continue;
}
/*
* We do not have detailed profiling information about the individual new keys, so we
* have to assume they split the probability of the old key.
*/
double newKeyProbability = keyProbabilities[i] / newKeys.size();
int newKeySuccessor = addNewSuccessor(keySuccessor(i), newSuccessors);
for (int newKey : newKeys) {
newKeyDatas.add(new KeyData(newKey, newKeyProbability, newKeySuccessor));
}
}
int newDefaultSuccessor = addNewSuccessor(defaultSuccessor(), newSuccessors);
double newDefaultProbability = keyProbabilities[keyProbabilities.length - 1];
/*
* We remove the array load, but we still need to preserve exception semantics by keeping
* the bounds check. Fortunately the array length is a constant.
*/
LogicNode boundsCheck = graph().unique(new IntegerBelowNode(newValue, ConstantNode.forInt(arrayLength, graph())));
graph().addBeforeFixed(this, graph().add(new FixedGuardNode(boundsCheck, DeoptimizationReason.BoundsCheckException, DeoptimizationAction.InvalidateReprofile)));
/*
* Build the low-level representation of the new switch keys and replace ourself with a new
* node.
*/
doReplace(newValue, newKeyDatas, newSuccessors, newDefaultSuccessor, newDefaultProbability);
/* The array load is now unnecessary. */
assert loadIndexed.hasNoUsages();
GraphUtil.removeFixedWithUnusedInputs(loadIndexed);
return true;
}
use of org.graalvm.compiler.nodes.ConstantNode in project graal by oracle.
the class AddressOfVMThreadLocalNode method lower.
@Override
public void lower(LoweringTool tool) {
assert threadLocalInfo.offset >= 0;
ValueNode base = holder;
if (base.getStackKind() == JavaKind.Object) {
base = graph().unique(new FloatingWordCastNode(FrameAccess.getWordStamp(), base));
}
assert base.getStackKind() == FrameAccess.getWordKind();
ConstantNode offset = ConstantNode.forIntegerKind(FrameAccess.getWordKind(), threadLocalInfo.offset, graph());
ValueNode address = graph().unique(new AddNode(base, offset));
replaceAtUsagesAndDelete(address);
}
Aggregations