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

Wed, 10 Jul 2013 13:25:07 +0530

author
sundar
date
Wed, 10 Jul 2013 13:25:07 +0530
changeset 425
997a3215744a
parent 423
7538a59ca241
child 427
c501b1666bda
permissions
-rw-r--r--

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

mercurial