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