use of org.graalvm.compiler.nodes.calc.ObjectEqualsNode in project graal by oracle.
the class HashMapGetTest method hashMapTest.
@Test
public void hashMapTest() {
HashMap<Integer, Integer> map = new HashMap<>();
ResolvedJavaMethod get = getResolvedJavaMethod(HashMapGetTest.class, "mapGet");
for (int i = 0; i < 5000; i++) {
mapGet(map, i);
map.put(i, i);
mapGet(map, i);
}
test(get, null, map, new Integer(0));
for (IfNode ifNode : lastCompiledGraph.getNodes(IfNode.TYPE)) {
LogicNode condition = ifNode.condition();
if (ifNode.getTrueSuccessorProbability() < 0.4 && condition instanceof ObjectEqualsNode) {
assertTrue(ifNode.trueSuccessor().next() instanceof ReturnNode, "Expected return.", ifNode.trueSuccessor(), ifNode.trueSuccessor().next());
}
}
}
use of org.graalvm.compiler.nodes.calc.ObjectEqualsNode in project graal by oracle.
the class JNIJavaCallWrapperMethod method loadAndUnboxArguments.
private List<Pair<ValueNode, ResolvedJavaType>> loadAndUnboxArguments(JNIGraphKit kit, HostedProviders providers, ResolvedJavaMethod invokeMethod, Signature invokeSignature) {
MetaAccessProvider metaAccess = providers.getMetaAccess();
List<Pair<ValueNode, ResolvedJavaType>> args = new ArrayList<>();
int javaIndex = 0;
javaIndex += metaAccess.lookupJavaType(JNIEnvironment.class).getJavaKind().getSlotCount();
if (!invokeMethod.isStatic()) {
JavaKind kind = metaAccess.lookupJavaType(JNIObjectHandle.class).getJavaKind();
ValueNode handle = kit.loadLocal(javaIndex, kind);
ValueNode unboxed = kit.unboxHandle(handle);
ValueNode receiver;
ResolvedJavaType receiverClass = invokeMethod.getDeclaringClass();
if (invokeMethod.isConstructor()) {
/*
* Our target method is a constructor and we might be called via `NewObject`, in
* which case we need to allocate the object before calling the constructor. We can
* detect when this is the case because unlike with `Call<Type>Method`, we are
* passed the object hub of our target class in place of the receiver object.
*/
Constant hub = providers.getConstantReflection().asObjectHub(receiverClass);
ConstantNode hubNode = kit.createConstant(hub, JavaKind.Object);
kit.startIf(kit.unique(new ObjectEqualsNode(unboxed, hubNode)), BranchProbabilityNode.FAST_PATH_PROBABILITY);
kit.thenPart();
ValueNode created = kit.append(new NewInstanceNode(receiverClass, true));
AbstractMergeNode merge = kit.endIf();
receiver = kit.unique(new ValuePhiNode(StampFactory.object(), merge, new ValueNode[] { created, unboxed }));
} else {
receiver = unboxed;
}
args.add(Pair.create(receiver, receiverClass));
}
javaIndex += metaAccess.lookupJavaType(JNIObjectHandle.class).getJavaKind().getSlotCount();
if (nonVirtual) {
javaIndex += metaAccess.lookupJavaType(JNIObjectHandle.class).getJavaKind().getSlotCount();
}
javaIndex += metaAccess.lookupJavaType(JNIMethodId.class).getJavaKind().getSlotCount();
int count = invokeSignature.getParameterCount(false);
if (callVariant == CallVariant.VARARGS) {
for (int i = 0; i < count; i++) {
ResolvedJavaType type = (ResolvedJavaType) invokeSignature.getParameterType(i, null);
JavaKind kind = type.getJavaKind();
JavaKind loadKind = kind;
if (loadKind == JavaKind.Float) {
// C varargs promote float to double
loadKind = JavaKind.Double;
}
ValueNode value = kit.loadLocal(javaIndex, loadKind);
if (kind == JavaKind.Float) {
value = kit.unique(new FloatConvertNode(FloatConvert.D2F, value));
} else if (kind.isObject()) {
value = kit.unboxHandle(value);
}
args.add(Pair.create(value, type));
javaIndex += loadKind.getSlotCount();
}
} else if (callVariant == CallVariant.ARRAY) {
ResolvedJavaType elementType = metaAccess.lookupJavaType(JNIValue.class);
int elementSize = SizeOf.get(JNIValue.class);
ValueNode array = kit.loadLocal(javaIndex, elementType.getJavaKind());
for (int i = 0; i < count; i++) {
ResolvedJavaType type = (ResolvedJavaType) invokeSignature.getParameterType(i, null);
JavaKind readKind = type.getJavaKind();
StructFieldInfo fieldInfo = getJNIValueOffsetOf(elementType, readKind);
int offset = i * elementSize + fieldInfo.getOffsetInfo().getProperty();
ConstantNode offsetConstant = kit.createConstant(JavaConstant.forInt(offset), providers.getWordTypes().getWordKind());
OffsetAddressNode address = kit.unique(new OffsetAddressNode(array, offsetConstant));
LocationIdentity locationIdentity = fieldInfo.getLocationIdentity();
if (locationIdentity == null) {
locationIdentity = LocationIdentity.any();
}
Stamp readStamp = getNarrowStamp(providers, readKind);
ValueNode value = kit.append(new CInterfaceReadNode(address, locationIdentity, readStamp, BarrierType.NONE, "args[" + i + "]"));
JavaKind stackKind = readKind.getStackKind();
if (readKind != stackKind) {
assert stackKind.getBitCount() > readKind.getBitCount() : "read kind must be narrower than stack kind";
if (readKind.isUnsigned()) {
// needed or another op may illegally sign-extend
value = kit.unique(new ZeroExtendNode(value, stackKind.getBitCount()));
} else {
value = kit.unique(new SignExtendNode(value, stackKind.getBitCount()));
}
} else if (readKind.isObject()) {
value = kit.unboxHandle(value);
}
args.add(Pair.create(value, type));
}
} else if (callVariant == CallVariant.VA_LIST) {
ValueNode valist = kit.loadLocal(javaIndex, metaAccess.lookupJavaType(WordBase.class).getJavaKind());
for (int i = 0; i < count; i++) {
ResolvedJavaType type = (ResolvedJavaType) invokeSignature.getParameterType(i, null);
JavaKind loadKind = type.getJavaKind();
if (loadKind.isObject()) {
loadKind = providers.getWordTypes().getWordKind();
}
ValueNode value = kit.append(new VaListNextArgNode(loadKind, valist));
if (type.getJavaKind().isObject()) {
value = kit.unboxHandle(value);
}
args.add(Pair.create(value, type));
}
} else {
throw VMError.unsupportedFeature("Call variant: " + callVariant);
}
return args;
}
use of org.graalvm.compiler.nodes.calc.ObjectEqualsNode 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.calc.ObjectEqualsNode in project graal by oracle.
the class IfNode method tryEliminateBoxedReferenceEquals.
/**
* Attempts to replace the following pattern:
*
* <pre>
* Integer x = ...;
* Integer y = ...;
* if ((x == y) || x.equals(y)) { ... }
* </pre>
*
* with:
*
* <pre>
* Integer x = ...;
* Integer y = ...;
* if (x.equals(y)) { ... }
* </pre>
*
* whenever the probability that the reference check will pass is relatively small.
*
* See GR-1315 for more information.
*/
private boolean tryEliminateBoxedReferenceEquals(SimplifierTool tool) {
if (!(condition instanceof ObjectEqualsNode)) {
return false;
}
MetaAccessProvider meta = tool.getMetaAccess();
ObjectEqualsNode equalsCondition = (ObjectEqualsNode) condition;
ValueNode x = equalsCondition.getX();
ValueNode y = equalsCondition.getY();
ResolvedJavaType integerType = meta.lookupJavaType(Integer.class);
// At least one argument for reference equal must be a boxed primitive.
NodeView view = NodeView.from(tool);
if (!x.stamp(view).javaType(meta).equals(integerType) && !y.stamp(view).javaType(meta).equals(integerType)) {
return false;
}
// no sense to eliminate it.
if (getTrueSuccessorProbability() > 0.4) {
return false;
}
// True branch must be empty.
if (trueSuccessor instanceof BeginNode || trueSuccessor instanceof LoopExitNode) {
if (trueSuccessor.next() instanceof EndNode) {
// Empty true branch.
} else {
return false;
}
} else {
return false;
}
// False branch must only check the unboxed values.
UnboxNode unbox = null;
FixedGuardNode unboxCheck = null;
for (FixedNode node : falseSuccessor.getBlockNodes()) {
if (!(node instanceof BeginNode || node instanceof UnboxNode || node instanceof FixedGuardNode || node instanceof EndNode || node instanceof LoadFieldNode || node instanceof LoopExitNode)) {
return false;
}
if (node instanceof UnboxNode) {
if (unbox == null) {
unbox = (UnboxNode) node;
} else {
return false;
}
}
if (!(node instanceof FixedGuardNode)) {
continue;
}
FixedGuardNode fixed = (FixedGuardNode) node;
if (!(fixed.condition() instanceof IntegerEqualsNode)) {
continue;
}
IntegerEqualsNode equals = (IntegerEqualsNode) fixed.condition();
if ((isUnboxedFrom(meta, view, equals.getX(), x) && isUnboxedFrom(meta, view, equals.getY(), y)) || (isUnboxedFrom(meta, view, equals.getX(), y) && isUnboxedFrom(meta, view, equals.getY(), x))) {
unboxCheck = fixed;
}
}
if (unbox == null || unboxCheck == null) {
return false;
}
// Falsify the reference check.
setCondition(graph().addOrUniqueWithInputs(LogicConstantNode.contradiction()));
return true;
}
use of org.graalvm.compiler.nodes.calc.ObjectEqualsNode in project graal by oracle.
the class VerifyUsageWithEquals method verify.
@Override
protected boolean verify(StructuredGraph graph, PhaseContext context) {
for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) {
// bail out if we compare an object of type klass with == or != (except null checks)
ResolvedJavaMethod method = graph.method();
ResolvedJavaType restrictedType = context.getMetaAccess().lookupJavaType(restrictedClass);
if (method.getDeclaringClass().equals(restrictedType)) {
// Allow violation in methods of the restricted type itself.
} else if (isIllegalUsage(method, cn.getX(), cn.getY(), context.getMetaAccess()) || isIllegalUsage(method, cn.getY(), cn.getX(), context.getMetaAccess())) {
throw new VerificationError("Verification of " + restrictedClass.getName() + " usage failed: Comparing " + cn.getX() + " and " + cn.getY() + " in " + method + " must use .equals() for object equality, not '==' or '!='");
}
}
return true;
}
Aggregations