package com.oracle.truffle.js.nodes.binary;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.instrumentation.Tag;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.js.nodes.JavaScriptNode;
import com.oracle.truffle.js.nodes.Truncatable;
import com.oracle.truffle.js.nodes.access.JSConstantNode.JSConstantNumericUnitNode;
import com.oracle.truffle.js.nodes.cast.JSToNumericNode;
import com.oracle.truffle.js.runtime.BigInt;
import java.util.Set;
@NodeInfo(shortName = "-")
public abstract class JSSubtractNode extends JSBinaryNode implements Truncatable {
@CompilationFinal boolean truncate;
protected JSSubtractNode(boolean truncate, JavaScriptNode left, JavaScriptNode right) {
super(left, right);
this.truncate = truncate;
}
public static JavaScriptNode create(JavaScriptNode left, JavaScriptNode right, boolean truncate) {
if (right instanceof JSConstantNumericUnitNode) {
return JSAddSubNumericUnitNode.create(left, false, truncate);
}
return JSSubtractNodeGen.create(truncate, left, right);
}
public static JavaScriptNode create(JavaScriptNode left, JavaScriptNode right) {
return create(left, right, false);
}
public abstract Object execute(Object a, Object b);
@Specialization(rewriteOn = ArithmeticException.class)
protected int doInt(int a, int b) {
if (truncate) {
return a - b;
} else {
return Math.subtractExact(a, b);
}
}
@Specialization(replaces = "doInt")
protected double doDouble(double a, double b) {
return a - b;
}
@Specialization()
protected BigInt doBigInt(BigInt a, BigInt b) {
return a.subtract(b);
}
@Specialization(replaces = {"doDouble", "doBigInt"})
protected Object doGeneric(Object a, Object b,
@Cached("create()") JSToNumericNode toNumericA,
@Cached("create()") JSToNumericNode toNumericB,
@Cached("copyRecursive()") JavaScriptNode subtract,
@Cached("create()") BranchProfile mixedNumericTypes) {
Object castA = toNumericA.execute(a);
Object castB = toNumericB.execute(b);
ensureBothSameNumericType(castA, castB, mixedNumericTypes);
return ((JSSubtractNode) subtract).execute(castA, castB);
}
public final JavaScriptNode copyRecursive() {
return create(null, null, truncate);
}
@Override
public boolean isResultAlwaysOfType(Class<?> clazz) {
return clazz == Number.class;
}
@Override
public void setTruncate() {
CompilerAsserts.neverPartOfCompilation();
if (truncate == false) {
truncate = true;
}
}
@Override
protected JavaScriptNode copyUninitialized(Set<Class<? extends Tag>> materializedTags) {
return JSSubtractNodeGen.create(cloneUninitialized(getLeft(), materializedTags), cloneUninitialized(getRight(), materializedTags), truncate);
}
}