# HG changeset patch # User attila # Date 1373884428 -7200 # Node ID ada98218aaae63772240a2edb87a107fff786756 # Parent 8ba96bd382d3fc640435e46a6b9fe1aefd8c4624 8020324: Implement Object.bindProperties(target, source) for beans Reviewed-by: hannesw, sundar diff -r 8ba96bd382d3 -r ada98218aaae nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java --- a/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java Fri Jul 12 20:06:41 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java Mon Jul 15 12:33:48 2013 +0200 @@ -92,6 +92,8 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -194,6 +196,22 @@ abstract FacetIntrospector createFacetIntrospector(); + Collection getReadablePropertyNames() { + return getUnmodifiableKeys(propertyGetters); + } + + Collection getWritablePropertyNames() { + return getUnmodifiableKeys(propertySetters); + } + + Collection getMethodNames() { + return getUnmodifiableKeys(methods); + } + + private static Collection getUnmodifiableKeys(Map m) { + return Collections.unmodifiableCollection(m.keySet()); + } + /** * Sets the specified dynamic method to be the property getter for the specified property. Note that you can only * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties diff -r 8ba96bd382d3 -r ada98218aaae nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java --- a/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java Fri Jul 12 20:06:41 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java Mon Jul 15 12:33:48 2013 +0200 @@ -84,6 +84,8 @@ package jdk.internal.dynalink.beans; import java.lang.invoke.MethodHandles; +import java.util.Collection; +import java.util.Collections; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.DynamicLinkerFactory; import jdk.internal.dynalink.linker.GuardedInvocation; @@ -166,6 +168,72 @@ return obj instanceof DynamicMethod; } + /** + * Returns a collection of names of all readable instance properties of a class. + * @param clazz the class + * @return a collection of names of all readable instance properties of a class. + */ + public static Collection getReadableInstancePropertyNames(Class clazz) { + TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); + if(linker instanceof BeanLinker) { + return ((BeanLinker)linker).getReadablePropertyNames(); + } + return Collections.emptySet(); + } + + /** + * Returns a collection of names of all writable instance properties of a class. + * @param clazz the class + * @return a collection of names of all writable instance properties of a class. + */ + public static Collection getWritableInstancePropertyNames(Class clazz) { + TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); + if(linker instanceof BeanLinker) { + return ((BeanLinker)linker).getWritablePropertyNames(); + } + return Collections.emptySet(); + } + + /** + * Returns a collection of names of all instance methods of a class. + * @param clazz the class + * @return a collection of names of all instance methods of a class. + */ + public static Collection getInstanceMethodNames(Class clazz) { + TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); + if(linker instanceof BeanLinker) { + return ((BeanLinker)linker).getMethodNames(); + } + return Collections.emptySet(); + } + + /** + * Returns a collection of names of all readable static properties of a class. + * @param clazz the class + * @return a collection of names of all readable static properties of a class. + */ + public static Collection getReadableStaticPropertyNames(Class clazz) { + return StaticClassLinker.getReadableStaticPropertyNames(clazz); + } + + /** + * Returns a collection of names of all writable static properties of a class. + * @param clazz the class + * @return a collection of names of all writable static properties of a class. + */ + public static Collection getWritableStaticPropertyNames(Class clazz) { + return StaticClassLinker.getWritableStaticPropertyNames(clazz); + } + + /** + * Returns a collection of names of all static methods of a class. + * @param clazz the class + * @return a collection of names of all static methods of a class. + */ + public static Collection getStaticMethodNames(Class clazz) { + return StaticClassLinker.getStaticMethodNames(clazz); + } + @Override public GuardedInvocation getGuardedInvocation(LinkRequest request, final LinkerServices linkerServices) throws Exception { diff -r 8ba96bd382d3 -r ada98218aaae nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java --- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java Fri Jul 12 20:06:41 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java Mon Jul 15 12:33:48 2013 +0200 @@ -88,10 +88,10 @@ import java.lang.invoke.MethodType; import java.lang.reflect.Array; import java.util.Arrays; +import java.util.Collection; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; import jdk.internal.dynalink.linker.GuardedInvocation; -import jdk.internal.dynalink.linker.GuardingDynamicLinker; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; @@ -102,9 +102,9 @@ * @author Attila Szegedi */ class StaticClassLinker implements TypeBasedGuardingDynamicLinker { - private final ClassValue linkers = new ClassValue() { + private static final ClassValue linkers = new ClassValue() { @Override - protected GuardingDynamicLinker computeValue(Class clazz) { + protected SingleClassStaticsLinker computeValue(Class clazz) { return new SingleClassStaticsLinker(clazz); } }; @@ -160,6 +160,18 @@ } } + static Collection getReadableStaticPropertyNames(Class clazz) { + return linkers.get(clazz).getReadablePropertyNames(); + } + + static Collection getWritableStaticPropertyNames(Class clazz) { + return linkers.get(clazz).getWritablePropertyNames(); + } + + static Collection getStaticMethodNames(Class clazz) { + return linkers.get(clazz).getMethodNames(); + } + @Override public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) throws Exception { final Object receiver = request.getReceiver(); diff -r 8ba96bd382d3 -r ada98218aaae nashorn/src/jdk/nashorn/internal/objects/NativeObject.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java Fri Jul 12 20:06:41 2013 +0530 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java Mon Jul 15 12:33:48 2013 +0200 @@ -29,8 +29,22 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import jdk.internal.dynalink.beans.BeansLinker; +import jdk.internal.dynalink.beans.StaticClass; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; +import jdk.internal.dynalink.support.LinkRequestImpl; import jdk.nashorn.api.scripting.ScriptObjectMirror; +import jdk.nashorn.internal.lookup.Lookup; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; @@ -58,6 +72,8 @@ @ScriptClass("Object") public final class NativeObject { private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); + private static final MethodType MIRROR_GETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class); + private static final MethodType MIRROR_SETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class, Object.class); // initialized by nasgen @SuppressWarnings("unused") @@ -577,14 +593,91 @@ final AccessorProperty[] props = new AccessorProperty[keys.length]; for (int idx = 0; idx < keys.length; idx++) { final String name = keys[idx]; - final MethodHandle getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, Object.class, ScriptObjectMirror.class); - final MethodHandle setter = Bootstrap.createDynamicInvoker("dyn:setProp|setElem:" + name, Object.class, ScriptObjectMirror.class, Object.class); + final MethodHandle getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, MIRROR_GETTER_TYPE); + final MethodHandle setter = Bootstrap.createDynamicInvoker("dyn:setProp|setElem:" + name, MIRROR_SETTER_TYPE); props[idx] = (AccessorProperty.create(name, 0, getter, setter)); } targetObj.addBoundProperties(source, props); + } else if (source instanceof StaticClass) { + final Class clazz = ((StaticClass)source).getRepresentedClass(); + bindBeanProperties(targetObj, source, BeansLinker.getReadableStaticPropertyNames(clazz), + BeansLinker.getWritableStaticPropertyNames(clazz), BeansLinker.getStaticMethodNames(clazz)); + } else { + final Class clazz = source.getClass(); + bindBeanProperties(targetObj, source, BeansLinker.getReadableInstancePropertyNames(clazz), + BeansLinker.getWritableInstancePropertyNames(clazz), BeansLinker.getInstanceMethodNames(clazz)); } return target; } + + private static void bindBeanProperties(final ScriptObject targetObj, final Object source, + final Collection readablePropertyNames, final Collection writablePropertyNames, + final Collection methodNames) { + final Set propertyNames = new HashSet<>(readablePropertyNames); + propertyNames.addAll(writablePropertyNames); + + final Class clazz = source.getClass(); + + final MethodType getterType = MethodType.methodType(Object.class, clazz); + final MethodType setterType = MethodType.methodType(Object.class, clazz, Object.class); + + final GuardingDynamicLinker linker = BeansLinker.getLinkerForClass(clazz); + + final List properties = new ArrayList<>(propertyNames.size() + methodNames.size()); + for(final String methodName: methodNames) { + properties.add(AccessorProperty.create(methodName, Property.NOT_WRITABLE, + getBoundBeanMethodGetter(source, getBeanOperation(linker, "dyn:getMethod:" + methodName, getterType, source)), + null)); + } + for(final String propertyName: propertyNames) { + final boolean isWritable = writablePropertyNames.contains(propertyName); + properties.add(AccessorProperty.create(propertyName, isWritable ? 0 : Property.NOT_WRITABLE, + readablePropertyNames.contains(propertyName) ? getBeanOperation(linker, "dyn:getProp:" + propertyName, getterType, source) : Lookup.EMPTY_GETTER, + isWritable ? getBeanOperation(linker, "dyn:setProp:" + propertyName, setterType, source) : Lookup.EMPTY_SETTER)); + } + + targetObj.addBoundProperties(source, properties.toArray(new AccessorProperty[properties.size()])); + } + + private static MethodHandle getBoundBeanMethodGetter(Object source, MethodHandle methodGetter) { + try { + // NOTE: we're relying on the fact that "dyn:getMethod:..." return value is constant for any given method + // name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is + // constant for any given method name and object's class.) + return MethodHandles.dropArguments(MethodHandles.constant(Object.class, + Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class); + } catch(RuntimeException|Error e) { + throw e; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final String operation, + final MethodType methodType, final Object source) { + final GuardedInvocation inv; + try { + inv = linker.getGuardedInvocation(createLinkRequest(operation, methodType, source), + Bootstrap.getLinkerServices()); + assert passesGuard(source, inv.getGuard()); + } catch(RuntimeException|Error e) { + throw e; + } catch(Throwable t) { + throw new RuntimeException(t); + } + assert inv.getSwitchPoint() == null; // Linkers in Dynalink's beans package don't use switchpoints. + // We discard the guard, as all method handles will be bound to a specific object. + return inv.getInvocation(); + } + + private static boolean passesGuard(final Object obj, final MethodHandle guard) throws Throwable { + return guard == null || (boolean)guard.invoke(obj); + } + + private static LinkRequest createLinkRequest(String operation, MethodType methodType, Object source) { + return new LinkRequestImpl(CallSiteDescriptorFactory.create(MethodHandles.publicLookup(), operation, + methodType), false, source); + } } diff -r 8ba96bd382d3 -r ada98218aaae nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Fri Jul 12 20:06:41 2013 +0530 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Mon Jul 15 12:33:48 2013 +0200 @@ -57,7 +57,7 @@ static { final DynamicLinkerFactory factory = new DynamicLinkerFactory(); factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(), - new JSObjectLinker(), new ReflectionCheckLinker()); + new BoundDynamicMethodLinker(), new JSObjectLinker(), new ReflectionCheckLinker()); factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker()); factory.setSyncOnRelink(true); final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1); @@ -208,6 +208,16 @@ } /** + * Binds a bean dynamic method (returned by invoking {@code dyn:getMethod} on an object linked with + * {@code BeansLinker} to a receiver. + * @param dynamicMethod the dynamic method to bind + * @param boundThis the bound "this" value. + * @return a bound dynamic method. + */ + public static Object bindDynamicMethod(Object dynamicMethod, Object boundThis) { + return new BoundDynamicMethod(dynamicMethod, boundThis); + } + /** * Returns the Nashorn's internally used dynamic linker's services object. Note that in code that is processing a * linking request, you will normally use the {@code LinkerServices} object passed by whatever top-level linker * invoked the linking (if the call site is in Nashorn-generated code, you'll get this object anyway). You should diff -r 8ba96bd382d3 -r ada98218aaae nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java Mon Jul 15 12:33:48 2013 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.runtime.linker; + +import jdk.internal.dynalink.beans.BeansLinker; + +/** + * Represents a Dynalink dynamic method bound to a receiver. Note that objects of this class are just the tuples of + * a method and a bound this, without any behavior. All the behavior is defined in the {@link BoundDynamicMethodLinker}. + */ +final class BoundDynamicMethod { + private final Object dynamicMethod; + private final Object boundThis; + + BoundDynamicMethod(final Object dynamicMethod, final Object boundThis) { + assert BeansLinker.isDynamicMethod(dynamicMethod); + this.dynamicMethod = dynamicMethod; + this.boundThis = boundThis; + } + + Object getDynamicMethod() { + return dynamicMethod; + } + + Object getBoundThis() { + return boundThis; + } +} diff -r 8ba96bd382d3 -r ada98218aaae nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java Mon Jul 15 12:33:48 2013 +0200 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.runtime.linker; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.beans.BeansLinker; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Guards; + +/** + * Links {@link BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method + * (they only respond to "dyn:call"), and modifies the returned invocation to deal with the receiver binding. + */ +final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker { + @Override + public boolean canLinkType(Class type) { + return type == BoundDynamicMethod.class; + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) throws Exception { + final Object objBoundDynamicMethod = linkRequest.getReceiver(); + if(!(objBoundDynamicMethod instanceof BoundDynamicMethod)) { + return null; + } + + final BoundDynamicMethod boundDynamicMethod = (BoundDynamicMethod)objBoundDynamicMethod; + final Object dynamicMethod = boundDynamicMethod.getDynamicMethod(); + final Object boundThis = boundDynamicMethod.getBoundThis(); + + // Replace arguments (boundDynamicMethod, this, ...) => (dynamicMethod, boundThis, ...) when delegating to + // BeansLinker + final Object[] args = linkRequest.getArguments(); + args[0] = dynamicMethod; + args[1] = boundThis; + + // Use R(T0, T1, ...) => R(dynamicMethod.class, boundThis.class, ...) call site type when delegating to + // BeansLinker. + final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor(); + final MethodType type = descriptor.getMethodType(); + final CallSiteDescriptor newDescriptor = descriptor.changeMethodType( + type.changeParameterType(0, dynamicMethod.getClass()).changeParameterType(1, boundThis.getClass())); + + // Delegate to BeansLinker + final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethod.getClass()).getGuardedInvocation( + linkRequest.replaceArguments(newDescriptor, args), linkerServices); + if(inv == null) { + return null; + } + + // Bind (dynamicMethod, boundThis) to the handle + final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, dynamicMethod, boundThis); + final Class p0Type = type.parameterType(0); + // Ignore incoming (boundDynamicMethod, this) + final MethodHandle droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1)); + // Identity guard on boundDynamicMethod object + final MethodHandle newGuard = Guards.getIdentityGuard(boundDynamicMethod); + + return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type))); + } +} diff -r 8ba96bd382d3 -r ada98218aaae nashorn/test/script/basic/JDK-8020324.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8020324.js Mon Jul 15 12:33:48 2013 +0200 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8020324: Implement Object.bindProperties(target, source) for beans + * + * @test + * @run + */ + +var PropertyBind = Java.type("jdk.nashorn.test.models.PropertyBind") +var bean = new PropertyBind + +var obj1 = {} +Object.bindProperties(obj1, bean) + +printBanner("Two-way read-write instance field") +printEval("obj1.publicInt = 13") +printEval("bean.publicInt") +printEval("bean.publicInt = 15") +printEval("obj1.publicInt") + +printBanner("Read only public instance field") +printEval("obj1.publicFinalInt") +printEval("obj1.publicFinalInt = 16") +printEval("obj1.publicFinalInt") +printEval("bean.publicFinalInt") + +printBanner("Two-way read-write instance property") +printEval("obj1.readWrite = 17") +printEval("bean.readWrite") +printEval("bean.readWrite = 18") +printEval("obj1.readWrite") +printEval("obj1.getReadWrite()") +printEval("obj1.setReadWrite(19)") +printEval("obj1.readWrite") +printEval("bean.readWrite") + +printBanner("Read only instance property") +printEval("obj1.readOnly") +printEval("obj1.readOnly = 20") +printEval("obj1.readOnly") +printEval("obj1.getReadOnly()") +printEval("bean.getReadOnly()") + +printBanner("Write only instance property") +printEval("obj1.writeOnly = 21") +printEval("obj1.writeOnly") +printEval("bean.writeOnly") +printEval("bean.peekWriteOnly()") + +var obj2 = {} +Object.bindProperties(obj2, PropertyBind) + +printBanner("Two-way read-write public static field") +printEval("obj2.publicStaticInt = 22") +printEval("PropertyBind.publicStaticInt") +printEval("PropertyBind.publicStaticInt = 23") +printEval("obj2.publicStaticInt") + +printBanner("Read only public static field") +printEval("obj2.publicStaticFinalInt") +printEval("obj2.publicStaticFinalInt = 24") +printEval("obj2.publicStaticFinalInt") +printEval("PropertyBind.publicStaticFinalInt") + +printBanner("Two-way read-write static property") +printEval("obj2.staticReadWrite = 25") +printEval("PropertyBind.staticReadWrite") +printEval("PropertyBind.staticReadWrite = 26") +printEval("obj2.staticReadWrite") +printEval("obj2.getStaticReadWrite()") +printEval("obj2.setStaticReadWrite(27)") +printEval("obj2.staticReadWrite") +printEval("PropertyBind.staticReadWrite") + +printBanner("Read only static property") +printEval("obj2.staticReadOnly") +printEval("obj2.staticReadOnly = 28") +printEval("obj2.staticReadOnly") +printEval("obj2.getStaticReadOnly()") +printEval("PropertyBind.getStaticReadOnly()") + +printBanner("Write only static property") +printEval("obj2.staticWriteOnly = 29") +printEval("obj2.staticWriteOnly") +printEval("PropertyBind.staticWriteOnly") +printEval("PropertyBind.peekStaticWriteOnly()") + +printBanner("Sanity check to ensure property values remained what they were") +printEval("obj1.publicInt") +printEval("bean.publicInt") +printEval("obj1.publicFinalInt") +printEval("bean.publicFinalInt") +printEval("obj1.readWrite") +printEval("bean.readWrite") +printEval("obj1.readOnly") +printEval("bean.readOnly") +printEval("bean.peekWriteOnly()") + +printEval("obj2.publicStaticInt") +printEval("PropertyBind.publicStaticInt") +printEval("obj2.publicStaticFinalInt") +printEval("PropertyBind.publicStaticFinalInt") +printEval("obj2.staticReadWrite") +printEval("PropertyBind.staticReadWrite") +printEval("obj2.staticReadOnly") +printEval("PropertyBind.staticReadOnly") +printEval("PropertyBind.peekStaticWriteOnly()") + + +function printEval(s) { + print(s + ": " + eval(s)) +} + +function printBanner(s) { + print() + print("==== " + s + " ====") +} diff -r 8ba96bd382d3 -r ada98218aaae nashorn/test/script/basic/JDK-8020324.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8020324.js.EXPECTED Mon Jul 15 12:33:48 2013 +0200 @@ -0,0 +1,90 @@ + +==== Two-way read-write instance field ==== +obj1.publicInt = 13: 13 +bean.publicInt: 13 +bean.publicInt = 15: 15 +obj1.publicInt: 15 + +==== Read only public instance field ==== +obj1.publicFinalInt: 42 +obj1.publicFinalInt = 16: 16 +obj1.publicFinalInt: 42 +bean.publicFinalInt: 42 + +==== Two-way read-write instance property ==== +obj1.readWrite = 17: 17 +bean.readWrite: 17 +bean.readWrite = 18: 18 +obj1.readWrite: 18 +obj1.getReadWrite(): 18 +obj1.setReadWrite(19): null +obj1.readWrite: 19 +bean.readWrite: 19 + +==== Read only instance property ==== +obj1.readOnly: 123 +obj1.readOnly = 20: 20 +obj1.readOnly: 123 +obj1.getReadOnly(): 123 +bean.getReadOnly(): 123 + +==== Write only instance property ==== +obj1.writeOnly = 21: 21 +obj1.writeOnly: undefined +bean.writeOnly: undefined +bean.peekWriteOnly(): 21 + +==== Two-way read-write public static field ==== +obj2.publicStaticInt = 22: 22 +PropertyBind.publicStaticInt: 22 +PropertyBind.publicStaticInt = 23: 23 +obj2.publicStaticInt: 23 + +==== Read only public static field ==== +obj2.publicStaticFinalInt: 2112 +obj2.publicStaticFinalInt = 24: 24 +obj2.publicStaticFinalInt: 2112 +PropertyBind.publicStaticFinalInt: 2112 + +==== Two-way read-write static property ==== +obj2.staticReadWrite = 25: 25 +PropertyBind.staticReadWrite: 25 +PropertyBind.staticReadWrite = 26: 26 +obj2.staticReadWrite: 26 +obj2.getStaticReadWrite(): 26 +obj2.setStaticReadWrite(27): null +obj2.staticReadWrite: 27 +PropertyBind.staticReadWrite: 27 + +==== Read only static property ==== +obj2.staticReadOnly: 1230 +obj2.staticReadOnly = 28: 28 +obj2.staticReadOnly: 1230 +obj2.getStaticReadOnly(): 1230 +PropertyBind.getStaticReadOnly(): 1230 + +==== Write only static property ==== +obj2.staticWriteOnly = 29: 29 +obj2.staticWriteOnly: undefined +PropertyBind.staticWriteOnly: undefined +PropertyBind.peekStaticWriteOnly(): 29 + +==== Sanity check to ensure property values remained what they were ==== +obj1.publicInt: 15 +bean.publicInt: 15 +obj1.publicFinalInt: 42 +bean.publicFinalInt: 42 +obj1.readWrite: 19 +bean.readWrite: 19 +obj1.readOnly: 123 +bean.readOnly: 123 +bean.peekWriteOnly(): 21 +obj2.publicStaticInt: 23 +PropertyBind.publicStaticInt: 23 +obj2.publicStaticFinalInt: 2112 +PropertyBind.publicStaticFinalInt: 2112 +obj2.staticReadWrite: 27 +PropertyBind.staticReadWrite: 27 +obj2.staticReadOnly: 1230 +PropertyBind.staticReadOnly: 1230 +PropertyBind.peekStaticWriteOnly(): 29 diff -r 8ba96bd382d3 -r ada98218aaae nashorn/test/src/jdk/nashorn/test/models/PropertyBind.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/src/jdk/nashorn/test/models/PropertyBind.java Mon Jul 15 12:33:48 2013 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.test.models; + +public class PropertyBind { + public static int publicStaticInt; + public static final int publicStaticFinalInt = 2112; + + private static int staticReadWrite; + private static int staticReadOnly = 1230; + private static int staticWriteOnly; + + public int publicInt; + public final int publicFinalInt = 42; + + private int readWrite; + private int readOnly = 123; + private int writeOnly; + + public int getReadWrite() { + return readWrite; + } + + public void setReadWrite(int readWrite) { + this.readWrite = readWrite; + } + + public int getReadOnly() { + return readOnly; + } + + public void setWriteOnly(int writeOnly) { + this.writeOnly = writeOnly; + } + + public int peekWriteOnly() { + return writeOnly; + } + + public static int getStaticReadWrite() { + return staticReadWrite; + } + + public static void setStaticReadWrite(int staticReadWrite) { + PropertyBind.staticReadWrite = staticReadWrite; + } + + public static int getStaticReadOnly() { + return staticReadOnly; + } + + public static void setStaticWriteOnly(int staticWriteOnly) { + PropertyBind.staticWriteOnly = staticWriteOnly; + } + + public static int peekStaticWriteOnly() { + return PropertyBind.staticWriteOnly; + } +}