@Override public Object eval(final String s) { return inGlobal(new Callable<Object>() { @Override public Object call() { final Context context = AccessController.doPrivileged( new PrivilegedAction<Context>() { @Override public Context run() { return Context.getContext(); } }, GET_CONTEXT_ACC_CTXT); return wrap(context.eval(global, s, sobj, null, false), global); } }); }
private static void checkLinkRequest(final LinkRequest request) { final Global global = Context.getGlobal(); final ClassFilter cf = global.getClassFilter(); if (cf != null) { throw typeError("no.reflection.with.classfilter"); } final SecurityManager sm = System.getSecurityManager(); if (sm != null) { final Object self = request.getReceiver(); // allow 'static' access on Class objects representing public classes of non-restricted packages if ((self instanceof Class) && Modifier.isPublic(((Class<?>)self).getModifiers())) { final CallSiteDescriptor desc = request.getCallSiteDescriptor(); if ("static".equals(NashornCallSiteDescriptor.getOperand(desc)) && NashornCallSiteDescriptor.contains(desc, StandardOperation.GET, StandardNamespace.PROPERTY)) { if (Context.isAccessibleClass((Class<?>)self) && !isReflectionClass((Class<?>)self)) { // If "GET:PROPERTY:static" passes access checks, allow access. return; } } } checkReflectionPermission(sm); } }
private static String findFunctionalInterfaceMethodName(final Class<?> clazz) { if (clazz == null) { return null; } for (final Class<?> iface : clazz.getInterfaces()) { // check accessibility up-front if (! Context.isAccessibleClass(iface)) { continue; } // check for @FunctionalInterface if (iface.isAnnotationPresent(FunctionalInterface.class)) { // return the first abstract method for (final Method m : iface.getMethods()) { if (Modifier.isAbstract(m.getModifiers()) && !isOverridableObjectMethod(m)) { return m.getName(); } } } } // did not find here, try super class return findFunctionalInterfaceMethodName(clazz.getSuperclass()); }
private static Object evalImpl(final Context.MultiGlobalCompiledScript mgcs, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException { final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != ctxtGlobal); try { if (globalChanged) { Context.setGlobal(ctxtGlobal); } final ScriptFunction script = mgcs.getFunction(ctxtGlobal); ctxtGlobal.setScriptContext(ctxt); return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal)); } catch (final Exception e) { throwAsScriptException(e, ctxtGlobal); throw new AssertionError("should not reach here"); } finally { if (globalChanged) { Context.setGlobal(oldGlobal); } } }
private static Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException { if (script == null) { return null; } final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != ctxtGlobal); try { if (globalChanged) { Context.setGlobal(ctxtGlobal); } ctxtGlobal.setScriptContext(ctxt); return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal)); } catch (final Exception e) { throwAsScriptException(e, ctxtGlobal); throw new AssertionError("should not reach here"); } finally { if (globalChanged) { Context.setGlobal(oldGlobal); } } }
private ScriptFunction compileImpl(final Source source, final Global newGlobal) throws ScriptException { final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != newGlobal); try { if (globalChanged) { Context.setGlobal(newGlobal); } return nashornContext.compileScript(source, newGlobal); } catch (final Exception e) { throwAsScriptException(e, newGlobal); throw new AssertionError("should not reach here"); } finally { if (globalChanged) { Context.setGlobal(oldGlobal); } } }
/** * Dump all Nashorn debug mode counters. Calling this may be better if * you want to print all counters. This way you can avoid too many callsites * due to counter access itself!! * @param self self reference * @return undefined */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object dumpCounters(final Object self) { final PrintWriter out = Context.getCurrentErr(); out.println("ScriptObject count " + ScriptObject.getCount()); out.println("Scope count " + ScriptObject.getScopeCount()); out.println("ScriptObject listeners added " + PropertyListeners.getListenersAdded()); out.println("ScriptObject listeners removed " + PropertyListeners.getListenersRemoved()); out.println("ScriptFunction constructor calls " + ScriptFunction.getConstructorCount()); out.println("ScriptFunction invokes " + ScriptFunction.getInvokes()); out.println("ScriptFunction allocations " + ScriptFunction.getAllocations()); out.println("PropertyMap count " + PropertyMap.getCount()); out.println("PropertyMap cloned " + PropertyMap.getClonedCount()); out.println("PropertyMap history hit " + PropertyMap.getHistoryHit()); out.println("PropertyMap proto invalidations " + PropertyMap.getProtoInvalidations()); out.println("PropertyMap proto history hit " + PropertyMap.getProtoHistoryHit()); out.println("PropertyMap setProtoNewMapCount " + PropertyMap.getSetProtoNewMapCount()); out.println("Callsite count " + LinkerCallSite.getCount()); out.println("Callsite misses " + LinkerCallSite.getMissCount()); out.println("Callsite misses by site at " + LinkerCallSite.getMissSamplingPercentage() + "%"); LinkerCallSite.getMissCounts(out); return UNDEFINED; }
/** * Run method logic. * * @param in input stream for Shell * @param out output stream for Shell * @param err error stream for Shell * @param args arguments to Shell * * @return exit code * * @throws IOException if there's a problem setting up the streams */ protected final int run(final InputStream in, final OutputStream out, final OutputStream err, final String[] args) throws IOException { final Context context = makeContext(in, out, err, args); if (context == null) { return COMMANDLINE_ERROR; } final Global global = context.createGlobal(); final ScriptEnvironment env = context.getEnv(); final List<String> files = env.getFiles(); if (files.isEmpty()) { return readEvalPrint(context, global); } if (env._compile_only) { return compileScripts(context, global, files); } if (env._fx) { return runFXScripts(context, global, files); } return runScripts(context, global, files); }
private Object createProperty(final String name) { final int len = args.length; for (int i = len - 1; i > -1; i--) { final Object obj = args[i]; if (obj instanceof StaticClass) { if (((StaticClass)obj).getRepresentedClass().getSimpleName().equals(name)) { return obj; } } else if (obj instanceof NativeJavaPackage) { final String pkgName = ((NativeJavaPackage)obj).getName(); final String fullName = pkgName.isEmpty() ? name : (pkgName + "." + name); final Context context = Global.instance().getContext(); try { return StaticClass.forClass(context.findClass(fullName)); } catch (final ClassNotFoundException e) { // IGNORE } } } return null; }
private static Method findFunctionalInterfaceMethod(final Class<?> clazz) { if (clazz == null) { return null; } for (final Class<?> iface : clazz.getInterfaces()) { // check accessiblity up-front if (! Context.isAccessibleClass(iface)) { continue; } // check for @FunctionalInterface if (iface.isAnnotationPresent(FunctionalInterface.class)) { // return the first abstract method for (final Method m : iface.getMethods()) { if (Modifier.isAbstract(m.getModifiers())) { return m; } } } } // did not find here, try super class return findFunctionalInterfaceMethod(clazz.getSuperclass()); }
@Test public void compileErrorTest() { final Options options = new Options(""); final ErrorManager errors = new ErrorManager(); final Context cx = new Context(options, errors, Thread.currentThread().getContextClassLoader()); final Global oldGlobal = Context.getGlobal(); Context.setGlobal(cx.createGlobal()); try { final ScriptFunction script = cx.compileScript(sourceFor("<evalCompileErrorTest>", "*/"), Context.getGlobal()); if (script != null) { fail("Invalid script compiled without errors"); } if (errors.getNumberOfErrors() != 1) { fail("Wrong number of errors: " + errors.getNumberOfErrors()); } } finally { Context.setGlobal(oldGlobal); } }
/** * Disassemble an array of byte code. * @param bytecode byte array representing bytecode * @return disassembly as human readable string */ static String disassemble(final byte[] bytecode) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (final PrintWriter pw = new PrintWriter(baos)) { final NashornClassReader cr = new NashornClassReader(bytecode); final Context ctx = AccessController.doPrivileged(new PrivilegedAction<Context>() { @Override public Context run() { return Context.getContext(); } }); final TraceClassVisitor tcv = new TraceClassVisitor(null, new NashornTextifier(ctx.getEnv(), cr), pw); cr.accept(tcv, 0); } final String str = new String(baos.toByteArray()); return str; }
/** * Runs launches "fx:bootstrap.js" with the given JavaScript files provided * as arguments. * * @param context the nashorn context * @param global the global scope * @param files the list of script files to provide * * @return error code * @throws IOException when any script file read results in I/O error */ private static int runFXScripts(final Context context, final Global global, final List<String> files) throws IOException { final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); try { if (globalChanged) { Context.setGlobal(global); } global.addOwnProperty("$GLOBAL", Property.NOT_ENUMERABLE, global); global.addOwnProperty("$SCRIPTS", Property.NOT_ENUMERABLE, files); context.load(global, "fx:bootstrap.js"); } catch (final NashornException e) { context.getErrorManager().error(e.toString()); if (context.getEnv()._dump_on_error) { e.printStackTrace(context.getErr()); } return RUNTIME_ERROR; } finally { context.getOut().flush(); context.getErr().flush(); if (globalChanged) { Context.setGlobal(oldGlobal); } } return SUCCESS; }
@Test public void evalTest() { final Options options = new Options(""); final ErrorManager errors = new ErrorManager(); final Context cx = new Context(options, errors, Thread.currentThread().getContextClassLoader()); final Global oldGlobal = Context.getGlobal(); Context.setGlobal(cx.createGlobal()); try { String code = "22 + 10"; assertTrue(32.0 == ((Number)(eval(cx, "<evalTest>", code))).doubleValue()); code = "obj = { js: 'nashorn' }; obj.js"; assertEquals(eval(cx, "<evalTest2>", code), "nashorn"); } finally { Context.setGlobal(oldGlobal); } }
@Override public Object eval(final String s) { return inGlobal(new Callable<Object>() { @Override public Object call() { final Context context = AccessController.doPrivileged( new PrivilegedAction<Context>() { @Override public Context run() { return Context.getContext(); } }, GET_CONTEXT_ACC_CTXT); return wrapLikeMe(context.eval(global, s, sobj, null)); } }); }
@Override public void putAll(final Map<? extends String, ? extends Object> map) { Objects.requireNonNull(map); final ScriptObject oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); inGlobal(new Callable<Object>() { @Override public Object call() { for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) { final Object value = entry.getValue(); final Object modValue = globalChanged? wrapLikeMe(value, oldGlobal) : value; final String key = entry.getKey(); checkKey(key); sobj.set(key, unwrap(modValue, global), getCallSiteFlags()); } return null; } }); }
/** * ECMA 15.4.4.7 Array.prototype.push (args...) * * @param self self reference * @param args arguments to push * @return array length after pushes */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) public static Object push(final Object self, final Object... args) { try { final ScriptObject sobj = (ScriptObject)self; if (bulkable(sobj) && sobj.getArray().length() + args.length <= JSType.MAX_UINT) { final ArrayData newData = sobj.getArray().push(true, args); sobj.setArray(newData); return JSType.toNarrowestNumber(newData.length()); } long len = JSType.toUint32(sobj.getLength()); for (final Object element : args) { sobj.set(len++, element, CALLSITE_STRICT); } sobj.set("length", len, CALLSITE_STRICT); return JSType.toNarrowestNumber(len); } catch (final ClassCastException | NullPointerException e) { throw typeError(Context.getGlobal(), e, "not.an.object", ScriptRuntime.safeToString(self)); } }
@Override public Object call(final Object thiz, final Object... args) { final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); try { if (globalChanged) { Context.setGlobal(global); } if (sobj instanceof ScriptFunction) { final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; final Object self = globalChanged? wrap(thiz, oldGlobal) : thiz; return wrap(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)), global); } throw new RuntimeException("not a function: " + toString()); } catch (final NashornException ne) { throw ne.initEcmaError(global); } catch (final RuntimeException | Error e) { throw e; } catch (final Throwable t) { throw new RuntimeException(t); } finally { if (globalChanged) { Context.setGlobal(oldGlobal); } } }
@Override public Object newObject(final Object... args) { final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); try { if (globalChanged) { Context.setGlobal(global); } if (sobj instanceof ScriptFunction) { final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; return wrap(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)), global); } throw new RuntimeException("not a constructor: " + toString()); } catch (final NashornException ne) { throw ne.initEcmaError(global); } catch (final RuntimeException | Error e) { throw e; } catch (final Throwable t) { throw new RuntimeException(t); } finally { if (globalChanged) { Context.setGlobal(oldGlobal); } } }
/** * Apply action main loop. * @return result of apply */ public final T apply() { final boolean strict = Bootstrap.isStrictCallable(callbackfn); // for non-strict callback, need to translate undefined thisArg to be global object thisArg = (thisArg == ScriptRuntime.UNDEFINED && !strict)? Context.getGlobal() : thisArg; applyLoopBegin(iter); final boolean reverse = iter.isReverse(); while (iter.hasNext()) { final Object val = iter.next(); index = iter.nextIndex() + (reverse ? 1 : -1); try { if (!forEach(val, index)) { return result; } } catch (final RuntimeException | Error e) { throw e; } catch (final Throwable t) { throw new RuntimeException(t); } } return result; }
@Override public void putAll(final Map<? extends String, ? extends Object> map) { final ScriptObject oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); inGlobal(new Callable<Object>() { @Override public Object call() { for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) { final Object value = entry.getValue(); final Object modValue = globalChanged? wrap(value, oldGlobal) : value; sobj.set(entry.getKey(), unwrap(modValue, global), getCallSiteFlags()); } return null; } }); }
/** * Wrap an array of object to script object mirrors if needed. * * @param args array to be unwrapped * @return wrapped array */ public static Object[] wrapArray(final Object[] args) { if (args == null || args.length == 0) { return args; } return ScriptObjectMirror.wrapArray(args, Context.getGlobal()); }
/** * Convenience constructor for non on-demand compiler instances. */ private Compiler( final Context context, final CodeInstaller installer, final Source source, final ErrorManager errors, final boolean isStrict) { this(context, installer, source, errors, isStrict, false, null, null, null, null, null, null); }
private static Class<?> simpleType(final String typeName) throws ClassNotFoundException { final Class<?> primClass = TypeUtilities.getPrimitiveTypeByName(typeName); if(primClass != null) { return primClass; } final Context ctx = Global.getThisContext(); try { return ctx.findClass(typeName); } catch(final ClassNotFoundException e) { // The logic below compensates for a frequent user error - when people use dot notation to separate inner // class names, i.e. "java.lang.Character.UnicodeBlock" vs."java.lang.Character$UnicodeBlock". The logic // below will try alternative class names, replacing dots at the end of the name with dollar signs. final StringBuilder nextName = new StringBuilder(typeName); int lastDot = nextName.length(); for(;;) { lastDot = nextName.lastIndexOf(".", lastDot - 1); if(lastDot == -1) { // Exhausted the search space, class not found - rethrow the original exception. throw e; } nextName.setCharAt(lastDot, '$'); try { return ctx.findClass(nextName.toString()); } catch(final ClassNotFoundException cnfe) { // Intentionally ignored, so the loop retries with the next name } } } }
private CompiledScript asCompiledScript(final Source source) throws ScriptException { final Context.MultiGlobalCompiledScript mgcs; final ScriptFunction func; final Global oldGlobal = Context.getGlobal(); final Global newGlobal = getNashornGlobalFrom(context); final boolean globalChanged = (oldGlobal != newGlobal); try { if (globalChanged) { Context.setGlobal(newGlobal); } mgcs = nashornContext.compileScript(source); func = mgcs.getFunction(newGlobal); } catch (final Exception e) { throwAsScriptException(e, newGlobal); throw new AssertionError("should not reach here"); } finally { if (globalChanged) { Context.setGlobal(oldGlobal); } } return new CompiledScript() { @Override public Object eval(final ScriptContext ctxt) throws ScriptException { final Global globalObject = getNashornGlobalFrom(ctxt); // Are we running the script in the same global in which it was compiled? if (func.getScope() == globalObject) { return evalImpl(func, ctxt, globalObject); } // different global return evalImpl(mgcs, ctxt, globalObject); } @Override public ScriptEngine getEngine() { return NashornScriptEngine.this; } }; }
/** * Constructor from the compiler. * * @param env Script environment * @param sourceName Source name * @param unitClassName Compile unit class name. * @param strictMode Should we generate this method in strict mode */ ClassEmitter(final Context context, final String sourceName, final String unitClassName, final boolean strictMode) { this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { private static final String OBJECT_CLASS = "java/lang/Object"; @Override protected String getCommonSuperClass(final String type1, final String type2) { try { return super.getCommonSuperClass(type1, type2); } catch (final RuntimeException e) { if (isScriptObject(Compiler.SCRIPTS_PACKAGE, type1) && isScriptObject(Compiler.SCRIPTS_PACKAGE, type2)) { return className(ScriptObject.class); } return OBJECT_CLASS; } } }); this.unitClassName = unitClassName; this.constantMethodNeeded = new HashSet<>(); cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, unitClassName, null, pathName(jdk.nashorn.internal.scripts.JS.class.getName()), null); cw.visitSource(sourceName, null); defineCommonStatics(strictMode); }
private void evalImpl(final Context context, final Global global, final String source, final PrintWriter err, final boolean doe) { try { final Object res = context.eval(global, source, global, "<shell>"); if (res != UNDEFINED) { err.println(toString(res, global)); } } catch (final Exception e) { err.println(e); if (doe) { e.printStackTrace(err); } } }
private static void logEvent(final RuntimeEvent<?> event) { if (event != null) { final Global global = Context.getGlobal(); if (global.has("Debug")) { final ScriptObject debug = (ScriptObject)global.get("Debug"); final ScriptFunction addRuntimeEvent = (ScriptFunction)debug.get("addRuntimeEvent"); ScriptRuntime.apply(addRuntimeEvent, debug, event); } } }
/** * Returns AST as JSON compatible string. * * @param context context * @param code code to be parsed * @param name name of the code source (used for location) * @param includeLoc tells whether to include location information for nodes or not * @return JSON string representation of AST of the supplied code */ public static String parse(final Context context, final String code, final String name, final boolean includeLoc) { final Parser parser = new Parser(context.getEnv(), sourceFor(name, code), new Context.ThrowErrorManager(), context.getEnv()._strict, context.getLogger(Parser.class)); final JSONWriter jsonWriter = new JSONWriter(includeLoc); try { final FunctionNode functionNode = parser.parse(); //symbol name is ":program", default functionNode.accept(jsonWriter); return jsonWriter.getString(); } catch (final ParserException e) { e.throwAsEcmaException(); return null; } }
/** * Returns true if the passed function is the built-in "Java.to". * @param fn the function in question * @return true if the function is built-in "Java.to" */ public static boolean isBuiltInJavaTo(final ScriptFunction fn) { if(!"to".equals(fn.getName())) { // Avoid hitting the thread local if the name doesn't match. return false; } return fn == Context.getGlobal().builtInJavaTo; }
/** * Locate (or indirectly create) the object container class. */ private void findClass() { fieldObjectClassName = isScope() ? ObjectClassGenerator.getClassName(fieldCount, paramCount, codegen.useDualFields()) : ObjectClassGenerator.getClassName(paddedFieldCount, codegen.useDualFields()); try { this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName)); } catch (final ClassNotFoundException e) { throw new AssertionError("Nashorn has encountered an internal error. Structure can not be created."); } }
@Override public Node leaveFunctionNode(final FunctionNode functionNode) { try { final boolean markOptimistic; if (emittedMethods.add(functionNode.getName())) { markOptimistic = generateUnwarrantedOptimismExceptionHandlers(functionNode); generateContinuationHandler(); method.end(); // wrap up this method unit = lc.popCompileUnit(functionNode.getCompileUnit()); popMethodEmitter(); log.info("=== END ", functionNode.getName()); } else { markOptimistic = false; } FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.BYTECODE_GENERATED); if (markOptimistic) { newFunctionNode = newFunctionNode.setFlag(lc, FunctionNode.IS_DEOPTIMIZABLE); } newFunctionObject(newFunctionNode, true); return newFunctionNode; } catch (final Throwable t) { Context.printStackTrace(t); final VerifyError e = new VerifyError("Code generation bug in \"" + functionNode.getName() + "\": likely stack misaligned: " + t + " " + functionNode.getSource().getName()); e.initCause(t); throw e; } }
@Override public Object call(final Object thiz, final Object... args) { final Global oldGlobal = Context.getGlobal(); final boolean globalChanged = (oldGlobal != global); try { if (globalChanged) { Context.setGlobal(global); } if (sobj instanceof ScriptFunction) { final Object[] modArgs = globalChanged? wrapArrayLikeMe(args, oldGlobal) : args; final Object self = globalChanged? wrapLikeMe(thiz, oldGlobal) : thiz; return wrapLikeMe(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global))); } throw new RuntimeException("not a function: " + toString()); } catch (final NashornException ne) { throw ne.initEcmaError(global); } catch (final RuntimeException | Error e) { throw e; } catch (final Throwable t) { throw new RuntimeException(t); } finally { if (globalChanged) { Context.setGlobal(oldGlobal); } } }