/*
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.nashorn.internal.runtime;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.logging.Level;
import jdk.nashorn.internal.codegen.Namespace;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.options.KeyValueOption;
import jdk.nashorn.internal.runtime.options.LoggingOption;
import jdk.nashorn.internal.runtime.options.LoggingOption.LoggerInfo;
import jdk.nashorn.internal.runtime.options.Option;
import jdk.nashorn.internal.runtime.options.Options;

Script environment consists of command line options, arguments, script files and output and error writers, top level Namespace etc.
/** * Script environment consists of command line options, arguments, script files * and output and error writers, top level Namespace etc. */
public final class ScriptEnvironment { // Primarily intended to be used in test environments so that eager compilation tests work without an // error when tested with optimistic compilation. private static final boolean ALLOW_EAGER_COMPILATION_SILENT_OVERRIDE = Options.getBooleanProperty( "nashorn.options.allowEagerCompilationSilentOverride", false);
Output writer for this environment
/** Output writer for this environment */
private final PrintWriter out;
Error writer for this environment
/** Error writer for this environment */
private final PrintWriter err;
Top level namespace.
/** Top level namespace. */
private final Namespace namespace;
Current Options object.
/** Current Options object. */
private final Options options;
Size of the per-global Class cache size
/** Size of the per-global Class cache size */
public final int _class_cache_size;
-classpath value.
/** -classpath value. */
public final String _classpath;
Only compile script, do not run it or generate other ScriptObjects
/** Only compile script, do not run it or generate other ScriptObjects */
public final boolean _compile_only;
Accept "const" keyword and treat it as variable. Interim feature
/** Accept "const" keyword and treat it as variable. Interim feature */
public final boolean _const_as_var;
Accumulated callsite flags that will be used when bootstrapping script callsites
/** Accumulated callsite flags that will be used when bootstrapping script callsites */
public final int _callsite_flags;
Generate line number table in class files
/** Generate line number table in class files */
public final boolean _debug_lines;
Put all variables in scopes to make them debuggable
/** Put all variables in scopes to make them debuggable */
public final boolean _debug_scopes;
Directory in which source files and generated class files are dumped
/** Directory in which source files and generated class files are dumped */
public final String _dest_dir;
Display stack trace upon error, default is false
/** Display stack trace upon error, default is false */
public final boolean _dump_on_error;
Invalid lvalue expressions should be reported as early errors
/** Invalid lvalue expressions should be reported as early errors */
public final boolean _early_lvalue_error;
Empty statements should be preserved in the AST
/** Empty statements should be preserved in the AST */
public final boolean _empty_statements;
Show full Nashorn version
/** Show full Nashorn version */
public final boolean _fullversion;
Launch using as fx application
/** Launch using as fx application */
public final boolean _fx;
Use single Global instance per jsr223 engine instance.
/** Use single Global instance per jsr223 engine instance. */
public final boolean _global_per_engine;
Enable experimental ECMAScript 6 features.
/** Enable experimental ECMAScript 6 features. */
public final boolean _es6;
Number of times a dynamic call site has to be relinked before it is considered unstable (and thus should be linked as if it were megamorphic).
/** Number of times a dynamic call site has to be relinked before it is * considered unstable (and thus should be linked as if it were megamorphic). */
public final int _unstable_relink_threshold;
Argument passed to compile only if optimistic compilation should take place
/** Argument passed to compile only if optimistic compilation should take place */
public static final String COMPILE_ONLY_OPTIMISTIC_ARG = "optimistic";
Behavior when encountering a function declaration in a lexical context where only statements are acceptable (function declarations are source elements, but not statements).
/** * Behavior when encountering a function declaration in a lexical context where only statements are acceptable * (function declarations are source elements, but not statements). */
public enum FunctionStatementBehavior {
Accept the function declaration silently and treat it as if it were a function expression assigned to a local variable.
/** * Accept the function declaration silently and treat it as if it were a function expression assigned to a local * variable. */
ACCEPT,
Log a parser warning, but accept the function declaration and treat it as if it were a function expression assigned to a local variable.
/** * Log a parser warning, but accept the function declaration and treat it as if it were a function expression * assigned to a local variable. */
WARNING,
Raise a SyntaxError.
/** * Raise a {@code SyntaxError}. */
ERROR }
Behavior when encountering a function declaration in a lexical context where only statements are acceptable (function declarations are source elements, but not statements).
/** * Behavior when encountering a function declaration in a lexical context where only statements are acceptable * (function declarations are source elements, but not statements). */
public final FunctionStatementBehavior _function_statement;
Should lazy compilation take place
/** Should lazy compilation take place */
public final boolean _lazy_compilation;
Should optimistic types be used
/** Should optimistic types be used */
public final boolean _optimistic_types;
Create a new class loaded for each compilation
/** Create a new class loaded for each compilation */
public final boolean _loader_per_compile;
--module-path, if any
/** --module-path, if any */
public final String _module_path;
--add-modules, if any
/** --add-modules, if any */
public final String _add_modules;
Do not support Java support extensions.
/** Do not support Java support extensions. */
public final boolean _no_java;
Do not support non-standard syntax extensions.
/** Do not support non-standard syntax extensions. */
public final boolean _no_syntax_extensions;
Do not support typed arrays.
/** Do not support typed arrays. */
public final boolean _no_typed_arrays;
Only parse the source code, do not compile
/** Only parse the source code, do not compile */
public final boolean _parse_only;
Enable disk cache for compiled scripts
/** Enable disk cache for compiled scripts */
public final boolean _persistent_cache;
Print the AST before lowering
/** Print the AST before lowering */
public final boolean _print_ast;
Print the AST after lowering
/** Print the AST after lowering */
public final boolean _print_lower_ast;
Print resulting bytecode for script
/** Print resulting bytecode for script */
public final boolean _print_code;
Directory (optional) to print files to
/** Directory (optional) to print files to */
public final String _print_code_dir;
List of functions to write to the print code dir, optional
/** List of functions to write to the print code dir, optional */
public final String _print_code_func;
Print function will no print newline characters
/** Print function will no print newline characters */
public final boolean _print_no_newline;
Print AST in more human readable form
/** Print AST in more human readable form */
public final boolean _print_parse;
Print AST in more human readable form after Lowering
/** Print AST in more human readable form after Lowering */
public final boolean _print_lower_parse;
print symbols and their contents for the script
/** print symbols and their contents for the script */
public final boolean _print_symbols;
is this environment in scripting mode?
/** is this environment in scripting mode? */
public final boolean _scripting;
is this environment in strict mode?
/** is this environment in strict mode? */
public final boolean _strict;
print version info of Nashorn
/** print version info of Nashorn */
public final boolean _version;
should code verification be done of generated bytecode
/** should code verification be done of generated bytecode */
public final boolean _verify_code;
time zone for this environment
/** time zone for this environment */
public final TimeZone _timezone;
Local for error messages
/** Local for error messages */
public final Locale _locale;
Logging
/** Logging */
public final Map<String, LoggerInfo> _loggers;
Timing
/** Timing */
public final Timing _timing;
Whether to use anonymous classes. See useAnonymousClasses(int).
/** Whether to use anonymous classes. See {@link #useAnonymousClasses(int)}. */
private final AnonymousClasses _anonymousClasses; private enum AnonymousClasses { AUTO, OFF, ON }
Size threshold up to which we use anonymous classes in AnonymousClasses.AUTO setting
/** Size threshold up to which we use anonymous classes in {@link AnonymousClasses#AUTO} setting */
private final int _anonymous_classes_threshold;
Default value for anonymous class threshold
/** Default value for anonymous class threshold */
private final static int DEFAULT_ANON_CLASS_THRESHOLD = 512;
Constructor
Params:
  • options – a Options object
  • out – output print writer
  • err – error print writer
/** * Constructor * * @param options a Options object * @param out output print writer * @param err error print writer */
@SuppressWarnings("unused") public ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) { this.out = out; this.err = err; this.namespace = new Namespace(); this.options = options; _class_cache_size = options.getInteger("class.cache.size"); _classpath = options.getString("classpath"); _compile_only = options.getBoolean("compile.only"); _const_as_var = options.getBoolean("const.as.var"); _debug_lines = options.getBoolean("debug.lines"); _debug_scopes = options.getBoolean("debug.scopes"); _dest_dir = options.getString("d"); _dump_on_error = options.getBoolean("doe"); _early_lvalue_error = options.getBoolean("early.lvalue.error"); _empty_statements = options.getBoolean("empty.statements"); _fullversion = options.getBoolean("fullversion"); if (options.getBoolean("function.statement.error")) { _function_statement = FunctionStatementBehavior.ERROR; } else if (options.getBoolean("function.statement.warning")) { _function_statement = FunctionStatementBehavior.WARNING; } else { _function_statement = FunctionStatementBehavior.ACCEPT; } _fx = options.getBoolean("fx"); _global_per_engine = options.getBoolean("global.per.engine"); _optimistic_types = options.getBoolean("optimistic.types"); final boolean lazy_compilation = options.getBoolean("lazy.compilation"); if (!lazy_compilation && _optimistic_types) { if (!ALLOW_EAGER_COMPILATION_SILENT_OVERRIDE) { throw new IllegalStateException( ECMAErrors.getMessage( "config.error.eagerCompilationConflictsWithOptimisticTypes", options.getOptionTemplateByKey("lazy.compilation").getName(), options.getOptionTemplateByKey("optimistic.types").getName())); } _lazy_compilation = true; } else { _lazy_compilation = lazy_compilation; } _loader_per_compile = options.getBoolean("loader.per.compile"); _module_path = options.getString("module.path"); _add_modules = options.getString("add.modules"); _no_java = options.getBoolean("no.java"); _no_syntax_extensions = options.getBoolean("no.syntax.extensions"); _no_typed_arrays = options.getBoolean("no.typed.arrays"); _parse_only = options.getBoolean("parse.only"); _persistent_cache = options.getBoolean("persistent.code.cache"); _print_ast = options.getBoolean("print.ast"); _print_lower_ast = options.getBoolean("print.lower.ast"); _print_code = options.getString("print.code") != null; _print_no_newline = options.getBoolean("print.no.newline"); _print_parse = options.getBoolean("print.parse"); _print_lower_parse = options.getBoolean("print.lower.parse"); _print_symbols = options.getBoolean("print.symbols"); _scripting = options.getBoolean("scripting"); _strict = options.getBoolean("strict"); _version = options.getBoolean("version"); _verify_code = options.getBoolean("verify.code"); final int configuredUrt = options.getInteger("unstable.relink.threshold"); // The default for this property is -1, so we can easily detect when // it is not specified on command line. if (configuredUrt < 0) { // In this case, use a default of 8, or 16 for optimistic types. // Optimistic types come with dual fields, and in order to get // performance on benchmarks with a lot of object instantiation and // then field reassignment, it can take slightly more relinks to // become stable with type changes swapping out an entire property // map and making a map guard fail. Also, honor the "nashorn.*" // system property for now. It was documented in DEVELOPER_README // so we should recognize it for the time being. _unstable_relink_threshold = Options.getIntProperty( "nashorn.unstable.relink.threshold", _optimistic_types ? 16 : 8); } else { _unstable_relink_threshold = configuredUrt; } final String anonClasses = options.getString("anonymous.classes"); if (anonClasses == null || anonClasses.equals("auto")) { _anonymousClasses = AnonymousClasses.AUTO; } else if (anonClasses.equals("true")) { _anonymousClasses = AnonymousClasses.ON; } else if (anonClasses.equals("false")) { _anonymousClasses = AnonymousClasses.OFF; } else { throw new RuntimeException("Unsupported value for anonymous classes: " + anonClasses); } this._anonymous_classes_threshold = Options.getIntProperty( "nashorn.anonymous.classes.threshold", DEFAULT_ANON_CLASS_THRESHOLD); final String language = options.getString("language"); if (language == null || language.equals("es5")) { _es6 = false; } else if (language.equals("es6")) { _es6 = true; } else { throw new RuntimeException("Unsupported language: " + language); } String dir = null; String func = null; final String pc = options.getString("print.code"); if (pc != null) { final StringTokenizer st = new StringTokenizer(pc, ","); while (st.hasMoreTokens()) { final StringTokenizer st2 = new StringTokenizer(st.nextToken(), ":"); while (st2.hasMoreTokens()) { final String cmd = st2.nextToken(); if ("dir".equals(cmd)) { dir = st2.nextToken(); } else if ("function".equals(cmd)) { func = st2.nextToken(); } } } } _print_code_dir = dir; _print_code_func = func; int callSiteFlags = 0; if (options.getBoolean("profile.callsites")) { callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE; } if (options.get("trace.callsites") instanceof KeyValueOption) { callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE; final KeyValueOption kv = (KeyValueOption)options.get("trace.callsites"); if (kv.hasValue("miss")) { callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES; } if (kv.hasValue("enterexit") || (callSiteFlags & NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES) == 0) { callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_ENTEREXIT; } if (kv.hasValue("objects")) { callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES; } } this._callsite_flags = callSiteFlags; final Option<?> timezoneOption = options.get("timezone"); if (timezoneOption != null) { this._timezone = (TimeZone)timezoneOption.getValue(); } else { this._timezone = TimeZone.getDefault(); } final Option<?> localeOption = options.get("locale"); if (localeOption != null) { this._locale = (Locale)localeOption.getValue(); } else { this._locale = Locale.getDefault(); } final LoggingOption loggingOption = (LoggingOption)options.get("log"); this._loggers = loggingOption == null ? new HashMap<String, LoggerInfo>() : loggingOption.getLoggers(); final LoggerInfo timeLoggerInfo = _loggers.get(Timing.getLoggerName()); this._timing = new Timing(timeLoggerInfo != null && timeLoggerInfo.getLevel() != Level.OFF); }
Get the output stream for this environment
Returns:output print writer
/** * Get the output stream for this environment * @return output print writer */
public PrintWriter getOut() { return out; }
Get the error stream for this environment
Returns:error print writer
/** * Get the error stream for this environment * @return error print writer */
public PrintWriter getErr() { return err; }
Get the namespace for this environment
Returns:namespace
/** * Get the namespace for this environment * @return namespace */
public Namespace getNamespace() { return namespace; }
Return the JavaScript files passed to the program
Returns:a list of files
/** * Return the JavaScript files passed to the program * * @return a list of files */
public List<String> getFiles() { return options.getFiles(); }
Return the user arguments to the program, i.e. those trailing "--" after the filename
Returns:a list of user arguments
/** * Return the user arguments to the program, i.e. those trailing "--" after * the filename * * @return a list of user arguments */
public List<String> getArguments() { return options.getArguments(); }
Check if there is a logger registered for a particular name: typically the "name" attribute of a Loggable annotation on a class
Params:
  • name – logger name
Returns:true, if a logger exists for that name, false otherwise
/** * Check if there is a logger registered for a particular name: typically * the "name" attribute of a Loggable annotation on a class * * @param name logger name * @return true, if a logger exists for that name, false otherwise */
public boolean hasLogger(final String name) { return _loggers.get(name) != null; }
Check if compilation/runtime timings are enabled
Returns:true if enabled
/** * Check if compilation/runtime timings are enabled * @return true if enabled */
public boolean isTimingEnabled() { return _timing != null ? _timing.isEnabled() : false; }
Returns true if compilation should use anonymous classes.
Params:
  • sourceLength – length of source being compiled.
Returns:true if anonymous classes should be used
/** * Returns true if compilation should use anonymous classes. * @param sourceLength length of source being compiled. * @return true if anonymous classes should be used */
public boolean useAnonymousClasses(final int sourceLength) { return _anonymousClasses == AnonymousClasses.ON || (_anonymousClasses == AnonymousClasses.AUTO && sourceLength <= _anonymous_classes_threshold); } }