@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; }
/** * Creates a compiler for an on-demand compilation job. * * @param installer code installer * @param source source to compile * @param isStrict is this a strict compilation * @param compiledFunction compiled function, if any * @param types parameter and return value type information, if any is known * @param invalidatedProgramPoints invalidated program points for recompilation * @param typeInformationFile descriptor of the location where type information is persisted * @param continuationEntryPoints continuation entry points for restof method * @param runtimeScope runtime scope for recompilation type lookup in {@code TypeEvaluator} * @return a new compiler */ public static Compiler forOnDemandCompilation( final CodeInstaller installer, final Source source, final boolean isStrict, final RecompilableScriptFunctionData compiledFunction, final TypeMap types, final Map<Integer, Type> invalidatedProgramPoints, final Object typeInformationFile, final int[] continuationEntryPoints, final ScriptObject runtimeScope) { final Context context = installer.getContext(); return new Compiler(context, installer, source, context.getErrorManager(), isStrict, true, compiledFunction, types, invalidatedProgramPoints, typeInformationFile, continuationEntryPoints, runtimeScope); }
private static DebugLogger getLogger() { try { return Context.getContext().getLogger(RecompilableScriptFunctionData.class); } catch (final Exception e) { e.printStackTrace(); return DebugLogger.DISABLED_LOGGER; } }
/** * Constructor * * @param context context * @param env script environment * @param installer code installer * @param source source to compile * @param errors error manager * @param isStrict is this a strict compilation * @param isOnDemand is this an on demand compilation * @param compiledFunction compiled function, if any * @param types parameter and return value type information, if any is known * @param invalidatedProgramPoints invalidated program points for recompilation * @param typeInformationFile descriptor of the location where type information is persisted * @param continuationEntryPoints continuation entry points for restof method * @param runtimeScope runtime scope for recompilation type lookup in {@code TypeEvaluator} */ @SuppressWarnings("unused") public Compiler( final Context context, final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> 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 = env; 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; }
private String firstCompileUnitName() { final StringBuilder sb = new StringBuilder(SCRIPTS_PACKAGE). append('/'). append(CompilerConstants.DEFAULT_SCRIPT_NAME.symbolName()). append('$'); if (isOnDemandCompilation()) { sb.append(RecompilableScriptFunctionData.RECOMPILATION_PREFIX); } if (compilationId > 0) { sb.append(compilationId).append('$'); } if (types != null && compiledFunction.getFunctionNodeId() > 0) { sb.append(compiledFunction.getFunctionNodeId()); final Type[] paramTypes = types.getParameterTypes(compiledFunction.getFunctionNodeId()); for (final Type t : paramTypes) { sb.append(Type.getShortSignatureDescriptor(t)); } sb.append('$'); } sb.append(Compiler.safeSourceName(env, installer, source)); return sb.toString(); }
void addFunctionInitializer(final RecompilableScriptFunctionData functionData, final FunctionNode functionNode) { if (functionInitializers == null) { functionInitializers = new HashMap<>(); } if (!functionInitializers.containsKey(functionData)) { functionInitializers.put(functionData.getFunctionNodeId(), new FunctionInitializer(functionNode)); } }
@Override public Node leaveFunctionNode(final FunctionNode functionNode) { final RecompilableScriptFunctionData data = dataStack.pop(); if (functionNode.isSplit()) { // NOTE: cache only split function ASTs from eager pass. Caching non-split functions would require // some additional work, namely creating the concept of "uncacheable" function and reworking // ApplySpecialization to ensure that functions undergoing apply-to-call transformations are not // cacheable as well as recomputing Symbol.useCount when caching the eagerly parsed AST. // Recomputing Symbol.useCount would be needed so it will only reflect uses from within the // function being cached (and not reflect uses from its own nested functions or functions it is // nested in). This is consistent with the count an on-demand recompilation of the function would // produce. This is important as the decision to emit shared scope calls is based on this count, // and if it is not matched between a previous version of the code and its deoptimizing rest-of // compilation, it can result in rest-of not emitting a shared scope call where a previous version // of the code (compiled from a cached eager pre-pass seeing higher (global) useCount) would emit // it, causing a mismatch in stack shapes between previous code and its rest-of. data.setCachedAst(functionNode); } if (!dataStack.isEmpty() && ((dataStack.peek().getFunctionFlags() & FunctionNode.IS_SPLIT) != 0)) { // Return a function node with no body so that caching outer functions doesn't hold on to nested // functions' bodies. Note we're doing this only for functions directly nested inside split // functions, since we're only caching the split ones. It is not necessary to limit body removal // to just these functions, but it's a cheap way to prevent unnecessary AST mutations. return functionNode.setBody(lc, functionNode.getBody().setStatements(null, Collections.<Statement>emptyList())); } return functionNode; }
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<>() : 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; }
private String firstCompileUnitName() { final StringBuilder sb = new StringBuilder(SCRIPTS_PACKAGE). append('/'). append(CompilerConstants.DEFAULT_SCRIPT_NAME.symbolName()). append('$'); if (isOnDemandCompilation()) { sb.append(RecompilableScriptFunctionData.RECOMPILATION_PREFIX); } if (compilationId > 0) { sb.append(compilationId).append('$'); } if (types != null && compiledFunction.getFunctionNodeId() > 0) { sb.append(compiledFunction.getFunctionNodeId()); final Type[] paramTypes = types.getParameterTypes(compiledFunction.getFunctionNodeId()); for (final Type t : paramTypes) { sb.append(Type.getShortSignatureDescriptor(t)); } sb.append('$'); } sb.append(safeSourceName()); return sb.toString(); }
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; }
private ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope, final Global global) { super(data, getMap(data.isStrict()), scope); init(global); }
void setData(final RecompilableScriptFunctionData data) { assert this.compiledFunction == null : data; this.compiledFunction = data; }
RecompilableScriptFunctionData getScriptFunctionData(final int functionId) { assert compiledFunction != null; final RecompilableScriptFunctionData fn = compiledFunction.getScriptFunctionData(functionId); assert fn != null : functionId; return fn; }