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