8008197: Cross script engine function calls do not work as expected

Thu, 14 Feb 2013 14:16:58 +0530

author
sundar
date
Thu, 14 Feb 2013 14:16:58 +0530
changeset 88
8c72a2bec1be
parent 87
222b9f32b674
child 89
43e32b36153c

8008197: Cross script engine function calls do not work as expected
Reviewed-by: lagergren, hannesw

src/jdk/nashorn/api/scripting/NashornScriptEngine.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/api/scripting/ScriptObjectMirror.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptFunction.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptRuntime.java file | annotate | diff | comparison | revisions
test/script/basic/JDK-8008197.js file | annotate | diff | comparison | revisions
test/script/basic/jquery.js file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Thu Feb 14 09:14:31 2013 +0530
     1.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Thu Feb 14 14:16:58 2013 +0530
     1.3 @@ -329,7 +329,7 @@
     1.4          final ScriptObject ctxtGlobal    = getNashornGlobalFrom(context);
     1.5          final boolean globalChanged = (oldGlobal != ctxtGlobal);
     1.6  
     1.7 -        Object self = selfObject;
     1.8 +        Object self = globalChanged? ScriptObjectMirror.wrap(selfObject, oldGlobal) : selfObject;
     1.9  
    1.10          try {
    1.11              if (globalChanged) {
    1.12 @@ -354,7 +354,8 @@
    1.13              if (value instanceof ScriptFunction) {
    1.14                  final Object res;
    1.15                  try {
    1.16 -                    res = ScriptRuntime.apply((ScriptFunction)value, self, ScriptObjectMirror.unwrapArray(args, ctxtGlobal));
    1.17 +                    final Object[] modArgs = globalChanged? ScriptObjectMirror.wrapArray(args, oldGlobal) : args;
    1.18 +                    res = ScriptRuntime.checkAndApply((ScriptFunction)value, self, ScriptObjectMirror.unwrapArray(modArgs, ctxtGlobal));
    1.19                  } catch (final Exception e) {
    1.20                      throwAsScriptException(e);
    1.21                      throw new AssertionError("should not reach here");
     2.1 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Thu Feb 14 09:14:31 2013 +0530
     2.2 +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Thu Feb 14 14:16:58 2013 +0530
     2.3 @@ -104,38 +104,30 @@
     2.4      // JSObject methods
     2.5      @Override
     2.6      public Object call(final String methodName, final Object args[]) {
     2.7 -        final Object val = sobj.get(methodName);
     2.8          final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal();
     2.9          final boolean globalChanged = (oldGlobal != global);
    2.10  
    2.11 -        if (val instanceof ScriptFunction) {
    2.12 -            final Object[] modifiedArgs = unwrapArray(args, global);
    2.13 -            if (modifiedArgs != null) {
    2.14 -                for (int i = 0; i < modifiedArgs.length; i++) {
    2.15 -                    final Object arg = modifiedArgs[i];
    2.16 -                    if (arg instanceof ScriptObject) {
    2.17 -                        modifiedArgs[i] = wrap(arg, oldGlobal);
    2.18 -                    }
    2.19 -                }
    2.20 +        try {
    2.21 +            if (globalChanged) {
    2.22 +                NashornScriptEngine.setNashornGlobal(global);
    2.23              }
    2.24  
    2.25 -            try {
    2.26 -                if (globalChanged) {
    2.27 -                    NashornScriptEngine.setNashornGlobal(global);
    2.28 -                }
    2.29 -                return wrap(((ScriptFunction)val).invoke(sobj, modifiedArgs), global);
    2.30 -            } catch (final RuntimeException | Error e) {
    2.31 -                throw e;
    2.32 -            } catch (final Throwable t) {
    2.33 -                throw new RuntimeException(t);
    2.34 -            } finally {
    2.35 -                if (globalChanged) {
    2.36 -                    NashornScriptEngine.setNashornGlobal(oldGlobal);
    2.37 -                }
    2.38 +            final Object val = sobj.get(methodName);
    2.39 +            if (! (val instanceof ScriptFunction)) {
    2.40 +                throw new RuntimeException("No such method: " + methodName);
    2.41              }
    2.42 -       }
    2.43  
    2.44 -       throw new RuntimeException("No such method: " + methodName);
    2.45 +            final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
    2.46 +            return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
    2.47 +        } catch (final RuntimeException | Error e) {
    2.48 +            throw e;
    2.49 +        } catch (final Throwable t) {
    2.50 +            throw new RuntimeException(t);
    2.51 +        } finally {
    2.52 +            if (globalChanged) {
    2.53 +                NashornScriptEngine.setNashornGlobal(oldGlobal);
    2.54 +            }
    2.55 +        }
    2.56      }
    2.57  
    2.58      @Override
    2.59 @@ -180,7 +172,7 @@
    2.60  
    2.61      @Override
    2.62      public void setMember(final String name, final Object value) {
    2.63 -        put(name, wrap(value, NashornScriptEngine.getNashornGlobal()));
    2.64 +        put(name, value);
    2.65      }
    2.66  
    2.67      @Override
    2.68 @@ -275,20 +267,27 @@
    2.69  
    2.70      @Override
    2.71      public Object put(final String key, final Object value) {
    2.72 +        final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal();
    2.73 +        final boolean globalChanged = (oldGlobal != global);
    2.74          return inGlobal(new Callable<Object>() {
    2.75              @Override public Object call() {
    2.76 -                return sobj.put(key, unwrap(value, global));
    2.77 +                final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
    2.78 +                return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global)), global));
    2.79              }
    2.80          });
    2.81      }
    2.82  
    2.83      @Override
    2.84      public void putAll(final Map<? extends String, ? extends Object> map) {
    2.85 +        final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal();
    2.86 +        final boolean globalChanged = (oldGlobal != global);
    2.87          final boolean strict = sobj.isStrictContext();
    2.88          inGlobal(new Callable<Object>() {
    2.89              @Override public Object call() {
    2.90                  for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
    2.91 -                    sobj.set(entry.getKey(), unwrap(entry.getValue(), global), strict);
    2.92 +                    final Object value = entry.getValue();
    2.93 +                    final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
    2.94 +                    sobj.set(entry.getKey(), unwrap(modValue, global), strict);
    2.95                  }
    2.96                  return null;
    2.97              }
    2.98 @@ -321,7 +320,7 @@
    2.99                  final Iterator<Object> iter   = sobj.valueIterator();
   2.100  
   2.101                  while (iter.hasNext()) {
   2.102 -                    values.add(wrap(iter.next(), global));
   2.103 +                    values.add(translateUndefined(wrap(iter.next(), global)));
   2.104                  }
   2.105  
   2.106                  return Collections.unmodifiableList(values);
     3.1 --- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Thu Feb 14 09:14:31 2013 +0530
     3.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Thu Feb 14 14:16:58 2013 +0530
     3.3 @@ -192,7 +192,7 @@
     3.4       * @return ScriptFunction result.
     3.5       * @throws Throwable if there is an exception/error with the invocation or thrown from it
     3.6       */
     3.7 -    public Object invoke(final Object self, final Object... arguments) throws Throwable {
     3.8 +    Object invoke(final Object self, final Object... arguments) throws Throwable {
     3.9          if (Context.DEBUG) {
    3.10              invokes++;
    3.11          }
     4.1 --- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Thu Feb 14 09:14:31 2013 +0530
     4.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Thu Feb 14 14:16:58 2013 +0530
     4.3 @@ -302,6 +302,37 @@
     4.4      }
     4.5  
     4.6      /**
     4.7 +     * Check that the target function is associated with current Context. And also make sure that 'self', if
     4.8 +     * ScriptObject, is from current context.
     4.9 +     *
    4.10 +     * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve
    4.11 +     * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker}
    4.12 +     * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead.
    4.13 +     *
    4.14 +     * @param target ScriptFunction object.
    4.15 +     * @param self   Receiver in call.
    4.16 +     * @param args   Call arguments.
    4.17 +     * @return Call result.
    4.18 +     */
    4.19 +    public static Object checkAndApply(final ScriptFunction target, final Object self, final Object... args) {
    4.20 +        final ScriptObject global = Context.getGlobalTrusted();
    4.21 +        if (! (global instanceof GlobalObject)) {
    4.22 +            throw new IllegalStateException("No current global set");
    4.23 +        }
    4.24 +
    4.25 +        if (target.getContext() != global.getContext()) {
    4.26 +            throw new IllegalArgumentException("'target' function is not from current Context");
    4.27 +        }
    4.28 +
    4.29 +        if (self instanceof ScriptObject && ((ScriptObject)self).getContext() != global.getContext()) {
    4.30 +            throw new IllegalArgumentException("'self' object is not from current Context");
    4.31 +        }
    4.32 +
    4.33 +        // all in order - call real 'apply'
    4.34 +        return apply(target, self, args);
    4.35 +    }
    4.36 +
    4.37 +    /**
    4.38       * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve
    4.39       * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker}
    4.40       * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead.
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/script/basic/JDK-8008197.js	Thu Feb 14 14:16:58 2013 +0530
     5.3 @@ -0,0 +1,69 @@
     5.4 +/*
     5.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + * 
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.
    5.11 + * 
    5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 + * version 2 for more details (a copy is included in the LICENSE file that
    5.16 + * accompanied this code).
    5.17 + * 
    5.18 + * You should have received a copy of the GNU General Public License version
    5.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 + * 
    5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 + * or visit www.oracle.com if you need additional information or have any
    5.24 + * questions.
    5.25 + */
    5.26 +
    5.27 +/**
    5.28 + * JDK-8008197: Cross script engine function calls do not work as expected
    5.29 + *
    5.30 + * @test
    5.31 + * @run
    5.32 + */
    5.33 +
    5.34 +
    5.35 +var m = new javax.script.ScriptEngineManager();
    5.36 +var e = m.getEngineByName("nashorn");
    5.37 +
    5.38 +var obj = {
    5.39 +    func: function(str) { 
    5.40 +        return /hello/.exec(str);
    5.41 +    }
    5.42 +};
    5.43 +
    5.44 +// set our object as object to the engine created
    5.45 +e.put("obj", obj);
    5.46 +
    5.47 +// try to invoke method from the other engine
    5.48 +if (e.eval("obj.func('hello')") == null) {
    5.49 +    fail("FAILED: #1 obj.func('hello') returns null");
    5.50 +}
    5.51 +
    5.52 +// define an object in the engine
    5.53 + e.eval("var foo = { callMe: function(callback) { return callback() } }");
    5.54 +
    5.55 +// try to invoke a script method from here but callback is from this engine
    5.56 +var res = e.invokeMethod(e.get("foo"), "callMe", function() {
    5.57 +    return /nashorn/;
    5.58 +});
    5.59 +
    5.60 +if (! res.exec("nashorn")) {
    5.61 +    fail("FAILED: #2 /nashorn/ does not match 'nashorn'");
    5.62 +}
    5.63 +
    5.64 +// invoke a script method from here with callback from this engine.
    5.65 +// This uses JSObject.call interface
    5.66 +res = e.get("foo").callMe(function() {
    5.67 +    return /ecmascript/;
    5.68 +});
    5.69 +
    5.70 +if (! res.exec("ecmascript")) {
    5.71 +    fail("FAILED: #3 /ecmascript/ does not match 'ecmascript'");
    5.72 +}
     6.1 --- a/test/script/basic/jquery.js	Thu Feb 14 09:14:31 2013 +0530
     6.2 +++ b/test/script/basic/jquery.js	Thu Feb 14 14:16:58 2013 +0530
     6.3 @@ -60,23 +60,13 @@
     6.4      var name;
     6.5      
     6.6      try {    
     6.7 +	var split = url.split('/');
     6.8 +	name = split[split.length - 1];
     6.9 +	var path  = __DIR__ + "../external/jquery/" + name;
    6.10  	try {
    6.11 -	    var split = url.split('/');
    6.12 -	    name = split[split.length - 1];
    6.13 -	    var path  = __DIR__ + "../external/jquery/" + name;
    6.14 -	    try {
    6.15 -		load(path);
    6.16 -	    } catch (e) {
    6.17 -		checkWindow(e);
    6.18 -	    }
    6.19 +	    load(path);
    6.20  	} catch (e) {
    6.21 -	    // try to load it from the internet, if we for some licensing reason
    6.22 -	    // aren't allowed to ship third party code under MIT license
    6.23 -	    try {
    6.24 -		load(url);
    6.25 -	    } catch (e) {
    6.26 -		checkWindow(e);
    6.27 -	    }
    6.28 +	    checkWindow(e);
    6.29  	}
    6.30      } catch (e) {
    6.31  	print("Unexpected exception " + e);
    6.32 @@ -85,8 +75,6 @@
    6.33      print("done " + name);
    6.34  }
    6.35  
    6.36 -
    6.37 -
    6.38  for each (url in urls) {
    6.39      test_jquery(url);
    6.40  }

mercurial