/** * Debug code used to print symbols * * @param block the block we are in * @param function the function we are in * @param ident identifier for block or function where applicable */ private void printSymbols(final Block block, final FunctionNode function, final String ident) { if (compiler.getScriptEnvironment()._print_symbols || function.getDebugFlag(FunctionNode.DEBUG_PRINT_SYMBOLS)) { final PrintWriter out = compiler.getScriptEnvironment().getErr(); out.println("[BLOCK in '" + ident + "']"); if (!block.printSymbols(out)) { out.println("<no symbols>"); } out.println(); } }
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; }
/** * 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); }
private static void markEval(final LexicalContext lc) { final Iterator<FunctionNode> iter = lc.getFunctions(); boolean flaggedCurrentFn = false; while (iter.hasNext()) { final FunctionNode fn = iter.next(); if (!flaggedCurrentFn) { lc.setFlag(fn, FunctionNode.HAS_EVAL); flaggedCurrentFn = true; } else { lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL); } // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip // parsing a nested function. functionBody() contains code to compensate for the lack of invoking // this method when the parser skips a nested function. lc.setBlockNeedsScope(lc.getFunctionBody(fn)); } }
@Override public boolean enterFunctionNode(final FunctionNode functionNode) { if (compiler.isOnDemandCompilation()) { return true; } if (isDynamicScopeBoundary(functionNode)) { increaseDynamicScopeCount(functionNode); } final int fnId = functionNode.getId(); Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.get(fnId); if (nestedFunctions == null) { nestedFunctions = new HashMap<>(); fnIdToNestedFunctions.put(fnId, nestedFunctions); } return true; }
private int fixScopeSlot(final FunctionNode functionNode, final int extraSlot) { // TODO hack to move the scope to the expected slot (needed because split methods reuse the same slots as the root method) final int actualScopeSlot = functionNode.compilerConstant(SCOPE).getSlot(SCOPE_TYPE); final int defaultScopeSlot = SCOPE.slot(); int newExtraSlot = extraSlot; if (actualScopeSlot != defaultScopeSlot) { if (actualScopeSlot == extraSlot) { newExtraSlot = extraSlot + 1; method.defineBlockLocalVariable(newExtraSlot, newExtraSlot + 1); method.load(Type.OBJECT, extraSlot); method.storeHidden(Type.OBJECT, newExtraSlot); } else { method.defineBlockLocalVariable(actualScopeSlot, actualScopeSlot + 1); } method.load(SCOPE_TYPE, defaultScopeSlot); method.storeCompilerConstant(SCOPE); } return newExtraSlot; }
private FunctionNode extractFunctionFromScript(final FunctionNode script) { final Set<FunctionNode> fns = new HashSet<>(); script.getBody().accept(new SimpleNodeVisitor() { @Override public boolean enterFunctionNode(final FunctionNode fn) { fns.add(fn); return false; } }); assert fns.size() == 1 : "got back more than one method in recompilation"; final FunctionNode f = fns.iterator().next(); assert f.getId() == functionNodeId; if (!getFunctionFlag(FunctionNode.IS_DECLARED) && f.isDeclared()) { return f.clearFlag(null, FunctionNode.IS_DECLARED); } return f; }
Compiler getCompiler(final FunctionNode functionNode, final MethodType actualCallSiteType, final ScriptObject runtimeScope, final Map<Integer, Type> invalidatedProgramPoints, final int[] continuationEntryPoints) { final TypeMap typeMap = typeMap(actualCallSiteType); final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId); final Object typeInformationFile = OptimisticTypesPersistence.getLocationDescriptor(source, functionNodeId, paramTypes); final Context context = Context.getContextTrusted(); return new Compiler( context, context.getEnv(), getInstallerForNewCode(), functionNode.getSource(), // source context.getErrorManager(), isStrict() | functionNode.isStrict(), // is strict true, // is on demand this, // compiledFunction, i.e. this RecompilableScriptFunctionData typeMap, // type map getEffectiveInvalidatedProgramPoints(invalidatedProgramPoints, typeInformationFile), // invalidated program points typeInformationFile, continuationEntryPoints, // continuation entry points runtimeScope); // runtime scope }
private MethodHandle restOfHandle(final OptimismInfo info, final FunctionNode restOfFunction, final boolean canBeDeoptimized) { assert info != null; assert restOfFunction.getCompileUnit().getUnitClassName().contains("restOf"); final MethodHandle restOf = changeReturnType( info.data.lookupCodeMethod( restOfFunction.getCompileUnit().getCode(), MH.type(restOfFunction.getReturnType().getTypeClass(), RewriteException.class)), Object.class); if (!canBeDeoptimized) { return restOf; } // If rest-of is itself optimistic, we must make sure that we can repeat a deoptimization if it, too hits an exception. return MH.catchException(restOf, RewriteException.class, createRewriteExceptionHandler()); }
private void pushExplodedArgs(final FunctionNode functionNode) { int start = 0; final MethodType actualCallSiteType = compiler.getCallSiteType(functionNode); if (actualCallSiteType == null) { throw new TransformFailedException(lc.getCurrentFunction(), "No callsite type"); } assert actualCallSiteType.parameterType(actualCallSiteType.parameterCount() - 1) != Object[].class : "error vararg callsite passed to apply2call " + functionNode.getName() + " " + actualCallSiteType; final TypeMap ptm = compiler.getTypeMap(); if (ptm.needsCallee()) { start++; } start++; // we always use this assert functionNode.getNumOfParams() == 0 : "apply2call on function with named paramaters!"; final List<IdentNode> newParams = new ArrayList<>(); final long to = actualCallSiteType.parameterCount() - start; for (int i = 0; i < to; i++) { newParams.add(new IdentNode(functionNode.getToken(), functionNode.getFinish(), EXPLODED_ARGUMENT_PREFIX.symbolName() + (i))); } callSiteTypes.push(actualCallSiteType); explodedArguments.push(newParams); }
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 }
@Override FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { final CompileUnit outermostCompileUnit = compiler.addCompileUnit(0L); FunctionNode newFunctionNode; //ensure elementTypes, postsets and presets exist for splitter and arraynodes newFunctionNode = transformFunction(fn, new SimpleNodeVisitor() { @Override public LiteralNode<?> leaveLiteralNode(final LiteralNode<?> literalNode) { return literalNode.initialize(lc); } }); newFunctionNode = new Splitter(compiler, newFunctionNode, outermostCompileUnit).split(newFunctionNode, true); newFunctionNode = transformFunction(newFunctionNode, new SplitIntoFunctions(compiler)); assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn=" + fn.getName() + ", fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit; assert newFunctionNode.isStrict() == compiler.isStrict() : "functionNode.isStrict() != compiler.isStrict() for " + quote(newFunctionNode.getName()); return newFunctionNode; }
private FunctionNode getCachedAst() { final Object lCachedAst = cachedAst; // Are we softly caching the AST? if (lCachedAst instanceof Reference<?>) { final FunctionNode fn = (FunctionNode)((Reference<?>)lCachedAst).get(); if (fn != null) { // Yes we are - this is fast return cloneSymbols(fn); } // Are we strongly caching a serialized AST (for split functions only)? } else if (lCachedAst instanceof SerializedAst) { final SerializedAst serializedAst = (SerializedAst)lCachedAst; // Even so, are we also softly caching the AST? final FunctionNode cachedFn = serializedAst.cachedAst == null ? null : serializedAst.cachedAst.get(); if (cachedFn != null) { // Yes we are - this is fast return cloneSymbols(cachedFn); } final FunctionNode deserializedFn = deserialize(serializedAst.serializedAst); // Softly cache after deserialization, maybe next time we won't need to deserialize serializedAst.cachedAst = new SoftReference<>(deserializedFn); return deserializedFn; } // No cached representation; return null for reparsing return null; }
@Override FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler)); final ScriptEnvironment senv = compiler.getScriptEnvironment(); final PrintWriter err = senv.getErr(); //TODO separate phase for the debug printouts for abstraction and clarity if (senv._print_lower_ast || fn.getDebugFlag(FunctionNode.DEBUG_PRINT_LOWER_AST)) { err.println("Lower AST for: " + quote(newFunctionNode.getName())); err.println(new ASTWriter(newFunctionNode)); } if (senv._print_lower_parse || fn.getDebugFlag(FunctionNode.DEBUG_PRINT_LOWER_PARSE)) { err.println("Lower AST for: " + quote(newFunctionNode.getName())); err.println(new PrintVisitor(newFunctionNode)); } return newFunctionNode; }
private void checkPropertyRedefinition(final PropertyNode property, final Expression value, final FunctionNode getter, final FunctionNode setter, final Expression prevValue, final FunctionNode prevGetter, final FunctionNode prevSetter) { // ECMA 11.1.5 strict mode restrictions if (isStrictMode && value != null && prevValue != null) { throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); } final boolean isPrevAccessor = prevGetter != null || prevSetter != null; final boolean isAccessor = getter != null || setter != null; // data property redefined as accessor property if (prevValue != null && isAccessor) { throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); } // accessor property redefined as data if (isPrevAccessor && value != null) { throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); } if (isAccessor && isPrevAccessor) { if (getter != null && prevGetter != null || setter != null && prevSetter != null) { throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); } } }
private List<? extends ExpressionTree> translateParameters(final FunctionNode func) { final Map<IdentNode, Expression> paramExprs = func.getParameterExpressions(); if (paramExprs != null) { final List<IdentNode> params = func.getParameters(); final List<ExpressionTreeImpl> exprTrees = new ArrayList<>(params.size()); for (final IdentNode ident : params) { final Expression expr = paramExprs.containsKey(ident)? paramExprs.get(ident) : ident; curExpr = null; expr.accept(this); assert curExpr != null; exprTrees.add(curExpr); } return exprTrees; } else { return translateExprs(func.getParameters()); } }
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; }
@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); }
static int findInternalDepth(final LexicalContext lc, final FunctionNode fn, final Block block, final Symbol symbol) { final Block bodyBlock = findBodyBlock(lc, fn, block); final Iterator<Block> iter = lc.getBlocks(block); Block b = iter.next(); int scopesToStart = 0; while (true) { if (definedInBlock(b, symbol)) { return scopesToStart; } if (b.needsScope()) { scopesToStart++; } if (b == bodyBlock) { break; //don't go past body block, but process it } b = iter.next(); } return -1; }
/** * Persist current compilation with the given {@code cacheKey}. * @param cacheKey cache key * @param functionNode function node */ public void persistClassInfo(final String cacheKey, final FunctionNode functionNode) { if (cacheKey != null && env._persistent_cache) { // If this is an on-demand compilation create a function initializer for the function being compiled. // Otherwise use function initializer map generated by codegen. final Map<Integer, FunctionInitializer> initializers = new HashMap<>(); if (isOnDemandCompilation()) { initializers.put(functionNode.getId(), new FunctionInitializer(functionNode, getInvalidatedProgramPoints())); } else { for (final CompileUnit compileUnit : getCompileUnits()) { for (final FunctionNode fn : compileUnit.getFunctionNodes()) { initializers.put(fn.getId(), new FunctionInitializer(fn)); } } } final String mainClassName = getFirstCompileUnit().getUnitClassName(); installer.storeScript(cacheKey, source, mainClassName, bytecode, initializers, constantData.toArray(), compilationId); } }
@Override public boolean enterFunctionNode(final FunctionNode functionNode) { assert !functionNode.isDeclared() || functionNode.isAnonymous() : "should not reach here for function declaration"; final List<? extends ExpressionTree> paramTrees = translateParameters(functionNode); final BlockTree blockTree = (BlockTree) translateBlock(functionNode.getBody(), true); curExpr = new FunctionExpressionTreeImpl(functionNode, paramTrees, blockTree); return false; }
private FunctionNode deserialize(final byte[] serializedAst) { final ScriptEnvironment env = installer.getContext().getEnv(); final Timing timing = env._timing; final long t1 = System.nanoTime(); try { return AstDeserializer.deserialize(serializedAst).initializeDeserialized(source, new Namespace(env.getNamespace())); } finally { timing.accumulateTime("'Deserialize'", System.nanoTime() - t1); } }
/** * Constructor - internal use from ClassEmitter only * @see ClassEmitter#method * * @param classEmitter the class emitter weaving the class this method is in * @param method a method visitor * @param functionNode a function node representing this method */ MethodEmitter(final ClassEmitter classEmitter, final MethodVisitor method, final FunctionNode functionNode) { this.context = classEmitter.getContext(); this.classEmitter = classEmitter; this.method = method; this.functionNode = functionNode; this.stack = null; this.log = context.getLogger(CodeGenerator.class); this.debug = log.isEnabled(); }
private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) { final Block newBody = restoreBlock(lc.getFunctionBody(functionNode)); return lc.pop(functionNode). setBody(lc, newBody). setLastToken(lc, lastToken). setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); }
/** * Program : * SourceElements? * * See 14 * * Parse the top level script. */ private FunctionNode program(final String scriptName, final boolean allowPropertyFunction) { // Make a pseudo-token for the script holding its start and length. final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength()); final int functionLine = line; // Set up the script to append elements. FunctionNode script = newFunctionNode( functionToken, new IdentNode(functionToken, Token.descPosition(functionToken), scriptName), new ArrayList<IdentNode>(), FunctionNode.Kind.SCRIPT, functionLine); functionDeclarations = new ArrayList<>(); sourceElements(allowPropertyFunction); addFunctionDeclarations(script); functionDeclarations = null; expect(EOF); script.setFinish(source.getLength() - 1); script = restoreFunctionNode(script, token); //commit code script = script.setBody(lc, script.getBody().setNeedsScope(lc)); return script; }
private ModuleTreeImpl(final FunctionNode func, final List<? extends ImportEntryTree> imports, final List<? extends ExportEntryTree> localExports, final List<? extends ExportEntryTree> indirectExports, final List<? extends ExportEntryTree> starExports) { super(func); assert func.getKind() == FunctionNode.Kind.MODULE : "module function node expected"; this.mod = func.getModule(); this.imports = imports; this.localExports = localExports; this.indirectExports = indirectExports; this.starExports = starExports; }
@Override FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { if (compiler.useOptimisticTypes()) { return transformFunction(fn, new OptimisticTypesCalculator(compiler)); } return fn; }
/** * 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 allocationDescriptor descriptor for the allocation behavior when this function is used as a constructor * @param nestedFunctions nested function map * @param externalScopeDepths external scope depths * @param internalSymbols internal symbols to method, defined in its scope * @param serializedAst a serialized AST representation. Normally only used for split functions. */ public RecompilableScriptFunctionData( final FunctionNode functionNode, final CodeInstaller<ScriptEnvironment> installer, final AllocatorDescriptor allocationDescriptor, final Map<Integer, RecompilableScriptFunctionData> nestedFunctions, final Map<String, Integer> externalScopeDepths, final Set<String> internalSymbols, final byte[] serializedAst) { super(functionName(functionNode), Math.min(functionNode.getParameters().size(), MAX_ARITY), getDataFlags(functionNode)); this.functionName = functionNode.getName(); this.lineNumber = functionNode.getLineNumber(); this.functionFlags = functionNode.getFlags() | (functionNode.needsCallee() ? FunctionNode.NEEDS_CALLEE : 0); this.functionNodeId = functionNode.getId(); this.source = functionNode.getSource(); this.endParserState = functionNode.getEndParserState(); this.token = tokenFor(functionNode); this.installer = installer; this.allocationStrategy = AllocationStrategy.get(allocationDescriptor); this.nestedFunctions = smallMap(nestedFunctions); this.externalScopeDepths = smallMap(externalScopeDepths); this.internalSymbols = smallSet(new HashSet<>(internalSymbols)); for (final RecompilableScriptFunctionData nfn : nestedFunctions.values()) { assert nfn.getParent() == null; nfn.setParent(this); } this.serializedAst = serializedAst; createLogger(); }
/** * ReturnStatement : * return Expression? ; // [no LineTerminator here] * * See 12.9 * * Parse RETURN statement. */ private void returnStatement() { // check for return outside function if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT || lc.getCurrentFunction().getKind() == FunctionNode.Kind.MODULE) { throw error(AbstractParser.message("invalid.return")); } // Capture RETURN token. final int returnLine = line; final long returnToken = token; // RETURN tested in caller. nextOrEOL(); Expression expression = null; // SEMICOLON or expression. switch (type) { case RBRACE: case SEMICOLON: case EOL: case EOF: break; default: expression = expression(); break; } endOfLine(); // Construct and add RETURN node. appendStatement(new ReturnNode(returnLine, returnToken, finish, expression)); }
/** * Start a compilation phase * @param compiler the compiler to use * @param functionNode function to compile * @return function node */ protected FunctionNode begin(final Compiler compiler, final FunctionNode functionNode) { compiler.getLogger().indent(); startTime = System.nanoTime(); return functionNode; }
FunctionNode reparse() { if (isSerialized()) { return deserialize(); } 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), true); // 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); }
private void pushExplodedArgs(final FunctionNode functionNode) { int start = 0; final MethodType actualCallSiteType = compiler.getCallSiteType(functionNode); if (actualCallSiteType == null) { throw new TransformFailedException(lc.getCurrentFunction(), "No callsite type"); } assert actualCallSiteType.parameterType(actualCallSiteType.parameterCount() - 1) != Object[].class : "error vararg callsite passed to apply2call " + functionNode.getName() + " " + actualCallSiteType; final TypeMap ptm = compiler.getTypeMap(); if (ptm.needsCallee()) { start++; } start++; //we always uses this final List<IdentNode> params = functionNode.getParameters(); final List<IdentNode> newParams = new ArrayList<>(); final long to = Math.max(params.size(), actualCallSiteType.parameterCount() - start); for (int i = 0; i < to; i++) { if (i >= params.size()) { newParams.add(new IdentNode(functionNode.getToken(), functionNode.getFinish(), EXPLODED_ARGUMENT_PREFIX.symbolName() + (i))); } else { newParams.add(params.get(i)); } } callSiteTypes.push(actualCallSiteType); explodedArguments.push(newParams); }
private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body) { // assert body.isFunctionBody() || body.getFlag(Block.IS_PARAMETER_BLOCK) && ((BlockStatement) body.getLastStatement()).getBlock().isFunctionBody(); // Start new block. final FunctionNode functionNode = new FunctionNode( source, functionLine, body.getToken(), Token.descPosition(body.getToken()), startToken, function.getLastToken(), namespace, ident, function.getName(), parameters, function.getParameterExpressions(), kind, function.getFlags(), body, function.getEndParserState(), function.getModule(), function.getDebugFlags()); printAST(functionNode); return functionNode; }
private static String functionName(final FunctionNode fn) { if (fn.isAnonymous()) { return ""; } final FunctionNode.Kind kind = fn.getKind(); if (kind == FunctionNode.Kind.GETTER || kind == FunctionNode.Kind.SETTER) { final String name = NameCodec.decode(fn.getIdent().getName()); return name.substring(GET_SET_PREFIX_LENGTH); } return fn.getIdent().getName(); }
/** * Check whether a certain name is a global symbol, i.e. only exists as defined * in outermost scope and not shadowed by being parameter or assignment in inner * scopes * * @param functionNode function node to check * @param symbolName symbol name * @return true if global symbol */ public boolean isGlobalSymbol(final FunctionNode functionNode, final String symbolName) { RecompilableScriptFunctionData data = getScriptFunctionData(functionNode.getId()); assert data != null; do { if (data.hasInternalSymbol(symbolName)) { return false; } data = data.getParent(); } while(data != null); return true; }
/** * Initializes this function data with the eagerly generated version of the code. This method can only be invoked * by the compiler internals in Nashorn and is public for implementation reasons only. Attempting to invoke it * externally will result in an exception. * * @param functionNode FunctionNode for this data */ public void initializeCode(final FunctionNode functionNode) { // Since the method is public, we double-check that we aren't invoked with an inappropriate compile unit. if (!code.isEmpty() || functionNode.getId() != functionNodeId || !functionNode.getCompileUnit().isInitializing(this, functionNode)) { throw new IllegalStateException(name); } addCode(lookup(functionNode), null, null, functionNode.getFlags()); }
/** * Returns AST as JSON compatible string. * * @param context context * @param code code to be parsed * @param name name of the code source (used for location) * @param includeLoc tells whether to include location information for nodes or not * @return JSON string representation of AST of the supplied code */ public static String parse(final Context context, final String code, final String name, final boolean includeLoc) { final Parser parser = new Parser(context.getEnv(), sourceFor(name, code), new Context.ThrowErrorManager(), context.getEnv()._strict, context.getLogger(Parser.class)); final JSONWriter jsonWriter = new JSONWriter(includeLoc); try { final FunctionNode functionNode = parser.parse(); //symbol name is ":program", default functionNode.accept(jsonWriter); return jsonWriter.getString(); } catch (final ParserException e) { e.throwAsEcmaException(); return null; } }
@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; }