package com.oracle.truffle.llvm.runtime.nodes.op;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.llvm.runtime.library.internal.LLVMNativeLibrary;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMNode;
import com.oracle.truffle.llvm.runtime.nodes.util.LLVMSameObjectNode;
import com.oracle.truffle.llvm.runtime.pointer.LLVMManagedPointer;
import com.oracle.truffle.llvm.runtime.pointer.LLVMNativePointer;
import com.oracle.truffle.llvm.runtime.pointer.LLVMPointer;
@NodeChild(type = LLVMExpressionNode.class)
@NodeChild(type = LLVMExpressionNode.class)
public abstract class LLVMAddressEqualsNode extends LLVMAbstractCompareNode {
public static LLVMAddressEqualsNode create() {
return LLVMAddressEqualsNodeGen.create(null, null);
}
@GenerateUncached
public abstract static class Operation extends LLVMNode {
public abstract boolean executeWithTarget(Object a, Object b);
@Specialization
boolean doCompare(long a, long b) {
return a == b;
}
@Specialization
boolean doCompare(LLVMNativePointer a, LLVMNativePointer b) {
return a.asNative() == b.asNative();
}
@Specialization
boolean doCompare(Object a, Object b,
@Cached LLVMPointerEqualsNode equals) {
return equals.execute(a, b);
}
}
@Specialization
boolean doCompare(long a, long b) {
return a == b;
}
@Specialization
boolean doCompare(LLVMNativePointer a, LLVMNativePointer b) {
return a.asNative() == b.asNative();
}
@Specialization
boolean doCompare(Object a, Object b,
@Cached LLVMPointerEqualsNode equals) {
return equals.execute(a, b);
}
@GenerateUncached
public abstract static class LLVMPointerEqualsNode extends LLVMNode {
public abstract boolean execute(Object a, Object b);
@Specialization(guards = {"libA.isPointer(a)", "libB.isPointer(b)"}, limit = "8", rewriteOn = UnsupportedMessageException.class)
boolean doPointerPointer(Object a, Object b,
@CachedLibrary("a") LLVMNativeLibrary libA,
@CachedLibrary("b") LLVMNativeLibrary libB) throws UnsupportedMessageException {
return libA.asPointer(a) == libB.asPointer(b);
}
@Specialization(guards = {"libA.isPointer(a)", "libB.isPointer(b)"}, replaces = "doPointerPointer", limit = "8")
boolean doPointerPointerException(Object a, Object b,
@CachedLibrary("a") LLVMNativeLibrary libA,
@CachedLibrary("b") LLVMNativeLibrary libB,
@Cached LLVMManagedEqualsNode managedEquals) {
try {
return doPointerPointer(a, b, libA, libB);
} catch (UnsupportedMessageException ex) {
return doOther(a, b, libA, libB, managedEquals);
}
}
@Specialization(guards = "!libA.isPointer(a) || !libB.isPointer(b)", limit = "8")
boolean doOther(Object a, Object b,
@SuppressWarnings("unused") @CachedLibrary("a") LLVMNativeLibrary libA,
@SuppressWarnings("unused") @CachedLibrary("b") LLVMNativeLibrary libB,
@Cached LLVMManagedEqualsNode managedEquals) {
return managedEquals.execute(a, b);
}
}
@GenerateUncached
abstract static class LLVMManagedEqualsNode extends LLVMNode {
abstract boolean execute(Object a, Object b);
@Specialization
protected boolean doForeign(LLVMManagedPointer a, LLVMManagedPointer b,
@Cached LLVMSameObjectNode pointToSameObject) {
return pointToSameObject.execute(a.getObject(), b.getObject()) && a.getOffset() == b.getOffset();
}
@Specialization(guards = "isNative(p1) || isNative(p2)")
protected boolean doManagedNative(LLVMPointer p1, LLVMPointer p2) {
assert LLVMManagedPointer.isInstance(p1) || LLVMManagedPointer.isInstance(p2) : "the case where both pointers are native is handled earlier, so one has to be managed";
return false;
}
@Specialization(guards = "a.getClass() != b.getClass()")
protected boolean doDifferentType(Object a, Object b) {
return false;
}
protected static boolean isNative(LLVMPointer p) {
return LLVMNativePointer.isInstance(p);
}
}
}