1 /*
   2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.runtime;
  27 
  28 import static jdk.internal.org.objectweb.asm.Opcodes.V1_7;
  29 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
  30 import static jdk.nashorn.internal.codegen.CompilerConstants.CREATE_PROGRAM_FUNCTION;
  31 import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
  32 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
  33 import static jdk.nashorn.internal.runtime.CodeStore.newCodeStore;
  34 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
  35 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
  36 import static jdk.nashorn.internal.runtime.Source.sourceFor;
  37 
  38 import java.io.File;
  39 import java.io.InputStream;
  40 import java.io.IOException;
  41 import java.io.PrintWriter;
  42 import java.io.UncheckedIOException;
  43 import java.lang.invoke.MethodHandle;
  44 import java.lang.invoke.MethodHandles;
  45 import java.lang.invoke.MethodType;
  46 import java.lang.invoke.SwitchPoint;
  47 import java.lang.ref.ReferenceQueue;
  48 import java.lang.ref.SoftReference;
  49 import java.lang.module.Configuration;
  50 import java.lang.module.ModuleDescriptor;
  51 import java.lang.module.ModuleFinder;
  52 import java.lang.module.ModuleReference;
  53 import java.lang.reflect.Field;
  54 import java.lang.reflect.Layer;
  55 import java.lang.reflect.Modifier;
  56 import java.lang.reflect.Module;
  57 import java.net.MalformedURLException;
  58 import java.net.URL;
  59 import java.security.AccessControlContext;
  60 import java.security.AccessController;
  61 import java.security.CodeSigner;
  62 import java.security.CodeSource;
  63 import java.security.Permissions;
  64 import java.security.PrivilegedAction;
  65 import java.security.PrivilegedActionException;
  66 import java.security.PrivilegedExceptionAction;
  67 import java.security.ProtectionDomain;
  68 import java.util.Collection;
  69 import java.util.HashMap;
  70 import java.util.HashSet;
  71 import java.util.LinkedHashMap;
  72 import java.util.Map;
  73 import java.util.Objects;
  74 import java.util.Optional;
  75 import java.util.Set;
  76 import java.util.concurrent.ConcurrentHashMap;
  77 import java.util.concurrent.ConcurrentMap;
  78 import java.util.concurrent.atomic.AtomicLong;
  79 import java.util.concurrent.atomic.AtomicReference;
  80 import java.util.concurrent.atomic.LongAdder;
  81 import java.util.function.Consumer;
  82 import java.util.function.Supplier;
  83 import java.util.logging.Level;
  84 import javax.script.ScriptEngine;
  85 import jdk.dynalink.DynamicLinker;
  86 import jdk.internal.org.objectweb.asm.ClassReader;
  87 import jdk.internal.org.objectweb.asm.ClassWriter;
  88 import jdk.internal.org.objectweb.asm.Opcodes;
  89 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
  90 import jdk.nashorn.api.scripting.ClassFilter;
  91 import jdk.nashorn.api.scripting.ScriptObjectMirror;
  92 import jdk.nashorn.internal.WeakValueCache;
  93 import jdk.nashorn.internal.codegen.Compiler;
  94 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
  95 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
  96 import jdk.nashorn.internal.ir.FunctionNode;
  97 import jdk.nashorn.internal.ir.debug.ASTWriter;
  98 import jdk.nashorn.internal.ir.debug.PrintVisitor;
  99 import jdk.nashorn.internal.lookup.MethodHandleFactory;
 100 import jdk.nashorn.internal.objects.Global;
 101 import jdk.nashorn.internal.parser.Parser;
 102 import jdk.nashorn.internal.runtime.events.RuntimeEvent;
 103 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 104 import jdk.nashorn.internal.runtime.logging.DebugLogger;
 105 import jdk.nashorn.internal.runtime.logging.Loggable;
 106 import jdk.nashorn.internal.runtime.logging.Logger;
 107 import jdk.nashorn.internal.runtime.options.LoggingOption.LoggerInfo;
 108 import jdk.nashorn.internal.runtime.options.Options;
 109 import jdk.internal.misc.Unsafe;
 110 
 111 /**
 112  * This class manages the global state of execution. Context is immutable.
 113  */
 114 public final class Context {
 115     // nashorn specific security runtime access permission names
 116     /**
 117      * Permission needed to pass arbitrary nashorn command line options when creating Context.
 118      */
 119     public static final String NASHORN_SET_CONFIG      = "nashorn.setConfig";
 120 
 121     /**
 122      * Permission needed to create Nashorn Context instance.
 123      */
 124     public static final String NASHORN_CREATE_CONTEXT  = "nashorn.createContext";
 125 
 126     /**
 127      * Permission needed to create Nashorn Global instance.
 128      */
 129     public static final String NASHORN_CREATE_GLOBAL   = "nashorn.createGlobal";
 130 
 131     /**
 132      * Permission to get current Nashorn Context from thread local storage.
 133      */
 134     public static final String NASHORN_GET_CONTEXT     = "nashorn.getContext";
 135 
 136     /**
 137      * Permission to use Java reflection/jsr292 from script code.
 138      */
 139     public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection";
 140 
 141     /**
 142      * Permission to create a new Module
 143      */
 144     public static final String NASHORN_CREATE_MODULE = "nashorn.createModule";
 145 
 146     /**
 147      * Permission to enable nashorn debug mode.
 148      */
 149     public static final String NASHORN_DEBUG_MODE = "nashorn.debugMode";
 150 
 151     // nashorn load psuedo URL prefixes
 152     private static final String LOAD_CLASSPATH = "classpath:";
 153     private static final String LOAD_FX = "fx:";
 154     private static final String LOAD_NASHORN = "nashorn:";
 155 
 156     private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
 157     private static final MethodType CREATE_PROGRAM_FUNCTION_TYPE = MethodType.methodType(ScriptFunction.class, ScriptObject.class);
 158 
 159     private static final LongAdder NAMED_INSTALLED_SCRIPT_COUNT = new LongAdder();
 160     private static final LongAdder ANONYMOUS_INSTALLED_SCRIPT_COUNT = new LongAdder();
 161 
 162     /**
 163      * Should scripts use only object slots for fields, or dual long/object slots? The default
 164      * behaviour is to couple this to optimistic types, using dual representation if optimistic types are enabled
 165      * and single field representation otherwise. This can be overridden by setting either the "nashorn.fields.objects"
 166      * or "nashorn.fields.dual" system property.
 167      */
 168     private final FieldMode fieldMode;
 169 
 170     private static enum FieldMode {
 171         /** Value for automatic field representation depending on optimistic types setting */
 172         AUTO,
 173         /** Value for object field representation regardless of optimistic types setting */
 174         OBJECTS,
 175         /** Value for dual primitive/object field representation regardless of optimistic types setting */
 176         DUAL
 177     }
 178 
 179     /**
 180      * Keeps track of which builtin prototypes and properties have been relinked
 181      * Currently we are conservative and associate the name of a builtin class with all
 182      * its properties, so it's enough to invalidate a property to break all assumptions
 183      * about a prototype. This can be changed to a more fine grained approach, but no one
 184      * ever needs this, given the very rare occurrence of swapping out only parts of
 185      * a builtin v.s. the entire builtin object
 186      */
 187     private final Map<String, SwitchPoint> builtinSwitchPoints = new HashMap<>();
 188 
 189     /* Force DebuggerSupport to be loaded. */
 190     static {
 191         DebuggerSupport.FORCELOAD = true;
 192     }
 193 
 194     static long getNamedInstalledScriptCount() {
 195         return NAMED_INSTALLED_SCRIPT_COUNT.sum();
 196     }
 197 
 198     static long getAnonymousInstalledScriptCount() {
 199         return ANONYMOUS_INSTALLED_SCRIPT_COUNT.sum();
 200     }
 201 
 202     /**
 203      * ContextCodeInstaller that has the privilege of installing classes in the Context.
 204      * Can only be instantiated from inside the context and is opaque to other classes
 205      */
 206     private abstract static class ContextCodeInstaller implements CodeInstaller {
 207         final Context context;
 208         final CodeSource codeSource;
 209 
 210         ContextCodeInstaller(final Context context, final CodeSource codeSource) {
 211             this.context = context;
 212             this.codeSource = codeSource;
 213         }
 214 
 215         @Override
 216         public Context getContext() {
 217             return context;
 218         }
 219 
 220         @Override
 221         public void initialize(final Collection<Class<?>> classes, final Source source, final Object[] constants) {
 222             try {
 223                 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
 224                     @Override
 225                     public Void run() throws Exception {
 226                         for (final Class<?> clazz : classes) {
 227                             //use reflection to write source and constants table to installed classes
 228                             final Field sourceField = clazz.getDeclaredField(SOURCE.symbolName());
 229                             sourceField.setAccessible(true);
 230                             sourceField.set(null, source);
 231 
 232                             final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName());
 233                             constantsField.setAccessible(true);
 234                             constantsField.set(null, constants);
 235                         }
 236                         return null;
 237                     }
 238                 });
 239             } catch (final PrivilegedActionException e) {
 240                 throw new RuntimeException(e);
 241             }
 242         }
 243 
 244         @Override
 245         public void verify(final byte[] code) {
 246             context.verify(code);
 247         }
 248 
 249         @Override
 250         public long getUniqueScriptId() {
 251             return context.getUniqueScriptId();
 252         }
 253 
 254         @Override
 255         public void storeScript(final String cacheKey, final Source source, final String mainClassName,
 256                                 final Map<String,byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers,
 257                                 final Object[] constants, final int compilationId) {
 258             if (context.codeStore != null) {
 259                 context.codeStore.store(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId);
 260             }
 261         }
 262 
 263         @Override
 264         public StoredScript loadScript(final Source source, final String functionKey) {
 265             if (context.codeStore != null) {
 266                 return context.codeStore.load(source, functionKey);
 267             }
 268             return null;
 269         }
 270 
 271         @Override
 272         public boolean isCompatibleWith(final CodeInstaller other) {
 273             if (other instanceof ContextCodeInstaller) {
 274                 final ContextCodeInstaller cci = (ContextCodeInstaller)other;
 275                 return cci.context == context && cci.codeSource == codeSource;
 276             }
 277             return false;
 278         }
 279     }
 280 
 281     private static class NamedContextCodeInstaller extends ContextCodeInstaller {
 282         private final ScriptLoader loader;
 283         private int usageCount = 0;
 284         private int bytesDefined = 0;
 285 
 286         // We reuse this installer for 10 compilations or 200000 defined bytes. Usually the first condition
 287         // will occur much earlier, the second is a safety measure for very large scripts/functions.
 288         private final static int MAX_USAGES = 10;
 289         private final static int MAX_BYTES_DEFINED = 200_000;
 290 
 291         private NamedContextCodeInstaller(final Context context, final CodeSource codeSource, final ScriptLoader loader) {
 292             super(context, codeSource);
 293             this.loader = loader;
 294         }
 295 
 296         @Override
 297         public Class<?> install(final String className, final byte[] bytecode) {
 298             usageCount++;
 299             bytesDefined += bytecode.length;
 300             NAMED_INSTALLED_SCRIPT_COUNT.increment();
 301             return loader.installClass(Compiler.binaryName(className), bytecode, codeSource);
 302         }
 303 
 304         @Override
 305         public CodeInstaller getOnDemandCompilationInstaller() {
 306             // Reuse this installer if we're within our limits.
 307             if (usageCount < MAX_USAGES && bytesDefined < MAX_BYTES_DEFINED) {
 308                 return this;
 309             }
 310             return new NamedContextCodeInstaller(context, codeSource, context.createNewLoader());
 311         }
 312 
 313         @Override
 314         public CodeInstaller getMultiClassCodeInstaller() {
 315             // This installer is perfectly suitable for installing multiple classes that reference each other
 316             // as it produces classes with resolvable names, all defined in a single class loader.
 317             return this;
 318         }
 319     }
 320 
 321     private final WeakValueCache<CodeSource, Class<?>> anonymousHostClasses = new WeakValueCache<>();
 322 
 323     private static final class AnonymousContextCodeInstaller extends ContextCodeInstaller {
 324         private static final Unsafe UNSAFE = getUnsafe();
 325         private static final String ANONYMOUS_HOST_CLASS_NAME = Compiler.SCRIPTS_PACKAGE.replace('/', '.') + ".AnonymousHost";
 326         private static final byte[] ANONYMOUS_HOST_CLASS_BYTES = getAnonymousHostClassBytes();
 327 
 328         private final Class<?> hostClass;
 329 
 330         private AnonymousContextCodeInstaller(final Context context, final CodeSource codeSource, final Class<?> hostClass) {
 331             super(context, codeSource);
 332             this.hostClass = hostClass;
 333         }
 334 
 335         @Override
 336         public Class<?> install(final String className, final byte[] bytecode) {
 337             ANONYMOUS_INSTALLED_SCRIPT_COUNT.increment();
 338             return UNSAFE.defineAnonymousClass(hostClass, bytecode, null);
 339         }
 340 
 341         @Override
 342         public CodeInstaller getOnDemandCompilationInstaller() {
 343             // This code loader can be indefinitely reused for on-demand recompilations for the same code source.
 344             return this;
 345         }
 346 
 347         @Override
 348         public CodeInstaller getMultiClassCodeInstaller() {
 349             // This code loader can not be used to install multiple classes that reference each other, as they
 350             // would have no resolvable names. Therefore, in such situation we must revert to an installer that
 351             // produces named classes.
 352             return new NamedContextCodeInstaller(context, codeSource, context.createNewLoader());
 353         }
 354 
 355         private static byte[] getAnonymousHostClassBytes() {
 356             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
 357             cw.visit(V1_7, Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT, ANONYMOUS_HOST_CLASS_NAME.replace('.', '/'), null, "java/lang/Object", null);
 358             cw.visitEnd();
 359             return cw.toByteArray();
 360         }
 361 
 362         private static Unsafe getUnsafe() {
 363             return AccessController.doPrivileged(new PrivilegedAction<Unsafe>() {
 364                 @Override
 365                 public Unsafe run() {
 366                     try {
 367                         final Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
 368                         theUnsafeField.setAccessible(true);
 369                         return (Unsafe)theUnsafeField.get(null);
 370                     } catch (final ReflectiveOperationException e) {
 371                         throw new RuntimeException(e);
 372                     }
 373                 }
 374             });
 375         }
 376     }
 377 
 378     /** Is Context global debug mode enabled ? */
 379     public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
 380 
 381     private static final ThreadLocal<Global> currentGlobal = new ThreadLocal<>();
 382 
 383     // in-memory cache for loaded classes
 384     private ClassCache classCache;
 385 
 386     // persistent code store
 387     private CodeStore codeStore;
 388 
 389     // A factory for linking global properties as constant method handles. It is created when the first Global
 390     // is created, and invalidated forever once the second global is created.
 391     private final AtomicReference<GlobalConstants> globalConstantsRef = new AtomicReference<>();
 392 
 393     /**
 394      * Get the current global scope
 395      * @return the current global scope
 396      */
 397     public static Global getGlobal() {
 398         // This class in a package.access protected package.
 399         // Trusted code only can call this method.
 400         return currentGlobal.get();
 401     }
 402 
 403     /**
 404      * Set the current global scope
 405      * @param global the global scope
 406      */
 407     public static void setGlobal(final ScriptObject global) {
 408         if (global != null && !(global instanceof Global)) {
 409             throw new IllegalArgumentException("not a global!");
 410         }
 411         setGlobal((Global)global);
 412     }
 413 
 414     /**
 415      * Set the current global scope
 416      * @param global the global scope
 417      */
 418     public static void setGlobal(final Global global) {
 419         // This class in a package.access protected package.
 420         // Trusted code only can call this method.
 421         assert getGlobal() != global;
 422         //same code can be cached between globals, then we need to invalidate method handle constants
 423         if (global != null) {
 424             final GlobalConstants globalConstants = getContext(global).getGlobalConstants();
 425             if (globalConstants != null) {
 426                 globalConstants.invalidateAll();
 427             }
 428         }
 429         currentGlobal.set(global);
 430     }
 431 
 432     /**
 433      * Get context of the current global
 434      * @return current global scope's context.
 435      */
 436     public static Context getContext() {
 437         final SecurityManager sm = System.getSecurityManager();
 438         if (sm != null) {
 439             sm.checkPermission(new RuntimePermission(NASHORN_GET_CONTEXT));
 440         }
 441         return getContextTrusted();
 442     }
 443 
 444     /**
 445      * Get current context's error writer
 446      *
 447      * @return error writer of the current context
 448      */
 449     public static PrintWriter getCurrentErr() {
 450         final ScriptObject global = getGlobal();
 451         return (global != null)? global.getContext().getErr() : new PrintWriter(System.err);
 452     }
 453 
 454     /**
 455      * Output text to this Context's error stream
 456      * @param str text to write
 457      */
 458     public static void err(final String str) {
 459         err(str, true);
 460     }
 461 
 462     /**
 463      * Output text to this Context's error stream, optionally with
 464      * a newline afterwards
 465      *
 466      * @param str  text to write
 467      * @param crlf write a carriage return/new line after text
 468      */
 469     public static void err(final String str, final boolean crlf) {
 470         final PrintWriter err = Context.getCurrentErr();
 471         if (err != null) {
 472             if (crlf) {
 473                 err.println(str);
 474             } else {
 475                 err.print(str);
 476             }
 477         }
 478     }
 479 
 480     /** Current environment. */
 481     private final ScriptEnvironment env;
 482 
 483     /** is this context in strict mode? Cached from env. as this is used heavily. */
 484     final boolean _strict;
 485 
 486     /** class loader to resolve classes from script. */
 487     private final ClassLoader appLoader;
 488 
 489     /*package-private*/
 490     ClassLoader getAppLoader() {
 491         return appLoader;
 492     }
 493 
 494     /** Class loader to load classes compiled from scripts. */
 495     private final ScriptLoader scriptLoader;
 496 
 497     /** Dynamic linker for linking call sites in script code loaded by this context */
 498     private final DynamicLinker dynamicLinker;
 499 
 500     /** Current error manager. */
 501     private final ErrorManager errors;
 502 
 503     /** Unique id for script. Used only when --loader-per-compile=false */
 504     private final AtomicLong uniqueScriptId;
 505 
 506     /** Optional class filter to use for Java classes. Can be null. */
 507     private final ClassFilter classFilter;
 508 
 509     /** Process-wide singleton structure loader */
 510     private static final StructureLoader theStructLoader;
 511     private static final ConcurrentMap<String, Class<?>> structureClasses = new ConcurrentHashMap<>();
 512 
 513     /*package-private*/ @SuppressWarnings("static-method")
 514     StructureLoader getStructLoader() {
 515         return theStructLoader;
 516     }
 517 
 518     private static AccessControlContext createNoPermAccCtxt() {
 519         return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) });
 520     }
 521 
 522     private static AccessControlContext createPermAccCtxt(final String permName) {
 523         final Permissions perms = new Permissions();
 524         perms.add(new RuntimePermission(permName));
 525         return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
 526     }
 527 
 528     private static final AccessControlContext NO_PERMISSIONS_ACC_CTXT = createNoPermAccCtxt();
 529     private static final AccessControlContext CREATE_LOADER_ACC_CTXT  = createPermAccCtxt("createClassLoader");
 530     private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT  = createPermAccCtxt(NASHORN_CREATE_GLOBAL);
 531     private static final AccessControlContext GET_LOADER_ACC_CTXT     = createPermAccCtxt("getClassLoader");
 532 
 533     static {
 534         final ClassLoader myLoader = Context.class.getClassLoader();
 535         theStructLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
 536             @Override
 537             public StructureLoader run() {
 538                 return new StructureLoader(myLoader);
 539             }
 540         }, CREATE_LOADER_ACC_CTXT);
 541     }
 542 
 543     /**
 544      * ThrowErrorManager that throws ParserException upon error conditions.
 545      */
 546     public static class ThrowErrorManager extends ErrorManager {
 547         @Override
 548         public void error(final String message) {
 549             throw new ParserException(message);
 550         }
 551 
 552         @Override
 553         public void error(final ParserException e) {
 554             throw e;
 555         }
 556     }
 557 
 558     /**
 559      * Constructor
 560      *
 561      * @param options options from command line or Context creator
 562      * @param errors  error manger
 563      * @param appLoader application class loader
 564      */
 565     public Context(final Options options, final ErrorManager errors, final ClassLoader appLoader) {
 566         this(options, errors, appLoader, null);
 567     }
 568 
 569     /**
 570      * Constructor
 571      *
 572      * @param options options from command line or Context creator
 573      * @param errors  error manger
 574      * @param appLoader application class loader
 575      * @param classFilter class filter to use
 576      */
 577     public Context(final Options options, final ErrorManager errors, final ClassLoader appLoader, final ClassFilter classFilter) {
 578         this(options, errors, new PrintWriter(System.out, true), new PrintWriter(System.err, true), appLoader, classFilter);
 579     }
 580 
 581     /**
 582      * Constructor
 583      *
 584      * @param options options from command line or Context creator
 585      * @param errors  error manger
 586      * @param out     output writer for this Context
 587      * @param err     error writer for this Context
 588      * @param appLoader application class loader
 589      */
 590     public Context(final Options options, final ErrorManager errors, final PrintWriter out, final PrintWriter err, final ClassLoader appLoader) {
 591         this(options, errors, out, err, appLoader, (ClassFilter)null);
 592     }
 593 
 594     /**
 595      * Constructor
 596      *
 597      * @param options options from command line or Context creator
 598      * @param errors  error manger
 599      * @param out     output writer for this Context
 600      * @param err     error writer for this Context
 601      * @param appLoader application class loader
 602      * @param classFilter class filter to use
 603      */
 604     public Context(final Options options, final ErrorManager errors, final PrintWriter out, final PrintWriter err, final ClassLoader appLoader, final ClassFilter classFilter) {
 605         final SecurityManager sm = System.getSecurityManager();
 606         if (sm != null) {
 607             sm.checkPermission(new RuntimePermission(NASHORN_CREATE_CONTEXT));
 608         }
 609 
 610         this.classFilter = classFilter;
 611         this.env       = new ScriptEnvironment(options, out, err);
 612         this._strict   = env._strict;
 613         if (env._loader_per_compile) {
 614             this.scriptLoader = null;
 615             this.uniqueScriptId = null;
 616         } else {
 617             this.scriptLoader = createNewLoader();
 618             this.uniqueScriptId = new AtomicLong();
 619         }
 620         this.errors    = errors;
 621 
 622         // if user passed -classpath option, make a URLClassLoader with that and
 623         // the app loader as the parent.
 624         final String classPath = options.getString("classpath");
 625         if (!env._compile_only && classPath != null && !classPath.isEmpty()) {
 626             // make sure that caller can create a class loader.
 627             if (sm != null) {
 628                 sm.checkCreateClassLoader();
 629             }
 630             this.appLoader = NashornLoader.createClassLoader(classPath, appLoader);
 631         } else {
 632             this.appLoader = appLoader;
 633         }
 634         this.dynamicLinker = Bootstrap.createDynamicLinker(this.appLoader, env._unstable_relink_threshold);
 635 
 636         final int cacheSize = env._class_cache_size;
 637         if (cacheSize > 0) {
 638             classCache = new ClassCache(this, cacheSize);
 639         }
 640 
 641         if (env._persistent_cache) {
 642             codeStore = newCodeStore(this);
 643         }
 644 
 645         // print version info if asked.
 646         if (env._version) {
 647             getErr().println("nashorn " + Version.version());
 648         }
 649 
 650         if (env._fullversion) {
 651             getErr().println("nashorn full version " + Version.fullVersion());
 652         }
 653 
 654         if (Options.getBooleanProperty("nashorn.fields.dual")) {
 655             fieldMode = FieldMode.DUAL;
 656         } else if (Options.getBooleanProperty("nashorn.fields.objects")) {
 657             fieldMode = FieldMode.OBJECTS;
 658         } else {
 659             fieldMode = FieldMode.AUTO;
 660         }
 661 
 662         initLoggers();
 663     }
 664 
 665 
 666     /**
 667      * Get the class filter for this context
 668      * @return class filter
 669      */
 670     public ClassFilter getClassFilter() {
 671         return classFilter;
 672     }
 673 
 674     /**
 675      * Returns the factory for constant method handles for global properties. The returned factory can be
 676      * invalidated if this Context has more than one Global.
 677      * @return the factory for constant method handles for global properties.
 678      */
 679     GlobalConstants getGlobalConstants() {
 680         return globalConstantsRef.get();
 681     }
 682 
 683     /**
 684      * Get the error manager for this context
 685      * @return error manger
 686      */
 687     public ErrorManager getErrorManager() {
 688         return errors;
 689     }
 690 
 691     /**
 692      * Get the script environment for this context
 693      * @return script environment
 694      */
 695     public ScriptEnvironment getEnv() {
 696         return env;
 697     }
 698 
 699     /**
 700      * Get the output stream for this context
 701      * @return output print writer
 702      */
 703     public PrintWriter getOut() {
 704         return env.getOut();
 705     }
 706 
 707     /**
 708      * Get the error stream for this context
 709      * @return error print writer
 710      */
 711     public PrintWriter getErr() {
 712         return env.getErr();
 713     }
 714 
 715     /**
 716      * Should scripts compiled by this context use dual field representation?
 717      * @return true if using dual fields, false for object-only fields
 718      */
 719     public boolean useDualFields() {
 720         return fieldMode == FieldMode.DUAL || (fieldMode == FieldMode.AUTO && env._optimistic_types);
 721     }
 722 
 723     /**
 724      * Get the PropertyMap of the current global scope
 725      * @return the property map of the current global scope
 726      */
 727     public static PropertyMap getGlobalMap() {
 728         return Context.getGlobal().getMap();
 729     }
 730 
 731     /**
 732      * Compile a top level script.
 733      *
 734      * @param source the source
 735      * @param scope  the scope
 736      *
 737      * @return top level function for script
 738      */
 739     public ScriptFunction compileScript(final Source source, final ScriptObject scope) {
 740         return compileScript(source, scope, this.errors);
 741     }
 742 
 743     /**
 744      * Interface to represent compiled code that can be re-used across many
 745      * global scope instances
 746      */
 747     public static interface MultiGlobalCompiledScript {
 748         /**
 749          * Obtain script function object for a specific global scope object.
 750          *
 751          * @param newGlobal global scope for which function object is obtained
 752          * @return script function for script level expressions
 753          */
 754         public ScriptFunction getFunction(final Global newGlobal);
 755     }
 756 
 757     /**
 758      * Compile a top level script.
 759      *
 760      * @param source the script source
 761      * @return reusable compiled script across many global scopes.
 762      */
 763     public MultiGlobalCompiledScript compileScript(final Source source) {
 764         final Class<?> clazz = compile(source, this.errors, this._strict, false);
 765         final MethodHandle createProgramFunctionHandle = getCreateProgramFunctionHandle(clazz);
 766 
 767         return new MultiGlobalCompiledScript() {
 768             @Override
 769             public ScriptFunction getFunction(final Global newGlobal) {
 770                 return invokeCreateProgramFunctionHandle(createProgramFunctionHandle, newGlobal);
 771             }
 772         };
 773     }
 774 
 775     /**
 776      * Entry point for {@code eval}
 777      *
 778      * @param initialScope The scope of this eval call
 779      * @param string       Evaluated code as a String
 780      * @param callThis     "this" to be passed to the evaluated code
 781      * @param location     location of the eval call
 782      * @return the return value of the {@code eval}
 783      */
 784     public Object eval(final ScriptObject initialScope, final String string,
 785             final Object callThis, final Object location) {
 786         return eval(initialScope, string, callThis, location, false, false);
 787     }
 788 
 789     /**
 790      * Entry point for {@code eval}
 791      *
 792      * @param initialScope The scope of this eval call
 793      * @param string       Evaluated code as a String
 794      * @param callThis     "this" to be passed to the evaluated code
 795      * @param location     location of the eval call
 796      * @param strict       is this {@code eval} call from a strict mode code?
 797      * @param evalCall     is this called from "eval" builtin?
 798      *
 799      * @return the return value of the {@code eval}
 800      */
 801     public Object eval(final ScriptObject initialScope, final String string,
 802             final Object callThis, final Object location, final boolean strict, final boolean evalCall) {
 803         final String  file       = location == UNDEFINED || location == null ? "<eval>" : location.toString();
 804         final Source  source     = sourceFor(file, string, evalCall);
 805         // is this direct 'eval' builtin call?
 806         final boolean directEval = evalCall && (location != UNDEFINED);
 807         final Global  global = Context.getGlobal();
 808         ScriptObject scope = initialScope;
 809 
 810         // ECMA section 10.1.1 point 2 says eval code is strict if it begins
 811         // with "use strict" directive or eval direct call itself is made
 812         // from from strict mode code. We are passed with caller's strict mode.
 813         // Nashorn extension: any 'eval' is unconditionally strict when -strict is specified.
 814         boolean strictFlag = strict || this._strict;
 815 
 816         Class<?> clazz;
 817         try {
 818             clazz = compile(source, new ThrowErrorManager(), strictFlag, true);
 819         } catch (final ParserException e) {
 820             e.throwAsEcmaException(global);
 821             return null;
 822         }
 823 
 824         if (!strictFlag) {
 825             // We need to get strict mode flag from compiled class. This is
 826             // because eval code may start with "use strict" directive.
 827             try {
 828                 strictFlag = clazz.getField(STRICT_MODE.symbolName()).getBoolean(null);
 829             } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
 830                 //ignored
 831                 strictFlag = false;
 832             }
 833         }
 834 
 835         // In strict mode, eval does not instantiate variables and functions
 836         // in the caller's environment. A new environment is created!
 837         if (strictFlag) {
 838             // Create a new scope object with given scope as its prototype
 839             scope = newScope(scope);
 840         }
 841 
 842         final ScriptFunction func = getProgramFunction(clazz, scope);
 843         Object evalThis;
 844         if (directEval) {
 845             evalThis = (callThis != UNDEFINED && callThis != null) || strictFlag ? callThis : global;
 846         } else {
 847             // either indirect evalCall or non-eval (Function, engine.eval, ScriptObjectMirror.eval..)
 848             evalThis = callThis;
 849         }
 850 
 851         return ScriptRuntime.apply(func, evalThis);
 852     }
 853 
 854     private static ScriptObject newScope(final ScriptObject callerScope) {
 855         return new Scope(callerScope, PropertyMap.newMap(Scope.class));
 856     }
 857 
 858     private static Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
 859         if (srcStr.startsWith(prefix)) {
 860             final String resource = resourcePath + srcStr.substring(prefix.length());
 861             // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme
 862             // These scripts are always available and are loaded from nashorn.jar's resources.
 863             return AccessController.doPrivileged(
 864                     new PrivilegedAction<Source>() {
 865                         @Override
 866                         public Source run() {
 867                             try {
 868                                 final InputStream resStream = Context.class.getResourceAsStream(resource);
 869                                 return resStream != null ? sourceFor(srcStr, Source.readFully(resStream)) : null;
 870                             } catch (final IOException exp) {
 871                                 return null;
 872                             }
 873                         }
 874                     });
 875         }
 876 
 877         return null;
 878     }
 879 
 880     /**
 881      * Implementation of {@code load} Nashorn extension. Load a script file from a source
 882      * expression
 883      *
 884      * @param scope  the scope
 885      * @param from   source expression for script
 886      *
 887      * @return return value for load call (undefined)
 888      *
 889      * @throws IOException if source cannot be found or loaded
 890      */
 891     public Object load(final Object scope, final Object from) throws IOException {
 892         final Object src = from instanceof ConsString ? from.toString() : from;
 893         Source source = null;
 894 
 895         // load accepts a String (which could be a URL or a file name), a File, a URL
 896         // or a ScriptObject that has "name" and "source" (string valued) properties.
 897         if (src instanceof String) {
 898             final String srcStr = (String)src;
 899             if (srcStr.startsWith(LOAD_CLASSPATH)) {
 900                 final URL url = getResourceURL(srcStr.substring(LOAD_CLASSPATH.length()));
 901                 source = url != null ? sourceFor(url.toString(), url) : null;
 902             } else {
 903                 final File file = new File(srcStr);
 904                 if (srcStr.indexOf(':') != -1) {
 905                     if ((source = loadInternal(srcStr, LOAD_NASHORN, "resources/")) == null &&
 906                         (source = loadInternal(srcStr, LOAD_FX, "resources/fx/")) == null) {
 907                         URL url;
 908                         try {
 909                             //check for malformed url. if malformed, it may still be a valid file
 910                             url = new URL(srcStr);
 911                         } catch (final MalformedURLException e) {
 912                             url = file.toURI().toURL();
 913                         }
 914                         source = sourceFor(url.toString(), url);
 915                     }
 916                 } else if (file.isFile()) {
 917                     source = sourceFor(srcStr, file);
 918                 }
 919             }
 920         } else if (src instanceof File && ((File)src).isFile()) {
 921             final File file = (File)src;
 922             source = sourceFor(file.getName(), file);
 923         } else if (src instanceof URL) {
 924             final URL url = (URL)src;
 925             source = sourceFor(url.toString(), url);
 926         } else if (src instanceof ScriptObject) {
 927             final ScriptObject sobj = (ScriptObject)src;
 928             if (sobj.has("script") && sobj.has("name")) {
 929                 final String script = JSType.toString(sobj.get("script"));
 930                 final String name   = JSType.toString(sobj.get("name"));
 931                 source = sourceFor(name, script);
 932             }
 933         } else if (src instanceof Map) {
 934             final Map<?,?> map = (Map<?,?>)src;
 935             if (map.containsKey("script") && map.containsKey("name")) {
 936                 final String script = JSType.toString(map.get("script"));
 937                 final String name   = JSType.toString(map.get("name"));
 938                 source = sourceFor(name, script);
 939             }
 940         }
 941 
 942         if (source != null) {
 943             if (scope instanceof ScriptObject && ((ScriptObject)scope).isScope()) {
 944                 final ScriptObject sobj = (ScriptObject)scope;
 945                 // passed object is a script object
 946                 // Global is the only user accessible scope ScriptObject
 947                 assert sobj.isGlobal() : "non-Global scope object!!";
 948                 return evaluateSource(source, sobj, sobj);
 949             } else if (scope == null || scope == UNDEFINED) {
 950                 // undefined or null scope. Use current global instance.
 951                 final Global global = getGlobal();
 952                 return evaluateSource(source, global, global);
 953             } else {
 954                 /*
 955                  * Arbitrary object passed for scope.
 956                  * Indirect load that is equivalent to:
 957                  *
 958                  *    (function(scope, source) {
 959                  *        with (scope) {
 960                  *            eval(<script_from_source>);
 961                  *        }
 962                  *    })(scope, source);
 963                  */
 964                 final Global global = getGlobal();
 965                 // Create a new object. This is where all declarations
 966                 // (var, function) from the evaluated code go.
 967                 // make global to be its __proto__ so that global
 968                 // definitions are accessible to the evaluated code.
 969                 final ScriptObject evalScope = newScope(global);
 970 
 971                 // finally, make a WithObject around user supplied scope object
 972                 // so that it's properties are accessible as variables.
 973                 final ScriptObject withObj = ScriptRuntime.openWith(evalScope, scope);
 974 
 975                 // evaluate given source with 'withObj' as scope
 976                 // but use global object as "this".
 977                 return evaluateSource(source, withObj, global);
 978             }
 979         }
 980 
 981         throw typeError("cant.load.script", ScriptRuntime.safeToString(from));
 982     }
 983 
 984     /**
 985      * Implementation of {@code loadWithNewGlobal} Nashorn extension. Load a script file from a source
 986      * expression, after creating a new global scope.
 987      *
 988      * @param from source expression for script
 989      * @param args (optional) arguments to be passed to the loaded script
 990      *
 991      * @return return value for load call (undefined)
 992      *
 993      * @throws IOException if source cannot be found or loaded
 994      */
 995     public Object loadWithNewGlobal(final Object from, final Object...args) throws IOException {
 996         final Global oldGlobal = getGlobal();
 997         final Global newGlobal = AccessController.doPrivileged(new PrivilegedAction<Global>() {
 998            @Override
 999            public Global run() {
1000                try {
1001                    return newGlobal();
1002                } catch (final RuntimeException e) {
1003                    if (Context.DEBUG) {
1004                        e.printStackTrace();
1005                    }
1006                    throw e;
1007                }
1008            }
1009         }, CREATE_GLOBAL_ACC_CTXT);
1010         // initialize newly created Global instance
1011         initGlobal(newGlobal);
1012         setGlobal(newGlobal);
1013 
1014         final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY :  ScriptObjectMirror.wrapArray(args, oldGlobal);
1015         newGlobal.put("arguments", newGlobal.wrapAsObject(wrapped), env._strict);
1016 
1017         try {
1018             // wrap objects from newGlobal's world as mirrors - but if result
1019             // is from oldGlobal's world, unwrap it!
1020             return ScriptObjectMirror.unwrap(ScriptObjectMirror.wrap(load(newGlobal, from), newGlobal), oldGlobal);
1021         } finally {
1022             setGlobal(oldGlobal);
1023         }
1024     }
1025 
1026     /**
1027      * Load or get a structure class. Structure class names are based on the number of parameter fields
1028      * and {@link AccessorProperty} fields in them. Structure classes are used to represent ScriptObjects
1029      *
1030      * @see ObjectClassGenerator
1031      * @see AccessorProperty
1032      * @see ScriptObject
1033      *
1034      * @param fullName  full name of class, e.g. jdk.nashorn.internal.objects.JO2P1 contains 2 fields and 1 parameter.
1035      *
1036      * @return the {@code Class<?>} for this structure
1037      *
1038      * @throws ClassNotFoundException if structure class cannot be resolved
1039      */
1040     @SuppressWarnings("unchecked")
1041     public static Class<? extends ScriptObject> forStructureClass(final String fullName) throws ClassNotFoundException {
1042         if (System.getSecurityManager() != null && !StructureLoader.isStructureClass(fullName)) {
1043             throw new ClassNotFoundException(fullName);
1044         }
1045         return (Class<? extends ScriptObject>)structureClasses.computeIfAbsent(fullName, (name) -> {
1046             try {
1047                 return Class.forName(name, true, theStructLoader);
1048             } catch (final ClassNotFoundException e) {
1049                 throw new AssertionError(e);
1050             }
1051         });
1052     }
1053 
1054     /**
1055      * Is {@code className} the name of a structure class?
1056      *
1057      * @param className a class name
1058      * @return true if className is a structure class name
1059      */
1060     public static boolean isStructureClass(final String className) {
1061         return StructureLoader.isStructureClass(className);
1062     }
1063 
1064     /**
1065      * Checks that the given Class can be accessed from no permissions context.
1066      *
1067      * @param clazz Class object
1068      * @throws SecurityException if not accessible
1069      */
1070     public static void checkPackageAccess(final Class<?> clazz) {
1071         final SecurityManager sm = System.getSecurityManager();
1072         if (sm != null) {
1073             Class<?> bottomClazz = clazz;
1074             while (bottomClazz.isArray()) {
1075                 bottomClazz = bottomClazz.getComponentType();
1076             }
1077             checkPackageAccess(sm, bottomClazz.getName());
1078         }
1079     }
1080 
1081     /**
1082      * Checks that the given package name can be accessed from no permissions context.
1083      *
1084      * @param pkgName package name
1085      * @throws SecurityException if not accessible
1086      */
1087     public static void checkPackageAccess(final String pkgName) {
1088         final SecurityManager sm = System.getSecurityManager();
1089         if (sm != null) {
1090             checkPackageAccess(sm, pkgName.endsWith(".") ? pkgName : pkgName + ".");
1091         }
1092     }
1093 
1094     /**
1095      * Checks that the given package can be accessed from no permissions context.
1096      *
1097      * @param sm current security manager instance
1098      * @param fullName fully qualified package name
1099      * @throw SecurityException if not accessible
1100      */
1101     private static void checkPackageAccess(final SecurityManager sm, final String fullName) {
1102         Objects.requireNonNull(sm);
1103         final int index = fullName.lastIndexOf('.');
1104         if (index != -1) {
1105             final String pkgName = fullName.substring(0, index);
1106             AccessController.doPrivileged(new PrivilegedAction<Void>() {
1107                 @Override
1108                 public Void run() {
1109                     sm.checkPackageAccess(pkgName);
1110                     return null;
1111                 }
1112             }, NO_PERMISSIONS_ACC_CTXT);
1113         }
1114     }
1115 
1116     /**
1117      * Checks that the given Class can be accessed from no permissions context.
1118      *
1119      * @param clazz Class object
1120      * @return true if package is accessible, false otherwise
1121      */
1122     private static boolean isAccessiblePackage(final Class<?> clazz) {
1123         try {
1124             checkPackageAccess(clazz);
1125             return true;
1126         } catch (final SecurityException se) {
1127             return false;
1128         }
1129     }
1130 
1131     /**
1132      * Checks that the given Class is public and it can be accessed from no permissions context.
1133      *
1134      * @param clazz Class object to check
1135      * @return true if Class is accessible, false otherwise
1136      */
1137     public static boolean isAccessibleClass(final Class<?> clazz) {
1138         return Modifier.isPublic(clazz.getModifiers()) && Context.isAccessiblePackage(clazz);
1139     }
1140 
1141     /**
1142      * Lookup a Java class. This is used for JSR-223 stuff linking in from
1143      * {@code jdk.nashorn.internal.objects.NativeJava} and {@code jdk.nashorn.internal.runtime.NativeJavaPackage}
1144      *
1145      * @param fullName full name of class to load
1146      *
1147      * @return the {@code Class<?>} for the name
1148      *
1149      * @throws ClassNotFoundException if class cannot be resolved
1150      */
1151     public Class<?> findClass(final String fullName) throws ClassNotFoundException {
1152         if (fullName.indexOf('[') != -1 || fullName.indexOf('/') != -1) {
1153             // don't allow array class names or internal names.
1154             throw new ClassNotFoundException(fullName);
1155         }
1156 
1157         // give chance to ClassFilter to filter out, if present
1158         if (classFilter != null && !classFilter.exposeToScripts(fullName)) {
1159             throw new ClassNotFoundException(fullName);
1160         }
1161 
1162         // check package access as soon as possible!
1163         final SecurityManager sm = System.getSecurityManager();
1164         if (sm != null) {
1165             checkPackageAccess(sm, fullName);
1166         }
1167 
1168         // Try finding using the "app" loader.
1169         if (appLoader != null) {
1170             return Class.forName(fullName, true, appLoader);
1171         } else {
1172             final Class<?> cl = Class.forName(fullName);
1173             // return the Class only if it was loaded by boot loader
1174             if (cl.getClassLoader() == null) {
1175                 return cl;
1176             } else {
1177                 throw new ClassNotFoundException(fullName);
1178             }
1179         }
1180     }
1181 
1182     /**
1183      * Hook to print stack trace for a {@link Throwable} that occurred during
1184      * execution
1185      *
1186      * @param t throwable for which to dump stack
1187      */
1188     public static void printStackTrace(final Throwable t) {
1189         if (Context.DEBUG) {
1190             t.printStackTrace(Context.getCurrentErr());
1191         }
1192     }
1193 
1194     /**
1195      * Verify generated bytecode before emission. This is called back from the
1196      * {@link ObjectClassGenerator} or the {@link Compiler}. If the "--verify-code" parameter
1197      * hasn't been given, this is a nop
1198      *
1199      * Note that verification may load classes -- we don't want to do that unless
1200      * user specified verify option. We check it here even though caller
1201      * may have already checked that flag
1202      *
1203      * @param bytecode bytecode to verify
1204      */
1205     public void verify(final byte[] bytecode) {
1206         if (env._verify_code) {
1207             // No verification when security manager is around as verifier
1208             // may load further classes - which should be avoided.
1209             if (System.getSecurityManager() == null) {
1210                 CheckClassAdapter.verify(new ClassReader(bytecode), theStructLoader, false, new PrintWriter(System.err, true));
1211             }
1212         }
1213     }
1214 
1215     /**
1216      * Create and initialize a new global scope object.
1217      *
1218      * @return the initialized global scope object.
1219      */
1220     public Global createGlobal() {
1221         return initGlobal(newGlobal());
1222     }
1223 
1224     /**
1225      * Create a new uninitialized global scope object
1226      * @return the global script object
1227      */
1228     public Global newGlobal() {
1229         createOrInvalidateGlobalConstants();
1230         return new Global(this);
1231     }
1232 
1233     private void createOrInvalidateGlobalConstants() {
1234         for (;;) {
1235             final GlobalConstants currentGlobalConstants = getGlobalConstants();
1236             if (currentGlobalConstants != null) {
1237                 // Subsequent invocation; we're creating our second or later Global. GlobalConstants is not safe to use
1238                 // with more than one Global, as the constant method handle linkages it creates create a coupling
1239                 // between the Global and the call sites in the compiled code.
1240                 currentGlobalConstants.invalidateForever();
1241                 return;
1242             }
1243             final GlobalConstants newGlobalConstants = new GlobalConstants(getLogger(GlobalConstants.class));
1244             if (globalConstantsRef.compareAndSet(null, newGlobalConstants)) {
1245                 // First invocation; we're creating the first Global in this Context. Create the GlobalConstants object
1246                 // for this Context.
1247                 return;
1248             }
1249 
1250             // If we reach here, then we started out as the first invocation, but another concurrent invocation won the
1251             // CAS race. We'll just let the loop repeat and invalidate the CAS race winner.
1252         }
1253     }
1254 
1255     /**
1256      * Initialize given global scope object.
1257      *
1258      * @param global the global
1259      * @param engine the associated ScriptEngine instance, can be null
1260      * @return the initialized global scope object.
1261      */
1262     public Global initGlobal(final Global global, final ScriptEngine engine) {
1263         // Need only minimal global object, if we are just compiling.
1264         if (!env._compile_only) {
1265             final Global oldGlobal = Context.getGlobal();
1266             try {
1267                 Context.setGlobal(global);
1268                 // initialize global scope with builtin global objects
1269                 global.initBuiltinObjects(engine);
1270             } finally {
1271                 Context.setGlobal(oldGlobal);
1272             }
1273         }
1274 
1275         return global;
1276     }
1277 
1278     /**
1279      * Initialize given global scope object.
1280      *
1281      * @param global the global
1282      * @return the initialized global scope object.
1283      */
1284     public Global initGlobal(final Global global) {
1285         return initGlobal(global, null);
1286     }
1287 
1288     /**
1289      * Return the current global's context
1290      * @return current global's context
1291      */
1292     static Context getContextTrusted() {
1293         return getContext(getGlobal());
1294     }
1295 
1296     /**
1297      * Gets the Nashorn dynamic linker for the specified class. If the class is
1298      * a script class, the dynamic linker associated with its context is
1299      * returned. Otherwise the dynamic linker associated with the current
1300      * context is returned.
1301      * @param clazz the class for which we want to retrieve a dynamic linker.
1302      * @return the Nashorn dynamic linker for the specified class.
1303      */
1304     public static DynamicLinker getDynamicLinker(final Class<?> clazz) {
1305         return fromClass(clazz).dynamicLinker;
1306     }
1307 
1308     /**
1309      * Gets the Nashorn dynamic linker associated with the current context.
1310      * @return the Nashorn dynamic linker for the current context.
1311      */
1312     public static DynamicLinker getDynamicLinker() {
1313         return getContextTrusted().dynamicLinker;
1314     }
1315 
1316     /**
1317      * Creates a module layer with one module that is defined to the given class
1318      * loader.
1319      *
1320      * @param descriptor the module descriptor for the newly created module
1321      * @param loader the class loader of the module
1322      * @return the new Module
1323      */
1324     public static Module createModule(final ModuleDescriptor descriptor, final ClassLoader loader) {
1325         final SecurityManager sm = System.getSecurityManager();
1326         if (sm != null) {
1327             sm.checkPermission(new RuntimePermission(NASHORN_CREATE_MODULE));
1328         }
1329         return createModuleTrusted(descriptor, loader);
1330     }
1331 
1332     /**
1333      * Creates a module layer with one module that is defined to the given class
1334      * loader.
1335      *
1336      * @param descriptor the module descriptor for the newly created module
1337      * @param loader the class loader of the module
1338      * @return the new Module
1339      */
1340     static Module createModuleTrusted(final ModuleDescriptor descriptor, final ClassLoader loader) {
1341         return createModuleTrusted(Layer.boot(), descriptor, loader);
1342     }
1343 
1344     /**
1345      * Creates a module layer with one module that is defined to the given class
1346      * loader.
1347      *
1348      * @param parent the parent layer of the new module
1349      * @param descriptor the module descriptor for the newly created module
1350      * @param loader the class loader of the module
1351      * @return the new Module
1352      */
1353     static Module createModuleTrusted(final Layer parent, final ModuleDescriptor descriptor, final ClassLoader loader) {
1354         final String mn = descriptor.name();
1355 
1356         final ModuleReference mref = new ModuleReference(descriptor, null, () -> {
1357             IOException ioe = new IOException("<dynamic module>");
1358             throw new UncheckedIOException(ioe);
1359         });
1360 
1361         final ModuleFinder finder = new ModuleFinder() {
1362             @Override
1363             public Optional<ModuleReference> find(String name) {
1364                 if (name.equals(mn)) {
1365                     return Optional.of(mref);
1366                 } else {
1367                     return Optional.empty();
1368                 }
1369             }
1370             @Override
1371             public Set<ModuleReference> findAll() {
1372                 return Set.of(mref);
1373             }
1374         };
1375 
1376         final Configuration cf = parent.configuration()
1377                 .resolveRequires(finder, ModuleFinder.of(), Set.of(mn));
1378 
1379         final PrivilegedAction<Layer> pa = () -> parent.defineModules(cf, name -> loader);
1380         final Layer layer = AccessController.doPrivileged(pa, GET_LOADER_ACC_CTXT);
1381 
1382         final Module m = layer.findModule(mn).get();
1383         assert m.getLayer() == layer;
1384 
1385         return m;
1386     }
1387 
1388     static Context getContextTrustedOrNull() {
1389         final Global global = Context.getGlobal();
1390         return global == null ? null : getContext(global);
1391     }
1392 
1393     private static Context getContext(final Global global) {
1394         // We can't invoke Global.getContext() directly, as it's a protected override, and Global isn't in our package.
1395         // In order to access the method, we must cast it to ScriptObject first (which is in our package) and then let
1396         // virtual invocation do its thing.
1397         return ((ScriptObject)global).getContext();
1398     }
1399 
1400     /**
1401      * Try to infer Context instance from the Class. If we cannot,
1402      * then get it from the thread local variable.
1403      *
1404      * @param clazz the class
1405      * @return context
1406      */
1407     static Context fromClass(final Class<?> clazz) {
1408         ClassLoader loader = null;
1409         try {
1410             loader = clazz.getClassLoader();
1411         } catch (SecurityException ignored) {
1412             // This could fail because of anonymous classes being used.
1413             // Accessing loader of anonymous class fails (for extension
1414             // loader class too?). In any case, for us fetching Context
1415             // from class loader is just an optimization. We can always
1416             // get Context from thread local storage (below).
1417         }
1418 
1419         if (loader instanceof ScriptLoader) {
1420             return ((ScriptLoader)loader).getContext();
1421         }
1422 
1423         return Context.getContextTrusted();
1424     }
1425 
1426     private URL getResourceURL(final String resName) {
1427         if (appLoader != null) {
1428             return appLoader.getResource(resName);
1429         }
1430         return ClassLoader.getSystemResource(resName);
1431     }
1432 
1433     private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
1434         ScriptFunction script = null;
1435 
1436         try {
1437             script = compileScript(source, scope, new Context.ThrowErrorManager());
1438         } catch (final ParserException e) {
1439             e.throwAsEcmaException();
1440         }
1441 
1442         return ScriptRuntime.apply(script, thiz);
1443     }
1444 
1445     private static ScriptFunction getProgramFunction(final Class<?> script, final ScriptObject scope) {
1446         if (script == null) {
1447             return null;
1448         }
1449         return invokeCreateProgramFunctionHandle(getCreateProgramFunctionHandle(script), scope);
1450     }
1451 
1452     private static MethodHandle getCreateProgramFunctionHandle(final Class<?> script) {
1453         try {
1454             return LOOKUP.findStatic(script, CREATE_PROGRAM_FUNCTION.symbolName(), CREATE_PROGRAM_FUNCTION_TYPE);
1455         } catch (NoSuchMethodException | IllegalAccessException e) {
1456             throw new AssertionError("Failed to retrieve a handle for the program function for " + script.getName(), e);
1457         }
1458     }
1459 
1460     private static ScriptFunction invokeCreateProgramFunctionHandle(final MethodHandle createProgramFunctionHandle, final ScriptObject scope) {
1461         try {
1462             return (ScriptFunction)createProgramFunctionHandle.invokeExact(scope);
1463         } catch (final RuntimeException|Error e) {
1464             throw e;
1465         } catch (final Throwable t) {
1466             throw new AssertionError("Failed to create a program function", t);
1467         }
1468     }
1469 
1470     private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) {
1471         return getProgramFunction(compile(source, errMan, this._strict, false), scope);
1472     }
1473 
1474     private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict, final boolean isEval) {
1475         // start with no errors, no warnings.
1476         errMan.reset();
1477 
1478         Class<?> script = findCachedClass(source);
1479         if (script != null) {
1480             final DebugLogger log = getLogger(Compiler.class);
1481             if (log.isEnabled()) {
1482                 log.fine(new RuntimeEvent<>(Level.INFO, source), "Code cache hit for ", source, " avoiding recompile.");
1483             }
1484             return script;
1485         }
1486 
1487         StoredScript storedScript = null;
1488         FunctionNode functionNode = null;
1489         // Don't use code store if optimistic types is enabled but lazy compilation is not.
1490         // This would store a full script compilation with many wrong optimistic assumptions that would
1491         // do more harm than good on later runs with both optimistic types and lazy compilation enabled.
1492         final boolean useCodeStore = codeStore != null && !env._parse_only && (!env._optimistic_types || env._lazy_compilation);
1493         final String cacheKey = useCodeStore ? CodeStore.getCacheKey("script", null) : null;
1494 
1495         if (useCodeStore) {
1496             storedScript = codeStore.load(source, cacheKey);
1497         }
1498 
1499         if (storedScript == null) {
1500             if (env._dest_dir != null) {
1501                 source.dump(env._dest_dir);
1502             }
1503 
1504             functionNode = new Parser(env, source, errMan, strict, getLogger(Parser.class)).parse();
1505 
1506             if (errMan.hasErrors()) {
1507                 return null;
1508             }
1509 
1510             if (env._print_ast || functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) {
1511                 getErr().println(new ASTWriter(functionNode));
1512             }
1513 
1514             if (env._print_parse || functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) {
1515                 getErr().println(new PrintVisitor(functionNode, true, false));
1516             }
1517         }
1518 
1519         if (env._parse_only) {
1520             return null;
1521         }
1522 
1523         final URL          url    = source.getURL();
1524         final CodeSource   cs     = new CodeSource(url, (CodeSigner[])null);
1525         final CodeInstaller installer;
1526         if (!env.useAnonymousClasses(isEval) || env._persistent_cache || !env._lazy_compilation) {
1527             // Persistent code cache and eager compilation preclude use of VM anonymous classes
1528             final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
1529             installer = new NamedContextCodeInstaller(this, cs, loader);
1530         } else {
1531             installer = new AnonymousContextCodeInstaller(this, cs,
1532                     anonymousHostClasses.getOrCreate(cs, (key) ->
1533                             createNewLoader().installClass(
1534                                     // NOTE: we're defining these constants in AnonymousContextCodeInstaller so they are not
1535                                     // initialized if we don't use AnonymousContextCodeInstaller. As this method is only ever
1536                                     // invoked from AnonymousContextCodeInstaller, this is okay.
1537                                     AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_NAME,
1538                                     AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_BYTES, cs)));
1539         }
1540 
1541         if (storedScript == null) {
1542             final CompilationPhases phases = Compiler.CompilationPhases.COMPILE_ALL;
1543 
1544             final Compiler compiler = Compiler.forInitialCompilation(
1545                     installer,
1546                     source,
1547                     errMan,
1548                     strict | functionNode.isStrict());
1549 
1550             final FunctionNode compiledFunction = compiler.compile(functionNode, phases);
1551             if (errMan.hasErrors()) {
1552                 return null;
1553             }
1554             script = compiledFunction.getRootClass();
1555             compiler.persistClassInfo(cacheKey, compiledFunction);
1556         } else {
1557             Compiler.updateCompilationId(storedScript.getCompilationId());
1558             script = storedScript.installScript(source, installer);
1559         }
1560 
1561         cacheClass(source, script);
1562         return script;
1563     }
1564 
1565     private ScriptLoader createNewLoader() {
1566         return AccessController.doPrivileged(
1567              new PrivilegedAction<ScriptLoader>() {
1568                 @Override
1569                 public ScriptLoader run() {
1570                     return new ScriptLoader(Context.this);
1571                 }
1572              }, CREATE_LOADER_ACC_CTXT);
1573     }
1574 
1575     private long getUniqueScriptId() {
1576         return uniqueScriptId.getAndIncrement();
1577     }
1578 
1579     /**
1580      * Cache for compiled script classes.
1581      */
1582     @SuppressWarnings("serial")
1583     @Logger(name="classcache")
1584     private static class ClassCache extends LinkedHashMap<Source, ClassReference> implements Loggable {
1585         private final int size;
1586         private final ReferenceQueue<Class<?>> queue;
1587         private final DebugLogger log;
1588 
1589         ClassCache(final Context context, final int size) {
1590             super(size, 0.75f, true);
1591             this.size = size;
1592             this.queue = new ReferenceQueue<>();
1593             this.log   = initLogger(context);
1594         }
1595 
1596         void cache(final Source source, final Class<?> clazz) {
1597             if (log.isEnabled()) {
1598                 log.info("Caching ", source, " in class cache");
1599             }
1600             put(source, new ClassReference(clazz, queue, source));
1601         }
1602 
1603         @Override
1604         protected boolean removeEldestEntry(final Map.Entry<Source, ClassReference> eldest) {
1605             return size() > size;
1606         }
1607 
1608         @Override
1609         public ClassReference get(final Object key) {
1610             for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
1611                 final Source source = ref.source;
1612                 if (log.isEnabled()) {
1613                     log.info("Evicting ", source, " from class cache.");
1614                 }
1615                 remove(source);
1616             }
1617 
1618             final ClassReference ref = super.get(key);
1619             if (ref != null && log.isEnabled()) {
1620                 log.info("Retrieved class reference for ", ref.source, " from class cache");
1621             }
1622             return ref;
1623         }
1624 
1625         @Override
1626         public DebugLogger initLogger(final Context context) {
1627             return context.getLogger(getClass());
1628         }
1629 
1630         @Override
1631         public DebugLogger getLogger() {
1632             return log;
1633         }
1634 
1635     }
1636 
1637     private static class ClassReference extends SoftReference<Class<?>> {
1638         private final Source source;
1639 
1640         ClassReference(final Class<?> clazz, final ReferenceQueue<Class<?>> queue, final Source source) {
1641             super(clazz, queue);
1642             this.source = source;
1643         }
1644     }
1645 
1646     // Class cache management
1647     private Class<?> findCachedClass(final Source source) {
1648         final ClassReference ref = classCache == null ? null : classCache.get(source);
1649         return ref != null ? ref.get() : null;
1650     }
1651 
1652     private void cacheClass(final Source source, final Class<?> clazz) {
1653         if (classCache != null) {
1654             classCache.cache(source, clazz);
1655         }
1656     }
1657 
1658     // logging
1659     private final Map<String, DebugLogger> loggers = new HashMap<>();
1660 
1661     private void initLoggers() {
1662         ((Loggable)MethodHandleFactory.getFunctionality()).initLogger(this);
1663     }
1664 
1665     /**
1666      * Get a logger, given a loggable class
1667      * @param clazz a Loggable class
1668      * @return debuglogger associated with that class
1669      */
1670     public DebugLogger getLogger(final Class<? extends Loggable> clazz) {
1671         return getLogger(clazz, null);
1672     }
1673 
1674     /**
1675      * Get a logger, given a loggable class
1676      * @param clazz a Loggable class
1677      * @param initHook an init hook - if this is the first time the logger is created in the context, run the init hook
1678      * @return debuglogger associated with that class
1679      */
1680     public DebugLogger getLogger(final Class<? extends Loggable> clazz, final Consumer<DebugLogger> initHook) {
1681         final String name = getLoggerName(clazz);
1682         DebugLogger logger = loggers.get(name);
1683         if (logger == null) {
1684             if (!env.hasLogger(name)) {
1685                 return DebugLogger.DISABLED_LOGGER;
1686             }
1687             final LoggerInfo info = env._loggers.get(name);
1688             logger = new DebugLogger(name, info.getLevel(), info.isQuiet());
1689             if (initHook != null) {
1690                 initHook.accept(logger);
1691             }
1692             loggers.put(name, logger);
1693         }
1694         return logger;
1695     }
1696 
1697     /**
1698      * Given a Loggable class, weave debug info info a method handle for that logger.
1699      * Level.INFO is used
1700      *
1701      * @param clazz loggable
1702      * @param mh    method handle
1703      * @param text  debug printout to add
1704      *
1705      * @return instrumented method handle, or null if logger not enabled
1706      */
1707     public MethodHandle addLoggingToHandle(final Class<? extends Loggable> clazz, final MethodHandle mh, final Supplier<String> text) {
1708         return addLoggingToHandle(clazz, Level.INFO, mh, Integer.MAX_VALUE, false, text);
1709     }
1710 
1711     /**
1712      * Given a Loggable class, weave debug info info a method handle for that logger.
1713      *
1714      * @param clazz            loggable
1715      * @param level            log level
1716      * @param mh               method handle
1717      * @param paramStart       first parameter to print
1718      * @param printReturnValue should we print the return value?
1719      * @param text             debug printout to add
1720      *
1721      * @return instrumented method handle, or null if logger not enabled
1722      */
1723     public MethodHandle addLoggingToHandle(final Class<? extends Loggable> clazz, final Level level, final MethodHandle mh, final int paramStart, final boolean printReturnValue, final Supplier<String> text) {
1724         final DebugLogger log = getLogger(clazz);
1725         if (log.isEnabled()) {
1726             return MethodHandleFactory.addDebugPrintout(log, level, mh, paramStart, printReturnValue, text.get());
1727         }
1728         return mh;
1729     }
1730 
1731     private static String getLoggerName(final Class<?> clazz) {
1732         Class<?> current = clazz;
1733         while (current != null) {
1734             final Logger log = current.getAnnotation(Logger.class);
1735             if (log != null) {
1736                 assert !"".equals(log.name());
1737                 return log.name();
1738             }
1739             current = current.getSuperclass();
1740         }
1741         assert false;
1742         return null;
1743     }
1744 
1745     /**
1746      * This is a special kind of switchpoint used to guard builtin
1747      * properties and prototypes. In the future it might contain
1748      * logic to e.g. multiple switchpoint classes.
1749      */
1750     public static final class BuiltinSwitchPoint extends SwitchPoint {
1751         //empty
1752     }
1753 
1754     /**
1755      * Create a new builtin switchpoint and return it
1756      * @param name key name
1757      * @return new builtin switchpoint
1758      */
1759     public SwitchPoint newBuiltinSwitchPoint(final String name) {
1760         assert builtinSwitchPoints.get(name) == null;
1761         final SwitchPoint sp = new BuiltinSwitchPoint();
1762         builtinSwitchPoints.put(name, sp);
1763         return sp;
1764     }
1765 
1766     /**
1767      * Return the builtin switchpoint for a particular key name
1768      * @param name key name
1769      * @return builtin switchpoint or null if none
1770      */
1771     public SwitchPoint getBuiltinSwitchPoint(final String name) {
1772         return builtinSwitchPoints.get(name);
1773     }
1774 }