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

示例1
/**
 * This has to run before fix assignment types, store any type specializations for
 * parameters, then turn them into objects for the generic version of this method.
 *
 * @param functionNode functionNode
 */
private FunctionNode finalizeParameters(final FunctionNode functionNode) {
    final List<IdentNode> newParams = new ArrayList<>();
    final boolean isVarArg = functionNode.isVarArg();

    final Block body = functionNode.getBody();
    for (final IdentNode param : functionNode.getParameters()) {
        final Symbol paramSymbol = body.getExistingSymbol(param.getName());
        assert paramSymbol != null;
        assert paramSymbol.isParam() : paramSymbol + " " + paramSymbol.getFlags();
        newParams.add(param.setSymbol(paramSymbol));

        // parameters should not be slots for a function that uses variable arity signature
        if (isVarArg) {
            paramSymbol.setNeedsSlot(false);
        }
    }

    return functionNode.setParameters(lc, newParams);
}
 
示例2
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
    if (functionNode.isLazy()) {
        return false;
    }

    // If the function doesn't need a callee, we ensure its __callee__ symbol doesn't get a slot. We can't do
    // this earlier, as access to scoped variables, self symbol, etc. in previous phases can all trigger the
    // need for the callee.
    if (!functionNode.needsCallee()) {
        functionNode.compilerConstant(CALLEE).setNeedsSlot(false);
    }
    // Similar reasoning applies to __scope__ symbol: if the function doesn't need either parent scope and none of
    // its blocks create a scope, we ensure it doesn't get a slot, but we can't determine whether it needs a scope
    // earlier than this phase.
    if (!(functionNode.hasScopeBlock() || functionNode.needsParentScope())) {
        functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
    }

    return true;
}
 
示例3
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
    final FunctionNode finalizedFunction;
    if (isUnparsedFunction(functionNode)) {
        finalizedFunction = functionNode;
    } else {
        finalizedFunction =
           markProgramBlock(
           removeUnusedSlots(
           createSyntheticInitializers(
           finalizeParameters(
                   lc.applyTopFlags(functionNode))))
                   .setThisProperties(lc, thisProperties.pop().size()));
    }
    return finalizedFunction;
}
 
示例4
/**
 * Constructor - public as scripts use it
 *
 * @param functionNode       functionNode that represents this function code
 * @param installer          installer for code regeneration versions of this function
 * @param allocatorClassName name of our allocator class, will be looked up dynamically if used as a constructor
 * @param allocatorMap       allocator map to seed instances with, when constructing
 */
public RecompilableScriptFunctionData(final FunctionNode functionNode, final CodeInstaller<ScriptEnvironment> installer, final String allocatorClassName, final PropertyMap allocatorMap) {
    super(functionNode.isAnonymous() ?
            "" :
            functionNode.getIdent().getName(),
          functionNode.getParameters().size(),
          functionNode.isStrict(),
          false,
          true);

    this.functionNode       = functionNode;
    this.source             = functionNode.getSource();
    this.token              = tokenFor(functionNode);
    this.installer          = installer;
    this.allocatorClassName = allocatorClassName;
    this.allocatorMap       = allocatorMap;
}
 
示例5
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
    if (functionNode.isLazy()) {
        return false;
    }

    // If the function doesn't need a callee, we ensure its __callee__ symbol doesn't get a slot. We can't do
    // this earlier, as access to scoped variables, self symbol, etc. in previous phases can all trigger the
    // need for the callee.
    if (!functionNode.needsCallee()) {
        functionNode.compilerConstant(CALLEE).setNeedsSlot(false);
    }
    // Similar reasoning applies to __scope__ symbol: if the function doesn't need either parent scope and none of
    // its blocks create a scope, we ensure it doesn't get a slot, but we can't determine whether it needs a scope
    // earlier than this phase.
    if (!(functionNode.hasScopeBlock() || functionNode.needsParentScope())) {
        functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
    }

    return true;
}
 
示例6
/**
 * 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;
        }
    });
}
 
示例7
/**
 * Sets the AST to cache in this function
 * @param astToCache the new AST to cache
 */
public void setCachedAst(final FunctionNode astToCache) {
    assert astToCache.getId() == functionNodeId; // same function
    assert !(cachedAst instanceof SerializedAst); // Can't overwrite serialized AST

    final boolean isSplit = astToCache.isSplit();
    // If we're caching a split function, we're doing it in the eager pass, hence there can be no other
    // cached representation already. In other words, isSplit implies cachedAst == null.
    assert !isSplit || cachedAst == null; //

    final FunctionNode symbolClonedAst = cloneSymbols(astToCache);
    final Reference<FunctionNode> ref = new SoftReference<>(symbolClonedAst);
    cachedAst = ref;

    // Asynchronously serialize split functions.
    if (isSplit) {
        astSerializerExecutorService.execute(() -> {
            cachedAst = new SerializedAst(symbolClonedAst, ref);
        });
    }
}
 
示例8
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
    start(functionNode, false);

    if (functionNode.isLazy()) {
        return false;
    }

    //an outermost function in our lexical context that is not a program (runScript)
    //is possible - it is a function being compiled lazily
    if (functionNode.isDeclared()) {
        final Iterator<Block> blocks = lc.getBlocks();
        if (blocks.hasNext()) {
            defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR);
        }
    }

    returnTypes.push(functionNode.getReturnType());
    pushLocalsFunction();

    return true;
}
 
示例9
private boolean hasApplies(final FunctionNode functionNode) {
    try {
        functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
            @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
}
 
示例10
@Override
public Node leaveBlock(final Block block) {
    //now we have committed the entire statement list to the block, but we need to truncate
    //whatever is after the last terminal. block append won't append past it


    if (lc.isFunctionBody()) {
        final FunctionNode currentFunction = lc.getCurrentFunction();
        final boolean isProgram = currentFunction.isProgram();
        final Statement last = lc.getLastStatement();
        final ReturnNode returnNode = new ReturnNode(
            last == null ? currentFunction.getLineNumber() : last.getLineNumber(), //TODO?
            currentFunction.getToken(),
            currentFunction.getFinish(),
            isProgram ?
                compilerConstant(RETURN) :
                LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED));

        returnNode.accept(this);
    }

    return block;
}
 
示例11
MethodType getCallSiteType(final FunctionNode functionNode) {
    assert this.functionNodeId == functionNode.getId();
    final Type[] types = paramTypes;
    MethodType mt = MethodType.methodType(returnType.getTypeClass());
    if (needsCallee) {
        mt = mt.appendParameterTypes(ScriptFunction.class);
    }

    mt = mt.appendParameterTypes(Object.class); //this

    for (final Type type : types) {
        if (type == null) {
            return null; // not all parameter information is supplied
        }
        mt = mt.appendParameterTypes(type.getTypeClass());
    }

    return mt;
}
 
示例12
/**
 * 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;
        }
    });
}
 
示例13
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
    try {
        if(emittedMethods.add(functionNode.getName())) {
            method.end(); // wrap up this method
            unit   = lc.popCompileUnit(functionNode.getCompileUnit());
            method = lc.popMethodEmitter(method);
            LOG.info("=== END ", functionNode.getName());
        }

        final FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED);
        newFunctionObject(newFunctionNode, functionNode);
        return newFunctionNode;
    } catch (final Throwable t) {
        Context.printStackTrace(t);
        final VerifyError e = new VerifyError("Code generation bug in \"" + functionNode.getName() + "\": likely stack misaligned: " + t + " " + functionNode.getSource().getName());
        e.initCause(t);
        throw e;
    }
}
 
示例14
private static List<FunctionNode> directChildren(final FunctionNode functionNode) {
    final List<FunctionNode> dc = new ArrayList<>();
    functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
        @Override
        public boolean enterFunctionNode(final FunctionNode child) {
            if (child == functionNode) {
                return true;
            }
            if (lc.getParentFunction(child) == functionNode) {
                dc.add(child);
            }
            return false;
        }
    });
    return dc;
}
 
示例15
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
}
 
示例16
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
    if (functionNode == topFunction) {
        // the function being weighted; descend into its statements
        return true;
    }
    // just a reference to inner function from outer function
    weight += FUNC_EXPR_WEIGHT;
    return false;
}
 
示例17
/**
 * Create a new split node from statements contained in a parent block.
 *
 * @param parent     Parent block.
 * @param statements Statements to include.
 *
 * @return New split node.
 */
private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Statement> statements, final long weight) {
    final long   token      = parent.getToken();
    final int    finish     = parent.getFinish();
    final String name       = function.uniqueName(SPLIT_PREFIX.symbolName());

    final Block newBlock = new Block(token, finish, statements);

    return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
}
 
示例18
/**
 * Constructor.
 *
 * @param functionNode the function node
 * @param invalidatedProgramPoints invalidated program points
 */
public FunctionInitializer(final FunctionNode functionNode, final Map<Integer, Type> invalidatedProgramPoints) {
    this.className  = functionNode.getCompileUnit().getUnitClassName();
    this.methodType = new FunctionSignature(functionNode).getMethodType();
    this.flags = functionNode.getFlags();
    this.invalidatedProgramPoints = invalidatedProgramPoints;

    final CompileUnit cu = functionNode.getCompileUnit();
    if (cu != null) {
        this.code = cu.getCode();
    }

    assert className != null;
}
 
示例19
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
    start(functionNode, false);

    thisProperties.push(new HashSet<String>());

    // Every function has a body, even the ones skipped on reparse (they have an empty one). We're
    // asserting this as even for those, enterBlock() must be invoked to correctly process symbols that
    // are used in them.
    assert functionNode.getBody() != null;

    return true;
}
 
示例20
private FunctionNode markProgramBlock(final FunctionNode functionNode) {
    if (isOnDemand || !functionNode.isProgram()) {
        return functionNode;
    }

    return functionNode.setBody(lc, functionNode.getBody().setFlag(lc, Block.IS_GLOBAL_SCOPE));
}
 
示例21
/**
 * Execute parse and return the resulting function node.
 * Errors will be thrown and the error manager will contain information
 * if parsing should fail
 *
 * This should be used to create one and only one function node
 *
 * @param scriptName name for the script, given to the parsed FunctionNode
 * @param startPos start position in source
 * @param len length of parse
 * @param allowPropertyFunction if true, "get" and "set" are allowed as first tokens of the program, followed by
 * a property getter or setter function. This is used when reparsing a function that can potentially be defined as a
 * property getter or setter in an object literal.
 *
 * @return function node resulting from successful parse
 */
public FunctionNode parse(final String scriptName, final int startPos, final int len, final boolean allowPropertyFunction) {
    final boolean isTimingEnabled = env.isTimingEnabled();
    final long t0 = isTimingEnabled ? System.nanoTime() : 0L;
    log.info(this, " begin for '", scriptName, "'");

    try {
        stream = new TokenStream();
        lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, reparsedFunction != null);
        lexer.line = lexer.pendingLine = lineOffset + 1;
        line = lineOffset;

        // Set up first token (skips opening EOL.)
        k = -1;
        next();
        // Begin parse.
        return program(scriptName, allowPropertyFunction);
    } catch (final Exception e) {
        handleParseException(e);

        return null;
    } finally {
        final String end = this + " end '" + scriptName + "'";
        if (isTimingEnabled) {
            env._timing.accumulateTime(toString(), System.nanoTime() - t0);
            log.info(end, "' in ", Timing.toMillisPrint(System.nanoTime() - t0), " ms");
        } else {
            log.info(end);
        }
    }
}
 
示例22
/**
 * 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;
}
 
示例23
private boolean isDynamicScopeBoundary(final LexicalContextNode node) {
    if (node instanceof Block) {
        // Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture
        // processing of WithNode.expression too, but it should be unaffected.
        return !isEmpty() && peek() instanceof WithNode;
    } else if (node instanceof FunctionNode) {
        // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new
        // variable into the function's scope), and it isn't strict (as evals in strict functions get an
        // isolated scope).
        return isFunctionDynamicScope((FunctionNode)node);
    }
    return false;
}
 
示例24
private Compiler(
        final Context context,
        final CodeInstaller installer,
        final Source source,
        final ErrorManager errors,
        final boolean isStrict,
        final boolean isOnDemand,
        final RecompilableScriptFunctionData compiledFunction,
        final TypeMap types,
        final Map<Integer, Type> invalidatedProgramPoints,
        final Object typeInformationFile,
        final int[] continuationEntryPoints,
        final ScriptObject runtimeScope) {
    this.context                  = context;
    this.env                      = context.getEnv();
    this.installer                = installer;
    this.constantData             = new ConstantData();
    this.compileUnits             = CompileUnit.createCompileUnitSet();
    this.bytecode                 = new LinkedHashMap<>();
    this.log                      = initLogger(context);
    this.source                   = source;
    this.errors                   = errors;
    this.sourceName               = FunctionNode.getSourceName(source);
    this.onDemand                 = isOnDemand;
    this.compiledFunction         = compiledFunction;
    this.types                    = types;
    this.invalidatedProgramPoints = invalidatedProgramPoints == null ? new HashMap<Integer, Type>() : invalidatedProgramPoints;
    this.typeInformationFile      = typeInformationFile;
    this.continuationEntryPoints  = continuationEntryPoints == null ? null: continuationEntryPoints.clone();
    this.typeEvaluator            = new TypeEvaluator(this, runtimeScope);
    this.firstCompileUnitName     = firstCompileUnitName();
    this.strict                   = isStrict;

    this.optimistic = env._optimistic_types;
}
 
示例25
FunctionNode reparse() {
    final FunctionNode cachedFunction = getCachedAst();
    if (cachedFunction != null) {
        assert cachedFunction.isCached();
        return cachedFunction;
    }

    final int descPosition = Token.descPosition(token);
    final Context context = Context.getContextTrusted();
    final Parser parser = new Parser(
        context.getEnv(),
        source,
        new Context.ThrowErrorManager(),
        isStrict(),
        // source starts at line 0, so even though lineNumber is the correct declaration line, back off
        // one to make it exclusive
        lineNumber - 1,
        context.getLogger(Parser.class));

    if (getFunctionFlag(FunctionNode.IS_ANONYMOUS)) {
        parser.setFunctionName(functionName);
    }
    parser.setReparsedFunction(this);

    final FunctionNode program = parser.parse(CompilerConstants.PROGRAM.symbolName(), descPosition,
            Token.descLength(token), isPropertyAccessor());
    // Parser generates a program AST even if we're recompiling a single function, so when we are only
    // recompiling a single function, extract it from the program.
    return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
}
 
示例26
@Override
public boolean enterBlock(final Block block) {
    final FunctionNode   function = lc.getCurrentFunction();
    if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) {
        new ExpressionStatement(function.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
    }
    return true;
}
 
示例27
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
    if (compiler.useOptimisticTypes()) {
        return transformFunction(fn, new OptimisticTypesCalculator(compiler));
    }
    return fn;
}
 
示例28
private MethodHandle addCode(final FunctionNode fn, final MethodType runtimeType, final MethodHandle guard, final MethodHandle fallback) {
    final MethodType targetType = new FunctionSignature(fn).getMethodType();
    MethodHandle target =
        MH.findStatic(
                LOOKUP,
                fn.getCompileUnit().getCode(),
                fn.getName(),
                targetType);

    /*
     * For any integer argument. a double that is representable as an integer is OK.
     * otherwise the guard would have failed. in that case introduce a filter that
     * casts the double to an integer, which we know will preserve all precision.
     */
    for (int i = 0; i < targetType.parameterCount(); i++) {
        if (targetType.parameterType(i) == int.class) {
            //representable as int
            target = MH.filterArguments(target, i, ENSURE_INT);
        }
    }

    MethodHandle mh = target;
    if (guard != null) {
        mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback);
    }

    final CompiledFunction cf = new CompiledFunction(runtimeType == null ? targetType : runtimeType, mh);
    code.add(cf);

    return cf.getInvoker();
}
 
示例29
private void logRecompile(final String reason, final FunctionNode fn, final MethodType type, final Map<Integer, Type> ipp) {
    if (log.isEnabled()) {
        log.info(reason, DebugLogger.quote(fn.getName()), " signature: ", type);
        log.indent();
        for (final String str : toStringInvalidations(ipp)) {
            log.fine(str);
        }
        log.unindent();
    }
}
 
示例30
@Override
public boolean enterBlock(final Block block) {
    final FunctionNode   function = lc.getCurrentFunction();
    if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) {
        new ExpressionStatement(function.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
    }
    return true;
}