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.HashMap; 30 import java.util.List; 31 import java.util.Locale; 32 import java.util.Map; 33 import java.util.StringTokenizer; 34 import java.util.TimeZone; 35 import java.util.logging.Level; 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.LoggingOption; 40 import jdk.nashorn.internal.runtime.options.LoggingOption.LoggerInfo; 41 import jdk.nashorn.internal.runtime.options.Option; 42 import jdk.nashorn.internal.runtime.options.Options; 43 44 /** 45 * Script environment consists of command line options, arguments, script files 46 * and output and error writers, top level Namespace etc. 47 */ 48 public final class ScriptEnvironment { 49 // Primarily intended to be used in test environments so that eager compilation tests work without an 50 // error when tested with optimistic compilation. 51 private static final boolean ALLOW_EAGER_COMPILATION_SILENT_OVERRIDE = Options.getBooleanProperty( 52 "nashorn.options.allowEagerCompilationSilentOverride", false); 53 54 /** Output writer for this environment */ 55 private final PrintWriter out; 56 57 /** Error writer for this environment */ 58 private final PrintWriter err; 59 60 /** Top level namespace. */ 61 private final Namespace namespace; 62 63 /** Current Options object. */ 64 private final Options options; 65 66 /** Size of the per-global Class cache size */ 67 public final int _class_cache_size; 68 69 /** -classpath value. */ 70 public final String _classpath; 71 72 /** Only compile script, do not run it or generate other ScriptObjects */ 73 public final boolean _compile_only; 74 75 /** Accept "const" keyword and treat it as variable. Interim feature */ 76 public final boolean _const_as_var; 77 78 /** Accumulated callsite flags that will be used when bootstrapping script callsites */ 79 public final int _callsite_flags; 80 81 /** Generate line number table in class files */ 82 public final boolean _debug_lines; 83 84 /** Put all variables in scopes to make them debuggable */ 85 public final boolean _debug_scopes; 86 87 /** Directory in which source files and generated class files are dumped */ 88 public final String _dest_dir; 89 90 /** Display stack trace upon error, default is false */ 91 public final boolean _dump_on_error; 92 93 /** Invalid lvalue expressions should be reported as early errors */ 94 public final boolean _early_lvalue_error; 95 96 /** Empty statements should be preserved in the AST */ 97 public final boolean _empty_statements; 98 99 /** Show full Nashorn version */ 100 public final boolean _fullversion; 101 102 /** Launch using as fx application */ 103 public final boolean _fx; 104 105 /** Use single Global instance per jsr223 engine instance. */ 106 public final boolean _global_per_engine; 107 108 /** Enable experimental ECMAScript 6 features. */ 109 public final boolean _es6; 110 111 /** do not show deprecation warning for nashorn engine and jjs usage. */ 112 public final boolean _no_deprecation_warning; 113 114 /** Number of times a dynamic call site has to be relinked before it is 115 * considered unstable (and thus should be linked as if it were megamorphic). 116 */ 117 public final int _unstable_relink_threshold; 118 119 /** Argument passed to compile only if optimistic compilation should take place */ 120 public static final String COMPILE_ONLY_OPTIMISTIC_ARG = "optimistic"; 121 122 /** 123 * Behavior when encountering a function declaration in a lexical context where only statements are acceptable 124 * (function declarations are source elements, but not statements). 125 */ 126 public enum FunctionStatementBehavior { 127 /** 128 * Accept the function declaration silently and treat it as if it were a function expression assigned to a local 129 * variable. 130 */ 131 ACCEPT, 132 /** 133 * Log a parser warning, but accept the function declaration and treat it as if it were a function expression 134 * assigned to a local variable. 135 */ 136 WARNING, 137 /** 138 * Raise a {@code SyntaxError}. 139 */ 140 ERROR 141 } 142 143 /** 144 * Behavior when encountering a function declaration in a lexical context where only statements are acceptable 145 * (function declarations are source elements, but not statements). 146 */ 147 public final FunctionStatementBehavior _function_statement; 148 149 /** Should lazy compilation take place */ 150 public final boolean _lazy_compilation; 151 152 /** Should optimistic types be used */ 153 public final boolean _optimistic_types; 154 155 /** Create a new class loaded for each compilation */ 156 public final boolean _loader_per_compile; 157 158 /** --module-path, if any */ 159 public final String _module_path; 160 161 /** --add-modules, if any */ 162 public final String _add_modules; 163 164 /** Do not support Java support extensions. */ 165 public final boolean _no_java; 166 167 /** Do not support non-standard syntax extensions. */ 168 public final boolean _no_syntax_extensions; 169 170 /** Do not support typed arrays. */ 171 public final boolean _no_typed_arrays; 172 173 /** Only parse the source code, do not compile */ 174 public final boolean _parse_only; 175 176 /** Enable disk cache for compiled scripts */ 177 public final boolean _persistent_cache; 178 179 /** Print the AST before lowering */ 180 public final boolean _print_ast; 181 182 /** Print the AST after lowering */ 183 public final boolean _print_lower_ast; 184 185 /** Print resulting bytecode for script */ 186 public final boolean _print_code; 187 188 /** Directory (optional) to print files to */ 189 public final String _print_code_dir; 190 191 /** List of functions to write to the print code dir, optional */ 192 public final String _print_code_func; 193 194 /** Print function will no print newline characters */ 195 public final boolean _print_no_newline; 196 197 /** Print AST in more human readable form */ 198 public final boolean _print_parse; 199 200 /** Print AST in more human readable form after Lowering */ 201 public final boolean _print_lower_parse; 202 203 /** print symbols and their contents for the script */ 204 public final boolean _print_symbols; 205 206 /** is this environment in scripting mode? */ 207 public final boolean _scripting; 208 209 /** is this environment in strict mode? */ 210 public final boolean _strict; 211 212 /** print version info of Nashorn */ 213 public final boolean _version; 214 215 /** should code verification be done of generated bytecode */ 216 public final boolean _verify_code; 217 218 /** time zone for this environment */ 219 public final TimeZone _timezone; 220 221 /** Local for error messages */ 222 public final Locale _locale; 223 224 /** Logging */ 225 public final Map<String, LoggerInfo> _loggers; 226 227 /** Timing */ 228 public final Timing _timing; 229 230 /** Whether to use anonymous classes. See {@link #useAnonymousClasses(int)}. */ 231 private final AnonymousClasses _anonymousClasses; 232 private enum AnonymousClasses { 233 AUTO, 234 OFF, 235 ON 236 } 237 238 /** Size threshold up to which we use anonymous classes in {@link AnonymousClasses#AUTO} setting */ 239 private final int _anonymous_classes_threshold; 240 241 /** Default value for anonymous class threshold */ 242 private final static int DEFAULT_ANON_CLASS_THRESHOLD = 512; 243 244 /** 245 * Constructor 246 * 247 * @param options a Options object 248 * @param out output print writer 249 * @param err error print writer 250 */ 251 @SuppressWarnings("unused") 252 public ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) { 253 this.out = out; 254 this.err = err; 255 this.namespace = new Namespace(); 256 this.options = options; 257 258 _class_cache_size = options.getInteger("class.cache.size"); 259 _classpath = options.getString("classpath"); 260 _compile_only = options.getBoolean("compile.only"); 261 _const_as_var = options.getBoolean("const.as.var"); 262 _debug_lines = options.getBoolean("debug.lines"); 263 _debug_scopes = options.getBoolean("debug.scopes"); 264 _dest_dir = options.getString("d"); 265 _dump_on_error = options.getBoolean("doe"); 266 _early_lvalue_error = options.getBoolean("early.lvalue.error"); 267 _empty_statements = options.getBoolean("empty.statements"); 268 _fullversion = options.getBoolean("fullversion"); 269 if (options.getBoolean("function.statement.error")) { 270 _function_statement = FunctionStatementBehavior.ERROR; 271 } else if (options.getBoolean("function.statement.warning")) { 272 _function_statement = FunctionStatementBehavior.WARNING; 273 } else { 274 _function_statement = FunctionStatementBehavior.ACCEPT; 275 } 276 _fx = options.getBoolean("fx"); 277 _global_per_engine = options.getBoolean("global.per.engine"); 278 _optimistic_types = options.getBoolean("optimistic.types"); 279 final boolean lazy_compilation = options.getBoolean("lazy.compilation"); 280 if (!lazy_compilation && _optimistic_types) { 281 if (!ALLOW_EAGER_COMPILATION_SILENT_OVERRIDE) { 282 throw new IllegalStateException( 283 ECMAErrors.getMessage( 284 "config.error.eagerCompilationConflictsWithOptimisticTypes", 285 options.getOptionTemplateByKey("lazy.compilation").getName(), 286 options.getOptionTemplateByKey("optimistic.types").getName())); 287 } 288 _lazy_compilation = true; 289 } else { 290 _lazy_compilation = lazy_compilation; 291 } 292 _loader_per_compile = options.getBoolean("loader.per.compile"); 293 _module_path = options.getString("module.path"); 294 _add_modules = options.getString("add.modules"); 295 _no_java = options.getBoolean("no.java"); 296 _no_syntax_extensions = options.getBoolean("no.syntax.extensions"); 297 _no_typed_arrays = options.getBoolean("no.typed.arrays"); 298 _parse_only = options.getBoolean("parse.only"); 299 _persistent_cache = options.getBoolean("persistent.code.cache"); 300 _print_ast = options.getBoolean("print.ast"); 301 _print_lower_ast = options.getBoolean("print.lower.ast"); 302 _print_code = options.getString("print.code") != null; 303 _print_no_newline = options.getBoolean("print.no.newline"); 304 _print_parse = options.getBoolean("print.parse"); 305 _print_lower_parse = options.getBoolean("print.lower.parse"); 306 _print_symbols = options.getBoolean("print.symbols"); 307 _scripting = options.getBoolean("scripting"); 308 _strict = options.getBoolean("strict"); 309 _version = options.getBoolean("version"); 310 _verify_code = options.getBoolean("verify.code"); 311 _no_deprecation_warning = options.getBoolean("no.deprecation.warning"); 312 313 final int configuredUrt = options.getInteger("unstable.relink.threshold"); 314 // The default for this property is -1, so we can easily detect when 315 // it is not specified on command line. 316 if (configuredUrt < 0) { 317 // In this case, use a default of 8, or 16 for optimistic types. 318 // Optimistic types come with dual fields, and in order to get 319 // performance on benchmarks with a lot of object instantiation and 320 // then field reassignment, it can take slightly more relinks to 321 // become stable with type changes swapping out an entire property 322 // map and making a map guard fail. Also, honor the "nashorn.*" 323 // system property for now. It was documented in DEVELOPER_README 324 // so we should recognize it for the time being. 325 _unstable_relink_threshold = Options.getIntProperty( 326 "nashorn.unstable.relink.threshold", 327 _optimistic_types ? 16 : 8); 328 } else { 329 _unstable_relink_threshold = configuredUrt; 330 } 331 332 final String anonClasses = options.getString("anonymous.classes"); 333 if (anonClasses == null || anonClasses.equals("auto")) { 334 _anonymousClasses = AnonymousClasses.AUTO; 335 } else if (anonClasses.equals("true")) { 336 _anonymousClasses = AnonymousClasses.ON; 337 } else if (anonClasses.equals("false")) { 338 _anonymousClasses = AnonymousClasses.OFF; 339 } else { 340 throw new RuntimeException("Unsupported value for anonymous classes: " + anonClasses); 341 } 342 343 this._anonymous_classes_threshold = Options.getIntProperty( 344 "nashorn.anonymous.classes.threshold", DEFAULT_ANON_CLASS_THRESHOLD); 345 346 final String language = options.getString("language"); 347 if (language == null || language.equals("es5")) { 348 _es6 = false; 349 } else if (language.equals("es6")) { 350 _es6 = true; 351 } else { 352 throw new RuntimeException("Unsupported language: " + language); 353 } 354 355 String dir = null; 356 String func = null; 357 final String pc = options.getString("print.code"); 358 if (pc != null) { 359 final StringTokenizer st = new StringTokenizer(pc, ","); 360 while (st.hasMoreTokens()) { 361 final StringTokenizer st2 = new StringTokenizer(st.nextToken(), ":"); 362 while (st2.hasMoreTokens()) { 363 final String cmd = st2.nextToken(); 364 if ("dir".equals(cmd)) { 365 dir = st2.nextToken(); 366 } else if ("function".equals(cmd)) { 367 func = st2.nextToken(); 368 } 369 } 370 } 371 } 372 _print_code_dir = dir; 373 _print_code_func = func; 374 375 int callSiteFlags = 0; 376 if (options.getBoolean("profile.callsites")) { 377 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE; 378 } 379 380 if (options.get("trace.callsites") instanceof KeyValueOption) { 381 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE; 382 final KeyValueOption kv = (KeyValueOption)options.get("trace.callsites"); 383 if (kv.hasValue("miss")) { 384 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES; 385 } 386 if (kv.hasValue("enterexit") || (callSiteFlags & NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES) == 0) { 387 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_ENTEREXIT; 388 } 389 if (kv.hasValue("objects")) { 390 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES; 391 } 392 } 393 this._callsite_flags = callSiteFlags; 394 395 final Option<?> timezoneOption = options.get("timezone"); 396 if (timezoneOption != null) { 397 this._timezone = (TimeZone)timezoneOption.getValue(); 398 } else { 399 this._timezone = TimeZone.getDefault(); 400 } 401 402 final Option<?> localeOption = options.get("locale"); 403 if (localeOption != null) { 404 this._locale = (Locale)localeOption.getValue(); 405 } else { 406 this._locale = Locale.getDefault(); 407 } 408 409 final LoggingOption loggingOption = (LoggingOption)options.get("log"); 410 this._loggers = loggingOption == null ? new HashMap<String, LoggerInfo>() : loggingOption.getLoggers(); 411 412 final LoggerInfo timeLoggerInfo = _loggers.get(Timing.getLoggerName()); 413 this._timing = new Timing(timeLoggerInfo != null && timeLoggerInfo.getLevel() != Level.OFF); 414 } 415 416 /** 417 * Get the output stream for this environment 418 * @return output print writer 419 */ 420 public PrintWriter getOut() { 421 return out; 422 } 423 424 /** 425 * Get the error stream for this environment 426 * @return error print writer 427 */ 428 public PrintWriter getErr() { 429 return err; 430 } 431 432 /** 433 * Get the namespace for this environment 434 * @return namespace 435 */ 436 public Namespace getNamespace() { 437 return namespace; 438 } 439 440 /** 441 * Return the JavaScript files passed to the program 442 * 443 * @return a list of files 444 */ 445 public List<String> getFiles() { 446 return options.getFiles(); 447 } 448 449 /** 450 * Return the user arguments to the program, i.e. those trailing "--" after 451 * the filename 452 * 453 * @return a list of user arguments 454 */ 455 public List<String> getArguments() { 456 return options.getArguments(); 457 } 458 459 /** 460 * Check if there is a logger registered for a particular name: typically 461 * the "name" attribute of a Loggable annotation on a class 462 * 463 * @param name logger name 464 * @return true, if a logger exists for that name, false otherwise 465 */ 466 public boolean hasLogger(final String name) { 467 return _loggers.get(name) != null; 468 } 469 470 /** 471 * Check if compilation/runtime timings are enabled 472 * @return true if enabled 473 */ 474 public boolean isTimingEnabled() { 475 return _timing != null ? _timing.isEnabled() : false; 476 } 477 478 /** 479 * Returns true if compilation should use anonymous classes. 480 * @param sourceLength length of source being compiled. 481 * @return true if anonymous classes should be used 482 */ 483 public boolean useAnonymousClasses(final int sourceLength) { 484 return _anonymousClasses == AnonymousClasses.ON 485 || (_anonymousClasses == AnonymousClasses.AUTO && sourceLength <= _anonymous_classes_threshold); 486 } 487 488 }