1 /*
   2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.runtime;
  27 
  28 import java.io.PrintWriter;
  29 import java.util.HashSet;
  30 import java.util.List;
  31 import java.util.Locale;
  32 import java.util.Set;
  33 import java.util.StringTokenizer;
  34 import java.util.TimeZone;
  35 
  36 import jdk.nashorn.internal.codegen.Namespace;
  37 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  38 import jdk.nashorn.internal.runtime.options.KeyValueOption;
  39 import jdk.nashorn.internal.runtime.options.Option;
  40 import jdk.nashorn.internal.runtime.options.Options;
  41 
  42 /**
  43  * Script environment consists of command line options, arguments, script files
  44  * and output and error writers, top level Namespace etc.
  45  */
  46 public final class ScriptEnvironment {
  47     /** Output writer for this environment */
  48     private final PrintWriter out;
  49 
  50     /** Error writer for this environment */
  51     private final PrintWriter err;
  52 
  53     /** Top level namespace. */
  54     private final Namespace namespace;
  55 
  56     /** Current Options object. */
  57     private final Options options;
  58 
  59     /** Size of the per-global Class cache size */
  60     public final int     _class_cache_size;
  61 
  62     /** Only compile script, do not run it or generate other ScriptObjects */
  63     public final boolean _compile_only;
  64 
  65     /** Accumulated callsite flags that will be used when bootstrapping script callsites */
  66     public final int     _callsite_flags;
  67 
  68     /** Generate line number table in class files */
  69     public final boolean _debug_lines;
  70 
  71     /** Package to which generated class files are added */
  72     public final String  _dest_dir;
  73 
  74     /** Display stack trace upon error, default is false */
  75     public final boolean _dump_on_error;
  76 
  77     /** Invalid lvalue expressions should be reported as early errors */
  78     public final boolean _early_lvalue_error;
  79 
  80     /** Empty statements should be preserved in the AST */
  81     public final boolean _empty_statements;
  82 
  83     /** Show full Nashorn version */
  84     public final boolean _fullversion;
  85 
  86     /** Launch using as fx application */
  87     public final boolean _fx;
  88 
  89     /** Use single Global instance per jsr223 engine instance. */
  90     public final boolean _global_per_engine;
  91 
  92     /**
  93      * Behavior when encountering a function declaration in a lexical context where only statements are acceptable
  94      * (function declarations are source elements, but not statements).
  95      */
  96     public enum FunctionStatementBehavior {
  97         /**
  98          * Accept the function declaration silently and treat it as if it were a function expression assigned to a local
  99          * variable.
 100          */
 101         ACCEPT,
 102         /**
 103          * Log a parser warning, but accept the function declaration and treat it as if it were a function expression
 104          * assigned to a local variable.
 105          */
 106         WARNING,
 107         /**
 108          * Raise a {@code SyntaxError}.
 109          */
 110         ERROR
 111     }
 112 
 113     /**
 114      * Behavior when encountering a function declaration in a lexical context where only statements are acceptable
 115      * (function declarations are source elements, but not statements).
 116      */
 117     public final FunctionStatementBehavior _function_statement;
 118 
 119     /** Should lazy compilation take place */
 120     public final boolean _lazy_compilation;
 121 
 122     /** Create a new class loaded for each compilation */
 123     public final boolean _loader_per_compile;
 124 
 125     /** Do not support Java support extensions. */
 126     public final boolean _no_java;
 127 
 128     /** Do not support non-standard syntax extensions. */
 129     public final boolean _no_syntax_extensions;
 130 
 131     /** Do not support typed arrays. */
 132     public final boolean _no_typed_arrays;
 133 
 134     /** Only parse the source code, do not compile */
 135     public final boolean _parse_only;
 136 
 137     /** Print the AST before lowering */
 138     public final boolean _print_ast;
 139 
 140     /** Print the AST after lowering */
 141     public final boolean _print_lower_ast;
 142 
 143     /** Print resulting bytecode for script */
 144     public final boolean _print_code;
 145 
 146     /** Print memory usage for IR after each phase */
 147     public final boolean _print_mem_usage;
 148 
 149     /** Print function will no print newline characters */
 150     public final boolean _print_no_newline;
 151 
 152     /** Print AST in more human readable form */
 153     public final boolean _print_parse;
 154 
 155     /** Print AST in more human readable form after Lowering */
 156     public final boolean _print_lower_parse;
 157 
 158     /** print symbols and their contents for the script */
 159     public final boolean _print_symbols;
 160 
 161     /** range analysis for known types */
 162     public final boolean _range_analysis;
 163 
 164     /** is this environment in scripting mode? */
 165     public final boolean _scripting;
 166 
 167     /** is the JIT allowed to specializ calls based on callsite types? */
 168     public final Set<String> _specialize_calls;
 169 
 170     /** is this environment in strict mode? */
 171     public final boolean _strict;
 172 
 173     /** print version info of Nashorn */
 174     public final boolean _version;
 175 
 176     /** should code verification be done of generated bytecode */
 177     public final boolean _verify_code;
 178 
 179     /** time zone for this environment */
 180     public final TimeZone _timezone;
 181 
 182     /** Local for error messages */
 183     public final Locale _locale;
 184 
 185     /**
 186      * Constructor
 187      *
 188      * @param options a Options object
 189      * @param out output print writer
 190      * @param err error print writer
 191      */
 192     public ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) {
 193         this.out = out;
 194         this.err = err;
 195         this.namespace = new Namespace();
 196         this.options = options;
 197 
 198         _class_cache_size     = options.getInteger("class.cache.size");
 199         _compile_only         = options.getBoolean("compile.only");
 200         _debug_lines          = options.getBoolean("debug.lines");
 201         _dest_dir             = options.getString("d");
 202         _dump_on_error        = options.getBoolean("doe");
 203         _early_lvalue_error   = options.getBoolean("early.lvalue.error");
 204         _empty_statements     = options.getBoolean("empty.statements");
 205         _fullversion          = options.getBoolean("fullversion");
 206         if(options.getBoolean("function.statement.error")) {
 207             _function_statement = FunctionStatementBehavior.ERROR;
 208         } else if(options.getBoolean("function.statement.warning")) {
 209             _function_statement = FunctionStatementBehavior.WARNING;
 210         } else {
 211             _function_statement = FunctionStatementBehavior.ACCEPT;
 212         }
 213         _fx                   = options.getBoolean("fx");
 214         _global_per_engine    = options.getBoolean("global.per.engine");
 215         _lazy_compilation     = options.getBoolean("lazy.compilation");
 216         _loader_per_compile   = options.getBoolean("loader.per.compile");
 217         _no_java              = options.getBoolean("no.java");
 218         _no_syntax_extensions = options.getBoolean("no.syntax.extensions");
 219         _no_typed_arrays      = options.getBoolean("no.typed.arrays");
 220         _parse_only           = options.getBoolean("parse.only");
 221         _print_ast            = options.getBoolean("print.ast");
 222         _print_lower_ast      = options.getBoolean("print.lower.ast");
 223         _print_code           = options.getBoolean("print.code");
 224         _print_mem_usage      = options.getBoolean("print.mem.usage");
 225         _print_no_newline     = options.getBoolean("print.no.newline");
 226         _print_parse          = options.getBoolean("print.parse");
 227         _print_lower_parse    = options.getBoolean("print.lower.parse");
 228         _print_symbols        = options.getBoolean("print.symbols");
 229         _range_analysis       = options.getBoolean("range.analysis");
 230         _scripting            = options.getBoolean("scripting");
 231         _strict               = options.getBoolean("strict");
 232         _version              = options.getBoolean("version");
 233         _verify_code          = options.getBoolean("verify.code");
 234 
 235         final String specialize = options.getString("specialize.calls");
 236         if (specialize == null) {
 237             _specialize_calls = null;
 238         } else {
 239             _specialize_calls = new HashSet<>();
 240             final StringTokenizer st = new StringTokenizer(specialize, ",");
 241             while (st.hasMoreElements()) {
 242                 _specialize_calls.add(st.nextToken());
 243             }
 244         }
 245 
 246         int callSiteFlags = 0;
 247         if (options.getBoolean("profile.callsites")) {
 248             callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE;
 249         }
 250 
 251         if (options.get("trace.callsites") instanceof KeyValueOption) {
 252             callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE;
 253             final KeyValueOption kv = (KeyValueOption)options.get("trace.callsites");
 254             if (kv.hasValue("miss")) {
 255                 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES;
 256             }
 257             if (kv.hasValue("enterexit") || (callSiteFlags & NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES) == 0) {
 258                 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_ENTEREXIT;
 259             }
 260             if (kv.hasValue("objects")) {
 261                 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
 262             }
 263             if (kv.hasValue("scope")) {
 264                 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_SCOPE;
 265             }
 266         }
 267         this._callsite_flags = callSiteFlags;
 268 
 269         final Option<?> timezoneOption = options.get("timezone");
 270         if (timezoneOption != null) {
 271             this._timezone = (TimeZone)timezoneOption.getValue();
 272         } else {
 273             this._timezone  = TimeZone.getDefault();
 274         }
 275 
 276         final Option<?> localeOption = options.get("locale");
 277         if (localeOption != null) {
 278             this._locale = (Locale)localeOption.getValue();
 279         } else {
 280             this._locale = Locale.getDefault();
 281         }
 282     }
 283 
 284     /**
 285      * Can we specialize a particular method name?
 286      * @param functionName method name
 287      * @return true if we are allowed to generate versions of this method
 288      */
 289     public boolean canSpecialize(final String functionName) {
 290         if (_specialize_calls == null) {
 291             return false;
 292         }
 293         return _specialize_calls.isEmpty() || _specialize_calls.contains(functionName);
 294     }
 295 
 296     /**
 297      * Get the output stream for this environment
 298      * @return output print writer
 299      */
 300     public PrintWriter getOut() {
 301         return out;
 302     }
 303 
 304     /**
 305      * Get the error stream for this environment
 306      * @return error print writer
 307      */
 308     public PrintWriter getErr() {
 309         return err;
 310     }
 311 
 312     /**
 313      * Get the namespace for this environment
 314      * @return namespace
 315      */
 316     public Namespace getNamespace() {
 317         return namespace;
 318     }
 319 
 320     /**
 321      * Return the JavaScript files passed to the program
 322      *
 323      * @return a list of files
 324      */
 325     public List<String> getFiles() {
 326         return options.getFiles();
 327     }
 328 
 329     /**
 330      * Return the user arguments to the program, i.e. those trailing "--" after
 331      * the filename
 332      *
 333      * @return a list of user arguments
 334      */
 335     public List<String> getArguments() {
 336         return options.getArguments();
 337     }
 338 }