Tue, 23 Jul 2013 18:17:25 +0530
8021122: Not all callables are handled for toString and other function valued properties
Reviewed-by: attila, hannesw, jlaskey
1.1 --- a/src/jdk/nashorn/internal/ir/debug/ASTWriter.java Thu Jul 18 16:47:45 2013 +0200 1.2 +++ b/src/jdk/nashorn/internal/ir/debug/ASTWriter.java Tue Jul 23 18:17:25 2013 +0530 1.3 @@ -102,7 +102,7 @@ 1.4 preorder.add(node); 1.5 } 1.6 1.7 - final boolean isReference = field != null && field.getAnnotation(Reference.class) != null; 1.8 + final boolean isReference = field != null && field.isAnnotationPresent(Reference.class); 1.9 1.10 Class<?> clazz = node.getClass(); 1.11 String type = clazz.getName(); 1.12 @@ -183,7 +183,7 @@ 1.13 append('\n'); 1.14 1.15 for (final Field child : children) { 1.16 - if (child.getAnnotation(Ignore.class) != null) { 1.17 + if (child.isAnnotationPresent(Ignore.class)) { 1.18 continue; 1.19 } 1.20
2.1 --- a/src/jdk/nashorn/internal/objects/Global.java Thu Jul 18 16:47:45 2013 +0200 2.2 +++ b/src/jdk/nashorn/internal/objects/Global.java Tue Jul 23 18:17:25 2013 +0530 2.3 @@ -63,6 +63,7 @@ 2.4 import jdk.nashorn.internal.runtime.ScriptRuntime; 2.5 import jdk.nashorn.internal.runtime.ScriptingFunctions; 2.6 import jdk.nashorn.internal.runtime.Source; 2.7 +import jdk.nashorn.internal.runtime.linker.Bootstrap; 2.8 import jdk.nashorn.internal.runtime.linker.InvokeByName; 2.9 import jdk.nashorn.internal.scripts.JO; 2.10 2.11 @@ -548,7 +549,8 @@ 2.12 if (hint == String.class) { 2.13 2.14 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 2.15 - if (toString instanceof ScriptFunction) { 2.16 + 2.17 + if (Bootstrap.isCallable(toString)) { 2.18 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); 2.19 if (JSType.isPrimitive(value)) { 2.20 return value; 2.21 @@ -556,7 +558,7 @@ 2.22 } 2.23 2.24 final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); 2.25 - if (valueOf instanceof ScriptFunction) { 2.26 + if (Bootstrap.isCallable(valueOf)) { 2.27 final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); 2.28 if (JSType.isPrimitive(value)) { 2.29 return value; 2.30 @@ -567,7 +569,7 @@ 2.31 2.32 if (hint == Number.class) { 2.33 final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); 2.34 - if (valueOf instanceof ScriptFunction) { 2.35 + if (Bootstrap.isCallable(valueOf)) { 2.36 final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); 2.37 if (JSType.isPrimitive(value)) { 2.38 return value; 2.39 @@ -575,7 +577,7 @@ 2.40 } 2.41 2.42 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 2.43 - if (toString instanceof ScriptFunction) { 2.44 + if (Bootstrap.isCallable(toString)) { 2.45 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); 2.46 if (JSType.isPrimitive(value)) { 2.47 return value;
3.1 --- a/src/jdk/nashorn/internal/objects/NativeArray.java Thu Jul 18 16:47:45 2013 +0200 3.2 +++ b/src/jdk/nashorn/internal/objects/NativeArray.java Tue Jul 23 18:17:25 2013 +0530 3.3 @@ -360,7 +360,7 @@ 3.4 final ScriptObject sobj = (ScriptObject)obj; 3.5 try { 3.6 final Object join = JOIN.getGetter().invokeExact(sobj); 3.7 - if (join instanceof ScriptFunction) { 3.8 + if (Bootstrap.isCallable(join)) { 3.9 return JOIN.getInvoker().invokeExact(join, sobj); 3.10 } 3.11 } catch (final RuntimeException | Error e) { 3.12 @@ -396,7 +396,7 @@ 3.13 final ScriptObject sobj = (ScriptObject)val; 3.14 final Object toLocaleString = TO_LOCALE_STRING.getGetter().invokeExact(sobj); 3.15 3.16 - if (toLocaleString instanceof ScriptFunction) { 3.17 + if (Bootstrap.isCallable(toLocaleString)) { 3.18 sb.append((String)TO_LOCALE_STRING.getInvoker().invokeExact(toLocaleString, sobj)); 3.19 } else { 3.20 throw typeError("not.a.function", "toLocaleString");
4.1 --- a/src/jdk/nashorn/internal/objects/NativeDate.java Thu Jul 18 16:47:45 2013 +0200 4.2 +++ b/src/jdk/nashorn/internal/objects/NativeDate.java Tue Jul 23 18:17:25 2013 +0530 4.3 @@ -47,6 +47,7 @@ 4.4 import jdk.nashorn.internal.runtime.ScriptFunction; 4.5 import jdk.nashorn.internal.runtime.ScriptObject; 4.6 import jdk.nashorn.internal.runtime.ScriptRuntime; 4.7 +import jdk.nashorn.internal.runtime.linker.Bootstrap; 4.8 import jdk.nashorn.internal.runtime.linker.InvokeByName; 4.9 4.10 /** 4.11 @@ -862,7 +863,7 @@ 4.12 4.13 try { 4.14 final Object func = TO_ISO_STRING.getGetter().invokeExact(sobj); 4.15 - if (func instanceof ScriptFunction) { 4.16 + if (Bootstrap.isCallable(func)) { 4.17 return TO_ISO_STRING.getInvoker().invokeExact(func, sobj, key); 4.18 } 4.19 throw typeError("not.a.function", ScriptRuntime.safeToString(func));
5.1 --- a/src/jdk/nashorn/internal/objects/NativeJSON.java Thu Jul 18 16:47:45 2013 +0200 5.2 +++ b/src/jdk/nashorn/internal/objects/NativeJSON.java Tue Jul 23 18:17:25 2013 +0530 5.3 @@ -189,7 +189,7 @@ 5.4 if (value instanceof ScriptObject) { 5.5 final ScriptObject svalue = (ScriptObject)value; 5.6 final Object toJSON = TO_JSON.getGetter().invokeExact(svalue); 5.7 - if (toJSON instanceof ScriptFunction) { 5.8 + if (Bootstrap.isCallable(toJSON)) { 5.9 value = TO_JSON.getInvoker().invokeExact(toJSON, svalue, key); 5.10 } 5.11 }
6.1 --- a/src/jdk/nashorn/internal/objects/NativeObject.java Thu Jul 18 16:47:45 2013 +0200 6.2 +++ b/src/jdk/nashorn/internal/objects/NativeObject.java Tue Jul 23 18:17:25 2013 +0530 6.3 @@ -407,7 +407,7 @@ 6.4 try { 6.5 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 6.6 6.7 - if (toString instanceof ScriptFunction) { 6.8 + if (Bootstrap.isCallable(toString)) { 6.9 return TO_STRING.getInvoker().invokeExact(toString, sobj); 6.10 } 6.11 } catch (final RuntimeException | Error e) {
7.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Thu Jul 18 16:47:45 2013 +0200 7.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Tue Jul 23 18:17:25 2013 +0530 7.3 @@ -36,6 +36,7 @@ 7.4 import java.io.PrintWriter; 7.5 import java.lang.invoke.MethodHandle; 7.6 import java.lang.invoke.MethodHandles; 7.7 +import java.lang.reflect.Modifier; 7.8 import java.util.concurrent.atomic.AtomicLong; 7.9 import java.net.MalformedURLException; 7.10 import java.net.URL; 7.11 @@ -555,6 +556,7 @@ 7.12 * Checks that the given package can be accessed from current call stack. 7.13 * 7.14 * @param fullName fully qualified package name 7.15 + * @throw SecurityException if not accessible 7.16 */ 7.17 public static void checkPackageAccess(final String fullName) { 7.18 final int index = fullName.lastIndexOf('.'); 7.19 @@ -567,6 +569,31 @@ 7.20 } 7.21 7.22 /** 7.23 + * Checks that the given package can be accessed from current call stack. 7.24 + * 7.25 + * @param fullName fully qualified package name 7.26 + * @return true if package is accessible, false otherwise 7.27 + */ 7.28 + public static boolean isAccessiblePackage(final String fullName) { 7.29 + try { 7.30 + checkPackageAccess(fullName); 7.31 + return true; 7.32 + } catch (final SecurityException se) { 7.33 + return false; 7.34 + } 7.35 + } 7.36 + 7.37 + /** 7.38 + * Checks that the given Class can be accessed from current call stack and is public. 7.39 + * 7.40 + * @param clazz Class object to check 7.41 + * @return true if Class is accessible, false otherwise 7.42 + */ 7.43 + public static boolean isAccessibleClass(final Class<?> clazz) { 7.44 + return Modifier.isPublic(clazz.getModifiers()) && Context.isAccessiblePackage(clazz.getName()); 7.45 + } 7.46 + 7.47 + /** 7.48 * Lookup a Java class. This is used for JSR-223 stuff linking in from 7.49 * {@code jdk.nashorn.internal.objects.NativeJava} and {@code jdk.nashorn.internal.runtime.NativeJavaPackage} 7.50 *
8.1 --- a/src/jdk/nashorn/internal/runtime/ListAdapter.java Thu Jul 18 16:47:45 2013 +0200 8.2 +++ b/src/jdk/nashorn/internal/runtime/ListAdapter.java Tue Jul 23 18:17:25 2013 +0530 8.3 @@ -31,6 +31,7 @@ 8.4 import java.util.ListIterator; 8.5 import java.util.NoSuchElementException; 8.6 import java.util.RandomAccess; 8.7 +import jdk.nashorn.internal.runtime.linker.Bootstrap; 8.8 import jdk.nashorn.internal.runtime.linker.InvokeByName; 8.9 8.10 /** 8.11 @@ -157,7 +158,7 @@ 8.12 } 8.13 } 8.14 private static void checkFunction(Object fn, InvokeByName invoke) { 8.15 - if(!(fn instanceof ScriptFunction)) { 8.16 + if(!(Bootstrap.isCallable(fn))) { 8.17 throw new UnsupportedOperationException("The script object doesn't have a function named " + invoke.getName()); 8.18 } 8.19 }
9.1 --- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Thu Jul 18 16:47:45 2013 +0200 9.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Tue Jul 23 18:17:25 2013 +0530 9.3 @@ -381,9 +381,7 @@ 9.4 */ 9.5 public static Object checkAndConstruct(final ScriptFunction target, final Object... args) { 9.6 final ScriptObject global = Context.getGlobalTrusted(); 9.7 - if (! (global instanceof GlobalObject)) { 9.8 - throw new IllegalStateException("No current global set"); 9.9 - } 9.10 + assert (global instanceof GlobalObject): "No current global set"; 9.11 9.12 if (target.getContext() != global.getContext()) { 9.13 throw new IllegalArgumentException("'target' function is not from current Context");
10.1 --- a/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java Thu Jul 18 16:47:45 2013 +0200 10.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java Tue Jul 23 18:17:25 2013 +0530 10.3 @@ -31,6 +31,7 @@ 10.4 import jdk.nashorn.internal.runtime.Context; 10.5 import jdk.nashorn.internal.runtime.ScriptFunction; 10.6 import jdk.nashorn.internal.runtime.ScriptRuntime; 10.7 +import jdk.nashorn.internal.runtime.linker.Bootstrap; 10.8 10.9 /** 10.10 * Helper class for the various map/apply functions in {@link jdk.nashorn.internal.objects.NativeArray}. 10.11 @@ -103,6 +104,8 @@ 10.12 } else if (callbackfn instanceof ScriptObjectMirror && 10.13 ((ScriptObjectMirror)callbackfn).isFunction()) { 10.14 strict = ((ScriptObjectMirror)callbackfn).isStrictFunction(); 10.15 + } else if (Bootstrap.isDynamicMethod(callbackfn) || Bootstrap.isFunctionalInterfaceObject(callbackfn)) { 10.16 + strict = false; 10.17 } else { 10.18 throw typeError("not.a.function", ScriptRuntime.safeToString(callbackfn)); 10.19 }
11.1 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Thu Jul 18 16:47:45 2013 +0200 11.2 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Tue Jul 23 18:17:25 2013 +0530 11.3 @@ -38,8 +38,11 @@ 11.4 import jdk.internal.dynalink.beans.BeansLinker; 11.5 import jdk.internal.dynalink.linker.GuardedInvocation; 11.6 import jdk.internal.dynalink.linker.LinkerServices; 11.7 +import jdk.nashorn.api.scripting.ScriptObjectMirror; 11.8 import jdk.nashorn.internal.codegen.CompilerConstants.Call; 11.9 import jdk.nashorn.internal.codegen.RuntimeCallSite; 11.10 +import jdk.nashorn.internal.runtime.ScriptFunction; 11.11 +import jdk.nashorn.internal.runtime.ScriptRuntime; 11.12 import jdk.nashorn.internal.runtime.options.Options; 11.13 11.14 /** 11.15 @@ -68,6 +71,41 @@ 11.16 } 11.17 11.18 /** 11.19 + * Returns if the given object is a "callable" 11.20 + * @param obj object to be checked for callability 11.21 + * @return true if the obj is callable 11.22 + */ 11.23 + public static boolean isCallable(final Object obj) { 11.24 + if (obj == ScriptRuntime.UNDEFINED || obj == null) { 11.25 + return false; 11.26 + } 11.27 + 11.28 + return obj instanceof ScriptFunction || 11.29 + ((obj instanceof ScriptObjectMirror) && ((ScriptObjectMirror)obj).isFunction()) || 11.30 + isDynamicMethod(obj) || 11.31 + isFunctionalInterfaceObject(obj); 11.32 + } 11.33 + 11.34 + /** 11.35 + * Returns if the given object is a dynalink Dynamic method 11.36 + * @param obj object to be checked 11.37 + * @return true if the obj is a dynamic method 11.38 + */ 11.39 + public static boolean isDynamicMethod(final Object obj) { 11.40 + return obj instanceof BoundDynamicMethod || BeansLinker.isDynamicMethod(obj); 11.41 + } 11.42 + 11.43 + /** 11.44 + * Returns if the given object is an instance of an interface annotated with 11.45 + * java.lang.FunctionalInterface 11.46 + * @param obj object to be checked 11.47 + * @return true if the obj is an instance of @FunctionalInterface interface 11.48 + */ 11.49 + public static boolean isFunctionalInterfaceObject(final Object obj) { 11.50 + return obj != null && (NashornBottomLinker.getFunctionalInterfaceMethod(obj.getClass()) != null); 11.51 + } 11.52 + 11.53 + /** 11.54 * Create a call site and link it for Nashorn. This version of the method conforms to the invokedynamic bootstrap 11.55 * method expected signature and is referenced from Nashorn generated bytecode as the bootstrap method for all 11.56 * invokedynamic instructions.
12.1 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Thu Jul 18 16:47:45 2013 +0200 12.2 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Tue Jul 23 18:17:25 2013 +0530 12.3 @@ -924,6 +924,6 @@ 12.4 } 12.5 12.6 private static boolean isCallerSensitive(final AccessibleObject e) { 12.7 - return e.getAnnotation(CallerSensitive.class) != null; 12.8 + return e.isAnnotationPresent(CallerSensitive.class); 12.9 } 12.10 }
13.1 --- a/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Thu Jul 18 16:47:45 2013 +0200 13.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Tue Jul 23 18:17:25 2013 +0530 13.3 @@ -30,6 +30,9 @@ 13.4 import static jdk.nashorn.internal.lookup.Lookup.MH; 13.5 13.6 import java.lang.invoke.MethodHandle; 13.7 +import java.lang.invoke.MethodType; 13.8 +import java.lang.reflect.Method; 13.9 +import java.lang.reflect.Modifier; 13.10 import jdk.internal.dynalink.CallSiteDescriptor; 13.11 import jdk.internal.dynalink.beans.BeansLinker; 13.12 import jdk.internal.dynalink.linker.GuardedInvocation; 13.13 @@ -37,6 +40,7 @@ 13.14 import jdk.internal.dynalink.linker.LinkRequest; 13.15 import jdk.internal.dynalink.linker.LinkerServices; 13.16 import jdk.internal.dynalink.support.Guards; 13.17 +import jdk.nashorn.internal.runtime.Context; 13.18 import jdk.nashorn.internal.runtime.ScriptRuntime; 13.19 13.20 /** 13.21 @@ -73,7 +77,7 @@ 13.22 private static final MethodHandle EMPTY_ELEM_SETTER = 13.23 MH.dropArguments(EMPTY_PROP_SETTER, 0, Object.class); 13.24 13.25 - private static GuardedInvocation linkBean(final LinkRequest linkRequest, final LinkerServices linkerServices) { 13.26 + private static GuardedInvocation linkBean(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { 13.27 final NashornCallSiteDescriptor desc = (NashornCallSiteDescriptor)linkRequest.getCallSiteDescriptor(); 13.28 final Object self = linkRequest.getReceiver(); 13.29 final String operator = desc.getFirstOperator(); 13.30 @@ -84,6 +88,22 @@ 13.31 } 13.32 throw typeError("not.a.function", ScriptRuntime.safeToString(self)); 13.33 case "call": 13.34 + // Support dyn:call on any object that supports some @FunctionalInterface 13.35 + // annotated interface. This way Java method, constructor references or 13.36 + // implementations of java.util.function.* interfaces can be called as though 13.37 + // those are script functions. 13.38 + final Method m = getFunctionalInterfaceMethod(self.getClass()); 13.39 + if (m != null) { 13.40 + final MethodType callType = desc.getMethodType(); 13.41 + // 'callee' and 'thiz' passed from script + actual arguments 13.42 + if (callType.parameterCount() != m.getParameterCount() + 2) { 13.43 + throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self)); 13.44 + } 13.45 + return new GuardedInvocation( 13.46 + // drop 'thiz' passed from the script. 13.47 + MH.dropArguments(desc.getLookup().unreflect(m), 1, callType.parameterType(1)), 13.48 + Guards.getInstanceOfGuard(m.getDeclaringClass())).asType(callType); 13.49 + } 13.50 if(BeansLinker.isDynamicMethod(self)) { 13.51 throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self)); 13.52 } 13.53 @@ -148,4 +168,32 @@ 13.54 } 13.55 return ScriptRuntime.safeToString(linkRequest.getArguments()[1]); 13.56 } 13.57 + 13.58 + // Returns @FunctionalInterface annotated interface's single abstract method. 13.59 + // If not found, returns null 13.60 + static Method getFunctionalInterfaceMethod(final Class<?> clazz) { 13.61 + if (clazz == null) { 13.62 + return null; 13.63 + } 13.64 + 13.65 + for (Class<?> iface : clazz.getInterfaces()) { 13.66 + // check accessiblity up-front 13.67 + if (! Context.isAccessibleClass(iface)) { 13.68 + continue; 13.69 + } 13.70 + 13.71 + // check for @FunctionalInterface 13.72 + if (iface.isAnnotationPresent(FunctionalInterface.class)) { 13.73 + // return the first abstract method 13.74 + for (final Method m : iface.getMethods()) { 13.75 + if (Modifier.isAbstract(m.getModifiers())) { 13.76 + return m; 13.77 + } 13.78 + } 13.79 + } 13.80 + } 13.81 + 13.82 + // did not find here, try super class 13.83 + return getFunctionalInterfaceMethod(clazz.getSuperclass()); 13.84 + } 13.85 }
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/test/script/basic/JDK-8021122.js Tue Jul 23 18:17:25 2013 +0530 14.3 @@ -0,0 +1,93 @@ 14.4 +/* 14.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.7 + * 14.8 + * This code is free software; you can redistribute it and/or modify it 14.9 + * under the terms of the GNU General Public License version 2 only, as 14.10 + * published by the Free Software Foundation. 14.11 + * 14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14.15 + * version 2 for more details (a copy is included in the LICENSE file that 14.16 + * accompanied this code). 14.17 + * 14.18 + * You should have received a copy of the GNU General Public License version 14.19 + * 2 along with this work; if not, write to the Free Software Foundation, 14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 14.21 + * 14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 14.23 + * or visit www.oracle.com if you need additional information or have any 14.24 + * questions. 14.25 + */ 14.26 + 14.27 +/** 14.28 + * JDK-8021122: Not all callables are handled for toString and other function valued properties 14.29 + * 14.30 + * @test 14.31 + * @run 14.32 + */ 14.33 + 14.34 +var a = {} 14.35 +var obj = new java.util.HashMap(); 14.36 +Object.bindProperties(a, obj); 14.37 +try { 14.38 + print(a); 14.39 +} catch (e) { 14.40 + print(e); 14.41 +} 14.42 + 14.43 +var a = {} 14.44 +var global = loadWithNewGlobal({ name:"xx", script: "this" }); 14.45 +var obj = global.eval("({ toString: function() { return 'hello'; } })"); 14.46 +Object.bindProperties(a, obj); 14.47 +try { 14.48 + print(a); 14.49 +} catch (e) { 14.50 + print(e); 14.51 +} 14.52 + 14.53 +function runLambdaTests() { 14.54 + var r = new java.lang.Runnable() { 14.55 + run: function() { print("I am runnable"); } 14.56 + }; 14.57 + 14.58 + // call any @FunctionalInterface object as though it is a function 14.59 + r(); 14.60 + 14.61 + var twice = new java.util.function.Function() { 14.62 + apply: function(x) 2*x 14.63 + }; 14.64 + 14.65 + print(twice(34)); 14.66 + 14.67 + var sum = new java.util.function.BiFunction() { 14.68 + apply: function(x, y) x + y 14.69 + }; 14.70 + 14.71 + print(sum(32, 12)) 14.72 + 14.73 + // make toString to be a @FunctionalInterface object 14.74 + var a = {}; 14.75 + a.toString = new java.util.function.Supplier() { 14.76 + get: function() { return "MyString"; } 14.77 + }; 14.78 + 14.79 + try { 14.80 + print(a); 14.81 + } catch (e) { 14.82 + print(e); 14.83 + } 14.84 +} 14.85 + 14.86 +try { 14.87 + // check for java.util.function.Function class 14.88 + Java.type("java.util.function.Function"); 14.89 + runLambdaTests(); 14.90 +} catch (e) { 14.91 + // fake output to match .EXPECTED values 14.92 + print("I am runnable"); 14.93 + print("68"); 14.94 + print("44"); 14.95 + print("MyString"); 14.96 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/test/script/basic/JDK-8021122.js.EXPECTED Tue Jul 23 18:17:25 2013 +0530 15.3 @@ -0,0 +1,6 @@ 15.4 +{} 15.5 +hello 15.6 +I am runnable 15.7 +68 15.8 +44 15.9 +MyString