8041697: CompiledScript slower when eval with binding

Wed, 07 May 2014 14:07:19 +0530

author
sundar
date
Wed, 07 May 2014 14:07:19 +0530
changeset 849
dea8e0de23b2
parent 848
bb3e5d0fcc33
child 850
90d417fd526c

8041697: CompiledScript slower when eval with binding
Reviewed-by: lagergren, attila, hannesw

src/jdk/nashorn/api/scripting/NashornScriptEngine.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/tools/Shell.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Tue Feb 11 12:05:22 2014 +0100
     1.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Wed May 07 14:07:19 2014 +0530
     1.3 @@ -525,6 +525,31 @@
     1.4          return evalImpl(script, ctxt, getNashornGlobalFrom(ctxt));
     1.5      }
     1.6  
     1.7 +    private Object evalImpl(final Context.MultiGlobalCompiledScript mgcs, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
     1.8 +        final Global oldGlobal = Context.getGlobal();
     1.9 +        final boolean globalChanged = (oldGlobal != ctxtGlobal);
    1.10 +        try {
    1.11 +            if (globalChanged) {
    1.12 +                Context.setGlobal(ctxtGlobal);
    1.13 +            }
    1.14 +
    1.15 +            final ScriptFunction script = mgcs.getFunction(ctxtGlobal);
    1.16 +
    1.17 +            // set ScriptContext variables if ctxt is non-null
    1.18 +            if (ctxt != null) {
    1.19 +                setContextVariables(ctxtGlobal, ctxt);
    1.20 +            }
    1.21 +            return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
    1.22 +        } catch (final Exception e) {
    1.23 +            throwAsScriptException(e, ctxtGlobal);
    1.24 +            throw new AssertionError("should not reach here");
    1.25 +        } finally {
    1.26 +            if (globalChanged) {
    1.27 +                Context.setGlobal(oldGlobal);
    1.28 +            }
    1.29 +        }
    1.30 +    }
    1.31 +
    1.32      private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
    1.33          if (script == null) {
    1.34              return null;
    1.35 @@ -571,18 +596,38 @@
    1.36      }
    1.37  
    1.38      private CompiledScript asCompiledScript(final Source source) throws ScriptException {
    1.39 -        final ScriptFunction func = compileImpl(source, context);
    1.40 +        final Context.MultiGlobalCompiledScript mgcs;
    1.41 +        final ScriptFunction func;
    1.42 +        final Global oldGlobal = Context.getGlobal();
    1.43 +        final Global newGlobal = getNashornGlobalFrom(context);
    1.44 +        final boolean globalChanged = (oldGlobal != newGlobal);
    1.45 +        try {
    1.46 +            if (globalChanged) {
    1.47 +                Context.setGlobal(newGlobal);
    1.48 +            }
    1.49 +
    1.50 +            mgcs = nashornContext.compileScript(source);
    1.51 +            func = mgcs.getFunction(newGlobal);
    1.52 +        } catch (final Exception e) {
    1.53 +            throwAsScriptException(e, newGlobal);
    1.54 +            throw new AssertionError("should not reach here");
    1.55 +        } finally {
    1.56 +            if (globalChanged) {
    1.57 +                Context.setGlobal(oldGlobal);
    1.58 +            }
    1.59 +        }
    1.60 +
    1.61          return new CompiledScript() {
    1.62              @Override
    1.63              public Object eval(final ScriptContext ctxt) throws ScriptException {
    1.64                  final Global globalObject = getNashornGlobalFrom(ctxt);
    1.65 -                // Are we running the script in the correct global?
    1.66 +                // Are we running the script in the same global in which it was compiled?
    1.67                  if (func.getScope() == globalObject) {
    1.68                      return evalImpl(func, ctxt, globalObject);
    1.69                  }
    1.70 -                // ScriptContext with a different global. Compile again!
    1.71 -                // Note that we may still hit per-global compilation cache.
    1.72 -                return evalImpl(compileImpl(source, ctxt), ctxt, globalObject);
    1.73 +
    1.74 +                // different global
    1.75 +                return evalImpl(mgcs, ctxt, globalObject);
    1.76              }
    1.77              @Override
    1.78              public ScriptEngine getEngine() {
     2.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Tue Feb 11 12:05:22 2014 +0100
     2.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Wed May 07 14:07:19 2014 +0530
     2.3 @@ -491,6 +491,39 @@
     2.4      }
     2.5  
     2.6      /**
     2.7 +     * Interface to represent compiled code that can be re-used across many
     2.8 +     * global scope instances
     2.9 +     */
    2.10 +    public static interface MultiGlobalCompiledScript {
    2.11 +        /**
    2.12 +         * Obtain script function object for a specific global scope object.
    2.13 +         *
    2.14 +         * @param newGlobal global scope for which function object is obtained
    2.15 +         * @return script function for script level expressions
    2.16 +         */
    2.17 +        public ScriptFunction getFunction(final Global newGlobal);
    2.18 +    }
    2.19 +
    2.20 +    /**
    2.21 +     * Compile a top level script.
    2.22 +     *
    2.23 +     * @param source the script source
    2.24 +     * @return reusable compiled script across many global scopes.
    2.25 +     */
    2.26 +    public MultiGlobalCompiledScript compileScript(final Source source) {
    2.27 +        final Class<?> clazz = compile(source, this.errors, this._strict);
    2.28 +        final MethodHandle runMethodHandle = getRunScriptHandle(clazz);
    2.29 +        final boolean strict = isStrict(clazz);
    2.30 +
    2.31 +        return new MultiGlobalCompiledScript() {
    2.32 +            @Override
    2.33 +            public ScriptFunction getFunction(final Global newGlobal) {
    2.34 +                return Context.getGlobal().newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, newGlobal, strict);
    2.35 +            }
    2.36 +        };
    2.37 +    }
    2.38 +
    2.39 +    /**
    2.40       * Entry point for {@code eval}
    2.41       *
    2.42       * @param initialScope The scope of this eval call
    2.43 @@ -950,14 +983,8 @@
    2.44          return ScriptRuntime.apply(script, thiz);
    2.45      }
    2.46  
    2.47 -    private static ScriptFunction getRunScriptFunction(final Class<?> script, final ScriptObject scope) {
    2.48 -        if (script == null) {
    2.49 -            return null;
    2.50 -        }
    2.51 -
    2.52 -        // Get run method - the entry point to the script
    2.53 -        final MethodHandle runMethodHandle =
    2.54 -                MH.findStatic(
    2.55 +    private static MethodHandle getRunScriptHandle(final Class<?> script) {
    2.56 +        return MH.findStatic(
    2.57                      MethodHandles.lookup(),
    2.58                      script,
    2.59                      RUN_SCRIPT.symbolName(),
    2.60 @@ -965,15 +992,25 @@
    2.61                          Object.class,
    2.62                          ScriptFunction.class,
    2.63                          Object.class));
    2.64 +    }
    2.65  
    2.66 -        boolean strict;
    2.67 +    private static boolean isStrict(final Class<?> script) {
    2.68 +        try {
    2.69 +            return script.getField(STRICT_MODE.symbolName()).getBoolean(null);
    2.70 +        } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
    2.71 +            return false;
    2.72 +        }
    2.73 +    }
    2.74  
    2.75 -        try {
    2.76 -            strict = script.getField(STRICT_MODE.symbolName()).getBoolean(null);
    2.77 -        } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
    2.78 -            strict = false;
    2.79 +    private static ScriptFunction getRunScriptFunction(final Class<?> script, final ScriptObject scope) {
    2.80 +        if (script == null) {
    2.81 +            return null;
    2.82          }
    2.83  
    2.84 +        // Get run method - the entry point to the script
    2.85 +        final MethodHandle runMethodHandle = getRunScriptHandle(script);
    2.86 +        boolean strict = isStrict(script);
    2.87 +
    2.88          // Package as a JavaScript function and pass function back to shell.
    2.89          return Context.getGlobal().newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict);
    2.90      }
     3.1 --- a/src/jdk/nashorn/tools/Shell.java	Tue Feb 11 12:05:22 2014 +0100
     3.2 +++ b/src/jdk/nashorn/tools/Shell.java	Wed May 07 14:07:19 2014 +0530
     3.3 @@ -453,7 +453,7 @@
     3.4              }
     3.5          } finally {
     3.6              if (globalChanged) {
     3.7 -                Context.setGlobal(global);
     3.8 +                Context.setGlobal(oldGlobal);
     3.9              }
    3.10          }
    3.11  

mercurial