/** * When we eliminate dead code, we must preserve var declarations as they are scoped to the whole * function. This method gathers var nodes from code passed to it, removing their initializers. * * @param deadCodeRoot the root node of eliminated dead code * @param statements a list that will be receiving the var nodes from the dead code, with their * initializers removed. */ static void extractVarNodesFromDeadCode(final Node deadCodeRoot, final List<Statement> statements) { deadCodeRoot.accept(new SimpleNodeVisitor() { @Override public boolean enterVarNode(final VarNode varNode) { statements.add(varNode.setInit(null)); return false; } @Override public boolean enterFunctionNode(final FunctionNode functionNode) { // Don't descend into nested functions return false; } }); }
private static List<FunctionNode> directChildren(final FunctionNode functionNode) { final List<FunctionNode> dc = new ArrayList<>(); functionNode.accept(new SimpleNodeVisitor() { @Override public boolean enterFunctionNode(final FunctionNode child) { if (child == functionNode) { return true; } if (lc.getParentFunction(child) == functionNode) { dc.add(child); } return false; } }); return dc; }
private boolean hasApplies(final FunctionNode functionNode) { try { functionNode.accept(new SimpleNodeVisitor() { @Override public boolean enterFunctionNode(final FunctionNode fn) { return fn == functionNode; } @Override public boolean enterCallNode(final CallNode callNode) { if (isApply(callNode)) { throw HAS_APPLIES; } return true; } }); } catch (final AppliesFoundException e) { return true; } log.fine("There are no applies in ", DebugLogger.quote(functionNode.getName()), " - nothing to do."); return false; // no applies }
/** * Define symbols for all variable declarations at the top of the function scope. This way we can get around * problems like * * while (true) { * break; * if (true) { * var s; * } * } * * to an arbitrary nesting depth. * * see NASHORN-73 * * @param functionNode the FunctionNode we are entering * @param body the body of the FunctionNode we are entering */ private void acceptDeclarations(final FunctionNode functionNode, final Block body) { // This visitor will assign symbol to all declared variables. body.accept(new SimpleNodeVisitor() { @Override protected boolean enterDefault(final Node node) { // Don't bother visiting expressions; var is a statement, it can't be inside an expression. // This will also prevent visiting nested functions (as FunctionNode is an expression). return !(node instanceof Expression); } @Override public Node leaveVarNode(final VarNode varNode) { final IdentNode ident = varNode.getName(); final boolean blockScoped = varNode.isBlockScoped(); if (blockScoped && lc.inUnprotectedSwitchContext()) { throwUnprotectedSwitchError(varNode); } final Block block = blockScoped ? lc.getCurrentBlock() : body; final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags()); if (varNode.isFunctionDeclaration()) { symbol.setIsFunctionDeclaration(); } return varNode.setName(ident.setSymbol(symbol)); } }); }
@SuppressWarnings("unchecked") private static <T extends Node> T ensureUniqueNamesIn(final T node) { return (T)node.accept(new SimpleNodeVisitor() { @Override public Node leaveFunctionNode(final FunctionNode functionNode) { final String name = functionNode.getName(); return functionNode.setName(lc, lc.getCurrentFunction().uniqueName(name)); } @Override public Node leaveDefault(final Node labelledNode) { return labelledNode.ensureUniqueLabels(lc); } }); }
@Override FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { // It's not necessary to guard the marking of symbols as locals with this "if" condition for // correctness, it's just an optimization -- runtime type calculation is not used when the compilation // is not an on-demand optimistic compilation, so we can skip locals marking then. if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) { fn.getBody().accept(new SimpleNodeVisitor() { @Override public boolean enterFunctionNode(final FunctionNode functionNode) { // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand // compilation, and we're skipping parsing the function bodies for nested functions, this // basically only means their parameters. It'd be enough to mistakenly declare to be a local a // symbol in the outer function named the same as one of the parameters, though. return false; }; @Override public boolean enterBlock(final Block block) { for (final Symbol symbol: block.getSymbols()) { if (!symbol.isScope()) { compiler.declareLocalSymbol(symbol.getName()); } } return true; }; }); } return fn; }
/** * Check if a property value contains a particular program point * @param value value * @param pp program point * @return true if it's there. */ private static boolean propertyValueContains(final Expression value, final int pp) { return new Supplier<Boolean>() { boolean contains; @Override public Boolean get() { value.accept(new SimpleNodeVisitor() { @Override public boolean enterFunctionNode(final FunctionNode functionNode) { return false; } @Override public boolean enterDefault(final Node node) { if (contains) { return false; } if (node instanceof Optimistic && ((Optimistic)node).getProgramPoint() == pp) { contains = true; return false; } return true; } }); return contains; } }.get(); }
/** * Was this expression or any of its subexpressions deoptimized in the current recompilation chain of rest-of methods? * @param rootExpr the expression being tested * @return true if the expression or any of its subexpressions was deoptimized in the current recompilation chain. */ private boolean isDeoptimizedExpression(final Expression rootExpr) { if(!isRestOf()) { return false; } return new Supplier<Boolean>() { boolean contains; @Override public Boolean get() { rootExpr.accept(new SimpleNodeVisitor() { @Override public boolean enterFunctionNode(final FunctionNode functionNode) { return false; } @Override public boolean enterDefault(final Node node) { if(!contains && node instanceof Optimistic) { final int pp = ((Optimistic)node).getProgramPoint(); contains = isValid(pp) && isContinuationEntryPoint(pp); } return !contains; } }); return contains; } }.get(); }
/** * Check if a property value contains a particular program point * @param value value * @param pp program point * @return true if it's there. */ private static boolean propertyValueContains(final Expression value, final int pp) { return new Supplier<Boolean>() { boolean contains; @Override public Boolean get() { value.accept(new SimpleNodeVisitor() { @Override public boolean enterFunctionNode(final FunctionNode functionNode) { return false; } @Override public boolean enterObjectNode(final ObjectNode objectNode) { return false; } @Override public boolean enterDefault(final Node node) { if (contains) { return false; } if (node instanceof Optimistic && ((Optimistic)node).getProgramPoint() == pp) { contains = true; return false; } return true; } }); return contains; } }.get(); }
/** * Define symbols for all variable declarations at the top of the function * scope. This way we can get around problems like * * while (true) { break; if (true) { var s; } } * * to an arbitrary nesting depth. * * see NASHORN-73 * * @param functionNode the FunctionNode we are entering * @param body the body of the FunctionNode we are entering */ private void acceptDeclarations(final FunctionNode functionNode, final Block body) { // This visitor will assign symbol to all declared variables. body.accept(new SimpleNodeVisitor() { @Override protected boolean enterDefault(final Node node) { // Don't bother visiting expressions; var is a statement, it can't be inside an expression. // This will also prevent visiting nested functions (as FunctionNode is an expression). return !(node instanceof Expression); } @Override public Node leaveVarNode(final VarNode varNode) { final IdentNode ident = varNode.getName(); final boolean blockScoped = varNode.isBlockScoped(); if (blockScoped && lc.inUnprotectedSwitchContext()) { throw new ParserException("UnprotectedSwitchError"); } final Block block = blockScoped ? lc.getCurrentBlock() : body; final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags()); if (varNode.isFunctionDeclaration()) { symbol.setIsFunctionDeclaration(); } return varNode.setName(ident.setSymbol(symbol)); } }); }