use of org.graalvm.compiler.nodes.Invoke in project graal by oracle.
the class HostedBytecodeParser method finishInstruction.
/**
* Insert deopt entries after all state splits.
*/
@Override
protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, FrameStateBuilder stateBuilder) {
if (getMethod().compilationInfo.isDeoptTarget() && !parsingIntrinsic()) {
FrameState stateAfter = null;
if (instr instanceof StateSplit && !(instr instanceof DeoptEntryNode)) {
/*
* The regular case: the instruction is a state split and we insert a DeoptEntryNode
* right after it.
*/
StateSplit stateSplit = (StateSplit) instr;
stateAfter = stateSplit.stateAfter();
} else if (instr instanceof AbstractBeginNode) {
/*
* We are at a block begin. If the block predecessor is a LoopExitNode or an
* InvokeWithException (both are state splits), we didn't inserted a deopt entry
* yet. So we do it at the begin of a block.
*
* Note that this only happens if the LoopExitNode/InvokeWithException is the
* _single_ predcessor of this block. In case of multiple predecessors, the block
* starts with a MergeNode and this is handled like a regular case.
*/
Node predecessor = instr.predecessor();
if (predecessor instanceof KillingBeginNode) {
/*
* This is between an InvokeWithException and the BlockPlaceholderNode.
*/
predecessor = predecessor.predecessor();
}
if (predecessor instanceof StateSplit && !(predecessor instanceof DeoptEntryNode)) {
stateAfter = ((StateSplit) predecessor).stateAfter();
}
}
boolean needsDeoptEntry = false;
boolean needsProxies = false;
if (stateAfter != null) {
if (getMethod().compilationInfo.isDeoptEntry(stateAfter.bci, stateAfter.duringCall(), stateAfter.rethrowException())) {
needsDeoptEntry = true;
needsProxies = true;
} else if (instr.predecessor() instanceof Invoke && getMethod().compilationInfo.isDeoptEntry(((Invoke) instr.predecessor()).bci(), true, false)) {
/*
* Invoke nodes can be implicit deoptimization entry points. But we cannot
* anchor proxy nodes on invocations: The invoke has two successors (normal and
* exception handler), and we need to proxy values at the beginning of both.
*/
needsProxies = true;
} else if (instr instanceof ExceptionObjectNode && getMethod().compilationInfo.isDeoptEntry(((ExceptionObjectNode) instr).stateAfter().bci, true, false)) {
/*
* The predecessor of the ExceptionObjectNode will be an Invoke, but the Invoke
* has not been created yet. So the check above for the predecessor does not
* trigger.
*/
needsProxies = true;
}
}
if (needsProxies) {
long encodedBci = FrameInfoEncoder.encodeBci(stateAfter.bci, stateAfter.duringCall(), stateAfter.rethrowException());
DeoptProxyAnchorNode existingDeoptEntry = deoptEntries.get(encodedBci);
if (existingDeoptEntry != STICKY_DEOPT_ENTRY) {
if (existingDeoptEntry != null) {
/*
* Some state splits (i.e. MergeNode and DispatchBeginNode) do not have a
* correspondent byte code. Therefore there can be a previously added deopt
* entry with the same BCI. For MergeNodes we replace the previous entry
* because the new frame state has less live locals.
*/
existingDeoptEntry.replaceAtUsages(null);
graph.removeFixed(existingDeoptEntry);
deoptEntries.remove(encodedBci);
if (existingDeoptEntry instanceof DeoptEntryNode) {
/*
* We already had a DeoptEntryNode registered earlier for some reason,
* so be conservative and create one again (and not just a
* DeoptProxyAnchorNode).
*/
needsDeoptEntry = true;
}
}
assert !deoptEntries.containsKey(encodedBci) : "duplicate deopt entry for encoded BCI " + encodedBci;
DeoptProxyAnchorNode deoptEntry = createDeoptEntry(stateBuilder, stateAfter, !needsDeoptEntry);
if (instr instanceof LoopBeginNode) {
/*
* Loop headers to not have their own bci. Never move a deopt entry for the
* loop header down, e.g., into a loop end (that might then end up to be
* dead code).
*/
deoptEntries.put(encodedBci, STICKY_DEOPT_ENTRY);
} else {
deoptEntries.put(encodedBci, deoptEntry);
}
assert instr.next() == null : "cannot append instruction to instruction which isn't end (" + instr + "->" + instr.next() + ")";
instr.setNext(deoptEntry);
return deoptEntry;
}
}
}
return super.finishInstruction(instr, stateBuilder);
}
use of org.graalvm.compiler.nodes.Invoke in project graal by oracle.
the class UnsafeAutomaticSubstitutionProcessor method processArrayIndexShift.
/**
* Try to compute the arrayIndexShift. Return true if successful, false otherwise.
*/
private boolean processArrayIndexShift(ResolvedJavaType type, Class<?> arrayClass, ValueNode indexScaleValue, boolean silentFailure) {
NodeIterable<MethodCallTargetNode> loadMethodCallTargetUsages = indexScaleValue.usages().filter(MethodCallTargetNode.class);
for (MethodCallTargetNode methodCallTarget : loadMethodCallTargetUsages) {
/* Iterate over all the calls that use the index scale value. */
if (isInvokeTo(methodCallTarget.invoke(), integerNumberOfLeadingZerosMethod)) {
/*
* Found a call to Integer.numberOfLeadingZeros(int) that uses the array index scale
* field. Check if it is used to calculate the array index shift, i.e., log2 of the
* array index scale.
*/
ResolvedJavaField indexShiftField = null;
List<String> unsuccessfulReasons = new ArrayList<>();
Invoke numberOfLeadingZerosInvoke = methodCallTarget.invoke();
NodeIterable<SubNode> numberOfLeadingZerosInvokeSubUsages = numberOfLeadingZerosInvoke.asNode().usages().filter(SubNode.class);
if (numberOfLeadingZerosInvokeSubUsages.count() == 1) {
/*
* Found the SubNode. Determine if it computes the array index shift. If so find
* the field where the value is stored.
*/
SubNode subNode = numberOfLeadingZerosInvokeSubUsages.first();
if (subNodeComputesLog2(subNode, numberOfLeadingZerosInvoke)) {
indexShiftField = extractValueStoreField(subNode, unsuccessfulReasons);
} else {
unsuccessfulReasons.add("The index array scale value provided by " + indexScaleValue + " is not used to calculate the array index shift.");
}
} else {
unsuccessfulReasons.add("The call to " + methodCallTarget.targetMethod().format("%H.%n(%p)") + " has multiple uses.");
}
if (indexShiftField != null) {
ResolvedJavaField finalIndexShiftField = indexShiftField;
Supplier<ComputedValueField> supplier = () -> new ComputedValueField(finalIndexShiftField, null, Kind.ArrayIndexShift, arrayClass, null, true);
if (tryAutomaticRecomputation(indexShiftField, Kind.ArrayIndexShift, supplier)) {
reportSuccessfulAutomaticRecomputation(Kind.ArrayIndexShift, indexShiftField, arrayClass.getCanonicalName());
return true;
}
} else {
if (!silentFailure) {
reportUnsuccessfulAutomaticRecomputation(type, numberOfLeadingZerosInvoke, Kind.ArrayIndexShift, unsuccessfulReasons);
}
}
}
}
return false;
}
use of org.graalvm.compiler.nodes.Invoke in project graal by oracle.
the class UnsafeAutomaticSubstitutionProcessor method processUnsafeObjectFieldOffsetInvoke.
/**
* Process call to {@link sun.misc.Unsafe#objectFieldOffset(Field)}. The matching logic below
* applies to the following code pattern:
*
* <code> static final long fieldOffset = Unsafe.getUnsafe().objectFieldOffset(X.class.getDeclaredField("f")); </code>
*/
private void processUnsafeObjectFieldOffsetInvoke(ResolvedJavaType type, Invoke unsafeObjectFieldOffsetInvoke) {
SnippetReflectionProvider snippetReflectionProvider = GraalAccess.getOriginalSnippetReflection();
List<String> unsuccessfulReasons = new ArrayList<>();
Class<?> targetFieldHolder = null;
String targetFieldName = null;
ValueNode fieldArgument = unsafeObjectFieldOffsetInvoke.callTarget().arguments().get(1);
if (fieldArgument instanceof Invoke && isInvokeTo((Invoke) fieldArgument, classGetDeclaredFieldMethod)) {
Invoke getDeclaredFieldInvoke = (Invoke) fieldArgument;
/*
* If the first argument of Unsafe.objectFieldOffset() is a call to
* Class.getDeclaredField() and the arguments of Class.getDeclaredField(), i.e., the
* class and the field name, are constants then unwrap them.
*/
ValueNode holderClassNode = getDeclaredFieldInvoke.callTarget().arguments().get(0);
if (holderClassNode.isJavaConstant()) {
targetFieldHolder = snippetReflectionProvider.asObject(Class.class, holderClassNode.asJavaConstant());
} else {
unsuccessfulReasons.add("The receiver of the call to Class.getDeclaredField(), i.e., the field holder class, is not a constant.");
}
ValueNode fieldNameNode = getDeclaredFieldInvoke.callTarget().arguments().get(1);
if (fieldNameNode.isJavaConstant()) {
targetFieldName = snippetReflectionProvider.asObject(String.class, fieldNameNode.asJavaConstant());
} else {
unsuccessfulReasons.add("The first argument of the call to Class.getDeclaredField(), i.e., the field name, is not a constant.");
}
} else {
unsuccessfulReasons.add("The first argument of Unsafe.objectFieldOffset() is not a call to Class.getDeclaredField()");
}
/*
* If the value returned by the call to Unsafe.objectFieldOffset() is stored into a field
* then that must be the offset field.
*/
ResolvedJavaField offsetField = extractValueStoreField(unsafeObjectFieldOffsetInvoke.asNode(), unsuccessfulReasons);
/*
* If the target field holder and name, and the offset field were found try to register a
* substitution.
*/
if (targetFieldHolder != null && targetFieldName != null && offsetField != null) {
Class<?> finalTargetFieldHolder = targetFieldHolder;
String finalTargetFieldName = targetFieldName;
Supplier<ComputedValueField> supplier = () -> new ComputedValueField(offsetField, null, Kind.FieldOffset, finalTargetFieldHolder, finalTargetFieldName, false);
if (tryAutomaticRecomputation(offsetField, Kind.FieldOffset, supplier)) {
reportSuccessfulAutomaticRecomputation(Kind.FieldOffset, offsetField, targetFieldHolder.getName() + "." + targetFieldName);
}
} else {
reportUnsuccessfulAutomaticRecomputation(type, unsafeObjectFieldOffsetInvoke, Kind.FieldOffset, unsuccessfulReasons);
}
}
use of org.graalvm.compiler.nodes.Invoke in project graal by oracle.
the class UnsafeAutomaticSubstitutionProcessor method extractValueStoreField.
/**
* If the value produced by valueNode is stored into a static final field then that field is
* returned. If the field is either not static or not final the method returns null and the
* reason is recorded in the unsuccessfulReasons parameter.
*/
private static ResolvedJavaField extractValueStoreField(ValueNode valueNode, List<String> unsuccessfulReasons) {
ResolvedJavaField offsetField = null;
NodeIterable<Node> valueNodeUsages = valueNode.usages();
NodeIterable<StoreFieldNode> valueNodeStoreFieldUsages = valueNodeUsages.filter(StoreFieldNode.class);
NodeIterable<SignExtendNode> valueNodeSignExtendUsages = valueNodeUsages.filter(SignExtendNode.class);
if (valueNodeStoreFieldUsages.count() == 1) {
offsetField = valueNodeStoreFieldUsages.first().field();
} else if (valueNodeSignExtendUsages.count() == 1) {
SignExtendNode signExtendNode = valueNodeSignExtendUsages.first();
NodeIterable<StoreFieldNode> signExtendFieldStoreUsages = signExtendNode.usages().filter(StoreFieldNode.class);
if (signExtendFieldStoreUsages.count() == 1) {
offsetField = signExtendFieldStoreUsages.first().field();
}
}
if (offsetField != null) {
if (offsetField.isStatic() && offsetField.isFinal()) {
return offsetField;
} else {
if (!offsetField.isStatic()) {
unsuccessfulReasons.add("The offset field " + offsetField.format("%H.%n") + " is not static.");
}
if (!offsetField.isFinal()) {
unsuccessfulReasons.add("The offset field " + offsetField.format("%H.%n") + " is not final.");
}
}
} else {
String producer;
String operation;
if (valueNode instanceof Invoke) {
Invoke invokeNode = (Invoke) valueNode;
producer = "call to " + invokeNode.callTarget().targetMethod().format("%H.%n(%p)");
operation = "call";
} else if (valueNode instanceof SubNode) {
producer = "subtraction operation " + valueNode;
operation = "subtraction";
} else {
throw VMError.shouldNotReachHere();
}
String message = "Could not determine the field where the value produced by the " + producer + " is stored. The " + operation + " is not directly followed by a field store or by a sign extend node followed directly by a field store. ";
unsuccessfulReasons.add(message);
}
return null;
}
use of org.graalvm.compiler.nodes.Invoke in project graal by oracle.
the class LoopFragment method computeNodes.
protected static void computeNodes(NodeBitMap nodes, Graph graph, Iterable<AbstractBeginNode> blocks, Iterable<AbstractBeginNode> earlyExits) {
for (AbstractBeginNode b : blocks) {
if (b.isDeleted()) {
continue;
}
for (Node n : b.getBlockNodes()) {
if (n instanceof Invoke) {
nodes.mark(((Invoke) n).callTarget());
}
if (n instanceof NodeWithState) {
NodeWithState withState = (NodeWithState) n;
withState.states().forEach(state -> state.applyToVirtual(node -> nodes.mark(node)));
}
if (n instanceof AbstractMergeNode) {
// if a merge is in the loop, all of its phis are also in the loop
for (PhiNode phi : ((AbstractMergeNode) n).phis()) {
nodes.mark(phi);
}
}
nodes.mark(n);
}
}
for (AbstractBeginNode earlyExit : earlyExits) {
if (earlyExit.isDeleted()) {
continue;
}
nodes.mark(earlyExit);
if (earlyExit instanceof LoopExitNode) {
LoopExitNode loopExit = (LoopExitNode) earlyExit;
FrameState stateAfter = loopExit.stateAfter();
if (stateAfter != null) {
stateAfter.applyToVirtual(node -> nodes.mark(node));
}
for (ProxyNode proxy : loopExit.proxies()) {
nodes.mark(proxy);
}
}
}
final NodeBitMap nonLoopNodes = graph.createNodeBitMap();
Deque<WorkListEntry> worklist = new ArrayDeque<>();
for (AbstractBeginNode b : blocks) {
if (b.isDeleted()) {
continue;
}
for (Node n : b.getBlockNodes()) {
if (n instanceof CommitAllocationNode) {
for (VirtualObjectNode obj : ((CommitAllocationNode) n).getVirtualObjects()) {
markFloating(worklist, obj, nodes, nonLoopNodes);
}
}
if (n instanceof MonitorEnterNode) {
markFloating(worklist, ((MonitorEnterNode) n).getMonitorId(), nodes, nonLoopNodes);
}
if (n instanceof AbstractMergeNode) {
/*
* Since we already marked all phi nodes as being in the loop to break cycles,
* we also have to iterate over their usages here.
*/
for (PhiNode phi : ((AbstractMergeNode) n).phis()) {
for (Node usage : phi.usages()) {
markFloating(worklist, usage, nodes, nonLoopNodes);
}
}
}
for (Node usage : n.usages()) {
markFloating(worklist, usage, nodes, nonLoopNodes);
}
}
}
}
Aggregations