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