/* the type of an expression is relatively unknown. Cases we can be sure about are - Literals, Arithmetic operations - always return a Number */ private static int findExpressionType(OptFunctionNode fn, Node n, int[] varTypes) { switch (n.getType()) { case Token.NUMBER: return Optimizer.NumberType; case Token.CALL: case Token.NEW: case Token.REF_CALL: return Optimizer.AnyType; case Token.GETELEM: return Optimizer.AnyType; case Token.GETVAR: return varTypes[fn.getVarIndex(n)]; case Token.INC: case Token.DEC: case Token.MUL: case Token.DIV: case Token.MOD: case Token.BITOR: case Token.BITXOR: case Token.BITAND: case Token.LSH: case Token.RSH: case Token.URSH: case Token.SUB: case Token.POS: case Token.NEG: return Optimizer.NumberType; case Token.ARRAYLIT: case Token.OBJECTLIT: return Optimizer.AnyType; // XXX: actually, we know it's not // number, but no type yet for that case Token.ADD: { // if the lhs & rhs are known to be numbers, we can be sure that's // the result, otherwise it could be a string. Node child = n.getFirstChild(); int lType = findExpressionType(fn, child, varTypes); int rType = findExpressionType(fn, child.getNext(), varTypes); return lType | rType; // we're not distinguishing strings yet } } Node child = n.getFirstChild(); if (child == null) { return Optimizer.AnyType; } else { int result = Optimizer.NoType; while (child != null) { result |= findExpressionType(fn, child, varTypes); child = child.getNext(); } return result; } }
private void printLiveOnEntrySet(OptFunctionNode fn) { if (DEBUG) { for (int i = 0; i < fn.getVarCount(); i++) { String name = fn.fnode.getParamOrVarName(i); if (itsUseBeforeDefSet.test(i)) System.out.println(name + " is used before def'd"); if (itsNotDefSet.test(i)) System.out.println(name + " is not def'd"); if (itsLiveOnEntrySet.test(i)) System.out.println(name + " is live on entry"); if (itsLiveOnExitSet.test(i)) System.out.println(name + " is live on exit"); } } }
/* build the live on entry/exit sets. Then walk the trees looking for defs/uses of variables and build the def and useBeforeDef sets. */ private void initLiveOnEntrySets(OptFunctionNode fn, Node[] statementNodes) { int listLength = fn.getVarCount(); itsUseBeforeDefSet = new DataFlowBitSet(listLength); itsNotDefSet = new DataFlowBitSet(listLength); itsLiveOnEntrySet = new DataFlowBitSet(listLength); itsLiveOnExitSet = new DataFlowBitSet(listLength); for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) { Node n = statementNodes[i]; lookForVariableAccess(fn, n); } itsNotDefSet.not(); // truth in advertising }
private static boolean findDefPoints(OptFunctionNode fn, Node n, int[] varTypes) { boolean result = false; Node child = n.getFirstChild(); switch (n.getType()) { default: while (child != null) { result |= findDefPoints(fn, child, varTypes); child = child.getNext(); } break; case Token.DEC: case Token.INC: if (child.getType() == Token.GETVAR) { // theVar is a Number now int i = fn.getVarIndex(child); result |= assignType(varTypes, i, Optimizer.NumberType); } break; case Token.SETPROP: case Token.SETPROP_OP: if (child.getType() == Token.GETVAR) { int i = fn.getVarIndex(child); assignType(varTypes, i, Optimizer.AnyType); } while (child != null) { result |= findDefPoints(fn, child, varTypes); child = child.getNext(); } break; case Token.SETVAR: { Node rValue = child.getNext(); int theType = findExpressionType(fn, rValue, varTypes); int i = fn.getVarIndex(n); result |= assignType(varTypes, i, theType); break; } } return result; }
/* We're tracking uses and defs - in order to build the def set and to identify the last use nodes. The itsNotDefSet is built reversed then flipped later. */ private void lookForVariableAccess(OptFunctionNode fn, Node n) { switch (n.getType()) { case Token.DEC: case Token.INC: { Node child = n.getFirstChild(); if (child.getType() == Token.GETVAR) { int varIndex = fn.getVarIndex(child); if (!itsNotDefSet.test(varIndex)) itsUseBeforeDefSet.set(varIndex); itsNotDefSet.set(varIndex); } } break; case Token.SETVAR: { Node lhs = n.getFirstChild(); Node rhs = lhs.getNext(); lookForVariableAccess(fn, rhs); itsNotDefSet.set(fn.getVarIndex(n)); } break; case Token.GETVAR: { int varIndex = fn.getVarIndex(n); if (!itsNotDefSet.test(varIndex)) itsUseBeforeDefSet.set(varIndex); } break; default: Node child = n.getFirstChild(); while (child != null) { lookForVariableAccess(fn, child); child = child.getNext(); } break; } }
static void runFlowAnalyzes(OptFunctionNode fn, Node[] statementNodes) { int paramCount = fn.fnode.getParamCount(); int varCount = fn.fnode.getParamAndVarCount(); int[] varTypes = new int[varCount]; // If the variable is a parameter, it could have any type. for (int i = 0; i != paramCount; ++i) { varTypes[i] = Optimizer.AnyType; } // If the variable is from a "var" statement, its typeEvent will be set // when we see the setVar node. for (int i = paramCount; i != varCount; ++i) { varTypes[i] = Optimizer.NoType; } Block[] theBlocks = buildBlocks(statementNodes); if (DEBUG) { ++debug_blockCount; System.out.println( "-------------------" + fn.fnode.getFunctionName() + " " + debug_blockCount + "--------"); System.out.println(toString(theBlocks, statementNodes)); } reachingDefDataFlow(fn, statementNodes, theBlocks, varTypes); typeFlow(fn, statementNodes, theBlocks, varTypes); if (DEBUG) { for (int i = 0; i < theBlocks.length; i++) { System.out.println("For block " + theBlocks[i].itsBlockID); theBlocks[i].printLiveOnEntrySet(fn); } System.out.println("Variable Table, size = " + varCount); for (int i = 0; i != varCount; i++) { System.out.println("[" + i + "] type: " + varTypes[i]); } } for (int i = paramCount; i != varCount; i++) { if (varTypes[i] == Optimizer.NumberType) { fn.setIsNumberVar(i); } } }