@Override public boolean enterCatchNode(final CatchNode catchNode) { enterDefault(catchNode); type("CatchClause"); comma(); property("param"); catchNode.getException().accept(this); comma(); final Node guard = catchNode.getExceptionCondition(); if (guard != null) { property("guard"); guard.accept(this); comma(); } property("body"); catchNode.getBody().accept(this); return leave(); }
@Override public Node leaveForNode(final ForNode forNode) { ForNode newForNode = forNode; final Expression test = forNode.getTest(); if (!forNode.isForIn() && isAlwaysTrue(test)) { newForNode = forNode.setTest(lc, null); } newForNode = checkEscape(newForNode); if(newForNode.isForIn()) { // Wrap it in a block so its internally created iterator is restricted in scope addStatementEnclosedInBlock(newForNode); } else { addStatement(newForNode); } return newForNode; }
@Override public <T extends Node> T pop(final T node) { final T popped = super.pop(node); if (isWithBoundary(node)) { dynamicScopeCount--; assert dynamicScopeCount >= 0; } else if (node instanceof FunctionNode) { if (((FunctionNode)node).inDynamicContext()) { dynamicScopeCount--; assert dynamicScopeCount >= 0; } assert splitNodes.peek() == 0; splitNodes.pop(); } return popped; }
@Override public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) { final Expression expr = expressionStatement.getExpression(); ExpressionStatement node = expressionStatement; final FunctionNode currentFunction = lc.getCurrentFunction(); if (currentFunction.isProgram()) { if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) { node = expressionStatement.setExpression( new BinaryNode( Token.recast( expressionStatement.getToken(), TokenType.ASSIGN), compilerConstant(RETURN), expr)); } } if (es6 && expressionStatement.destructuringDeclarationType() != null) { throwNotImplementedYet("es6.destructuring", expressionStatement); } return addStatement(node); }
@Override public Node leaveIdentNode(final IdentNode identNode) { if (identNode.isPropertyName()) { return identNode; } final Symbol symbol = nameIsUsed(identNode.getName(), identNode); if (!identNode.isInitializedHere()) { symbol.increaseUseCount(); } IdentNode newIdentNode = identNode.setSymbol(symbol); // If a block-scoped var is used before its declaration mark it as dead. // We can only statically detect this for local vars, cross-function symbols require runtime checks. if (symbol.isBlockScoped() && !symbol.hasBeenDeclared() && !identNode.isDeclaredHere() && isLocal(lc.getCurrentFunction(), symbol)) { newIdentNode = newIdentNode.markDead(); } return end(newIdentNode); }
private boolean start(final Node node, final boolean printNode) { if (debug) { final StringBuilder sb = new StringBuilder(); sb.append("[ENTER "). append(name(node)). append("] "). append(printNode ? node.toString() : ""). append(" in '"). append(lc.getCurrentFunction().getName()). append("'"); log.info(sb); log.indent(); } return true; }
private Node leaveTYPEOF(final UnaryNode unaryNode) { final Expression rhs = unaryNode.getExpression(); final List<Expression> args = new ArrayList<>(); if (rhs instanceof IdentNode && !isParamOrVar((IdentNode)rhs)) { args.add(compilerConstantIdentifier(SCOPE)); args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName())); //null } else { args.add(rhs); args.add(LiteralNode.newInstance(unaryNode)); //null, do not reuse token of identifier rhs, it can be e.g. 'this' } final Node runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args); end(unaryNode); return runtimeNode; }
@Override public Node leaveForNode(final ForNode forNode) { ForNode newForNode = forNode; final Expression test = forNode.getTest(); if (!forNode.isForInOrOf() && isAlwaysTrue(test)) { newForNode = forNode.setTest(lc, null); } newForNode = checkEscape(newForNode); if(!es6 && newForNode.isForInOrOf()) { // Wrap it in a block so its internally created iterator is restricted in scope, unless we are running // in ES6 mode, in which case the parser already created a block to capture let/const declarations. addStatementEnclosedInBlock(newForNode); } else { addStatement(newForNode); } return newForNode; }
@Override public Node leaveIdentNode(final IdentNode identNode) { if(identNode.isPropertyName()) { return identNode; } return setProgramPoint(identNode); }
private static boolean isNumericArray(final Node[] values) { for (final Node node : values) { if (node instanceof LiteralNode && ((LiteralNode<?>)node).getValue() instanceof Number) { continue; } return false; } return true; }
private <T extends Node> T end(final T node, final boolean printNode) { if (debug) { final StringBuilder sb = new StringBuilder(); sb.append("[LEAVE "). append(name(node)). append("] "). append(printNode ? node.toString() : ""). append(" in '"). append(lc.getCurrentFunction().getName()). append('\''); if (node instanceof IdentNode) { final Symbol symbol = ((IdentNode)node).getSymbol(); if (symbol == null) { sb.append(" <NO SYMBOL>"); } else { sb.append(" <symbol=").append(symbol).append('>'); } } log.unindent(); log.info(sb); } return node; }
@Override public Node leaveLiteralNode(final LiteralNode<?> literalNode) { //for e.g. ArrayLiteralNodes the initial types may have been narrowed due to the //introduction of optimistic behavior - hence ensure that all literal nodes are //reinitialized return literalNode.initialize(lc); }
@Override public Node leaveCaseNode(final CaseNode caseNode) { // Try to represent the case test as an integer final Node test = caseNode.getTest(); if (test instanceof LiteralNode) { final LiteralNode<?> lit = (LiteralNode<?>)test; if (lit.isNumeric() && !(lit.getValue() instanceof Integer)) { if (JSType.isRepresentableAsInt(lit.getNumber())) { return caseNode.setTest((Expression)LiteralNode.newInstance(lit, lit.getInt32()).accept(this)); } } } return caseNode; }
@Override public Node leaveTernaryNode(final TernaryNode ternaryNode) { final Node test = ternaryNode.getTest(); if (test instanceof LiteralNode.PrimitiveLiteralNode) { return (((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression()).getExpression(); } return ternaryNode; }
@Override protected boolean enterDefault(final Node node) { objectStart(); location(node); return true; }
@Override public Node leaveIndexNode(final IndexNode indexNode) { final String name = getConstantPropertyName(indexNode.getIndex()); if (name != null) { // If index node is a constant property name convert index node to access node. assert indexNode.isIndex(); return new AccessNode(indexNode.getToken(), indexNode.getFinish(), indexNode.getBase(), name); } return super.leaveIndexNode(indexNode); }
@SuppressWarnings("rawtypes") @Override public boolean enterLiteralNode(final LiteralNode literalNode) { weight += LITERAL_WEIGHT; if (literalNode instanceof ArrayLiteralNode) { final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode; final Node[] value = arrayLiteralNode.getValue(); final int[] postsets = arrayLiteralNode.getPostsets(); final List<Splittable.SplitRange> units = arrayLiteralNode.getSplitRanges(); if (units == null) { for (final int postset : postsets) { weight += AASTORE_WEIGHT; final Node element = value[postset]; if (element != null) { element.accept(this); } } } return false; } return true; }
/** * Is this an assignment to the special variable that hosts scripting eval * results, i.e. __return__? * * @param expression expression to check whether it is $evalresult = X * @return true if an assignment to eval result, false otherwise */ private static boolean isEvalResultAssignment(final Node expression) { final Node e = expression; if (e instanceof BinaryNode) { final Node lhs = ((BinaryNode)e).lhs(); if (lhs instanceof IdentNode) { return ((IdentNode)lhs).getName().equals(RETURN.symbolName()); } } return false; }
/** * Try to do the apply to call transformation * @return true if successful, false otherwise */ @Override public Node leaveFunctionNode(final FunctionNode functionNode) { FunctionNode newFunctionNode = functionNode; final String functionName = newFunctionNode.getName(); if (changed.contains(newFunctionNode.getId())) { newFunctionNode = newFunctionNode.clearFlag(lc, FunctionNode.USES_ARGUMENTS). setFlag(lc, FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION). setParameters(lc, explodedArguments.peek()); if (log.isEnabled()) { log.info("Success: ", massageURL(newFunctionNode.getSource().getURL()), '.', functionName, "' id=", newFunctionNode.getId(), " params=", callSiteTypes.peek()); } } callSiteTypes.pop(); explodedArguments.pop(); return newFunctionNode.setState(lc, CompilationState.BUILTINS_TRANSFORMED); }
private Node leaveASSIGN(final BinaryNode binaryNode) { // If we're assigning a property of the this object ("this.foo = ..."), record it. final Expression lhs = binaryNode.lhs(); if (lhs instanceof AccessNode) { final AccessNode accessNode = (AccessNode) lhs; final Expression base = accessNode.getBase(); if (base instanceof IdentNode) { final Symbol symbol = ((IdentNode)base).getSymbol(); if(symbol.isThis()) { thisProperties.peek().add(accessNode.getProperty()); } } } return binaryNode; }
private void location(final Node node) { if (includeLocation) { objectStart("loc"); // source name final Source src = lc.getCurrentFunction().getSource(); property("source", src.getName()); comma(); // start position objectStart("start"); final int start = node.getStart(); property("line", src.getLine(start)); comma(); property("column", src.getColumn(start)); objectEnd(); comma(); // end position objectStart("end"); final int end = node.getFinish(); property("line", src.getLine(end)); comma(); property("column", src.getColumn(end)); objectEnd(); // end 'loc' objectEnd(); comma(); } }
@Override public Node leaveSwitchNode(final SwitchNode switchNode) { // We only need a symbol for the tag if it's not an integer switch node if(!switchNode.isUniqueInteger()) { return switchNode.setTag(lc, newObjectInternal(SWITCH_TAG_PREFIX)); } return switchNode; }
@Override public Node leaveBinaryNode(final BinaryNode binaryNode) { if (binaryNode.isAssignment() && binaryNode.lhs() instanceof IdentNode) { checkConstAssignment((IdentNode) binaryNode.lhs()); } switch (binaryNode.tokenType()) { case ASSIGN: return leaveASSIGN(binaryNode); default: return super.leaveBinaryNode(binaryNode); } }
@Override public Node leaveVarNode(final VarNode varNode) { addStatement(varNode); if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && lc.getCurrentFunction().isProgram()) { new ExpressionStatement(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this); } return varNode; }
@SuppressWarnings("rawtypes") @Override public boolean enterLiteralNode(final LiteralNode literalNode) { weight += LITERAL_WEIGHT; if (literalNode instanceof ArrayLiteralNode) { final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode; final Node[] value = arrayLiteralNode.getValue(); final int[] postsets = arrayLiteralNode.getPostsets(); final List<ArrayUnit> units = arrayLiteralNode.getUnits(); if (units == null) { for (final int postset : postsets) { weight += AASTORE_WEIGHT; final Node element = value[postset]; if (element != null) { element.accept(this); } } } return false; } return true; }
@Override public Node leaveWhileNode(final WhileNode whileNode) { final Expression test = whileNode.getTest(); final Block body = whileNode.getBody(); if (isAlwaysTrue(test)) { //turn it into a for node without a test. final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, 0).accept(this); lc.replace(whileNode, forNode); return forNode; } return addStatement(checkEscape(whileNode)); }
@Override protected Node leaveDefault(final Node node) { if(node instanceof Optimistic) { return leaveOptimistic((Optimistic)node); } return node; }
@Override public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
TreeImpl(final Node node) { this.node = node; }
@Override public Node leaveBIND(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
@Override public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) { weight += BREAK_WEIGHT; return jumpToInlinedFinally; }
@Override public Node leaveINSTANCEOF(final BinaryNode binaryNode) { return new RuntimeNode(binaryNode); }
@Override public Node leaveFunctionNode(final FunctionNode functionNode) { nextProgramPoint.pop(); return functionNode; }
@Override public Node leaveLT(final BinaryNode binaryNode) { return compareWeight(binaryNode); }
@Override public Node leaveASSIGN_ADD(final BinaryNode binaryNode) { weight += ADD_WEIGHT; return binaryNode; }
@Override public Node leaveSUB(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
@Override public Node leaveReturnNode(final ReturnNode returnNode) { addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor return returnNode; }
@Override protected boolean enterDefault(final Node node) { throw new AssertionError("Code generator entered node of type " + node.getClass().getName()); }
@Override public Node leaveUnaryNode(final UnaryNode unaryNode) { return setProgramPoint(unaryNode); }
@Override public Node leaveSUB(final UnaryNode unaryNode) { return unaryNodeWeight(unaryNode); }