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

Fri, 09 Aug 2013 20:48:44 +0530

author
sundar
date
Fri, 09 Aug 2013 20:48:44 +0530
changeset 492
47e2b609fe31
parent 469
d203d68f6624
child 505
36fb36217e1d
permissions
-rw-r--r--

8022707: Revisit all doPrivileged blocks
Reviewed-by: jlaskey, hannesw

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@459 39 import java.lang.reflect.Modifier;
sundar@427 40 import java.util.concurrent.atomic.AtomicLong;
lagergren@110 41 import java.net.MalformedURLException;
jlaskey@3 42 import java.net.URL;
sundar@468 43 import java.security.AccessControlContext;
jlaskey@3 44 import java.security.AccessController;
jlaskey@3 45 import java.security.CodeSigner;
jlaskey@3 46 import java.security.CodeSource;
sundar@468 47 import java.security.Permissions;
jlaskey@3 48 import java.security.PrivilegedAction;
sundar@468 49 import java.security.ProtectionDomain;
sundar@350 50 import java.util.Map;
jlaskey@3 51 import jdk.internal.org.objectweb.asm.ClassReader;
jlaskey@3 52 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
sundar@322 53 import jdk.nashorn.api.scripting.ScriptObjectMirror;
jlaskey@3 54 import jdk.nashorn.internal.codegen.Compiler;
lagergren@96 55 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
lagergren@89 56 import jdk.nashorn.internal.ir.FunctionNode;
lagergren@96 57 import jdk.nashorn.internal.ir.debug.ASTWriter;
lagergren@89 58 import jdk.nashorn.internal.ir.debug.PrintVisitor;
sundar@414 59 import jdk.nashorn.internal.objects.Global;
lagergren@89 60 import jdk.nashorn.internal.parser.Parser;
jlaskey@3 61 import jdk.nashorn.internal.runtime.options.Options;
jlaskey@3 62
jlaskey@3 63 /**
jlaskey@3 64 * This class manages the global state of execution. Context is immutable.
jlaskey@3 65 */
jlaskey@3 66 public final class Context {
sundar@492 67 // nashorn specific security runtime access permission names
sundar@492 68 /**
sundar@492 69 * Permission needed to pass arbitrary nashorn command line options when creating Context.
sundar@492 70 */
sundar@492 71 public static final String NASHORN_SET_CONFIG = "nashorn.setConfig";
sundar@492 72
sundar@492 73 /**
sundar@492 74 * Permission needed to create Nashorn Context instance.
sundar@492 75 */
sundar@492 76 public static final String NASHORN_CREATE_CONTEXT = "nashorn.createContext";
sundar@492 77
sundar@492 78 /**
sundar@492 79 * Permission needed to create Nashorn Global instance.
sundar@492 80 */
sundar@492 81 public static final String NASHORN_CREATE_GLOBAL = "nashorn.createGlobal";
sundar@492 82
sundar@492 83 /**
sundar@492 84 * Permission to get current Nashorn Context from thread local storage.
sundar@492 85 */
sundar@492 86 public static final String NASHORN_GET_CONTEXT = "nashorn.getContext";
sundar@492 87
sundar@492 88 /**
sundar@492 89 * Permission to use Java reflection/jsr292 from script code.
sundar@492 90 */
sundar@492 91 public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection";
jlaskey@3 92
lagergren@89 93 /**
lagergren@89 94 * ContextCodeInstaller that has the privilege of installing classes in the Context.
lagergren@89 95 * Can only be instantiated from inside the context and is opaque to other classes
lagergren@89 96 */
sundar@118 97 public static class ContextCodeInstaller implements CodeInstaller<ScriptEnvironment> {
lagergren@89 98 private final Context context;
lagergren@89 99 private final ScriptLoader loader;
lagergren@89 100 private final CodeSource codeSource;
lagergren@89 101
lagergren@89 102 private ContextCodeInstaller(final Context context, final ScriptLoader loader, final CodeSource codeSource) {
lagergren@89 103 this.context = context;
lagergren@89 104 this.loader = loader;
lagergren@89 105 this.codeSource = codeSource;
lagergren@89 106 }
lagergren@89 107
lagergren@89 108 /**
lagergren@89 109 * Return the context for this installer
lagergren@137 110 * @return ScriptEnvironment
lagergren@89 111 */
lagergren@89 112 @Override
sundar@118 113 public ScriptEnvironment getOwner() {
sundar@118 114 return context.env;
lagergren@89 115 }
lagergren@89 116
lagergren@89 117 @Override
lagergren@89 118 public Class<?> install(final String className, final byte[] bytecode) {
lagergren@89 119 return loader.installClass(className, bytecode, codeSource);
lagergren@89 120 }
sundar@118 121
sundar@118 122 @Override
sundar@118 123 public void verify(final byte[] code) {
sundar@118 124 context.verify(code);
sundar@118 125 }
sundar@425 126
sundar@425 127 @Override
sundar@425 128 public long getUniqueScriptId() {
sundar@425 129 return context.getUniqueScriptId();
sundar@425 130 }
lagergren@89 131 }
lagergren@89 132
jlaskey@3 133 /** Is Context global debug mode enabled ? */
jlaskey@3 134 public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
jlaskey@3 135
hannesw@380 136 private static final ThreadLocal<ScriptObject> currentGlobal = new ThreadLocal<>();
jlaskey@3 137
jlaskey@3 138 /**
sundar@44 139 * Get the current global scope
sundar@44 140 * @return the current global scope
jlaskey@3 141 */
jlaskey@3 142 public static ScriptObject getGlobal() {
sundar@209 143 // This class in a package.access protected package.
sundar@209 144 // Trusted code only can call this method.
sundar@44 145 return getGlobalTrusted();
jlaskey@3 146 }
jlaskey@3 147
jlaskey@3 148 /**
jlaskey@3 149 * Set the current global scope
jlaskey@3 150 * @param global the global scope
jlaskey@3 151 */
jlaskey@3 152 public static void setGlobal(final ScriptObject global) {
sundar@414 153 if (global != null && !(global instanceof Global)) {
sundar@414 154 throw new IllegalArgumentException("global is not an instance of Global!");
jlaskey@3 155 }
jlaskey@3 156
sundar@44 157 setGlobalTrusted(global);
jlaskey@3 158 }
jlaskey@3 159
jlaskey@3 160 /**
jlaskey@3 161 * Get context of the current global
jlaskey@3 162 * @return current global scope's context.
jlaskey@3 163 */
jlaskey@3 164 public static Context getContext() {
sundar@41 165 final SecurityManager sm = System.getSecurityManager();
sundar@41 166 if (sm != null) {
sundar@492 167 sm.checkPermission(new RuntimePermission(NASHORN_GET_CONTEXT));
sundar@41 168 }
sundar@41 169 return getContextTrusted();
sundar@41 170 }
sundar@41 171
sundar@41 172 /**
sundar@41 173 * Get current context's error writer
sundar@41 174 *
sundar@41 175 * @return error writer of the current context
sundar@41 176 */
sundar@41 177 public static PrintWriter getCurrentErr() {
sundar@44 178 final ScriptObject global = getGlobalTrusted();
sundar@41 179 return (global != null)? global.getContext().getErr() : new PrintWriter(System.err);
jlaskey@3 180 }
jlaskey@3 181
jlaskey@3 182 /**
jlaskey@3 183 * Output text to this Context's error stream
jlaskey@3 184 * @param str text to write
jlaskey@3 185 */
jlaskey@3 186 public static void err(final String str) {
jlaskey@3 187 err(str, true);
jlaskey@3 188 }
jlaskey@3 189
jlaskey@3 190 /**
jlaskey@3 191 * Output text to this Context's error stream, optionally with
jlaskey@3 192 * a newline afterwards
jlaskey@3 193 *
jlaskey@3 194 * @param str text to write
jlaskey@3 195 * @param crlf write a carriage return/new line after text
jlaskey@3 196 */
lagergren@253 197 @SuppressWarnings("resource")
jlaskey@3 198 public static void err(final String str, final boolean crlf) {
sundar@41 199 final PrintWriter err = Context.getCurrentErr();
lagergren@11 200 if (err != null) {
lagergren@11 201 if (crlf) {
lagergren@11 202 err.println(str);
jlaskey@3 203 } else {
lagergren@11 204 err.print(str);
jlaskey@3 205 }
jlaskey@3 206 }
jlaskey@3 207 }
jlaskey@3 208
sundar@118 209 /** Current environment. */
sundar@118 210 private final ScriptEnvironment env;
sundar@118 211
sundar@118 212 /** is this context in strict mode? Cached from env. as this is used heavily. */
sundar@344 213 final boolean _strict;
sundar@118 214
sundar@41 215 /** class loader to resolve classes from script. */
sundar@41 216 private final ClassLoader appLoader;
sundar@41 217
jlaskey@3 218 /** Class loader to load classes from -classpath option, if set. */
jlaskey@3 219 private final ClassLoader classPathLoader;
jlaskey@3 220
jlaskey@3 221 /** Class loader to load classes compiled from scripts. */
jlaskey@3 222 private final ScriptLoader scriptLoader;
jlaskey@3 223
jlaskey@3 224 /** Current error manager. */
jlaskey@3 225 private final ErrorManager errors;
jlaskey@3 226
sundar@425 227 /** Unique id for script. Used only when --loader-per-compile=false */
sundar@427 228 private final AtomicLong uniqueScriptId;
sundar@425 229
sundar@41 230 private static final ClassLoader myLoader = Context.class.getClassLoader();
jlaskey@3 231 private static final StructureLoader sharedLoader;
sundar@492 232
sundar@492 233 private static AccessControlContext createNoPermAccCtxt() {
sundar@492 234 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) });
sundar@492 235 }
sundar@492 236
sundar@492 237 private static AccessControlContext createPermAccCtxt(final String permName) {
sundar@492 238 final Permissions perms = new Permissions();
sundar@492 239 perms.add(new RuntimePermission(permName));
sundar@492 240 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
sundar@492 241 }
sundar@492 242
sundar@492 243 private static final AccessControlContext NO_PERMISSIONS_ACC_CTXT = createNoPermAccCtxt();
sundar@492 244 private static final AccessControlContext CREATE_LOADER_ACC_CTXT = createPermAccCtxt("createClassLoader");
sundar@492 245 private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(NASHORN_CREATE_GLOBAL);
jlaskey@3 246
jlaskey@3 247 static {
jlaskey@3 248 sharedLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
jlaskey@3 249 @Override
jlaskey@3 250 public StructureLoader run() {
sundar@41 251 return new StructureLoader(myLoader, null);
jlaskey@3 252 }
sundar@492 253 }, CREATE_LOADER_ACC_CTXT);
jlaskey@3 254 }
jlaskey@3 255
jlaskey@3 256 /**
jlaskey@3 257 * ThrowErrorManager that throws ParserException upon error conditions.
jlaskey@3 258 */
jlaskey@3 259 public static class ThrowErrorManager extends ErrorManager {
jlaskey@3 260 @Override
jlaskey@3 261 public void error(final String message) {
jlaskey@3 262 throw new ParserException(message);
jlaskey@3 263 }
jlaskey@3 264
jlaskey@3 265 @Override
jlaskey@3 266 public void error(final ParserException e) {
jlaskey@3 267 throw e;
jlaskey@3 268 }
jlaskey@3 269 }
jlaskey@3 270
jlaskey@3 271 /**
jlaskey@3 272 * Constructor
jlaskey@3 273 *
jlaskey@3 274 * @param options options from command line or Context creator
jlaskey@3 275 * @param errors error manger
sundar@41 276 * @param appLoader application class loader
jlaskey@3 277 */
sundar@41 278 public Context(final Options options, final ErrorManager errors, final ClassLoader appLoader) {
sundar@41 279 this(options, errors, new PrintWriter(System.out, true), new PrintWriter(System.err, true), appLoader);
jlaskey@3 280 }
jlaskey@3 281
jlaskey@3 282 /**
jlaskey@3 283 * Constructor
jlaskey@3 284 *
jlaskey@3 285 * @param options options from command line or Context creator
jlaskey@3 286 * @param errors error manger
jlaskey@3 287 * @param out output writer for this Context
jlaskey@3 288 * @param err error writer for this Context
sundar@41 289 * @param appLoader application class loader
jlaskey@3 290 */
sundar@41 291 public Context(final Options options, final ErrorManager errors, final PrintWriter out, final PrintWriter err, final ClassLoader appLoader) {
jlaskey@3 292 final SecurityManager sm = System.getSecurityManager();
jlaskey@3 293 if (sm != null) {
sundar@492 294 sm.checkPermission(new RuntimePermission(NASHORN_CREATE_CONTEXT));
jlaskey@3 295 }
jlaskey@3 296
sundar@118 297 this.env = new ScriptEnvironment(options, out, err);
sundar@118 298 this._strict = env._strict;
sundar@41 299 this.appLoader = appLoader;
sundar@427 300 if (env._loader_per_compile) {
sundar@427 301 this.scriptLoader = null;
sundar@427 302 this.uniqueScriptId = null;
sundar@427 303 } else {
sundar@427 304 this.scriptLoader = createNewLoader();
sundar@427 305 this.uniqueScriptId = new AtomicLong();
sundar@427 306 }
jlaskey@3 307 this.errors = errors;
jlaskey@3 308
jlaskey@3 309 // if user passed -classpath option, make a class loader with that and set it as
jlaskey@3 310 // thread context class loader so that script can access classes from that path.
jlaskey@3 311 final String classPath = options.getString("classpath");
sundar@118 312 if (! env._compile_only && classPath != null && !classPath.isEmpty()) {
jlaskey@3 313 // make sure that caller can create a class loader.
jlaskey@3 314 if (sm != null) {
jlaskey@3 315 sm.checkPermission(new RuntimePermission("createClassLoader"));
jlaskey@3 316 }
jlaskey@3 317 this.classPathLoader = NashornLoader.createClassLoader(classPath);
jlaskey@3 318 } else {
jlaskey@3 319 this.classPathLoader = null;
jlaskey@3 320 }
jlaskey@3 321
jlaskey@3 322 // print version info if asked.
sundar@118 323 if (env._version) {
jlaskey@3 324 getErr().println("nashorn " + Version.version());
jlaskey@3 325 }
jlaskey@3 326
sundar@118 327 if (env._fullversion) {
jlaskey@3 328 getErr().println("nashorn full version " + Version.fullVersion());
jlaskey@3 329 }
jlaskey@3 330 }
jlaskey@3 331
jlaskey@3 332 /**
jlaskey@3 333 * Get the error manager for this context
jlaskey@3 334 * @return error manger
jlaskey@3 335 */
sundar@41 336 public ErrorManager getErrorManager() {
jlaskey@3 337 return errors;
jlaskey@3 338 }
jlaskey@3 339
jlaskey@3 340 /**
sundar@118 341 * Get the script environment for this context
sundar@118 342 * @return script environment
sundar@118 343 */
sundar@118 344 public ScriptEnvironment getEnv() {
sundar@118 345 return env;
sundar@118 346 }
sundar@118 347
sundar@118 348 /**
jlaskey@3 349 * Get the output stream for this context
jlaskey@3 350 * @return output print writer
jlaskey@3 351 */
jlaskey@3 352 public PrintWriter getOut() {
sundar@118 353 return env.getOut();
jlaskey@3 354 }
jlaskey@3 355
jlaskey@3 356 /**
jlaskey@3 357 * Get the error stream for this context
jlaskey@3 358 * @return error print writer
jlaskey@3 359 */
jlaskey@3 360 public PrintWriter getErr() {
sundar@118 361 return env.getErr();
jlaskey@3 362 }
jlaskey@3 363
lagergren@57 364 /**
sundar@44 365 * Get the PropertyMap of the current global scope
sundar@44 366 * @return the property map of the current global scope
sundar@44 367 */
lagergren@57 368 public static PropertyMap getGlobalMap() {
sundar@44 369 return Context.getGlobalTrusted().getMap();
sundar@44 370 }
sundar@44 371
jlaskey@3 372 /**
jlaskey@3 373 * Compile a top level script.
jlaskey@3 374 *
jlaskey@3 375 * @param source the source
jlaskey@3 376 * @param scope the scope
jlaskey@3 377 *
jlaskey@3 378 * @return top level function for script
jlaskey@3 379 */
sundar@86 380 public ScriptFunction compileScript(final Source source, final ScriptObject scope) {
sundar@86 381 return compileScript(source, scope, this.errors);
jlaskey@3 382 }
jlaskey@3 383
jlaskey@3 384 /**
jlaskey@3 385 * Entry point for {@code eval}
jlaskey@3 386 *
jlaskey@3 387 * @param initialScope The scope of this eval call
jlaskey@3 388 * @param string Evaluated code as a String
jlaskey@3 389 * @param callThis "this" to be passed to the evaluated code
jlaskey@3 390 * @param location location of the eval call
jlaskey@3 391 * @param strict is this {@code eval} call from a strict mode code?
jlaskey@3 392 *
jlaskey@3 393 * @return the return value of the {@code eval}
jlaskey@3 394 */
jlaskey@3 395 public Object eval(final ScriptObject initialScope, final String string, final Object callThis, final Object location, final boolean strict) {
jlaskey@3 396 final String file = (location == UNDEFINED || location == null) ? "<eval>" : location.toString();
jlaskey@3 397 final Source source = new Source(file, string);
jlaskey@3 398 final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval?
sundar@44 399 final ScriptObject global = Context.getGlobalTrusted();
jlaskey@3 400
jlaskey@3 401 ScriptObject scope = initialScope;
jlaskey@3 402
jlaskey@3 403 // ECMA section 10.1.1 point 2 says eval code is strict if it begins
jlaskey@3 404 // with "use strict" directive or eval direct call itself is made
jlaskey@3 405 // from from strict mode code. We are passed with caller's strict mode.
jlaskey@3 406 boolean strictFlag = directEval && strict;
jlaskey@3 407
jlaskey@3 408 Class<?> clazz = null;
jlaskey@3 409 try {
jlaskey@3 410 clazz = compile(source, new ThrowErrorManager(), strictFlag);
jlaskey@3 411 } catch (final ParserException e) {
jlaskey@3 412 e.throwAsEcmaException(global);
jlaskey@3 413 return null;
jlaskey@3 414 }
jlaskey@3 415
jlaskey@3 416 if (!strictFlag) {
jlaskey@3 417 // We need to get strict mode flag from compiled class. This is
jlaskey@3 418 // because eval code may start with "use strict" directive.
jlaskey@3 419 try {
lagergren@211 420 strictFlag = clazz.getField(STRICT_MODE.symbolName()).getBoolean(null);
jlaskey@3 421 } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
jlaskey@3 422 //ignored
jlaskey@3 423 strictFlag = false;
jlaskey@3 424 }
jlaskey@3 425 }
jlaskey@3 426
jlaskey@3 427 // In strict mode, eval does not instantiate variables and functions
jlaskey@3 428 // in the caller's environment. A new environment is created!
jlaskey@3 429 if (strictFlag) {
jlaskey@3 430 // Create a new scope object
jlaskey@3 431 final ScriptObject strictEvalScope = ((GlobalObject)global).newObject();
jlaskey@3 432
jlaskey@3 433 // bless it as a "scope"
jlaskey@3 434 strictEvalScope.setIsScope();
jlaskey@3 435
jlaskey@3 436 // set given scope to be it's proto so that eval can still
jlaskey@3 437 // access caller environment vars in the new environment.
jlaskey@3 438 strictEvalScope.setProto(scope);
jlaskey@3 439 scope = strictEvalScope;
jlaskey@3 440 }
jlaskey@3 441
jlaskey@3 442 ScriptFunction func = getRunScriptFunction(clazz, scope);
jlaskey@3 443 Object evalThis;
jlaskey@3 444 if (directEval) {
jlaskey@3 445 evalThis = (callThis instanceof ScriptObject || strictFlag) ? callThis : global;
jlaskey@3 446 } else {
jlaskey@3 447 evalThis = global;
jlaskey@3 448 }
jlaskey@3 449
jlaskey@3 450 return ScriptRuntime.apply(func, evalThis);
jlaskey@3 451 }
jlaskey@3 452
lagergren@247 453 private static Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
jlaskey@222 454 if (srcStr.startsWith(prefix)) {
jlaskey@222 455 final String resource = resourcePath + srcStr.substring(prefix.length());
jlaskey@222 456 // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme
jlaskey@222 457 // These scripts are always available and are loaded from nashorn.jar's resources.
jlaskey@222 458 return AccessController.doPrivileged(
jlaskey@222 459 new PrivilegedAction<Source>() {
jlaskey@222 460 @Override
jlaskey@222 461 public Source run() {
jlaskey@222 462 try {
jlaskey@222 463 final URL resURL = Context.class.getResource(resource);
jlaskey@222 464 return (resURL != null)? new Source(srcStr, resURL) : null;
jlaskey@222 465 } catch (final IOException exp) {
jlaskey@222 466 return null;
jlaskey@222 467 }
jlaskey@222 468 }
jlaskey@222 469 });
jlaskey@222 470 }
jlaskey@222 471
jlaskey@222 472 return null;
jlaskey@222 473 }
jlaskey@222 474
jlaskey@3 475 /**
jlaskey@3 476 * Implementation of {@code load} Nashorn extension. Load a script file from a source
jlaskey@3 477 * expression
jlaskey@3 478 *
jlaskey@3 479 * @param scope the scope
sundar@86 480 * @param from source expression for script
jlaskey@3 481 *
jlaskey@3 482 * @return return value for load call (undefined)
jlaskey@3 483 *
jlaskey@3 484 * @throws IOException if source cannot be found or loaded
jlaskey@3 485 */
sundar@86 486 public Object load(final ScriptObject scope, final Object from) throws IOException {
jlaskey@222 487 final Object src = (from instanceof ConsString)? from.toString() : from;
sundar@86 488 Source source = null;
jlaskey@3 489
sundar@86 490 // load accepts a String (which could be a URL or a file name), a File, a URL
sundar@86 491 // or a ScriptObject that has "name" and "source" (string valued) properties.
jlaskey@3 492 if (src instanceof String) {
lagergren@107 493 final String srcStr = (String)src;
jlaskey@222 494 final File file = new File(srcStr);
sundar@86 495 if (srcStr.indexOf(':') != -1) {
jlaskey@222 496 if ((source = loadInternal(srcStr, "nashorn:", "resources/")) == null &&
jlaskey@222 497 (source = loadInternal(srcStr, "fx:", "resources/fx/")) == null) {
jlaskey@222 498 URL url;
lagergren@110 499 try {
lagergren@110 500 //check for malformed url. if malformed, it may still be a valid file
lagergren@110 501 url = new URL(srcStr);
lagergren@110 502 } catch (final MalformedURLException e) {
lagergren@110 503 url = file.toURI().toURL();
lagergren@110 504 }
sundar@86 505 source = new Source(url.toString(), url);
jlaskey@3 506 }
sundar@77 507 } else if (file.isFile()) {
sundar@86 508 source = new Source(srcStr, file);
jlaskey@3 509 }
sundar@86 510 } else if (src instanceof File && ((File)src).isFile()) {
jlaskey@3 511 final File file = (File)src;
sundar@86 512 source = new Source(file.getName(), file);
jlaskey@3 513 } else if (src instanceof URL) {
sundar@86 514 final URL url = (URL)src;
sundar@86 515 source = new Source(url.toString(), url);
jlaskey@3 516 } else if (src instanceof ScriptObject) {
jlaskey@3 517 final ScriptObject sobj = (ScriptObject)src;
jlaskey@3 518 if (sobj.has("script") && sobj.has("name")) {
jlaskey@3 519 final String script = JSType.toString(sobj.get("script"));
jlaskey@3 520 final String name = JSType.toString(sobj.get("name"));
sundar@86 521 source = new Source(name, script);
jlaskey@3 522 }
sundar@350 523 } else if (src instanceof Map) {
sundar@468 524 final Map<?,?> map = (Map<?,?>)src;
sundar@350 525 if (map.containsKey("script") && map.containsKey("name")) {
sundar@350 526 final String script = JSType.toString(map.get("script"));
sundar@350 527 final String name = JSType.toString(map.get("name"));
sundar@350 528 source = new Source(name, script);
sundar@350 529 }
jlaskey@3 530 }
jlaskey@3 531
sundar@86 532 if (source != null) {
sundar@86 533 return evaluateSource(source, scope, scope);
sundar@86 534 }
sundar@86 535
lagergren@112 536 throw typeError("cant.load.script", ScriptRuntime.safeToString(from));
jlaskey@3 537 }
jlaskey@3 538
jlaskey@3 539 /**
jlaskey@317 540 * Implementation of {@code loadWithNewGlobal} Nashorn extension. Load a script file from a source
jlaskey@317 541 * expression, after creating a new global scope.
jlaskey@317 542 *
jlaskey@317 543 * @param from source expression for script
sundar@337 544 * @param args (optional) arguments to be passed to the loaded script
jlaskey@317 545 *
jlaskey@317 546 * @return return value for load call (undefined)
jlaskey@317 547 *
jlaskey@317 548 * @throws IOException if source cannot be found or loaded
jlaskey@317 549 */
sundar@337 550 public Object loadWithNewGlobal(final Object from, final Object...args) throws IOException {
jlaskey@317 551 final ScriptObject oldGlobal = getGlobalTrusted();
jlaskey@319 552 final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction<ScriptObject>() {
jlaskey@319 553 @Override
jlaskey@319 554 public ScriptObject run() {
jlaskey@319 555 try {
sundar@492 556 return newGlobal();
jlaskey@319 557 } catch (final RuntimeException e) {
jlaskey@319 558 if (Context.DEBUG) {
jlaskey@319 559 e.printStackTrace();
jlaskey@319 560 }
jlaskey@319 561 throw e;
jlaskey@319 562 }
jlaskey@319 563 }
sundar@492 564 }, CREATE_GLOBAL_ACC_CTXT);
sundar@492 565 // initialize newly created Global instance
sundar@492 566 initGlobal(newGlobal);
jlaskey@317 567 setGlobalTrusted(newGlobal);
jlaskey@317 568
sundar@437 569 final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY : ScriptObjectMirror.wrapArray(args, oldGlobal);
sundar@337 570 newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped));
sundar@337 571
jlaskey@317 572 try {
sundar@437 573 // wrap objects from newGlobal's world as mirrors - but if result
sundar@437 574 // is from oldGlobal's world, unwrap it!
sundar@437 575 return ScriptObjectMirror.unwrap(ScriptObjectMirror.wrap(load(newGlobal, from), newGlobal), oldGlobal);
jlaskey@317 576 } finally {
jlaskey@317 577 setGlobalTrusted(oldGlobal);
jlaskey@317 578 }
jlaskey@317 579 }
jlaskey@317 580
jlaskey@317 581 /**
jlaskey@3 582 * Load or get a structure class. Structure class names are based on the number of parameter fields
jlaskey@3 583 * and {@link AccessorProperty} fields in them. Structure classes are used to represent ScriptObjects
jlaskey@3 584 *
jlaskey@3 585 * @see ObjectClassGenerator
jlaskey@3 586 * @see AccessorProperty
jlaskey@3 587 * @see ScriptObject
jlaskey@3 588 *
jlaskey@131 589 * @param fullName full name of class, e.g. jdk.nashorn.internal.objects.JO2P1 contains 2 fields and 1 parameter.
jlaskey@3 590 *
sundar@128 591 * @return the {@code Class<?>} for this structure
jlaskey@3 592 *
jlaskey@3 593 * @throws ClassNotFoundException if structure class cannot be resolved
jlaskey@3 594 */
jlaskey@3 595 public static Class<?> forStructureClass(final String fullName) throws ClassNotFoundException {
sundar@468 596 if (System.getSecurityManager() != null && !NashornLoader.isStructureClass(fullName)) {
sundar@468 597 throw new ClassNotFoundException(fullName);
sundar@468 598 }
jlaskey@3 599 return Class.forName(fullName, true, sharedLoader);
jlaskey@3 600 }
jlaskey@3 601
jlaskey@3 602 /**
sundar@468 603 * Checks that the given package can be accessed from no permissions context.
sundar@428 604 *
sundar@428 605 * @param fullName fully qualified package name
sundar@459 606 * @throw SecurityException if not accessible
sundar@428 607 */
sundar@428 608 public static void checkPackageAccess(final String fullName) {
sundar@428 609 final int index = fullName.lastIndexOf('.');
sundar@428 610 if (index != -1) {
sundar@428 611 final SecurityManager sm = System.getSecurityManager();
sundar@428 612 if (sm != null) {
sundar@468 613 AccessController.doPrivileged(new PrivilegedAction<Void>() {
sundar@468 614 @Override
sundar@468 615 public Void run() {
sundar@468 616 sm.checkPackageAccess(fullName.substring(0, index));
sundar@468 617 return null;
sundar@468 618 }
sundar@492 619 }, NO_PERMISSIONS_ACC_CTXT);
sundar@428 620 }
sundar@428 621 }
sundar@428 622 }
sundar@428 623
sundar@428 624 /**
sundar@468 625 * Checks that the given package can be accessed from no permissions context.
sundar@459 626 *
sundar@459 627 * @param fullName fully qualified package name
sundar@459 628 * @return true if package is accessible, false otherwise
sundar@459 629 */
sundar@459 630 public static boolean isAccessiblePackage(final String fullName) {
sundar@459 631 try {
sundar@459 632 checkPackageAccess(fullName);
sundar@459 633 return true;
sundar@459 634 } catch (final SecurityException se) {
sundar@459 635 return false;
sundar@459 636 }
sundar@459 637 }
sundar@459 638
sundar@459 639 /**
sundar@468 640 * Checks that the given Class is public and it can be accessed from no permissions context.
sundar@459 641 *
sundar@459 642 * @param clazz Class object to check
sundar@459 643 * @return true if Class is accessible, false otherwise
sundar@459 644 */
sundar@459 645 public static boolean isAccessibleClass(final Class<?> clazz) {
sundar@459 646 return Modifier.isPublic(clazz.getModifiers()) && Context.isAccessiblePackage(clazz.getName());
sundar@459 647 }
sundar@459 648
sundar@459 649 /**
jlaskey@3 650 * Lookup a Java class. This is used for JSR-223 stuff linking in from
lagergren@253 651 * {@code jdk.nashorn.internal.objects.NativeJava} and {@code jdk.nashorn.internal.runtime.NativeJavaPackage}
jlaskey@3 652 *
jlaskey@3 653 * @param fullName full name of class to load
jlaskey@3 654 *
sundar@128 655 * @return the {@code Class<?>} for the name
jlaskey@3 656 *
jlaskey@3 657 * @throws ClassNotFoundException if class cannot be resolved
jlaskey@3 658 */
jlaskey@3 659 public Class<?> findClass(final String fullName) throws ClassNotFoundException {
jlaskey@3 660 // check package access as soon as possible!
sundar@428 661 checkPackageAccess(fullName);
jlaskey@3 662
sundar@41 663 // try the script -classpath loader, if that is set
jlaskey@3 664 if (classPathLoader != null) {
jlaskey@3 665 try {
jlaskey@3 666 return Class.forName(fullName, true, classPathLoader);
sundar@41 667 } catch (final ClassNotFoundException ignored) {
jlaskey@3 668 // ignore, continue search
jlaskey@3 669 }
jlaskey@3 670 }
jlaskey@3 671
sundar@41 672 // Try finding using the "app" loader.
sundar@41 673 return Class.forName(fullName, true, appLoader);
jlaskey@3 674 }
jlaskey@3 675
jlaskey@3 676 /**
jlaskey@3 677 * Hook to print stack trace for a {@link Throwable} that occurred during
jlaskey@3 678 * execution
jlaskey@3 679 *
jlaskey@3 680 * @param t throwable for which to dump stack
jlaskey@3 681 */
jlaskey@3 682 public static void printStackTrace(final Throwable t) {
jlaskey@3 683 if (Context.DEBUG) {
sundar@41 684 t.printStackTrace(Context.getCurrentErr());
jlaskey@3 685 }
jlaskey@3 686 }
jlaskey@3 687
jlaskey@3 688 /**
jlaskey@3 689 * Verify generated bytecode before emission. This is called back from the
sundar@118 690 * {@link ObjectClassGenerator} or the {@link Compiler}. If the "--verify-code" parameter
jlaskey@3 691 * hasn't been given, this is a nop
jlaskey@3 692 *
jlaskey@3 693 * Note that verification may load classes -- we don't want to do that unless
jlaskey@3 694 * user specified verify option. We check it here even though caller
jlaskey@3 695 * may have already checked that flag
jlaskey@3 696 *
jlaskey@3 697 * @param bytecode bytecode to verify
jlaskey@3 698 */
jlaskey@3 699 public void verify(final byte[] bytecode) {
sundar@118 700 if (env._verify_code) {
jlaskey@3 701 // No verification when security manager is around as verifier
jlaskey@3 702 // may load further classes - which should be avoided.
jlaskey@3 703 if (System.getSecurityManager() == null) {
sundar@469 704 CheckClassAdapter.verify(new ClassReader(bytecode), sharedLoader, false, new PrintWriter(System.err, true));
jlaskey@3 705 }
jlaskey@3 706 }
jlaskey@3 707 }
jlaskey@3 708
jlaskey@3 709 /**
jlaskey@67 710 * Create and initialize a new global scope object.
jlaskey@67 711 *
jlaskey@67 712 * @return the initialized global scope object.
jlaskey@67 713 */
jlaskey@67 714 public ScriptObject createGlobal() {
jlaskey@67 715 return initGlobal(newGlobal());
jlaskey@67 716 }
jlaskey@67 717
jlaskey@67 718 /**
jlaskey@67 719 * Create a new uninitialized global scope object
jlaskey@3 720 * @return the global script object
jlaskey@3 721 */
jlaskey@67 722 public ScriptObject newGlobal() {
sundar@456 723 return new Global(this);
jlaskey@67 724 }
jlaskey@67 725
jlaskey@67 726 /**
jlaskey@67 727 * Initialize given global scope object.
jlaskey@67 728 *
lagergren@89 729 * @param global the global
jlaskey@67 730 * @return the initialized global scope object.
jlaskey@67 731 */
jlaskey@67 732 public ScriptObject initGlobal(final ScriptObject global) {
jlaskey@67 733 if (! (global instanceof GlobalObject)) {
jlaskey@67 734 throw new IllegalArgumentException("not a global object!");
jlaskey@67 735 }
jlaskey@67 736
jlaskey@3 737 // Need only minimal global object, if we are just compiling.
sundar@118 738 if (!env._compile_only) {
sundar@44 739 final ScriptObject oldGlobal = Context.getGlobalTrusted();
sundar@41 740 try {
sundar@44 741 Context.setGlobalTrusted(global);
sundar@41 742 // initialize global scope with builtin global objects
sundar@41 743 ((GlobalObject)global).initBuiltinObjects();
sundar@41 744 } finally {
sundar@44 745 Context.setGlobalTrusted(oldGlobal);
sundar@41 746 }
jlaskey@3 747 }
jlaskey@3 748
jlaskey@3 749 return global;
jlaskey@3 750 }
jlaskey@3 751
jlaskey@3 752 /**
sundar@44 753 * Trusted variants - package-private
sundar@44 754 */
sundar@44 755
sundar@44 756 /**
sundar@44 757 * Return the current global scope
sundar@44 758 * @return current global scope
sundar@44 759 */
sundar@44 760 static ScriptObject getGlobalTrusted() {
sundar@44 761 return currentGlobal.get();
sundar@44 762 }
sundar@44 763
sundar@44 764 /**
sundar@44 765 * Set the current global scope
sundar@44 766 */
sundar@44 767 static void setGlobalTrusted(ScriptObject global) {
sundar@44 768 currentGlobal.set(global);
sundar@44 769 }
sundar@44 770
sundar@44 771 /**
sundar@44 772 * Return the current global's context
sundar@44 773 * @return current global's context
sundar@41 774 */
sundar@41 775 static Context getContextTrusted() {
sundar@44 776 return Context.getGlobalTrusted().getContext();
sundar@41 777 }
sundar@41 778
sundar@41 779 /**
jlaskey@3 780 * Try to infer Context instance from the Class. If we cannot,
jlaskey@3 781 * then get it from the thread local variable.
jlaskey@3 782 *
jlaskey@3 783 * @param clazz the class
jlaskey@3 784 * @return context
jlaskey@3 785 */
jlaskey@3 786 static Context fromClass(final Class<?> clazz) {
jlaskey@3 787 final ClassLoader loader = clazz.getClassLoader();
jlaskey@3 788
jlaskey@3 789 Context context = null;
jlaskey@3 790 if (loader instanceof NashornLoader) {
jlaskey@3 791 context = ((NashornLoader)loader).getContext();
jlaskey@3 792 }
jlaskey@3 793
sundar@41 794 return (context != null) ? context : Context.getContextTrusted();
jlaskey@3 795 }
jlaskey@3 796
jlaskey@3 797 private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
jlaskey@3 798 ScriptFunction script = null;
jlaskey@3 799
jlaskey@3 800 try {
sundar@86 801 script = compileScript(source, scope, new Context.ThrowErrorManager());
jlaskey@3 802 } catch (final ParserException e) {
sundar@44 803 e.throwAsEcmaException();
jlaskey@3 804 }
jlaskey@3 805
jlaskey@3 806 return ScriptRuntime.apply(script, thiz);
jlaskey@3 807 }
jlaskey@3 808
jlaskey@3 809 private static ScriptFunction getRunScriptFunction(final Class<?> script, final ScriptObject scope) {
jlaskey@3 810 if (script == null) {
jlaskey@3 811 return null;
jlaskey@3 812 }
jlaskey@3 813
jlaskey@3 814 // Get run method - the entry point to the script
jlaskey@3 815 final MethodHandle runMethodHandle =
jlaskey@3 816 MH.findStatic(
jlaskey@3 817 MethodHandles.lookup(),
jlaskey@3 818 script,
lagergren@211 819 RUN_SCRIPT.symbolName(),
jlaskey@3 820 MH.type(
jlaskey@3 821 Object.class,
attila@81 822 ScriptFunction.class,
attila@81 823 Object.class));
jlaskey@3 824
jlaskey@3 825 boolean strict;
jlaskey@3 826
jlaskey@3 827 try {
lagergren@211 828 strict = script.getField(STRICT_MODE.symbolName()).getBoolean(null);
jlaskey@3 829 } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
jlaskey@3 830 strict = false;
jlaskey@3 831 }
jlaskey@3 832
jlaskey@3 833 // Package as a JavaScript function and pass function back to shell.
lagergren@211 834 return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict);
jlaskey@3 835 }
jlaskey@3 836
sundar@86 837 private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) {
sundar@86 838 return getRunScriptFunction(compile(source, errMan, this._strict), scope);
jlaskey@3 839 }
jlaskey@3 840
sundar@86 841 private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
jlaskey@3 842 // start with no errors, no warnings.
jlaskey@3 843 errMan.reset();
jlaskey@3 844
jlaskey@3 845 GlobalObject global = null;
jlaskey@3 846 Class<?> script;
jlaskey@3 847
sundar@118 848 if (env._class_cache_size > 0) {
sundar@44 849 global = (GlobalObject)Context.getGlobalTrusted();
jlaskey@3 850 script = global.findCachedClass(source);
jlaskey@3 851 if (script != null) {
lagergren@211 852 Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
jlaskey@3 853 return script;
jlaskey@3 854 }
jlaskey@3 855 }
jlaskey@3 856
sundar@118 857 final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
lagergren@211 858 if (errors.hasErrors()) {
jlaskey@3 859 return null;
jlaskey@3 860 }
jlaskey@3 861
sundar@118 862 if (env._print_ast) {
lagergren@96 863 getErr().println(new ASTWriter(functionNode));
lagergren@96 864 }
lagergren@96 865
sundar@118 866 if (env._print_parse) {
lagergren@89 867 getErr().println(new PrintVisitor(functionNode));
lagergren@89 868 }
lagergren@89 869
lagergren@211 870 if (env._parse_only) {
lagergren@211 871 return null;
lagergren@211 872 }
lagergren@211 873
lagergren@89 874 final URL url = source.getURL();
sundar@118 875 final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
jlaskey@3 876 final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null);
sundar@118 877 final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
jlaskey@3 878
lagergren@247 879 final Compiler compiler = new Compiler(installer, strict);
lagergren@89 880
lagergren@247 881 final FunctionNode newFunctionNode = compiler.compile(functionNode);
lagergren@247 882 script = compiler.install(newFunctionNode);
jlaskey@3 883
jlaskey@3 884 if (global != null) {
jlaskey@3 885 global.cacheClass(source, script);
jlaskey@3 886 }
jlaskey@3 887
jlaskey@3 888 return script;
jlaskey@3 889 }
jlaskey@3 890
jlaskey@3 891 private ScriptLoader createNewLoader() {
jlaskey@3 892 return AccessController.doPrivileged(
jlaskey@3 893 new PrivilegedAction<ScriptLoader>() {
jlaskey@3 894 @Override
jlaskey@3 895 public ScriptLoader run() {
sundar@414 896 return new ScriptLoader(sharedLoader, Context.this);
jlaskey@3 897 }
sundar@492 898 }, CREATE_LOADER_ACC_CTXT);
jlaskey@3 899 }
jlaskey@3 900
sundar@427 901 private long getUniqueScriptId() {
sundar@427 902 return uniqueScriptId.getAndIncrement();
sundar@425 903 }
jlaskey@3 904 }

mercurial