ScriptEnvironment.java revision 1387:864aaf4e6441
161981Sbrian/*
261981Sbrian * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
361981Sbrian * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
461981Sbrian *
561981Sbrian * This code is free software; you can redistribute it and/or modify it
661981Sbrian * under the terms of the GNU General Public License version 2 only, as
761981Sbrian * published by the Free Software Foundation.  Oracle designates this
861981Sbrian * particular file as subject to the "Classpath" exception as provided
961981Sbrian * by Oracle in the LICENSE file that accompanied this code.
1061981Sbrian *
1161981Sbrian * This code is distributed in the hope that it will be useful, but WITHOUT
1261981Sbrian * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1361981Sbrian * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1461981Sbrian * version 2 for more details (a copy is included in the LICENSE file that
1561981Sbrian * accompanied this code).
1661981Sbrian *
1761981Sbrian * You should have received a copy of the GNU General Public License version
1861981Sbrian * 2 along with this work; if not, write to the Free Software Foundation,
1961981Sbrian * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2061981Sbrian *
2161981Sbrian * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2261981Sbrian * or visit www.oracle.com if you need additional information or have any
2361981Sbrian * questions.
2461981Sbrian */
2565843Sbrian
2665843Sbrianpackage jdk.nashorn.internal.runtime;
2765843Sbrian
2865843Sbrianimport java.io.PrintWriter;
2965843Sbrianimport java.util.HashMap;
3065843Sbrianimport java.util.List;
3165843Sbrianimport java.util.Locale;
3265843Sbrianimport java.util.Map;
3365843Sbrianimport java.util.StringTokenizer;
3465843Sbrianimport java.util.TimeZone;
3561981Sbrianimport java.util.logging.Level;
3661981Sbrianimport jdk.nashorn.internal.codegen.Namespace;
3761981Sbrianimport jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
3861981Sbrianimport jdk.nashorn.internal.runtime.options.KeyValueOption;
3961981Sbrianimport jdk.nashorn.internal.runtime.options.LoggingOption;
4061981Sbrianimport jdk.nashorn.internal.runtime.options.LoggingOption.LoggerInfo;
4161981Sbrianimport jdk.nashorn.internal.runtime.options.Option;
4261981Sbrianimport jdk.nashorn.internal.runtime.options.Options;
4361981Sbrian
4461981Sbrian/**
4561981Sbrian * Script environment consists of command line options, arguments, script files
4661981Sbrian * and output and error writers, top level Namespace etc.
4761981Sbrian */
4861981Sbrianpublic final class ScriptEnvironment {
4961981Sbrian    // Primarily intended to be used in test environments so that eager compilation tests work without an
5061981Sbrian    // error when tested with optimistic compilation.
5161981Sbrian    private static final boolean ALLOW_EAGER_COMPILATION_SILENT_OVERRIDE = Options.getBooleanProperty(
5261981Sbrian            "nashorn.options.allowEagerCompilationSilentOverride", false);
5361981Sbrian
5461981Sbrian    /** Output writer for this environment */
5561981Sbrian    private final PrintWriter out;
5661981Sbrian
5761981Sbrian    /** Error writer for this environment */
5861981Sbrian    private final PrintWriter err;
5961981Sbrian
6061981Sbrian    /** Top level namespace. */
6161981Sbrian    private final Namespace namespace;
6261981Sbrian
63108959Swollman    /** Current Options object. */
64108959Swollman    private final Options options;
6561981Sbrian
6661981Sbrian    /** Size of the per-global Class cache size */
6761981Sbrian    public final int     _class_cache_size;
6861981Sbrian
6961981Sbrian    /** -classpath value. */
7061981Sbrian    public final String  _classpath;
7161981Sbrian
7261981Sbrian    /** Only compile script, do not run it or generate other ScriptObjects */
7361981Sbrian    public final boolean _compile_only;
7461981Sbrian
7561981Sbrian    /** Accept "const" keyword and treat it as variable. Interim feature */
7661981Sbrian    public final boolean _const_as_var;
7762054Sbrian
7877496Sbrian    /** Accumulated callsite flags that will be used when bootstrapping script callsites */
7977492Sbrian    public final int     _callsite_flags;
8061981Sbrian
8161981Sbrian    /** Generate line number table in class files */
8261981Sbrian    public final boolean _debug_lines;
8361981Sbrian
8461981Sbrian    /** Directory in which source files and generated class files are dumped */
8561981Sbrian    public final String  _dest_dir;
8662644Ssheldonh
8761981Sbrian    /** Display stack trace upon error, default is false */
88121620Sjesper    public final boolean _dump_on_error;
89123498Sjesper
90121620Sjesper    /** Invalid lvalue expressions should be reported as early errors */
9161981Sbrian    public final boolean _early_lvalue_error;
9261981Sbrian
9361981Sbrian    /** Empty statements should be preserved in the AST */
9461981Sbrian    public final boolean _empty_statements;
9561981Sbrian
9661981Sbrian    /** Show full Nashorn version */
9761981Sbrian    public final boolean _fullversion;
9861981Sbrian
9961981Sbrian    /** Launch using as fx application */
10061981Sbrian    public final boolean _fx;
10194342Sgshapiro
10261981Sbrian    /** Use single Global instance per jsr223 engine instance. */
10361981Sbrian    public final boolean _global_per_engine;
10461981Sbrian
10587514Scjc    /** Enable experimental ECMAScript 6 features. */
10661981Sbrian    public final boolean _es6;
10761981Sbrian
10861981Sbrian    /** Argument passed to compile only if optimistic compilation should take place */
10962274Sbrian    public static final String COMPILE_ONLY_OPTIMISTIC_ARG = "optimistic";
11061981Sbrian
11175809Sdirk    /**
11275809Sdirk     *  Behavior when encountering a function declaration in a lexical context where only statements are acceptable
11375809Sdirk     * (function declarations are source elements, but not statements).
11475809Sdirk     */
11572677Speter    public enum FunctionStatementBehavior {
11672677Speter        /**
11794342Sgshapiro         * Accept the function declaration silently and treat it as if it were a function expression assigned to a local
11872677Speter         * variable.
11961981Sbrian         */
12061981Sbrian        ACCEPT,
12161981Sbrian        /**
12261981Sbrian         * Log a parser warning, but accept the function declaration and treat it as if it were a function expression
12387514Scjc         * assigned to a local variable.
12487514Scjc         */
125101607Sfanf        WARNING,
12687514Scjc        /**
12787514Scjc         * Raise a {@code SyntaxError}.
12887514Scjc         */
12987514Scjc        ERROR
13087514Scjc    }
131135591Sjkoshy
13287514Scjc    /**
13387514Scjc     * Behavior when encountering a function declaration in a lexical context where only statements are acceptable
13487514Scjc     * (function declarations are source elements, but not statements).
13587514Scjc     */
13687514Scjc    public final FunctionStatementBehavior _function_statement;
13787514Scjc
13887514Scjc    /** Should lazy compilation take place */
13987514Scjc    public final boolean _lazy_compilation;
14087514Scjc
14187514Scjc    /** Should optimistic types be used */
14287514Scjc    public final boolean _optimistic_types;
14387514Scjc
14487514Scjc    /** Create a new class loaded for each compilation */
14587514Scjc    public final boolean _loader_per_compile;
14687514Scjc
14787514Scjc    /** Do not support Java support extensions. */
14887514Scjc    public final boolean _no_java;
14987514Scjc
150105937Sthomas    /** Do not support non-standard syntax extensions. */
151105937Sthomas    public final boolean _no_syntax_extensions;
152105937Sthomas
153138061Smlaier    /** Do not support typed arrays. */
154138061Smlaier    public final boolean _no_typed_arrays;
155138061Smlaier
15687514Scjc    /** Only parse the source code, do not compile */
15787514Scjc    public final boolean _parse_only;
15887514Scjc
15987514Scjc    /** Enable disk cache for compiled scripts */
16087514Scjc    public final boolean _persistent_cache;
16187514Scjc
162128473Sdarrenr    /** Print the AST before lowering */
163128473Sdarrenr    public final boolean _print_ast;
164128473Sdarrenr
16587514Scjc    /** Print the AST after lowering */
16687514Scjc    public final boolean _print_lower_ast;
16787514Scjc
16887514Scjc    /** Print resulting bytecode for script */
16987514Scjc    public final boolean _print_code;
17087514Scjc
17187514Scjc    /** Directory (optional) to print files to */
17287514Scjc    public final String _print_code_dir;
17387514Scjc
17487514Scjc    /** List of functions to write to the print code dir, optional */
17587514Scjc    public final String _print_code_func;
17687514Scjc
17787514Scjc    /** Print memory usage for IR after each phase */
17861981Sbrian    public final boolean _print_mem_usage;
17961981Sbrian
18065843Sbrian    /** Print function will no print newline characters */
18165843Sbrian    public final boolean _print_no_newline;
18265843Sbrian
18365843Sbrian    /** Print AST in more human readable form */
18465843Sbrian    public final boolean _print_parse;
18565843Sbrian
18665843Sbrian    /** Print AST in more human readable form after Lowering */
18765843Sbrian    public final boolean _print_lower_parse;
18865843Sbrian
18965843Sbrian    /** print symbols and their contents for the script */
19061981Sbrian    public final boolean _print_symbols;
19161981Sbrian
19261981Sbrian    /** is this environment in scripting mode? */
19361981Sbrian    public final boolean _scripting;
19461981Sbrian
19561981Sbrian    /** is this environment in strict mode? */
19661981Sbrian    public final boolean _strict;
19761981Sbrian
19861981Sbrian    /** print version info of Nashorn */
19961981Sbrian    public final boolean _version;
20061981Sbrian
20161981Sbrian    /** should code verification be done of generated bytecode */
20261981Sbrian    public final boolean _verify_code;
20361981Sbrian
20461981Sbrian    /** time zone for this environment */
20561981Sbrian    public final TimeZone _timezone;
20661981Sbrian
20761981Sbrian    /** Local for error messages */
20862206Sbrian    public final Locale _locale;
20962155Sbrian
210103948Sbrian    /** Logging */
211129424Sjoe    public final Map<String, LoggerInfo> _loggers;
21262155Sbrian
21361981Sbrian    /** Timing */
21461981Sbrian    public final Timing _timing;
21561981Sbrian
21661981Sbrian    /**
21761981Sbrian     * Constructor
21861981Sbrian     *
21965843Sbrian     * @param options a Options object
22065843Sbrian     * @param out output print writer
22165843Sbrian     * @param err error print writer
22265843Sbrian     */
22365843Sbrian    @SuppressWarnings("unused")
22465843Sbrian    public ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) {
22565843Sbrian        this.out = out;
22665843Sbrian        this.err = err;
22765843Sbrian        this.namespace = new Namespace();
22865843Sbrian        this.options = options;
22961981Sbrian
23061981Sbrian        _class_cache_size     = options.getInteger("class.cache.size");
23161981Sbrian        _classpath            = options.getString("classpath");
23261981Sbrian        _compile_only         = options.getBoolean("compile.only");
23361981Sbrian        _const_as_var         = options.getBoolean("const.as.var");
23461981Sbrian        _debug_lines          = options.getBoolean("debug.lines");
23561981Sbrian        _dest_dir             = options.getString("d");
23661981Sbrian        _dump_on_error        = options.getBoolean("doe");
23761981Sbrian        _early_lvalue_error   = options.getBoolean("early.lvalue.error");
23861981Sbrian        _empty_statements     = options.getBoolean("empty.statements");
23961981Sbrian        _fullversion          = options.getBoolean("fullversion");
24061981Sbrian        if (options.getBoolean("function.statement.error")) {
24161981Sbrian            _function_statement = FunctionStatementBehavior.ERROR;
24261981Sbrian        } else if (options.getBoolean("function.statement.warning")) {
24361981Sbrian            _function_statement = FunctionStatementBehavior.WARNING;
24461981Sbrian        } else {
24561981Sbrian            _function_statement = FunctionStatementBehavior.ACCEPT;
24661981Sbrian        }
24761981Sbrian        _fx                   = options.getBoolean("fx");
24861981Sbrian        _global_per_engine    = options.getBoolean("global.per.engine");
24961981Sbrian        _optimistic_types     = options.getBoolean("optimistic.types");
25061981Sbrian        final boolean lazy_compilation = options.getBoolean("lazy.compilation");
25161981Sbrian        if (!lazy_compilation && _optimistic_types) {
25261981Sbrian            if (!ALLOW_EAGER_COMPILATION_SILENT_OVERRIDE) {
25361981Sbrian                throw new IllegalStateException(
25461981Sbrian                        ECMAErrors.getMessage(
25561981Sbrian                                "config.error.eagerCompilationConflictsWithOptimisticTypes",
256                                options.getOptionTemplateByKey("lazy.compilation").getName(),
257                                options.getOptionTemplateByKey("optimistic.types").getName()));
258            }
259            _lazy_compilation = true;
260        } else {
261            _lazy_compilation = lazy_compilation;
262        }
263        _loader_per_compile   = options.getBoolean("loader.per.compile");
264        _no_java              = options.getBoolean("no.java");
265        _no_syntax_extensions = options.getBoolean("no.syntax.extensions");
266        _no_typed_arrays      = options.getBoolean("no.typed.arrays");
267        _parse_only           = options.getBoolean("parse.only");
268        _persistent_cache     = options.getBoolean("persistent.code.cache");
269        _print_ast            = options.getBoolean("print.ast");
270        _print_lower_ast      = options.getBoolean("print.lower.ast");
271        _print_code           = options.getString("print.code") != null;
272        _print_mem_usage      = options.getBoolean("print.mem.usage");
273        _print_no_newline     = options.getBoolean("print.no.newline");
274        _print_parse          = options.getBoolean("print.parse");
275        _print_lower_parse    = options.getBoolean("print.lower.parse");
276        _print_symbols        = options.getBoolean("print.symbols");
277        _scripting            = options.getBoolean("scripting");
278        _strict               = options.getBoolean("strict");
279        _version              = options.getBoolean("version");
280        _verify_code          = options.getBoolean("verify.code");
281
282        final String language = options.getString("language");
283        if (language == null || language.equals("es5")) {
284            _es6 = false;
285        } else if (language.equals("es6")) {
286            _es6 = true;
287        } else {
288            throw new RuntimeException("Unsupported language: " + language);
289        }
290
291        String dir = null;
292        String func = null;
293        final String pc = options.getString("print.code");
294        if (pc != null) {
295            final StringTokenizer st = new StringTokenizer(pc, ",");
296            while (st.hasMoreTokens()) {
297                final StringTokenizer st2 = new StringTokenizer(st.nextToken(), ":");
298                while (st2.hasMoreTokens()) {
299                    final String cmd = st2.nextToken();
300                    if ("dir".equals(cmd)) {
301                        dir = st2.nextToken();
302                    } else if ("function".equals(cmd)) {
303                        func = st2.nextToken();
304                    }
305                }
306            }
307        }
308        _print_code_dir = dir;
309        _print_code_func = func;
310
311        int callSiteFlags = 0;
312        if (options.getBoolean("profile.callsites")) {
313            callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE;
314        }
315
316        if (options.get("trace.callsites") instanceof KeyValueOption) {
317            callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE;
318            final KeyValueOption kv = (KeyValueOption)options.get("trace.callsites");
319            if (kv.hasValue("miss")) {
320                callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES;
321            }
322            if (kv.hasValue("enterexit") || (callSiteFlags & NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES) == 0) {
323                callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_ENTEREXIT;
324            }
325            if (kv.hasValue("objects")) {
326                callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
327            }
328        }
329        this._callsite_flags = callSiteFlags;
330
331        final Option<?> timezoneOption = options.get("timezone");
332        if (timezoneOption != null) {
333            this._timezone = (TimeZone)timezoneOption.getValue();
334        } else {
335            this._timezone  = TimeZone.getDefault();
336        }
337
338        final Option<?> localeOption = options.get("locale");
339        if (localeOption != null) {
340            this._locale = (Locale)localeOption.getValue();
341        } else {
342            this._locale = Locale.getDefault();
343        }
344
345        final LoggingOption loggingOption = (LoggingOption)options.get("log");
346        this._loggers = loggingOption == null ? new HashMap<String, LoggerInfo>() : loggingOption.getLoggers();
347
348        final LoggerInfo timeLoggerInfo = _loggers.get(Timing.getLoggerName());
349        this._timing = new Timing(timeLoggerInfo != null && timeLoggerInfo.getLevel() != Level.OFF);
350    }
351
352    /**
353     * Get the output stream for this environment
354     * @return output print writer
355     */
356    public PrintWriter getOut() {
357        return out;
358    }
359
360    /**
361     * Get the error stream for this environment
362     * @return error print writer
363     */
364    public PrintWriter getErr() {
365        return err;
366    }
367
368    /**
369     * Get the namespace for this environment
370     * @return namespace
371     */
372    public Namespace getNamespace() {
373        return namespace;
374    }
375
376    /**
377     * Return the JavaScript files passed to the program
378     *
379     * @return a list of files
380     */
381    public List<String> getFiles() {
382        return options.getFiles();
383    }
384
385    /**
386     * Return the user arguments to the program, i.e. those trailing "--" after
387     * the filename
388     *
389     * @return a list of user arguments
390     */
391    public List<String> getArguments() {
392        return options.getArguments();
393    }
394
395    /**
396     * Check if there is a logger registered for a particular name: typically
397     * the "name" attribute of a Loggable annotation on a class
398     *
399     * @param name logger name
400     * @return true, if a logger exists for that name, false otherwise
401     */
402    public boolean hasLogger(final String name) {
403        return _loggers.get(name) != null;
404    }
405
406    /**
407     * Check if compilation/runtime timings are enabled
408     * @return true if enabled
409     */
410    public boolean isTimingEnabled() {
411        return _timing != null ? _timing.isEnabled() : false;
412    }
413
414}
415