src/jdk/nashorn/internal/runtime/Context.java

Sat, 23 Mar 2013 00:58:39 +0100

author
attila
date
Sat, 23 Mar 2013 00:58:39 +0100
changeset 144
4be452026847
parent 139
390d44ba90cf
child 196
222a72df2f42
permissions
-rw-r--r--

8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
Reviewed-by: jlaskey, lagergren

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.runtime;
jlaskey@3 27
jlaskey@3 28 import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
jlaskey@3 29 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
attila@144 30 import static jdk.nashorn.internal.lookup.Lookup.MH;
jlaskey@3 31 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
jlaskey@3 32 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
jlaskey@3 33
jlaskey@3 34 import java.io.File;
jlaskey@3 35 import java.io.IOException;
jlaskey@3 36 import java.io.PrintWriter;
jlaskey@3 37 import java.lang.invoke.MethodHandle;
jlaskey@3 38 import java.lang.invoke.MethodHandles;
sundar@82 39 import java.lang.reflect.Constructor;
lagergren@110 40 import java.net.MalformedURLException;
jlaskey@3 41 import java.net.URL;
sundar@136 42 import java.security.AccessControlContext;
jlaskey@3 43 import java.security.AccessController;
jlaskey@3 44 import java.security.CodeSigner;
jlaskey@3 45 import java.security.CodeSource;
sundar@136 46 import java.security.Permissions;
jlaskey@3 47 import java.security.PrivilegedAction;
sundar@136 48 import java.security.ProtectionDomain;
jlaskey@3 49 import jdk.internal.org.objectweb.asm.ClassReader;
jlaskey@3 50 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
jlaskey@3 51 import jdk.nashorn.internal.codegen.Compiler;
lagergren@96 52 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
lagergren@89 53 import jdk.nashorn.internal.ir.FunctionNode;
lagergren@96 54 import jdk.nashorn.internal.ir.debug.ASTWriter;
lagergren@89 55 import jdk.nashorn.internal.ir.debug.PrintVisitor;
lagergren@89 56 import jdk.nashorn.internal.parser.Parser;
sundar@44 57 import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
jlaskey@3 58 import jdk.nashorn.internal.runtime.options.Options;
sundar@44 59 import sun.reflect.Reflection;
jlaskey@3 60
jlaskey@3 61 /**
jlaskey@3 62 * This class manages the global state of execution. Context is immutable.
jlaskey@3 63 */
jlaskey@3 64 public final class Context {
jlaskey@3 65
lagergren@89 66 /**
lagergren@89 67 * ContextCodeInstaller that has the privilege of installing classes in the Context.
lagergren@89 68 * Can only be instantiated from inside the context and is opaque to other classes
lagergren@89 69 */
sundar@118 70 public static class ContextCodeInstaller implements CodeInstaller<ScriptEnvironment> {
lagergren@89 71 private final Context context;
lagergren@89 72 private final ScriptLoader loader;
lagergren@89 73 private final CodeSource codeSource;
lagergren@89 74
lagergren@89 75 private ContextCodeInstaller(final Context context, final ScriptLoader loader, final CodeSource codeSource) {
lagergren@89 76 this.context = context;
lagergren@89 77 this.loader = loader;
lagergren@89 78 this.codeSource = codeSource;
lagergren@89 79 }
lagergren@89 80
lagergren@89 81 /**
lagergren@89 82 * Return the context for this installer
lagergren@137 83 * @return ScriptEnvironment
lagergren@89 84 */
lagergren@89 85 @Override
sundar@118 86 public ScriptEnvironment getOwner() {
sundar@118 87 return context.env;
lagergren@89 88 }
lagergren@89 89
lagergren@89 90 @Override
lagergren@89 91 public Class<?> install(final String className, final byte[] bytecode) {
lagergren@89 92 return loader.installClass(className, bytecode, codeSource);
lagergren@89 93 }
sundar@118 94
sundar@118 95 @Override
sundar@118 96 public void verify(final byte[] code) {
sundar@118 97 context.verify(code);
sundar@118 98 }
lagergren@89 99 }
lagergren@89 100
jlaskey@3 101 /** Is Context global debug mode enabled ? */
jlaskey@3 102 public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
jlaskey@3 103
jlaskey@3 104 private static final ThreadLocal<ScriptObject> currentGlobal =
jlaskey@3 105 new ThreadLocal<ScriptObject>() {
jlaskey@3 106 @Override
jlaskey@3 107 protected ScriptObject initialValue() {
jlaskey@3 108 return null;
jlaskey@3 109 }
jlaskey@3 110 };
jlaskey@3 111
jlaskey@3 112 /**
sundar@44 113 * Get the current global scope
sundar@44 114 * @return the current global scope
jlaskey@3 115 */
jlaskey@3 116 public static ScriptObject getGlobal() {
sundar@44 117 final SecurityManager sm = System.getSecurityManager();
sundar@44 118 if (sm != null) {
sundar@44 119 // skip getCallerClass and getGlobal and get to the real caller
sundar@44 120 Class<?> caller = Reflection.getCallerClass(2);
sundar@44 121 ClassLoader callerLoader = caller.getClassLoader();
sundar@44 122
sundar@82 123 // Allow this method only for nashorn's own classes, objects
sundar@82 124 // package classes and Java adapter classes. Rest should
sundar@44 125 // have the necessary security permission.
sundar@44 126 if (callerLoader != myLoader &&
sundar@82 127 !(callerLoader instanceof StructureLoader) &&
sundar@44 128 !(JavaAdapterFactory.isAdapterClass(caller))) {
sundar@136 129 sm.checkPermission(new RuntimePermission("nashorn.getGlobal"));
sundar@44 130 }
sundar@44 131 }
sundar@44 132
sundar@44 133 return getGlobalTrusted();
jlaskey@3 134 }
jlaskey@3 135
jlaskey@3 136 /**
jlaskey@3 137 * Set the current global scope
jlaskey@3 138 * @param global the global scope
jlaskey@3 139 */
jlaskey@3 140 public static void setGlobal(final ScriptObject global) {
jlaskey@3 141 final SecurityManager sm = System.getSecurityManager();
jlaskey@3 142 if (sm != null) {
sundar@136 143 sm.checkPermission(new RuntimePermission("nashorn.setGlobal"));
jlaskey@3 144 }
jlaskey@3 145
jlaskey@3 146 if (global != null && !(global instanceof GlobalObject)) {
jlaskey@3 147 throw new IllegalArgumentException("global does not implement GlobalObject!");
jlaskey@3 148 }
jlaskey@3 149
sundar@44 150 setGlobalTrusted(global);
jlaskey@3 151 }
jlaskey@3 152
jlaskey@3 153 /**
jlaskey@3 154 * Get context of the current global
jlaskey@3 155 * @return current global scope's context.
jlaskey@3 156 */
jlaskey@3 157 public static Context getContext() {
sundar@41 158 final SecurityManager sm = System.getSecurityManager();
sundar@41 159 if (sm != null) {
sundar@136 160 sm.checkPermission(new RuntimePermission("nashorn.getContext"));
sundar@41 161 }
sundar@41 162 return getContextTrusted();
sundar@41 163 }
sundar@41 164
sundar@41 165 /**
sundar@41 166 * Get current context's error writer
sundar@41 167 *
sundar@41 168 * @return error writer of the current context
sundar@41 169 */
sundar@41 170 public static PrintWriter getCurrentErr() {
sundar@44 171 final ScriptObject global = getGlobalTrusted();
sundar@41 172 return (global != null)? global.getContext().getErr() : new PrintWriter(System.err);
jlaskey@3 173 }
jlaskey@3 174
jlaskey@3 175 /**
jlaskey@3 176 * Output text to this Context's error stream
jlaskey@3 177 * @param str text to write
jlaskey@3 178 */
jlaskey@3 179 public static void err(final String str) {
jlaskey@3 180 err(str, true);
jlaskey@3 181 }
jlaskey@3 182
jlaskey@3 183 /**
jlaskey@3 184 * Output text to this Context's error stream, optionally with
jlaskey@3 185 * a newline afterwards
jlaskey@3 186 *
jlaskey@3 187 * @param str text to write
jlaskey@3 188 * @param crlf write a carriage return/new line after text
jlaskey@3 189 */
lagergren@11 190 @SuppressWarnings("resource")
jlaskey@3 191 public static void err(final String str, final boolean crlf) {
sundar@41 192 final PrintWriter err = Context.getCurrentErr();
lagergren@11 193 if (err != null) {
lagergren@11 194 if (crlf) {
lagergren@11 195 err.println(str);
jlaskey@3 196 } else {
lagergren@11 197 err.print(str);
jlaskey@3 198 }
jlaskey@3 199 }
jlaskey@3 200 }
jlaskey@3 201
sundar@118 202 /** Current environment. */
sundar@118 203 private final ScriptEnvironment env;
sundar@118 204
sundar@118 205 /** is this context in strict mode? Cached from env. as this is used heavily. */
sundar@118 206 public final boolean _strict;
sundar@118 207
sundar@41 208 /** class loader to resolve classes from script. */
sundar@41 209 private final ClassLoader appLoader;
sundar@41 210
jlaskey@3 211 /** Class loader to load classes from -classpath option, if set. */
jlaskey@3 212 private final ClassLoader classPathLoader;
jlaskey@3 213
jlaskey@3 214 /** Class loader to load classes compiled from scripts. */
jlaskey@3 215 private final ScriptLoader scriptLoader;
jlaskey@3 216
jlaskey@3 217 /** Current error manager. */
jlaskey@3 218 private final ErrorManager errors;
jlaskey@3 219
jlaskey@131 220 /** Empty map used for seed map for JO objects */
jlaskey@3 221 final PropertyMap emptyMap = PropertyMap.newEmptyMap(this);
jlaskey@3 222
sundar@41 223 private static final ClassLoader myLoader = Context.class.getClassLoader();
jlaskey@3 224 private static final StructureLoader sharedLoader;
jlaskey@3 225
jlaskey@3 226 static {
jlaskey@3 227 sharedLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
jlaskey@3 228 @Override
jlaskey@3 229 public StructureLoader run() {
sundar@41 230 return new StructureLoader(myLoader, null);
jlaskey@3 231 }
jlaskey@3 232 });
jlaskey@3 233 }
jlaskey@3 234
jlaskey@3 235 /**
jlaskey@3 236 * ThrowErrorManager that throws ParserException upon error conditions.
jlaskey@3 237 */
jlaskey@3 238 public static class ThrowErrorManager extends ErrorManager {
jlaskey@3 239 @Override
jlaskey@3 240 public void error(final String message) {
jlaskey@3 241 throw new ParserException(message);
jlaskey@3 242 }
jlaskey@3 243
jlaskey@3 244 @Override
jlaskey@3 245 public void error(final ParserException e) {
jlaskey@3 246 throw e;
jlaskey@3 247 }
jlaskey@3 248 }
jlaskey@3 249
jlaskey@3 250 /**
jlaskey@3 251 * Constructor
jlaskey@3 252 *
jlaskey@3 253 * @param options options from command line or Context creator
jlaskey@3 254 * @param errors error manger
sundar@41 255 * @param appLoader application class loader
jlaskey@3 256 */
sundar@41 257 public Context(final Options options, final ErrorManager errors, final ClassLoader appLoader) {
sundar@41 258 this(options, errors, new PrintWriter(System.out, true), new PrintWriter(System.err, true), appLoader);
jlaskey@3 259 }
jlaskey@3 260
jlaskey@3 261 /**
jlaskey@3 262 * Constructor
jlaskey@3 263 *
jlaskey@3 264 * @param options options from command line or Context creator
jlaskey@3 265 * @param errors error manger
jlaskey@3 266 * @param out output writer for this Context
jlaskey@3 267 * @param err error writer for this Context
sundar@41 268 * @param appLoader application class loader
jlaskey@3 269 */
sundar@41 270 public Context(final Options options, final ErrorManager errors, final PrintWriter out, final PrintWriter err, final ClassLoader appLoader) {
jlaskey@3 271 final SecurityManager sm = System.getSecurityManager();
jlaskey@3 272 if (sm != null) {
sundar@136 273 sm.checkPermission(new RuntimePermission("nashorn.createContext"));
jlaskey@3 274 }
jlaskey@3 275
sundar@118 276 this.env = new ScriptEnvironment(options, out, err);
sundar@118 277 this._strict = env._strict;
sundar@41 278 this.appLoader = appLoader;
jlaskey@3 279 this.scriptLoader = (ScriptLoader)AccessController.doPrivileged(
jlaskey@3 280 new PrivilegedAction<ClassLoader>() {
jlaskey@3 281 @Override
jlaskey@3 282 public ClassLoader run() {
sundar@82 283 final StructureLoader structureLoader = new StructureLoader(sharedLoader, Context.this);
jlaskey@3 284 return new ScriptLoader(structureLoader, Context.this);
jlaskey@3 285 }
jlaskey@3 286 });
jlaskey@3 287 this.errors = errors;
jlaskey@3 288
jlaskey@3 289 // if user passed -classpath option, make a class loader with that and set it as
jlaskey@3 290 // thread context class loader so that script can access classes from that path.
jlaskey@3 291 final String classPath = options.getString("classpath");
sundar@118 292 if (! env._compile_only && classPath != null && !classPath.isEmpty()) {
jlaskey@3 293 // make sure that caller can create a class loader.
jlaskey@3 294 if (sm != null) {
jlaskey@3 295 sm.checkPermission(new RuntimePermission("createClassLoader"));
jlaskey@3 296 }
jlaskey@3 297 this.classPathLoader = NashornLoader.createClassLoader(classPath);
jlaskey@3 298 } else {
jlaskey@3 299 this.classPathLoader = null;
jlaskey@3 300 }
jlaskey@3 301
jlaskey@3 302 // print version info if asked.
sundar@118 303 if (env._version) {
jlaskey@3 304 getErr().println("nashorn " + Version.version());
jlaskey@3 305 }
jlaskey@3 306
sundar@118 307 if (env._fullversion) {
jlaskey@3 308 getErr().println("nashorn full version " + Version.fullVersion());
jlaskey@3 309 }
jlaskey@3 310 }
jlaskey@3 311
jlaskey@3 312 /**
jlaskey@3 313 * Get the error manager for this context
jlaskey@3 314 * @return error manger
jlaskey@3 315 */
sundar@41 316 public ErrorManager getErrorManager() {
jlaskey@3 317 return errors;
jlaskey@3 318 }
jlaskey@3 319
jlaskey@3 320 /**
sundar@118 321 * Get the script environment for this context
sundar@118 322 * @return script environment
sundar@118 323 */
sundar@118 324 public ScriptEnvironment getEnv() {
sundar@118 325 return env;
sundar@118 326 }
sundar@118 327
sundar@118 328 /**
jlaskey@3 329 * Get the output stream for this context
jlaskey@3 330 * @return output print writer
jlaskey@3 331 */
jlaskey@3 332 public PrintWriter getOut() {
sundar@118 333 return env.getOut();
jlaskey@3 334 }
jlaskey@3 335
jlaskey@3 336 /**
jlaskey@3 337 * Get the error stream for this context
jlaskey@3 338 * @return error print writer
jlaskey@3 339 */
jlaskey@3 340 public PrintWriter getErr() {
sundar@118 341 return env.getErr();
jlaskey@3 342 }
jlaskey@3 343
lagergren@57 344 /**
sundar@44 345 * Get the PropertyMap of the current global scope
sundar@44 346 * @return the property map of the current global scope
sundar@44 347 */
lagergren@57 348 public static PropertyMap getGlobalMap() {
sundar@44 349 return Context.getGlobalTrusted().getMap();
sundar@44 350 }
sundar@44 351
jlaskey@3 352 /**
jlaskey@3 353 * Compile a top level script.
jlaskey@3 354 *
jlaskey@3 355 * @param source the source
jlaskey@3 356 * @param scope the scope
jlaskey@3 357 *
jlaskey@3 358 * @return top level function for script
jlaskey@3 359 */
sundar@86 360 public ScriptFunction compileScript(final Source source, final ScriptObject scope) {
sundar@86 361 return compileScript(source, scope, this.errors);
jlaskey@3 362 }
jlaskey@3 363
jlaskey@3 364 /**
jlaskey@3 365 * Entry point for {@code eval}
jlaskey@3 366 *
jlaskey@3 367 * @param initialScope The scope of this eval call
jlaskey@3 368 * @param string Evaluated code as a String
jlaskey@3 369 * @param callThis "this" to be passed to the evaluated code
jlaskey@3 370 * @param location location of the eval call
jlaskey@3 371 * @param strict is this {@code eval} call from a strict mode code?
jlaskey@3 372 *
jlaskey@3 373 * @return the return value of the {@code eval}
jlaskey@3 374 */
jlaskey@3 375 public Object eval(final ScriptObject initialScope, final String string, final Object callThis, final Object location, final boolean strict) {
jlaskey@3 376 final String file = (location == UNDEFINED || location == null) ? "<eval>" : location.toString();
jlaskey@3 377 final Source source = new Source(file, string);
jlaskey@3 378 final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval?
sundar@44 379 final ScriptObject global = Context.getGlobalTrusted();
jlaskey@3 380
jlaskey@3 381 ScriptObject scope = initialScope;
jlaskey@3 382
jlaskey@3 383 // ECMA section 10.1.1 point 2 says eval code is strict if it begins
jlaskey@3 384 // with "use strict" directive or eval direct call itself is made
jlaskey@3 385 // from from strict mode code. We are passed with caller's strict mode.
jlaskey@3 386 boolean strictFlag = directEval && strict;
jlaskey@3 387
jlaskey@3 388 Class<?> clazz = null;
jlaskey@3 389 try {
jlaskey@3 390 clazz = compile(source, new ThrowErrorManager(), strictFlag);
jlaskey@3 391 } catch (final ParserException e) {
jlaskey@3 392 e.throwAsEcmaException(global);
jlaskey@3 393 return null;
jlaskey@3 394 }
jlaskey@3 395
jlaskey@3 396 if (!strictFlag) {
jlaskey@3 397 // We need to get strict mode flag from compiled class. This is
jlaskey@3 398 // because eval code may start with "use strict" directive.
jlaskey@3 399 try {
jlaskey@3 400 strictFlag = clazz.getField(STRICT_MODE.tag()).getBoolean(null);
jlaskey@3 401 } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
jlaskey@3 402 //ignored
jlaskey@3 403 strictFlag = false;
jlaskey@3 404 }
jlaskey@3 405 }
jlaskey@3 406
jlaskey@3 407 // In strict mode, eval does not instantiate variables and functions
jlaskey@3 408 // in the caller's environment. A new environment is created!
jlaskey@3 409 if (strictFlag) {
jlaskey@3 410 // Create a new scope object
jlaskey@3 411 final ScriptObject strictEvalScope = ((GlobalObject)global).newObject();
jlaskey@3 412
jlaskey@3 413 // bless it as a "scope"
jlaskey@3 414 strictEvalScope.setIsScope();
jlaskey@3 415
jlaskey@3 416 // set given scope to be it's proto so that eval can still
jlaskey@3 417 // access caller environment vars in the new environment.
jlaskey@3 418 strictEvalScope.setProto(scope);
jlaskey@3 419 scope = strictEvalScope;
jlaskey@3 420 }
jlaskey@3 421
jlaskey@3 422 ScriptFunction func = getRunScriptFunction(clazz, scope);
jlaskey@3 423 Object evalThis;
jlaskey@3 424 if (directEval) {
jlaskey@3 425 evalThis = (callThis instanceof ScriptObject || strictFlag) ? callThis : global;
jlaskey@3 426 } else {
jlaskey@3 427 evalThis = global;
jlaskey@3 428 }
jlaskey@3 429
jlaskey@3 430 return ScriptRuntime.apply(func, evalThis);
jlaskey@3 431 }
jlaskey@3 432
jlaskey@3 433 /**
jlaskey@3 434 * Implementation of {@code load} Nashorn extension. Load a script file from a source
jlaskey@3 435 * expression
jlaskey@3 436 *
jlaskey@3 437 * @param scope the scope
sundar@86 438 * @param from source expression for script
jlaskey@3 439 *
jlaskey@3 440 * @return return value for load call (undefined)
jlaskey@3 441 *
jlaskey@3 442 * @throws IOException if source cannot be found or loaded
jlaskey@3 443 */
sundar@86 444 public Object load(final ScriptObject scope, final Object from) throws IOException {
sundar@86 445 Object src = (from instanceof ConsString)? from.toString() : from;
sundar@86 446 Source source = null;
jlaskey@3 447
sundar@86 448 // load accepts a String (which could be a URL or a file name), a File, a URL
sundar@86 449 // or a ScriptObject that has "name" and "source" (string valued) properties.
jlaskey@3 450 if (src instanceof String) {
lagergren@107 451 final String srcStr = (String)src;
lagergren@107 452 final File file = new File(srcStr);
sundar@86 453 if (srcStr.indexOf(':') != -1) {
lagergren@107 454 if (srcStr.startsWith("nashorn:")) {
lagergren@107 455 final String resource = "resources/" + srcStr.substring("nashorn:".length());
lagergren@107 456 // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme
lagergren@107 457 // These scripts are always available and are loaded from nashorn.jar's resources.
lagergren@107 458 source = AccessController.doPrivileged(
lagergren@107 459 new PrivilegedAction<Source>() {
lagergren@107 460 @Override
lagergren@107 461 public Source run() {
lagergren@107 462 try {
lagergren@107 463 final URL resURL = Context.class.getResource(resource);
lagergren@107 464 return (resURL != null)? new Source(srcStr, resURL) : null;
lagergren@107 465 } catch (final IOException exp) {
lagergren@107 466 return null;
lagergren@107 467 }
lagergren@107 468 }
lagergren@107 469 });
lagergren@107 470 } else {
lagergren@110 471 URL url = null;
lagergren@110 472 try {
lagergren@110 473 //check for malformed url. if malformed, it may still be a valid file
lagergren@110 474 url = new URL(srcStr);
lagergren@110 475 } catch (final MalformedURLException e) {
lagergren@110 476 url = file.toURI().toURL();
lagergren@110 477 }
sundar@86 478 source = new Source(url.toString(), url);
jlaskey@3 479 }
sundar@77 480 } else if (file.isFile()) {
sundar@86 481 source = new Source(srcStr, file);
jlaskey@3 482 }
sundar@86 483 } else if (src instanceof File && ((File)src).isFile()) {
jlaskey@3 484 final File file = (File)src;
sundar@86 485 source = new Source(file.getName(), file);
jlaskey@3 486 } else if (src instanceof URL) {
sundar@86 487 final URL url = (URL)src;
sundar@86 488 source = new Source(url.toString(), url);
jlaskey@3 489 } else if (src instanceof ScriptObject) {
jlaskey@3 490 final ScriptObject sobj = (ScriptObject)src;
jlaskey@3 491 if (sobj.has("script") && sobj.has("name")) {
jlaskey@3 492 final String script = JSType.toString(sobj.get("script"));
jlaskey@3 493 final String name = JSType.toString(sobj.get("name"));
sundar@86 494 source = new Source(name, script);
jlaskey@3 495 }
jlaskey@3 496 }
jlaskey@3 497
sundar@86 498 if (source != null) {
sundar@86 499 return evaluateSource(source, scope, scope);
sundar@86 500 }
sundar@86 501
lagergren@112 502 throw typeError("cant.load.script", ScriptRuntime.safeToString(from));
jlaskey@3 503 }
jlaskey@3 504
jlaskey@3 505 /**
jlaskey@3 506 * Load or get a structure class. Structure class names are based on the number of parameter fields
jlaskey@3 507 * and {@link AccessorProperty} fields in them. Structure classes are used to represent ScriptObjects
jlaskey@3 508 *
jlaskey@3 509 * @see ObjectClassGenerator
jlaskey@3 510 * @see AccessorProperty
jlaskey@3 511 * @see ScriptObject
jlaskey@3 512 *
jlaskey@131 513 * @param fullName full name of class, e.g. jdk.nashorn.internal.objects.JO2P1 contains 2 fields and 1 parameter.
jlaskey@3 514 *
sundar@128 515 * @return the {@code Class<?>} for this structure
jlaskey@3 516 *
jlaskey@3 517 * @throws ClassNotFoundException if structure class cannot be resolved
jlaskey@3 518 */
jlaskey@3 519 public static Class<?> forStructureClass(final String fullName) throws ClassNotFoundException {
jlaskey@3 520 return Class.forName(fullName, true, sharedLoader);
jlaskey@3 521 }
jlaskey@3 522
jlaskey@3 523 /**
jlaskey@3 524 * Lookup a Java class. This is used for JSR-223 stuff linking in from
jlaskey@3 525 * {@link jdk.nashorn.internal.objects.NativeJava} and {@link jdk.nashorn.internal.runtime.NativeJavaPackage}
jlaskey@3 526 *
jlaskey@3 527 * @param fullName full name of class to load
jlaskey@3 528 *
sundar@128 529 * @return the {@code Class<?>} for the name
jlaskey@3 530 *
jlaskey@3 531 * @throws ClassNotFoundException if class cannot be resolved
jlaskey@3 532 */
jlaskey@3 533 public Class<?> findClass(final String fullName) throws ClassNotFoundException {
jlaskey@3 534 // check package access as soon as possible!
jlaskey@3 535 final int index = fullName.lastIndexOf('.');
jlaskey@3 536 if (index != -1) {
jlaskey@3 537 final SecurityManager sm = System.getSecurityManager();
jlaskey@3 538 if (sm != null) {
sundar@136 539 AccessController.doPrivileged(new PrivilegedAction<Void>() {
sundar@136 540 @Override
sundar@136 541 public Void run() {
sundar@136 542 sm.checkPackageAccess(fullName.substring(0, index));
sundar@136 543 return null;
sundar@136 544 }
sundar@136 545 }, createNoPermissionsContext());
jlaskey@3 546 }
jlaskey@3 547 }
jlaskey@3 548
sundar@41 549 // try the script -classpath loader, if that is set
jlaskey@3 550 if (classPathLoader != null) {
jlaskey@3 551 try {
jlaskey@3 552 return Class.forName(fullName, true, classPathLoader);
sundar@41 553 } catch (final ClassNotFoundException ignored) {
jlaskey@3 554 // ignore, continue search
jlaskey@3 555 }
jlaskey@3 556 }
jlaskey@3 557
sundar@41 558 // Try finding using the "app" loader.
sundar@41 559 return Class.forName(fullName, true, appLoader);
jlaskey@3 560 }
jlaskey@3 561
jlaskey@3 562 /**
jlaskey@3 563 * Hook to print stack trace for a {@link Throwable} that occurred during
jlaskey@3 564 * execution
jlaskey@3 565 *
jlaskey@3 566 * @param t throwable for which to dump stack
jlaskey@3 567 */
jlaskey@3 568 public static void printStackTrace(final Throwable t) {
jlaskey@3 569 if (Context.DEBUG) {
sundar@41 570 t.printStackTrace(Context.getCurrentErr());
jlaskey@3 571 }
jlaskey@3 572 }
jlaskey@3 573
jlaskey@3 574 /**
jlaskey@3 575 * Verify generated bytecode before emission. This is called back from the
sundar@118 576 * {@link ObjectClassGenerator} or the {@link Compiler}. If the "--verify-code" parameter
jlaskey@3 577 * hasn't been given, this is a nop
jlaskey@3 578 *
jlaskey@3 579 * Note that verification may load classes -- we don't want to do that unless
jlaskey@3 580 * user specified verify option. We check it here even though caller
jlaskey@3 581 * may have already checked that flag
jlaskey@3 582 *
jlaskey@3 583 * @param bytecode bytecode to verify
jlaskey@3 584 */
jlaskey@3 585 public void verify(final byte[] bytecode) {
sundar@118 586 if (env._verify_code) {
jlaskey@3 587 // No verification when security manager is around as verifier
jlaskey@3 588 // may load further classes - which should be avoided.
jlaskey@3 589 if (System.getSecurityManager() == null) {
jlaskey@3 590 CheckClassAdapter.verify(new ClassReader(bytecode), scriptLoader, false, new PrintWriter(System.err, true));
jlaskey@3 591 }
jlaskey@3 592 }
jlaskey@3 593 }
jlaskey@3 594
jlaskey@3 595 /**
jlaskey@67 596 * Create and initialize a new global scope object.
jlaskey@67 597 *
jlaskey@67 598 * @return the initialized global scope object.
jlaskey@67 599 */
jlaskey@67 600 public ScriptObject createGlobal() {
jlaskey@67 601 return initGlobal(newGlobal());
jlaskey@67 602 }
jlaskey@67 603
jlaskey@67 604 /**
jlaskey@67 605 * Create a new uninitialized global scope object
jlaskey@3 606 * @return the global script object
jlaskey@3 607 */
jlaskey@67 608 public ScriptObject newGlobal() {
sundar@41 609 final SecurityManager sm = System.getSecurityManager();
sundar@41 610 if (sm != null) {
sundar@136 611 sm.checkPermission(new RuntimePermission("nashorn.newGlobal"));
sundar@41 612 }
sundar@41 613
jlaskey@67 614 return newGlobalTrusted();
jlaskey@67 615 }
jlaskey@67 616
jlaskey@67 617 /**
jlaskey@67 618 * Initialize given global scope object.
jlaskey@67 619 *
lagergren@89 620 * @param global the global
jlaskey@67 621 * @return the initialized global scope object.
jlaskey@67 622 */
jlaskey@67 623 public ScriptObject initGlobal(final ScriptObject global) {
jlaskey@67 624 if (! (global instanceof GlobalObject)) {
jlaskey@67 625 throw new IllegalArgumentException("not a global object!");
jlaskey@67 626 }
jlaskey@67 627
jlaskey@3 628 // Need only minimal global object, if we are just compiling.
sundar@118 629 if (!env._compile_only) {
sundar@44 630 final ScriptObject oldGlobal = Context.getGlobalTrusted();
sundar@41 631 try {
sundar@44 632 Context.setGlobalTrusted(global);
sundar@41 633 // initialize global scope with builtin global objects
sundar@41 634 ((GlobalObject)global).initBuiltinObjects();
sundar@41 635 } finally {
sundar@44 636 Context.setGlobalTrusted(oldGlobal);
sundar@41 637 }
jlaskey@3 638 }
jlaskey@3 639
jlaskey@3 640 return global;
jlaskey@3 641 }
jlaskey@3 642
jlaskey@3 643 /**
sundar@44 644 * Trusted variants - package-private
sundar@44 645 */
sundar@44 646
sundar@44 647 /**
sundar@44 648 * Return the current global scope
sundar@44 649 * @return current global scope
sundar@44 650 */
sundar@44 651 static ScriptObject getGlobalTrusted() {
sundar@44 652 return currentGlobal.get();
sundar@44 653 }
sundar@44 654
sundar@44 655 /**
sundar@44 656 * Set the current global scope
sundar@44 657 */
sundar@44 658 static void setGlobalTrusted(ScriptObject global) {
sundar@44 659 currentGlobal.set(global);
sundar@44 660 }
sundar@44 661
sundar@44 662 /**
sundar@44 663 * Return the current global's context
sundar@44 664 * @return current global's context
sundar@41 665 */
sundar@41 666 static Context getContextTrusted() {
sundar@44 667 return Context.getGlobalTrusted().getContext();
sundar@41 668 }
sundar@41 669
sundar@41 670 /**
jlaskey@3 671 * Try to infer Context instance from the Class. If we cannot,
jlaskey@3 672 * then get it from the thread local variable.
jlaskey@3 673 *
jlaskey@3 674 * @param clazz the class
jlaskey@3 675 * @return context
jlaskey@3 676 */
jlaskey@3 677 static Context fromClass(final Class<?> clazz) {
jlaskey@3 678 final ClassLoader loader = clazz.getClassLoader();
jlaskey@3 679
jlaskey@3 680 Context context = null;
jlaskey@3 681 if (loader instanceof NashornLoader) {
jlaskey@3 682 context = ((NashornLoader)loader).getContext();
jlaskey@3 683 }
jlaskey@3 684
sundar@41 685 return (context != null) ? context : Context.getContextTrusted();
jlaskey@3 686 }
jlaskey@3 687
sundar@136 688 private static AccessControlContext createNoPermissionsContext() {
sundar@136 689 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) });
sundar@136 690 }
sundar@136 691
jlaskey@3 692 private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
jlaskey@3 693 ScriptFunction script = null;
jlaskey@3 694
jlaskey@3 695 try {
sundar@86 696 script = compileScript(source, scope, new Context.ThrowErrorManager());
jlaskey@3 697 } catch (final ParserException e) {
sundar@44 698 e.throwAsEcmaException();
jlaskey@3 699 }
jlaskey@3 700
jlaskey@3 701 return ScriptRuntime.apply(script, thiz);
jlaskey@3 702 }
jlaskey@3 703
jlaskey@3 704 private static ScriptFunction getRunScriptFunction(final Class<?> script, final ScriptObject scope) {
jlaskey@3 705 if (script == null) {
jlaskey@3 706 return null;
jlaskey@3 707 }
jlaskey@3 708
jlaskey@3 709 // Get run method - the entry point to the script
jlaskey@3 710 final MethodHandle runMethodHandle =
jlaskey@3 711 MH.findStatic(
jlaskey@3 712 MethodHandles.lookup(),
jlaskey@3 713 script,
jlaskey@3 714 RUN_SCRIPT.tag(),
jlaskey@3 715 MH.type(
jlaskey@3 716 Object.class,
attila@81 717 ScriptFunction.class,
attila@81 718 Object.class));
jlaskey@3 719
jlaskey@3 720 boolean strict;
jlaskey@3 721
jlaskey@3 722 try {
jlaskey@3 723 strict = script.getField(STRICT_MODE.tag()).getBoolean(null);
jlaskey@3 724 } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
jlaskey@3 725 strict = false;
jlaskey@3 726 }
jlaskey@3 727
jlaskey@3 728 // Package as a JavaScript function and pass function back to shell.
sundar@44 729 return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.tag(), runMethodHandle, scope, strict);
jlaskey@3 730 }
jlaskey@3 731
sundar@86 732 private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) {
sundar@86 733 return getRunScriptFunction(compile(source, errMan, this._strict), scope);
jlaskey@3 734 }
jlaskey@3 735
sundar@86 736 private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
jlaskey@3 737 // start with no errors, no warnings.
jlaskey@3 738 errMan.reset();
jlaskey@3 739
jlaskey@3 740 GlobalObject global = null;
jlaskey@3 741 Class<?> script;
jlaskey@3 742
sundar@118 743 if (env._class_cache_size > 0) {
sundar@44 744 global = (GlobalObject)Context.getGlobalTrusted();
jlaskey@3 745 script = global.findCachedClass(source);
jlaskey@3 746 if (script != null) {
lagergren@139 747 Compiler.LOG.fine("Code cache hit for " + source + " avoiding recompile.");
jlaskey@3 748 return script;
jlaskey@3 749 }
jlaskey@3 750 }
jlaskey@3 751
sundar@118 752 final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
sundar@118 753 if (errors.hasErrors() || env._parse_only) {
jlaskey@3 754 return null;
jlaskey@3 755 }
jlaskey@3 756
sundar@118 757 if (env._print_ast) {
lagergren@96 758 getErr().println(new ASTWriter(functionNode));
lagergren@96 759 }
lagergren@96 760
sundar@118 761 if (env._print_parse) {
lagergren@89 762 getErr().println(new PrintVisitor(functionNode));
lagergren@89 763 }
lagergren@89 764
lagergren@89 765 final URL url = source.getURL();
sundar@118 766 final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
jlaskey@3 767 final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null);
sundar@118 768 final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
jlaskey@3 769
lagergren@89 770 final Compiler compiler = new Compiler(installer, functionNode, strict);
lagergren@89 771
lagergren@89 772 compiler.compile();
lagergren@89 773 script = compiler.install();
jlaskey@3 774
jlaskey@3 775 if (global != null) {
jlaskey@3 776 global.cacheClass(source, script);
jlaskey@3 777 }
jlaskey@3 778
jlaskey@3 779 return script;
jlaskey@3 780 }
jlaskey@3 781
jlaskey@3 782 private ScriptLoader createNewLoader() {
jlaskey@3 783 return AccessController.doPrivileged(
jlaskey@3 784 new PrivilegedAction<ScriptLoader>() {
jlaskey@3 785 @Override
jlaskey@3 786 public ScriptLoader run() {
jlaskey@3 787 // Generated code won't refer to any class generated by context
jlaskey@3 788 // script loader and so parent loader can be the structure
jlaskey@3 789 // loader -- which is parent of the context script loader.
sundar@82 790 return new ScriptLoader((StructureLoader)scriptLoader.getParent(), Context.this);
jlaskey@3 791 }
jlaskey@3 792 });
jlaskey@3 793 }
jlaskey@3 794
jlaskey@67 795 private ScriptObject newGlobalTrusted() {
jlaskey@3 796 try {
jlaskey@3 797 final Class<?> clazz = Class.forName("jdk.nashorn.internal.objects.Global", true, scriptLoader);
lagergren@89 798 final Constructor<?> cstr = clazz.getConstructor(Context.class);
sundar@82 799 return (ScriptObject) cstr.newInstance(this);
sundar@82 800 } catch (final Exception e) {
jlaskey@3 801 printStackTrace(e);
sundar@82 802 if (e instanceof RuntimeException) {
sundar@82 803 throw (RuntimeException)e;
sundar@82 804 }
lagergren@89 805 throw new RuntimeException(e);
jlaskey@3 806 }
jlaskey@3 807 }
jlaskey@3 808 }

mercurial