Fri, 01 Nov 2013 15:36:33 +0100
8027236: Ensure ScriptObject and ConsString aren't visible to Java
Reviewed-by: lagergren, sundar
1.1 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Fri Nov 01 19:54:48 2013 +0530 1.2 +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Fri Nov 01 15:36:33 2013 +0100 1.3 @@ -41,6 +41,7 @@ 1.4 import java.util.Set; 1.5 import java.util.concurrent.Callable; 1.6 import javax.script.Bindings; 1.7 +import jdk.nashorn.internal.runtime.ConsString; 1.8 import jdk.nashorn.internal.runtime.Context; 1.9 import jdk.nashorn.internal.runtime.GlobalObject; 1.10 import jdk.nashorn.internal.runtime.JSType; 1.11 @@ -594,14 +595,20 @@ 1.12 } 1.13 1.14 /** 1.15 - * Make a script object mirror on given object if needed. 1.16 + * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings. 1.17 * 1.18 - * @param obj object to be wrapped 1.19 - * @param homeGlobal global to which this object belongs 1.20 - * @return wrapped object 1.21 + * @param obj object to be wrapped/converted 1.22 + * @param homeGlobal global to which this object belongs. Not used for ConsStrings. 1.23 + * @return wrapped/converted object 1.24 */ 1.25 public static Object wrap(final Object obj, final ScriptObject homeGlobal) { 1.26 - return (obj instanceof ScriptObject && homeGlobal != null) ? new ScriptObjectMirror((ScriptObject)obj, homeGlobal) : obj; 1.27 + if(obj instanceof ScriptObject) { 1.28 + return homeGlobal != null ? new ScriptObjectMirror((ScriptObject)obj, homeGlobal) : obj; 1.29 + } 1.30 + if(obj instanceof ConsString) { 1.31 + return obj.toString(); 1.32 + } 1.33 + return obj; 1.34 } 1.35 1.36 /**
2.1 --- a/src/jdk/nashorn/internal/objects/Global.java Fri Nov 01 19:54:48 2013 +0530 2.2 +++ b/src/jdk/nashorn/internal/objects/Global.java Fri Nov 01 15:36:33 2013 +0100 2.3 @@ -53,19 +53,19 @@ 2.4 import jdk.nashorn.internal.runtime.GlobalObject; 2.5 import jdk.nashorn.internal.runtime.JSType; 2.6 import jdk.nashorn.internal.runtime.NativeJavaPackage; 2.7 +import jdk.nashorn.internal.runtime.PropertyDescriptor; 2.8 import jdk.nashorn.internal.runtime.PropertyMap; 2.9 +import jdk.nashorn.internal.runtime.Scope; 2.10 import jdk.nashorn.internal.runtime.ScriptEnvironment; 2.11 -import jdk.nashorn.internal.runtime.PropertyDescriptor; 2.12 -import jdk.nashorn.internal.runtime.arrays.ArrayData; 2.13 -import jdk.nashorn.internal.runtime.regexp.RegExpResult; 2.14 -import jdk.nashorn.internal.runtime.Scope; 2.15 import jdk.nashorn.internal.runtime.ScriptFunction; 2.16 import jdk.nashorn.internal.runtime.ScriptObject; 2.17 import jdk.nashorn.internal.runtime.ScriptRuntime; 2.18 import jdk.nashorn.internal.runtime.ScriptingFunctions; 2.19 import jdk.nashorn.internal.runtime.Source; 2.20 +import jdk.nashorn.internal.runtime.arrays.ArrayData; 2.21 import jdk.nashorn.internal.runtime.linker.Bootstrap; 2.22 import jdk.nashorn.internal.runtime.linker.InvokeByName; 2.23 +import jdk.nashorn.internal.runtime.regexp.RegExpResult; 2.24 import jdk.nashorn.internal.scripts.JO; 2.25 2.26 /**
3.1 --- a/src/jdk/nashorn/internal/objects/NativeObject.java Fri Nov 01 19:54:48 2013 +0530 3.2 +++ b/src/jdk/nashorn/internal/objects/NativeObject.java Fri Nov 01 15:36:33 2013 +0100 3.3 @@ -60,6 +60,7 @@ 3.4 import jdk.nashorn.internal.runtime.ScriptRuntime; 3.5 import jdk.nashorn.internal.runtime.linker.Bootstrap; 3.6 import jdk.nashorn.internal.runtime.linker.InvokeByName; 3.7 +import jdk.nashorn.internal.runtime.linker.NashornBeansLinker; 3.8 3.9 /** 3.10 * ECMA 15.2 Object objects 3.11 @@ -729,8 +730,7 @@ 3.12 final MethodType methodType, final Object source) { 3.13 final GuardedInvocation inv; 3.14 try { 3.15 - inv = linker.getGuardedInvocation(createLinkRequest(operation, methodType, source), 3.16 - Bootstrap.getLinkerServices()); 3.17 + inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(operation, methodType, source), Bootstrap.getLinkerServices()); 3.18 assert passesGuard(source, inv.getGuard()); 3.19 } catch(RuntimeException|Error e) { 3.20 throw e;
4.1 --- a/src/jdk/nashorn/internal/runtime/ConsString.java Fri Nov 01 19:54:48 2013 +0530 4.2 +++ b/src/jdk/nashorn/internal/runtime/ConsString.java Fri Nov 01 15:36:33 2013 +0100 4.3 @@ -57,10 +57,7 @@ 4.4 4.5 @Override 4.6 public String toString() { 4.7 - if (!flat) { 4.8 - flatten(); 4.9 - } 4.10 - return (String) left; 4.11 + return (String) flattened(); 4.12 } 4.13 4.14 @Override 4.15 @@ -70,18 +67,19 @@ 4.16 4.17 @Override 4.18 public char charAt(final int index) { 4.19 - if (!flat) { 4.20 - flatten(); 4.21 - } 4.22 - return left.charAt(index); 4.23 + return flattened().charAt(index); 4.24 } 4.25 4.26 @Override 4.27 public CharSequence subSequence(final int start, final int end) { 4.28 + return flattened().subSequence(start, end); 4.29 + } 4.30 + 4.31 + private CharSequence flattened() { 4.32 if (!flat) { 4.33 flatten(); 4.34 } 4.35 - return left.subSequence(start, end); 4.36 + return left; 4.37 } 4.38 4.39 private void flatten() {
5.1 --- a/src/jdk/nashorn/internal/runtime/JSType.java Fri Nov 01 19:54:48 2013 +0530 5.2 +++ b/src/jdk/nashorn/internal/runtime/JSType.java Fri Nov 01 15:36:33 2013 +0100 5.3 @@ -883,7 +883,7 @@ 5.4 */ 5.5 public static Object toJavaArray(final Object obj, final Class<?> componentType) { 5.6 if (obj instanceof ScriptObject) { 5.7 - return convertArray(((ScriptObject)obj).getArray().asObjectArray(), componentType); 5.8 + return ((ScriptObject)obj).getArray().asArrayOfType(componentType); 5.9 } else if (obj instanceof JSObject) { 5.10 final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj); 5.11 final int len = (int) itr.getLength(); 5.12 @@ -908,6 +908,15 @@ 5.13 * @return converted Java array 5.14 */ 5.15 public static Object convertArray(final Object[] src, final Class<?> componentType) { 5.16 + if(componentType == Object.class) { 5.17 + for(int i = 0; i < src.length; ++i) { 5.18 + final Object e = src[i]; 5.19 + if(e instanceof ConsString) { 5.20 + src[i] = e.toString(); 5.21 + } 5.22 + } 5.23 + } 5.24 + 5.25 final int l = src.length; 5.26 final Object dst = Array.newInstance(componentType, l); 5.27 final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType);
6.1 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Fri Nov 01 19:54:48 2013 +0530 6.2 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Fri Nov 01 15:36:33 2013 +0100 6.3 @@ -63,7 +63,7 @@ 6.4 final DynamicLinkerFactory factory = new DynamicLinkerFactory(); 6.5 factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(), 6.6 new BoundDynamicMethodLinker(), new JavaSuperAdapterLinker(), new JSObjectLinker(), new ReflectionCheckLinker()); 6.7 - factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker()); 6.8 + factory.setFallbackLinkers(new NashornBeansLinker(), new NashornBottomLinker()); 6.9 factory.setSyncOnRelink(true); 6.10 final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1); 6.11 if (relinkThreshold > -1) {
7.1 --- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java Fri Nov 01 19:54:48 2013 +0530 7.2 +++ b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java Fri Nov 01 15:36:33 2013 +0100 7.3 @@ -72,7 +72,7 @@ 7.4 type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass())); 7.5 7.6 // Delegate to BeansLinker 7.7 - final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethodClass).getGuardedInvocation( 7.8 + final GuardedInvocation inv = NashornBeansLinker.getGuardedInvocation(BeansLinker.getLinkerForClass(dynamicMethodClass), 7.9 linkRequest.replaceArguments(newDescriptor, args), linkerServices); 7.10 if(inv == null) { 7.11 return null;
8.1 --- a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Fri Nov 01 19:54:48 2013 +0530 8.2 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Fri Nov 01 15:36:33 2013 +0100 8.3 @@ -100,8 +100,9 @@ 8.4 type.changeParameterType(0, adapterClass), 0); 8.5 8.6 // Delegate to BeansLinker 8.7 - final GuardedInvocation guardedInv = BeansLinker.getLinkerForClass(adapterClass).getGuardedInvocation( 8.8 - linkRequest.replaceArguments(newDescriptor, args), linkerServices); 8.9 + final GuardedInvocation guardedInv = NashornBeansLinker.getGuardedInvocation( 8.10 + BeansLinker.getLinkerForClass(adapterClass), linkRequest.replaceArguments(newDescriptor, args), 8.11 + linkerServices); 8.12 8.13 final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass); 8.14 if(guardedInv == null) {
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Fri Nov 01 15:36:33 2013 +0100 9.3 @@ -0,0 +1,127 @@ 9.4 +/* 9.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 9.7 + * 9.8 + * This code is free software; you can redistribute it and/or modify it 9.9 + * under the terms of the GNU General Public License version 2 only, as 9.10 + * published by the Free Software Foundation. Oracle designates this 9.11 + * particular file as subject to the "Classpath" exception as provided 9.12 + * by Oracle in the LICENSE file that accompanied this code. 9.13 + * 9.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 9.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 9.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 9.17 + * version 2 for more details (a copy is included in the LICENSE file that 9.18 + * accompanied this code). 9.19 + * 9.20 + * You should have received a copy of the GNU General Public License version 9.21 + * 2 along with this work; if not, write to the Free Software Foundation, 9.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 9.23 + * 9.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 9.25 + * or visit www.oracle.com if you need additional information or have any 9.26 + * questions. 9.27 + */ 9.28 + 9.29 +package jdk.nashorn.internal.runtime.linker; 9.30 + 9.31 +import java.lang.invoke.MethodHandle; 9.32 +import java.lang.invoke.MethodHandles; 9.33 +import java.lang.invoke.MethodType; 9.34 +import jdk.internal.dynalink.beans.BeansLinker; 9.35 +import jdk.internal.dynalink.linker.ConversionComparator.Comparison; 9.36 +import jdk.internal.dynalink.linker.GuardedInvocation; 9.37 +import jdk.internal.dynalink.linker.GuardingDynamicLinker; 9.38 +import jdk.internal.dynalink.linker.LinkRequest; 9.39 +import jdk.internal.dynalink.linker.LinkerServices; 9.40 +import jdk.internal.dynalink.support.Lookup; 9.41 +import jdk.nashorn.internal.runtime.ConsString; 9.42 + 9.43 +/** 9.44 + * This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified 9.45 + * {@code asType} method that will ensure that we never pass internal engine objects that should not be externally 9.46 + * observable (currently only ConsString) to Java APIs, but rather that we flatten it into a String. We can't just add 9.47 + * this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when 9.48 + * the target method handle parameter signature is {@code Object}. 9.49 + */ 9.50 +public class NashornBeansLinker implements GuardingDynamicLinker { 9.51 + private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class); 9.52 + 9.53 + private final BeansLinker beansLinker = new BeansLinker(); 9.54 + 9.55 + @Override 9.56 + public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { 9.57 + return getGuardedInvocation(beansLinker, linkRequest, linkerServices); 9.58 + } 9.59 + 9.60 + /** 9.61 + * Delegates to the specified linker but injects its linker services wrapper so that it will apply all special 9.62 + * conversions that this class does. 9.63 + * @param delegateLinker the linker to which the actual work is delegated to. 9.64 + * @param linkRequest the delegated link request 9.65 + * @param linkerServices the original link services that will be augmented with special conversions 9.66 + * @return the guarded invocation from the delegate, possibly augmented with special conversions 9.67 + * @throws Exception if the delegate throws an exception 9.68 + */ 9.69 + public static GuardedInvocation getGuardedInvocation(final GuardingDynamicLinker delegateLinker, final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { 9.70 + return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices)); 9.71 + } 9.72 + 9.73 + @SuppressWarnings("unused") 9.74 + private static Object exportArgument(final Object arg) { 9.75 + return arg instanceof ConsString ? arg.toString() : arg; 9.76 + } 9.77 + 9.78 + private static class NashornBeansLinkerServices implements LinkerServices { 9.79 + private final LinkerServices linkerServices; 9.80 + 9.81 + NashornBeansLinkerServices(final LinkerServices linkerServices) { 9.82 + this.linkerServices = linkerServices; 9.83 + } 9.84 + 9.85 + @Override 9.86 + public MethodHandle asType(final MethodHandle handle, final MethodType fromType) { 9.87 + final MethodHandle typed = linkerServices.asType(handle, fromType); 9.88 + 9.89 + final MethodType handleType = handle.type(); 9.90 + final int paramCount = handleType.parameterCount(); 9.91 + assert fromType.parameterCount() == handleType.parameterCount(); 9.92 + 9.93 + MethodHandle[] filters = null; 9.94 + for(int i = 0; i < paramCount; ++i) { 9.95 + if(shouldConvert(handleType.parameterType(i), fromType.parameterType(i))) { 9.96 + if(filters == null) { 9.97 + filters = new MethodHandle[paramCount]; 9.98 + } 9.99 + filters[i] = EXPORT_ARGUMENT; 9.100 + } 9.101 + } 9.102 + 9.103 + return filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed; 9.104 + } 9.105 + 9.106 + private static boolean shouldConvert(final Class<?> handleType, final Class<?> fromType) { 9.107 + return handleType == Object.class && fromType == Object.class; 9.108 + } 9.109 + 9.110 + @Override 9.111 + public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) { 9.112 + return linkerServices.getTypeConverter(sourceType, targetType); 9.113 + } 9.114 + 9.115 + @Override 9.116 + public boolean canConvert(final Class<?> from, final Class<?> to) { 9.117 + return linkerServices.canConvert(from, to); 9.118 + } 9.119 + 9.120 + @Override 9.121 + public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception { 9.122 + return linkerServices.getGuardedInvocation(linkRequest); 9.123 + } 9.124 + 9.125 + @Override 9.126 + public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) { 9.127 + return linkerServices.compareConversion(sourceType, targetType1, targetType2); 9.128 + } 9.129 + } 9.130 +}
10.1 --- a/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java Fri Nov 01 19:54:48 2013 +0530 10.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java Fri Nov 01 15:36:33 2013 +0100 10.3 @@ -93,7 +93,7 @@ 10.4 } 10.5 10.6 private static GuardedInvocation delegate(LinkerServices linkerServices, final LinkRequest request) throws Exception { 10.7 - return staticClassLinker.getGuardedInvocation(request, linkerServices); 10.8 + return NashornBeansLinker.getGuardedInvocation(staticClassLinker, request, linkerServices); 10.9 } 10.10 10.11 private static GuardedInvocation checkNullConstructor(final GuardedInvocation ctorInvocation, final Class<?> receiverClass) {
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/test/script/basic/JDK-8027236.js Fri Nov 01 15:36:33 2013 +0100 11.3 @@ -0,0 +1,37 @@ 11.4 +/* 11.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 11.7 + * 11.8 + * This code is free software; you can redistribute it and/or modify it 11.9 + * under the terms of the GNU General Public License version 2 only, as 11.10 + * published by the Free Software Foundation. 11.11 + * 11.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 11.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11.15 + * version 2 for more details (a copy is included in the LICENSE file that 11.16 + * accompanied this code). 11.17 + * 11.18 + * You should have received a copy of the GNU General Public License version 11.19 + * 2 along with this work; if not, write to the Free Software Foundation, 11.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 11.21 + * 11.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 11.23 + * or visit www.oracle.com if you need additional information or have any 11.24 + * questions. 11.25 + */ 11.26 + 11.27 +/** 11.28 + * JDK-8027236: Ensure ScriptObject and ConsString aren't visible to Java 11.29 + * 11.30 + * @test 11.31 + * @run 11.32 + */ 11.33 + 11.34 +// Check that ConsString is flattened 11.35 +var m = new java.util.HashMap() 11.36 +var x = "f" 11.37 +x += "oo" 11.38 +m.put(x, "bar") 11.39 +print(m.get("foo")) 11.40 +// Note: many more tests are run by the JavaExportImportTest TestNG class.
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/test/script/basic/JDK-8027236.js.EXPECTED Fri Nov 01 15:36:33 2013 +0100 12.3 @@ -0,0 +1,1 @@ 12.4 +bar
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java Fri Nov 01 15:36:33 2013 +0100 13.3 @@ -0,0 +1,99 @@ 13.4 +/* 13.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 13.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 13.7 + * 13.8 + * This code is free software; you can redistribute it and/or modify it 13.9 + * under the terms of the GNU General Public License version 2 only, as 13.10 + * published by the Free Software Foundation. Oracle designates this 13.11 + * particular file as subject to the "Classpath" exception as provided 13.12 + * by Oracle in the LICENSE file that accompanied this code. 13.13 + * 13.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 13.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13.17 + * version 2 for more details (a copy is included in the LICENSE file that 13.18 + * accompanied this code). 13.19 + * 13.20 + * You should have received a copy of the GNU General Public License version 13.21 + * 2 along with this work; if not, write to the Free Software Foundation, 13.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 13.23 + * 13.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 13.25 + * or visit www.oracle.com if you need additional information or have any 13.26 + * questions. 13.27 + */ 13.28 + 13.29 +package jdk.nashorn.api.javaaccess; 13.30 + 13.31 +import static org.testng.AssertJUnit.assertEquals; 13.32 + 13.33 +import java.util.HashMap; 13.34 +import java.util.Map; 13.35 +import javax.script.Bindings; 13.36 +import javax.script.ScriptContext; 13.37 +import javax.script.ScriptEngine; 13.38 +import javax.script.ScriptEngineManager; 13.39 +import javax.script.ScriptException; 13.40 +import jdk.nashorn.api.scripting.JSObject; 13.41 +import org.testng.TestNG; 13.42 +import org.testng.annotations.AfterClass; 13.43 +import org.testng.annotations.BeforeClass; 13.44 +import org.testng.annotations.Test; 13.45 + 13.46 +public class ConsStringTest { 13.47 + private static ScriptEngine e = null; 13.48 + 13.49 + public static void main(final String[] args) { 13.50 + TestNG.main(args); 13.51 + } 13.52 + 13.53 + @BeforeClass 13.54 + public static void setUpClass() throws ScriptException { 13.55 + e = new ScriptEngineManager().getEngineByName("nashorn"); 13.56 + } 13.57 + 13.58 + @AfterClass 13.59 + public static void tearDownClass() { 13.60 + e = null; 13.61 + } 13.62 + 13.63 + @Test 13.64 + public void testConsStringFlattening() throws ScriptException { 13.65 + final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE); 13.66 + final Map<Object, Object> m = new HashMap<>(); 13.67 + b.put("m", m); 13.68 + e.eval("var x = 'f'; x += 'oo'; var y = 'b'; y += 'ar'; m.put(x, y)"); 13.69 + assertEquals("bar", m.get("foo")); 13.70 + } 13.71 + 13.72 + @Test 13.73 + public void testConsStringFromMirror() throws ScriptException { 13.74 + final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE); 13.75 + final Map<Object, Object> m = new HashMap<>(); 13.76 + e.eval("var x = 'f'; x += 'oo'; var obj = {x: x};"); 13.77 + assertEquals("foo", ((JSObject)b.get("obj")).getMember("x")); 13.78 + } 13.79 + 13.80 + @Test 13.81 + public void testArrayConsString() throws ScriptException { 13.82 + final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE); 13.83 + final ArrayHolder h = new ArrayHolder(); 13.84 + b.put("h", h); 13.85 + e.eval("var x = 'f'; x += 'oo'; h.array = [x];"); 13.86 + assertEquals(1, h.array.length); 13.87 + assertEquals("foo", h.array[0]); 13.88 + } 13.89 + 13.90 + 13.91 + public static class ArrayHolder { 13.92 + private Object[] array; 13.93 + 13.94 + public void setArray(Object[] array) { 13.95 + this.array = array; 13.96 + } 13.97 + 13.98 + public Object[] getArray() { 13.99 + return array; 13.100 + } 13.101 + } 13.102 +}