Java源码示例:jdk.nashorn.internal.ir.Block

示例1
@Override
public Node leaveIfNode(final IfNode ifNode) {
    final Node test = ifNode.getTest();
    if (test instanceof LiteralNode.PrimitiveLiteralNode) {
        final boolean isTrue = ((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue();
        final Block executed = isTrue ? ifNode.getPass() : ifNode.getFail();
        final Block dropped  = isTrue ? ifNode.getFail() : ifNode.getPass();
        final List<Statement> statements = new ArrayList<>();

        if (executed != null) {
            statements.addAll(executed.getStatements()); // Get statements form executed branch
        }
        if (dropped != null) {
            extractVarNodes(dropped, statements); // Get var-nodes from non-executed branch
        }
        if (statements.isEmpty()) {
            return new EmptyNode(ifNode);
        }
        return BlockStatement.createReplacement(ifNode, ifNode.getFinish(), statements);
    }
    return ifNode;
}
 
示例2
@Override
public boolean enterCatchNode(final CatchNode catchNode) {
    final IdentNode exception = catchNode.getException();
    final Block     block     = lc.getCurrentBlock();

    start(catchNode);

    // define block-local exception variable
    final String exname = exception.getName();
    // If the name of the exception starts with ":e", this is a synthetic catch block, likely a catch-all. Its
    // symbol is naturally internal, and should be treated as such.
    final boolean isInternal = exname.startsWith(EXCEPTION_PREFIX.symbolName());
    // IS_LET flag is required to make sure symbol is not visible outside catch block. However, we need to
    // clear the IS_LET flag after creation to allow redefinition of symbol inside the catch block.
    final Symbol symbol = defineSymbol(block, exname, catchNode, IS_VAR | IS_LET | (isInternal ? IS_INTERNAL : 0) | HAS_OBJECT_VALUE);
    symbol.clearFlag(IS_LET);

    return true;
}
 
示例3
@Override
public Node leaveBlock(final Block block) {
    assert !block.isCatchBlock();

    Block newBlock = block;

    // Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have
    // been split already, so weigh again before splitting.
    long weight = WeighNodes.weigh(block, weightCache);
    if (weight >= SPLIT_THRESHOLD) {
        final FunctionNode currentFunction = lc.getCurrentFunction();
        newBlock = splitBlock(block, currentFunction);
        weight   = WeighNodes.weigh(newBlock, weightCache);
        lc.setFlag(currentFunction, FunctionNode.IS_SPLIT);
    }
    weightCache.put(newBlock, weight);
    return newBlock;
}
 
示例4
/**
 * Initialize parameters for function node. This may require specializing
 * types if a specialization profile is known
 *
 * @param functionNode the function node
 */
private void initParameters(final FunctionNode functionNode, final Block body) {
    int pos = 0;
    for (final IdentNode param : functionNode.getParameters()) {
        addLocalDef(param.getName());

        final Type callSiteParamType = functionNode.getHints().getParameterType(pos);
        int flags = IS_PARAM;
        if (callSiteParamType != null) {
            LOG.info("Param ", param, " has a callsite type ", callSiteParamType, ". Using that.");
            flags |= Symbol.IS_SPECIALIZED_PARAM;
        }

        final Symbol paramSymbol = defineSymbol(body, param.getName(), flags);
        assert paramSymbol != null;

        newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType);

        LOG.info("Initialized param ", pos, "=", paramSymbol);
        pos++;
    }

}
 
示例5
@Override
public boolean enterBlock(final Block block) {
    start(block);

    if (lc.isFunctionBody()) {
        assert !block.hasSymbols();
        final FunctionNode fn = lc.getCurrentFunction();
        if (isUnparsedFunction(fn)) {
            // It's a skipped nested function. Just mark the symbols being used by it as being in use.
            for(final String name: compiler.getScriptFunctionData(fn.getId()).getExternalSymbolNames()) {
                nameIsUsed(name, null);
            }
            // Don't bother descending into it, it must be empty anyway.
            assert block.getStatements().isEmpty();
            return false;
        }

        enterFunctionBody();
    }

    return true;
}
 
示例6
@Override
public Node leaveIfNode(final IfNode ifNode) {
    final Node test = ifNode.getTest();
    if (test instanceof LiteralNode.PrimitiveLiteralNode) {
        final boolean isTrue = ((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue();
        final Block executed = isTrue ? ifNode.getPass() : ifNode.getFail();
        final Block dropped  = isTrue ? ifNode.getFail() : ifNode.getPass();
        final List<Statement> statements = new ArrayList<>();

        if (executed != null) {
            statements.addAll(executed.getStatements()); // Get statements form executed branch
        }
        if (dropped != null) {
            extractVarNodesFromDeadCode(dropped, statements); // Get var-nodes from non-executed branch
        }
        if (statements.isEmpty()) {
            return new EmptyNode(ifNode);
        }
        return BlockStatement.createReplacement(ifNode, ifNode.getFinish(), statements);
    }
    return ifNode;
}
 
示例7
private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) {
    initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL | HAS_OBJECT_VALUE);
    initCompileConstant(THIS, body, IS_PARAM | IS_THIS | HAS_OBJECT_VALUE);

    if (functionNode.isVarArg()) {
        initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL | HAS_OBJECT_VALUE);
        if (functionNode.needsArguments()) {
            initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | HAS_OBJECT_VALUE);
            defineSymbol(body, ARGUMENTS_VAR.symbolName(), null, IS_VAR | HAS_OBJECT_VALUE);
        }
    }

    initParameters(functionNode, body);
    initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | HAS_OBJECT_VALUE);
    initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL);
}
 
示例8
private void defineFunctionSelfSymbol(final FunctionNode functionNode, final Block body) {
    // Function self-symbol is only declared as a local variable for named function expressions. Declared functions
    // don't need it as they are local variables in their declaring scope.
    if (!functionNode.isNamedFunctionExpression()) {
        return;
    }

    final String name = functionNode.getIdent().getName();
    assert name != null; // As it's a named function expression.

    if (body.getExistingSymbol(name) != null) {
        // Body already has a declaration for the name. It's either a parameter "function x(x)" or a
        // top-level variable "function x() { ... var x; ... }".
        return;
    }

    defineSymbol(body, name, functionNode, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
    if(functionNode.allVarsInScope()) { // basically, has deep eval
        // We must conservatively presume that eval'd code can dynamically use the function symbol.
        lc.setFlag(functionNode, FunctionNode.USES_SELF_SYMBOL);
    }
}
 
示例9
@Override
public Node leaveBlock(final Block block) {
    if (!artificialBlock) {
        if (lc.isFunctionBody()) {
            // Prepend declaration-only var statements to the top of the statement list.
            lc.prependStatements(getCurrentFunctionState().varStatements);
        } else if (lc.isSplitBody()) {
            appendSplitReturn(FALLTHROUGH_STATE, NO_LINE_NUMBER);
            if (getCurrentFunctionState().fn.isProgram()) {
                // If we're splitting the program, make sure every shard ends with "return :return" and
                // begins with ":return = :return-in;".
                lc.prependStatement(new ExpressionStatement(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH,
                        new BinaryNode(Token.toDesc(TokenType.ASSIGN, 0, 0), createReturnIdent(), createReturnParamIdent())));
            }
        }
    }
    return block;
}
 
示例10
/**
 * ...IterationStatement :
 *           ...
 *           while ( Expression ) Statement
 *           ...
 *
 * See 12.6
 *
 * Parse while statement.
 */
private void whileStatement() {
    // Capture WHILE token.
    final long whileToken = token;
    // WHILE tested in caller.
    next();

    // Construct WHILE node.
    WhileNode whileNode = new WhileNode(line, whileToken, Token.descPosition(whileToken), false);
    lc.push(whileNode);

    try {
        expect(LPAREN);
        final int whileLine = line;
        final JoinPredecessorExpression test = joinPredecessorExpression();
        expect(RPAREN);
        final Block body = getStatement();
        appendStatement(whileNode =
            new WhileNode(whileLine, whileToken, finish, false).
                setTest(lc, test).
                setBody(lc, body));
    } finally {
        lc.pop(whileNode);
    }
}
 
示例11
/**
 * ...IterationStatement :
 *           ...
 *           while ( Expression ) Statement
 *           ...
 *
 * See 12.6
 *
 * Parse while statement.
 */
private void whileStatement() {
    // Capture WHILE token.
    final long whileToken = token;
    // WHILE tested in caller.
    next();

    // Construct WHILE node.
    WhileNode whileNode = new WhileNode(line, whileToken, Token.descPosition(whileToken), false);
    lc.push(whileNode);

    try {
        expect(LPAREN);
        final int whileLine = line;
        final JoinPredecessorExpression test = joinPredecessorExpression();
        expect(RPAREN);
        final Block body = getStatement();
        appendStatement(whileNode =
            new WhileNode(whileLine, whileToken, finish, false).
                setTest(lc, test).
                setBody(lc, body));
    } finally {
        lc.pop(whileNode);
    }
}
 
示例12
static int findScopesToStart(final LexicalContext lc, final FunctionNode fn, final Block block) {
    final Block bodyBlock = findBodyBlock(lc, fn, block);
    final Iterator<Block> iter = lc.getBlocks(block);
    Block b = iter.next();
    int scopesToStart = 0;
    while (true) {
        if (b.needsScope()) {
            scopesToStart++;
        }
        if (b == bodyBlock) {
            break;
        }
        b = iter.next();
    }
    return scopesToStart;
}
 
示例13
@Override
public boolean enterBlock(final Block block) {
    boolean cloned = false;
    for(final Symbol symbol: block.getSymbols()) {
        if(symbol.isBytecodeLocal()) {
            if (getLocalVariableTypeOrNull(symbol) == null) {
                if (!cloned) {
                    cloneOrNewLocalVariableTypes();
                    cloned = true;
                }
                localVariableTypes.put(symbol, LvarType.UNDEFINED);
            }
            // In case we're repeating analysis of a lexical scope (e.g. it's in a loop),
            // make sure all symbols lexically scoped by the block become valid again.
            invalidatedSymbols.remove(symbol);
        }
    }
    return true;
}
 
示例14
@Override
public boolean enterBlock(final Block block) {
    boolean cloned = false;
    for(final Symbol symbol: block.getSymbols()) {
        if(symbol.isBytecodeLocal()) {
            if (getLocalVariableTypeOrNull(symbol) == null) {
                if (!cloned) {
                    cloneOrNewLocalVariableTypes();
                    cloned = true;
                }
                localVariableTypes.put(symbol, LvarType.UNDEFINED);
            }
            // In case we're repeating analysis of a lexical scope (e.g. it's in a loop),
            // make sure all symbols lexically scoped by the block become valid again.
            invalidatedSymbols.remove(symbol);
        }
    }
    return true;
}
 
示例15
private Map<Symbol, LvarType> getBreakTargetTypes(final LexicalContextNode target) {
    // Remove symbols defined in the the blocks that are being broken out of.
    Map<Symbol, LvarType> types = localVariableTypes;
    for(final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
        final LexicalContextNode node = it.next();
        if(node instanceof Block) {
            for(final Symbol symbol: ((Block)node).getSymbols()) {
                if(localVariableTypes.containsKey(symbol)) {
                    if(types == localVariableTypes) {
                        types = cloneMap(localVariableTypes);
                    }
                    types.remove(symbol);
                }
            }
        }
        if(node == target) {
            break;
        }
    }
    return types;
}
 
示例16
/**
 * Initialize parameters for function node. This may require specializing
 * types if a specialization profile is known
 *
 * @param functionNode the function node
 */
private void initParameters(final FunctionNode functionNode, final Block body) {
    int pos = 0;
    for (final IdentNode param : functionNode.getParameters()) {
        addLocalDef(param.getName());

        final Type callSiteParamType = functionNode.getHints().getParameterType(pos);
        int flags = IS_PARAM;
        if (callSiteParamType != null) {
            LOG.info("Param ", param, " has a callsite type ", callSiteParamType, ". Using that.");
            flags |= Symbol.IS_SPECIALIZED_PARAM;
        }

        final Symbol paramSymbol = defineSymbol(body, param.getName(), flags);
        assert paramSymbol != null;

        newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType);

        LOG.info("Initialized param ", pos, "=", paramSymbol);
        pos++;
    }

}
 
示例17
@Override
public boolean enterBlock(final Block block) {
    start(block);

    if (lc.isFunctionBody()) {
        assert !block.hasSymbols();
        final FunctionNode fn = lc.getCurrentFunction();
        if (isUnparsedFunction(fn)) {
            // It's a skipped nested function. Just mark the symbols being used by it as being in use.
            for(final String name: compiler.getScriptFunctionData(fn.getId()).getExternalSymbolNames()) {
                nameIsUsed(name, null);
            }
            // Don't bother descending into it, it must be empty anyway.
            assert block.getStatements().isEmpty();
            return false;
        }

        enterFunctionBody();
    }

    return true;
}
 
示例18
private Map<Symbol, LvarType> getBreakTargetTypes(final LexicalContextNode target) {
    // Remove symbols defined in the the blocks that are being broken out of.
    Map<Symbol, LvarType> types = localVariableTypes;
    for(final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
        final LexicalContextNode node = it.next();
        if(node instanceof Block) {
            for(final Symbol symbol: ((Block)node).getSymbols()) {
                if(localVariableTypes.containsKey(symbol)) {
                    if(types == localVariableTypes) {
                        types = cloneMap(localVariableTypes);
                    }
                    types.remove(symbol);
                }
            }
        }
        if(node == target) {
            break;
        }
    }
    return types;
}
 
示例19
private static Block createFinallyBlock(final Block finallyBody) {
    final List<Statement> newStatements = new ArrayList<>();
    for (final Statement statement : finallyBody.getStatements()) {
        newStatements.add(statement);
        if (statement.hasTerminalFlags()) {
            break;
        }
    }
    return finallyBody.setStatements(null, newStatements);
}
 
示例20
@Override
public boolean enterIfNode(final IfNode ifNode) {
    lineNumber(ifNode);

    final Expression test = ifNode.getTest();
    final Block pass = ifNode.getPass();
    final Block fail = ifNode.getFail();

    final Label failLabel  = new Label("if_fail");
    final Label afterLabel = fail == null ? failLabel : new Label("if_done");

    new BranchOptimizer(this, method).execute(test, failLabel, false);

    boolean passTerminal = false;
    boolean failTerminal = false;

    pass.accept(this);
    if (!pass.hasTerminalFlags()) {
        method._goto(afterLabel); //don't fallthru to fail block
    } else {
        passTerminal = pass.isTerminal();
    }

    if (fail != null) {
        method.label(failLabel);
        fail.accept(this);
        failTerminal = fail.isTerminal();
    }

    //if if terminates, put the after label there
    if (!passTerminal || !failTerminal) {
        method.label(afterLabel);
    }

    return false;
}
 
示例21
private static Block prependFinally(final Block finallyBlock, final Statement statement) {
    final Block inlinedFinally = ensureUniqueNamesIn(finallyBlock);
    if (isTerminalFinally(finallyBlock)) {
        return inlinedFinally;
    }
    final List<Statement> stmts = inlinedFinally.getStatements();
    final List<Statement> newStmts = new ArrayList<>(stmts.size() + 1);
    newStmts.addAll(stmts);
    newStmts.add(statement);
    return new Block(inlinedFinally.getToken(), statement.getFinish(), newStmts);
}
 
示例22
private int assignSlots(final Block block, final int firstSlot) {
    int fromSlot = firstSlot;
    final MethodEmitter method = methodEmitters.peek();
    for (final Symbol symbol : block.getSymbols()) {
        if (symbol.hasSlot()) {
            symbol.setFirstSlot(fromSlot);
            final int toSlot = fromSlot + symbol.slotCount();
            method.defineBlockLocalVariable(fromSlot, toSlot);
            fromSlot = toSlot;
        }
    }
    return fromSlot;
}
 
示例23
/**
 * ...IterationStatement :
 *           ...
 *           do Statement while( Expression ) ;
 *           ...
 *
 * See 12.6
 *
 * Parse DO WHILE statement.
 */
private void doStatement() {
    // Capture DO token.
    final long doToken = token;
    // DO tested in the caller.
    next();

    WhileNode doWhileNode = new WhileNode(-1, doToken, Token.descPosition(doToken), true);
    lc.push(doWhileNode);

    try {
       // Get DO body.
        final Block body = getStatement();

        expect(WHILE);
        expect(LPAREN);
        final int doLine = line;
        final JoinPredecessorExpression test = joinPredecessorExpression();
        expect(RPAREN);

        if (type == SEMICOLON) {
            endOfLine();
        }
        doWhileNode.setFinish(finish);

        //line number is last
        appendStatement(doWhileNode =
            new WhileNode(doLine, doToken, finish, true).
                setBody(lc, body).
                setTest(lc, test));
    } finally {
        lc.pop(doWhileNode);
    }
}
 
示例24
private static void extractVarNodes(final Block block, final List<Statement> statements) {
    final LexicalContext lc = new LexicalContext();
    block.accept(lc, new NodeVisitor<LexicalContext>(lc) {
        @Override
        public boolean enterVarNode(VarNode varNode) {
            statements.add(varNode.setInit(null));
            return false;
        }
    });
}
 
示例25
private FunctionNode createSyntheticInitializers(final FunctionNode functionNode) {
    final List<VarNode> syntheticInitializers = new ArrayList<>(2);

    // Must visit the new var nodes in the context of the body. We could also just set the new statements into the
    // block and then revisit the entire block, but that seems to be too much double work.
    final Block body = functionNode.getBody();
    lc.push(body);
    try {
        if (functionNode.usesSelfSymbol()) {
            // "var fn = :callee"
            syntheticInitializers.add(createSyntheticInitializer(functionNode.getIdent(), CALLEE, functionNode));
        }

        if (functionNode.needsArguments()) {
            // "var arguments = :arguments"
            syntheticInitializers.add(createSyntheticInitializer(createImplicitIdentifier(ARGUMENTS_VAR.symbolName()),
                    ARGUMENTS, functionNode));
        }

        if (syntheticInitializers.isEmpty()) {
            return functionNode;
        }

        for(final ListIterator<VarNode> it = syntheticInitializers.listIterator(); it.hasNext();) {
            it.set((VarNode)it.next().accept(this));
        }
    } finally {
        lc.pop(body);
    }

    final List<Statement> stmts = body.getStatements();
    final List<Statement> newStatements = new ArrayList<>(stmts.size() + syntheticInitializers.size());
    newStatements.addAll(syntheticInitializers);
    newStatements.addAll(stmts);
    return functionNode.setBody(lc, body.setStatements(lc, newStatements));
}
 
示例26
/**
 * Search for symbol in the lexical context starting from the given block.
 * @param name Symbol name.
 * @return Found symbol or null if not found.
 */
private Symbol findSymbol(final Block block, final String name) {
    for (final Iterator<Block> blocks = lc.getBlocks(block); blocks.hasNext();) {
        final Symbol symbol = blocks.next().getExistingSymbol(name);
        if (symbol != null) {
            return symbol;
        }
    }
    return null;
}
 
示例27
@Override
public boolean enterIfNode(final IfNode ifNode) {
    lineNumber(ifNode);

    final Expression test = ifNode.getTest();
    final Block pass = ifNode.getPass();
    final Block fail = ifNode.getFail();

    final Label failLabel  = new Label("if_fail");
    final Label afterLabel = fail == null ? failLabel : new Label("if_done");

    new BranchOptimizer(this, method).execute(test, failLabel, false);

    boolean passTerminal = false;
    boolean failTerminal = false;

    pass.accept(this);
    if (!pass.hasTerminalFlags()) {
        method._goto(afterLabel); //don't fallthru to fail block
    } else {
        passTerminal = pass.isTerminal();
    }

    if (fail != null) {
        method.label(failLabel);
        fail.accept(this);
        failTerminal = fail.isTerminal();
    }

    //if if terminates, put the after label there
    if (!passTerminal || !failTerminal) {
        method.label(afterLabel);
    }

    return false;
}
 
示例28
/**
 * Split a block into sub methods.
 *
 * @param block Block or function to split.
 *
 * @return new weight for the resulting block.
 */
private Block splitBlock(final Block block, final FunctionNode function) {

    final List<Statement> splits = new ArrayList<>();
    List<Statement> statements = new ArrayList<>();
    long statementsWeight = 0;

    for (final Statement statement : block.getStatements()) {
        final long weight = WeighNodes.weigh(statement, weightCache);

        if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) {
            if (!statements.isEmpty()) {
                splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
                statements = new ArrayList<>();
                statementsWeight = 0;
            }
        }

        if (statement.isTerminal()) {
            splits.add(statement);
        } else {
            statements.add(statement);
            statementsWeight += weight;
        }
    }

    if (!statements.isEmpty()) {
        splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
    }

    return block.setStatements(lc, splits);
}
 
示例29
/**
 * Determines if the symbol has to be a scope symbol. In general terms, it has to be a scope symbol if it can only
 * be reached from the current block by traversing a function node, a split node, or a with node.
 * @param symbol the symbol checked for needing to be a scope symbol
 * @return true if the symbol has to be a scope symbol.
 */
private boolean symbolNeedsToBeScope(final Symbol symbol) {
    if (symbol.isThis() || symbol.isInternal()) {
        return false;
    }

    final FunctionNode func = lc.getCurrentFunction();
    if ( func.allVarsInScope() || (!symbol.isBlockScoped() && func.isProgram())) {
        return true;
    }

    boolean previousWasBlock = false;
    for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
        final LexicalContextNode node = it.next();
        if (node instanceof FunctionNode || isSplitLiteral(node)) {
            // We reached the function boundary or a splitting boundary without seeing a definition for the symbol.
            // It needs to be in scope.
            return true;
        } else if (node instanceof WithNode) {
            if (previousWasBlock) {
                // We reached a WithNode; the symbol must be scoped. Note that if the WithNode was not immediately
                // preceded by a block, this means we're currently processing its expression, not its body,
                // therefore it doesn't count.
                return true;
            }
            previousWasBlock = false;
        } else if (node instanceof Block) {
            if (((Block)node).getExistingSymbol(symbol.getName()) == symbol) {
                // We reached the block that defines the symbol without reaching either the function boundary, or a
                // WithNode. The symbol need not be scoped.
                return false;
            }
            previousWasBlock = true;
        } else {
            previousWasBlock = false;
        }
    }
    throw new AssertionError();
}
 
示例30
@Override
public boolean enterBlock(final Block block) {
    if (block.isCatchBlock()) {
        return false;
    }

    final long weight = WeighNodes.weigh(block, weightCache);

    if (weight < SPLIT_THRESHOLD) {
        weightCache.put(block, weight);
        return false;
    }

    return true;
}