use of jdk.vm.ci.meta.ResolvedJavaField in project graal by oracle.
the class ComputedValueField method computeAtomicFieldUpdaterOffset.
private JavaConstant computeAtomicFieldUpdaterOffset(JavaConstant receiver) {
assert !Modifier.isStatic(original.getModifiers());
assert receiver.isNonNull();
/*
* Explanation: java.util.concurrent is full of objects and classes that cache the offset of
* particular fields in the JDK. Here, Atomic<X>FieldUpdater implementation objects cache
* the offset of some specified field. Which field? Oh...only Doug Lea knows that. We have
* to search the declaring class for a field that has the same "unsafe" offset as the cached
* offset in this atomic updater object.
*/
ResolvedJavaField tclassField = findField(original.getDeclaringClass(), "tclass");
SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection();
Class<?> tclass = originalSnippetReflection.asObject(Class.class, ReadableJavaField.readFieldValue(GraalAccess.getOriginalProviders().getConstantReflection(), tclassField, receiver));
return translateFieldOffset(receiver, tclass);
}
use of jdk.vm.ci.meta.ResolvedJavaField in project graal by oracle.
the class UnsafeAutomaticSubstitutionProcessor method processUnsafeArrayIndexScaleInvoke.
/**
* Process call to {@link sun.misc.Unsafe#arrayIndexScale(Class)}. The matching logic below
* applies to the following code pattern:
*
* <code> static final long byteArrayIndexScale = Unsafe.getUnsafe().arrayIndexScale(byte[].class); </code>
*/
private void processUnsafeArrayIndexScaleInvoke(ResolvedJavaType type, Invoke unsafeArrayIndexScale, StructuredGraph clinitGraph) {
SnippetReflectionProvider snippetReflectionProvider = GraalAccess.getOriginalSnippetReflection();
List<String> unsuccessfulReasons = new ArrayList<>();
Class<?> arrayClass = null;
ValueNode arrayClassArgument = unsafeArrayIndexScale.callTarget().arguments().get(1);
if (arrayClassArgument.isJavaConstant()) {
arrayClass = snippetReflectionProvider.asObject(Class.class, arrayClassArgument.asJavaConstant());
} else {
unsuccessfulReasons.add("The first argument of the call to Unsafe.arrayIndexScale() is not a constant.");
}
/*
* If the value returned by the call to Unsafe.unsafeArrayIndexScale() is stored into a
* field then that must be the offset field.
*/
ResolvedJavaField indexScaleField = extractValueStoreField(unsafeArrayIndexScale.asNode(), unsuccessfulReasons);
boolean indexScaleComputed = false;
boolean indexShiftComputed = false;
if (arrayClass != null) {
if (indexScaleField != null) {
Class<?> finalArrayClass = arrayClass;
Supplier<ComputedValueField> supplier = () -> new ComputedValueField(indexScaleField, null, Kind.ArrayIndexScale, finalArrayClass, null, true);
if (tryAutomaticRecomputation(indexScaleField, Kind.ArrayIndexScale, supplier)) {
reportSuccessfulAutomaticRecomputation(Kind.ArrayIndexScale, indexScaleField, arrayClass.getCanonicalName());
indexScaleComputed = true;
/* Try substitution for the array index shift computation if present. */
indexShiftComputed = processArrayIndexShiftFromField(type, indexScaleField, arrayClass, clinitGraph);
}
} else {
/*
* The index scale is not stored into a field, it might be used to compute the index
* shift.
*/
indexShiftComputed = processArrayIndexShiftFromLocal(type, unsafeArrayIndexScale, arrayClass);
}
}
if (!indexScaleComputed && !indexShiftComputed) {
reportUnsuccessfulAutomaticRecomputation(type, unsafeArrayIndexScale, Kind.ArrayIndexScale, unsuccessfulReasons);
}
}
use of jdk.vm.ci.meta.ResolvedJavaField 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 jdk.vm.ci.meta.ResolvedJavaField 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 jdk.vm.ci.meta.ResolvedJavaField 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;
}
Aggregations