in rhino/src/main/java/org/mozilla/javascript/optimizer/Optimizer.java [109:408]
private int rewriteForNumberVariables(Node n, int desired) {
switch (n.getType()) {
case Token.EXPR_VOID:
{
Node child = n.getFirstChild();
int type = rewriteForNumberVariables(child, NumberType);
if (type == NumberType) n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
return NoType;
}
case Token.NUMBER:
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
return NumberType;
case Token.GETVAR:
{
int varIndex = theFunction.getVarIndex(n);
if (inDirectCallFunction
&& theFunction.isParameter(varIndex)
&& desired == NumberType) {
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
return NumberType;
} else if (theFunction.isNumberVar(varIndex)) {
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
return NumberType;
}
return NoType;
}
case Token.INC:
case Token.DEC:
{
Node child = n.getFirstChild();
if (child.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1) {
// Don't optimize super.prop++ and related
return NoType;
}
int type = rewriteForNumberVariables(child, NumberType);
if (child.getType() == Token.GETVAR) {
if (type == NumberType && !convertParameter(child)) {
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
markDCPNumberContext(child);
return NumberType;
}
return NoType;
} else if (child.getType() == Token.GETELEM
|| child.getType() == Token.GETPROP) {
return type;
}
return NoType;
}
case Token.SETVAR:
case Token.SETCONSTVAR:
{
Node lChild = n.getFirstChild();
Node rChild = lChild.getNext();
int rType = rewriteForNumberVariables(rChild, NumberType);
int varIndex = theFunction.getVarIndex(n);
if (inDirectCallFunction && theFunction.isParameter(varIndex)) {
if (rType == NumberType) {
if (!convertParameter(rChild)) {
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
return NumberType;
}
markDCPNumberContext(rChild);
return NoType;
}
return rType;
} else if (theFunction.isNumberVar(varIndex)) {
if (rType != NumberType) {
n.removeChild(rChild);
n.addChildToBack(new Node(Token.TO_DOUBLE, rChild));
}
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
markDCPNumberContext(rChild);
return NumberType;
} else {
if (rType == NumberType) {
if (!convertParameter(rChild)) {
n.removeChild(rChild);
n.addChildToBack(new Node(Token.TO_OBJECT, rChild));
}
}
return NoType;
}
}
case Token.LE:
case Token.LT:
case Token.GE:
case Token.GT:
{
Node lChild = n.getFirstChild();
Node rChild = lChild.getNext();
int lType = rewriteForNumberVariables(lChild, NumberType);
int rType = rewriteForNumberVariables(rChild, NumberType);
markDCPNumberContext(lChild);
markDCPNumberContext(rChild);
if (convertParameter(lChild)) {
if (convertParameter(rChild)) {
return NoType;
} else if (rType == NumberType) {
n.putIntProp(Node.ISNUMBER_PROP, Node.RIGHT);
}
} else if (convertParameter(rChild)) {
if (lType == NumberType) {
n.putIntProp(Node.ISNUMBER_PROP, Node.LEFT);
}
} else {
if (lType == NumberType) {
if (rType == NumberType) {
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
} else {
n.putIntProp(Node.ISNUMBER_PROP, Node.LEFT);
}
} else {
if (rType == NumberType) {
n.putIntProp(Node.ISNUMBER_PROP, Node.RIGHT);
}
}
}
// we actually build a boolean value
return NoType;
}
case Token.ADD:
{
Node lChild = n.getFirstChild();
Node rChild = lChild.getNext();
int lType = rewriteForNumberVariables(lChild, NumberType);
int rType = rewriteForNumberVariables(rChild, NumberType);
if (convertParameter(lChild)) {
if (convertParameter(rChild)) {
return NoType;
}
if (rType == NumberType) {
n.putIntProp(Node.ISNUMBER_PROP, Node.RIGHT);
}
} else {
if (convertParameter(rChild)) {
if (lType == NumberType) {
n.putIntProp(Node.ISNUMBER_PROP, Node.LEFT);
}
} else {
if (lType == NumberType) {
if (rType == NumberType) {
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
return NumberType;
}
n.putIntProp(Node.ISNUMBER_PROP, Node.LEFT);
} else {
if (rType == NumberType) {
n.putIntProp(Node.ISNUMBER_PROP, Node.RIGHT);
}
}
}
}
return NoType;
}
case Token.BITXOR:
case Token.BITOR:
case Token.BITAND:
case Token.RSH:
case Token.LSH:
case Token.SUB:
case Token.MUL:
case Token.DIV:
case Token.MOD:
case Token.EXP:
{
Node lChild = n.getFirstChild();
Node rChild = lChild.getNext();
int lType = rewriteForNumberVariables(lChild, NumberType);
int rType = rewriteForNumberVariables(rChild, NumberType);
markDCPNumberContext(lChild);
markDCPNumberContext(rChild);
if (lType == NumberType) {
if (rType == NumberType) {
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
return NumberType;
}
if (!convertParameter(rChild)) {
n.removeChild(rChild);
n.addChildToBack(new Node(Token.TO_DOUBLE, rChild));
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
}
return NumberType;
}
if (rType == NumberType) {
if (!convertParameter(lChild)) {
n.removeChild(lChild);
n.addChildToFront(new Node(Token.TO_DOUBLE, lChild));
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
}
return NumberType;
}
// Numeric Type (Number or BigInt)
return AnyType;
}
case Token.BITNOT:
case Token.POS:
case Token.NEG:
{
Node child = n.getFirstChild();
int type = rewriteForNumberVariables(child, NumberType);
if (type == NumberType && !convertParameter(child)) {
n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH);
markDCPNumberContext(child);
return NumberType;
}
return NoType;
}
case Token.SETELEM:
case Token.SETELEM_OP:
{
Node arrayBase = n.getFirstChild();
Node arrayIndex = arrayBase.getNext();
Node rValue = arrayIndex.getNext();
int baseType = rewriteForNumberVariables(arrayBase, NumberType);
if (baseType == NumberType) {
if (!convertParameter(arrayBase)) {
n.removeChild(arrayBase);
n.addChildToFront(new Node(Token.TO_OBJECT, arrayBase));
}
}
int indexType = rewriteForNumberVariables(arrayIndex, NumberType);
if (indexType == NumberType) {
if (!convertParameter(arrayIndex)) {
// setting the ISNUMBER_PROP signals the codegen
// to use the OptRuntime.setObjectIndex that takes
// a double index
n.putIntProp(Node.ISNUMBER_PROP, Node.LEFT);
}
}
int rValueType = rewriteForNumberVariables(rValue, NumberType);
if (rValueType == NumberType) {
if (!convertParameter(rValue)) {
n.removeChild(rValue);
n.addChildToBack(new Node(Token.TO_OBJECT, rValue));
}
}
return NoType;
}
case Token.GETELEM:
{
Node arrayBase = n.getFirstChild();
Node arrayIndex = arrayBase.getNext();
int baseType = rewriteForNumberVariables(arrayBase, NumberType);
if (baseType == NumberType) {
if (!convertParameter(arrayBase)) {
n.removeChild(arrayBase);
n.addChildToFront(new Node(Token.TO_OBJECT, arrayBase));
}
}
int indexType = rewriteForNumberVariables(arrayIndex, NumberType);
if (indexType == NumberType) {
if (!convertParameter(arrayIndex)) {
// setting the ISNUMBER_PROP signals the codegen
// to use the OptRuntime.getObjectIndex that takes
// a double index
n.putIntProp(Node.ISNUMBER_PROP, Node.RIGHT);
}
}
return NoType;
}
case Token.CALL:
{
Node child = n.getFirstChild(); // the function node
// must be an object
rewriteAsObjectChildren(child, child.getFirstChild());
child = child.getNext(); // the first arg
OptFunctionNode target = (OptFunctionNode) n.getProp(Node.DIRECTCALL_PROP);
if (target != null) {
/*
we leave each child as a Number if it can be. The codegen will
handle moving the pairs of parameters.
*/
while (child != null) {
int type = rewriteForNumberVariables(child, NumberType);
if (type == NumberType) {
markDCPNumberContext(child);
}
child = child.getNext();
}
} else {
rewriteAsObjectChildren(n, child);
}
return NoType;
}
default:
{
rewriteAsObjectChildren(n, n.getFirstChild());
return NoType;
}
}
}