Thu, 11 Sep 2014 18:04:54 +0200
8057021: UserAccessorProperty guards fail with multiple globals
Reviewed-by: attila, lagergren
1.1 --- a/src/jdk/nashorn/internal/objects/Global.java Thu Sep 11 17:12:38 2014 +0200 1.2 +++ b/src/jdk/nashorn/internal/objects/Global.java Thu Sep 11 18:04:54 2014 +0200 1.3 @@ -631,6 +631,24 @@ 1.4 } 1.5 1.6 /** 1.7 + * Returns a method handle that creates a wrapper object for a JS primitive value. 1.8 + * 1.9 + * @param self receiver object 1.10 + * @return method handle to create wrapper objects for primitive receiver 1.11 + */ 1.12 + public static MethodHandle getPrimitiveWrapFilter(final Object self) { 1.13 + if (self instanceof String || self instanceof ConsString) { 1.14 + return NativeString.WRAPFILTER; 1.15 + } else if (self instanceof Number) { 1.16 + return NativeNumber.WRAPFILTER; 1.17 + } else if (self instanceof Boolean) { 1.18 + return NativeBoolean.WRAPFILTER; 1.19 + } 1.20 + throw new IllegalArgumentException("Unsupported primitive: " + self); 1.21 + } 1.22 + 1.23 + 1.24 + /** 1.25 * Create a new empty script object 1.26 * 1.27 * @return the new ScriptObject
2.1 --- a/src/jdk/nashorn/internal/objects/NativeBoolean.java Thu Sep 11 17:12:38 2014 +0200 2.2 +++ b/src/jdk/nashorn/internal/objects/NativeBoolean.java Thu Sep 11 18:04:54 2014 +0200 2.3 @@ -51,9 +51,9 @@ 2.4 public final class NativeBoolean extends ScriptObject { 2.5 private final boolean value; 2.6 2.7 - // Method handle to create an object wrapper for a primitive boolean 2.8 - private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class)); 2.9 - // Method handle to retrieve the Boolean prototype object 2.10 + /** Method handle to create an object wrapper for a primitive boolean. */ 2.11 + static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class)); 2.12 + /** Method handle to retrieve the Boolean prototype object. */ 2.13 private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class)); 2.14 2.15 // initialized by nasgen
3.1 --- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java Thu Sep 11 17:12:38 2014 +0200 3.2 +++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java Thu Sep 11 18:04:54 2014 +0200 3.3 @@ -28,6 +28,7 @@ 3.4 import static jdk.nashorn.internal.lookup.Lookup.MH; 3.5 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 3.6 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 3.7 +import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; 3.8 3.9 import java.lang.invoke.MethodHandle; 3.10 import java.lang.invoke.MethodHandles; 3.11 @@ -697,7 +698,7 @@ 3.12 if (methodHandle != null) { 3.13 return new GuardedInvocation( 3.14 methodHandle, 3.15 - testJSAdaptor(adaptee, findData.getGetter(Object.class, UnwarrantedOptimismException.INVALID_PROGRAM_POINT), findData.getOwner(), func), 3.16 + testJSAdaptor(adaptee, findData.getGetter(Object.class, INVALID_PROGRAM_POINT, null), findData.getOwner(), func), 3.17 adaptee.getProtoSwitchPoint(hook, findData.getOwner())); 3.18 } 3.19 }
4.1 --- a/src/jdk/nashorn/internal/objects/NativeNumber.java Thu Sep 11 17:12:38 2014 +0200 4.2 +++ b/src/jdk/nashorn/internal/objects/NativeNumber.java Thu Sep 11 18:04:54 2014 +0200 4.3 @@ -57,9 +57,9 @@ 4.4 @ScriptClass("Number") 4.5 public final class NativeNumber extends ScriptObject { 4.6 4.7 - // Method handle to create an object wrapper for a primitive number 4.8 - private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class)); 4.9 - // Method handle to retrieve the Number prototype object 4.10 + /** Method handle to create an object wrapper for a primitive number. */ 4.11 + static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class)); 4.12 + /** Method handle to retrieve the Number prototype object. */ 4.13 private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class)); 4.14 4.15 /** ECMA 15.7.3.2 largest positive finite value */
5.1 --- a/src/jdk/nashorn/internal/objects/NativeString.java Thu Sep 11 17:12:38 2014 +0200 5.2 +++ b/src/jdk/nashorn/internal/objects/NativeString.java Thu Sep 11 18:04:54 2014 +0200 5.3 @@ -71,9 +71,9 @@ 5.4 5.5 private final CharSequence value; 5.6 5.7 - // Method handle to create an object wrapper for a primitive string 5.8 - private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class)); 5.9 - // Method handle to retrieve the String prototype object 5.10 + /** Method handle to create an object wrapper for a primitive string */ 5.11 + static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class)); 5.12 + /** Method handle to retrieve the String prototype object */ 5.13 private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class)); 5.14 5.15 // initialized by nasgen
6.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Thu Sep 11 17:12:38 2014 +0200 6.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Thu Sep 11 18:04:54 2014 +0200 6.3 @@ -196,11 +196,11 @@ 6.4 } 6.5 6.6 @Override 6.7 - public void storeScript(final String classInfoFile, final Source source, final String mainClassName, 6.8 + public void storeScript(final String cacheKey, final Source source, final String mainClassName, 6.9 final Map<String,byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers, 6.10 final Object[] constants, final int compilationId) { 6.11 if (context.codeStore != null) { 6.12 - context.codeStore.storeScript(classInfoFile, source, mainClassName, classBytes, initializers, constants, compilationId); 6.13 + context.codeStore.storeScript(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId); 6.14 } 6.15 } 6.16
7.1 --- a/src/jdk/nashorn/internal/runtime/FindProperty.java Thu Sep 11 17:12:38 2014 +0200 7.2 +++ b/src/jdk/nashorn/internal/runtime/FindProperty.java Thu Sep 11 18:04:54 2014 +0200 7.3 @@ -29,7 +29,9 @@ 7.4 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; 7.5 7.6 import java.lang.invoke.MethodHandle; 7.7 +import jdk.internal.dynalink.linker.LinkRequest; 7.8 import jdk.nashorn.internal.codegen.ObjectClassGenerator; 7.9 +import jdk.nashorn.internal.objects.Global; 7.10 7.11 /** 7.12 * This class represents the result from a find property search. 7.13 @@ -79,25 +81,17 @@ 7.14 * @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic 7.15 * @return method handle for the getter 7.16 */ 7.17 - public MethodHandle getGetter(final Class<?> type, final int programPoint) { 7.18 + public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) { 7.19 final MethodHandle getter; 7.20 if (isValid(programPoint)) { 7.21 getter = property.getOptimisticGetter(type, programPoint); 7.22 } else { 7.23 getter = property.getGetter(type); 7.24 } 7.25 - return getGetterInner(getter); 7.26 - } 7.27 - 7.28 - private MethodHandle getGetterInner(final MethodHandle getter) { 7.29 if (property instanceof UserAccessorProperty) { 7.30 - final UserAccessorProperty uc = (UserAccessorProperty)property; 7.31 - final ScriptObject owner = getOwner(); 7.32 - final ScriptObject container = (owner != null) ? owner : self; 7.33 - return MH.insertArguments(getter, 0, uc.getAccessors(container)); 7.34 + return insertAccessorsGetter((UserAccessorProperty) property, request, getter); 7.35 } 7.36 return getter; 7.37 - 7.38 } 7.39 7.40 /** 7.41 @@ -111,18 +105,31 @@ 7.42 * 7.43 * @return method handle for the getter 7.44 */ 7.45 - public MethodHandle getSetter(final Class<?> type, final boolean strict) { 7.46 - final MethodHandle setter = property.getSetter(type, getOwner().getMap()); 7.47 + public MethodHandle getSetter(final Class<?> type, final boolean strict, final LinkRequest request) { 7.48 + MethodHandle setter = property.getSetter(type, getOwner().getMap()); 7.49 if (property instanceof UserAccessorProperty) { 7.50 - final UserAccessorProperty uc = (UserAccessorProperty)property; 7.51 - final ScriptObject owner = getOwner(); 7.52 - final ScriptObject container = (owner != null) ? owner : self; 7.53 - return MH.insertArguments(setter, 0, uc.getAccessors(container), strict ? property.getKey() : null); 7.54 + setter = MH.insertArguments(setter, 1, strict ? property.getKey() : null); 7.55 + return insertAccessorsGetter((UserAccessorProperty) property, request, setter); 7.56 } 7.57 7.58 return setter; 7.59 } 7.60 7.61 + // Fold an accessor getter into the method handle of a user accessor property. 7.62 + private MethodHandle insertAccessorsGetter(final UserAccessorProperty uap, final LinkRequest request, final MethodHandle mh) { 7.63 + MethodHandle superGetter = uap.getAccessorsGetter(); 7.64 + if (isInherited()) { 7.65 + superGetter = ScriptObject.addProtoFilter(superGetter, getProtoChainLength()); 7.66 + } 7.67 + if (request != null && !(request.getReceiver() instanceof ScriptObject)) { 7.68 + final MethodHandle wrapFilter = Global.getPrimitiveWrapFilter(request.getReceiver()); 7.69 + superGetter = MH.filterArguments(superGetter, 0, wrapFilter.asType(wrapFilter.type().changeReturnType(superGetter.type().parameterType(0)))); 7.70 + } 7.71 + superGetter = MH.asType(superGetter, superGetter.type().changeParameterType(0, Object.class)); 7.72 + 7.73 + return MH.foldArguments(mh, superGetter); 7.74 + } 7.75 + 7.76 /** 7.77 * Return the {@code ScriptObject} owning of the property: this means the prototype. 7.78 * @return owner of property 7.79 @@ -136,7 +143,7 @@ 7.80 * @return appropriate receiver 7.81 */ 7.82 public ScriptObject getGetterReceiver() { 7.83 - return property != null && property.hasGetterFunction(prototype) ? self : prototype; 7.84 + return property != null && property instanceof UserAccessorProperty ? self : prototype; 7.85 } 7.86 7.87 /**
8.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu Sep 11 17:12:38 2014 +0200 8.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu Sep 11 18:04:54 2014 +0200 8.3 @@ -1050,7 +1050,7 @@ 8.4 } 8.5 8.6 private static int getIntValue(final FindProperty find, final int programPoint) { 8.7 - final MethodHandle getter = find.getGetter(int.class, programPoint); 8.8 + final MethodHandle getter = find.getGetter(int.class, programPoint, null); 8.9 if (getter != null) { 8.10 try { 8.11 return (int)getter.invokeExact((Object)find.getGetterReceiver()); 8.12 @@ -1065,7 +1065,7 @@ 8.13 } 8.14 8.15 private static long getLongValue(final FindProperty find, final int programPoint) { 8.16 - final MethodHandle getter = find.getGetter(long.class, programPoint); 8.17 + final MethodHandle getter = find.getGetter(long.class, programPoint, null); 8.18 if (getter != null) { 8.19 try { 8.20 return (long)getter.invokeExact((Object)find.getGetterReceiver()); 8.21 @@ -1080,7 +1080,7 @@ 8.22 } 8.23 8.24 private static double getDoubleValue(final FindProperty find, final int programPoint) { 8.25 - final MethodHandle getter = find.getGetter(double.class, programPoint); 8.26 + final MethodHandle getter = find.getGetter(double.class, programPoint, null); 8.27 if (getter != null) { 8.28 try { 8.29 return (double)getter.invokeExact((Object)find.getGetterReceiver()); 8.30 @@ -1983,7 +1983,7 @@ 8.31 NashornCallSiteDescriptor.getProgramPoint(desc) : 8.32 UnwarrantedOptimismException.INVALID_PROGRAM_POINT; 8.33 8.34 - mh = find.getGetter(returnType, programPoint); 8.35 + mh = find.getGetter(returnType, programPoint, request); 8.36 // Get the appropriate guard for this callsite and property. 8.37 final MethodHandle guard = NashornGuards.getGuard(this, property, desc, explicitInstanceOfCheck); 8.38 final ScriptObject owner = find.getOwner(); 8.39 @@ -1995,8 +1995,9 @@ 8.40 mh = Lookup.emptyGetter(returnType); 8.41 protoSwitchPoint = getProtoSwitchPoint(name, owner); 8.42 } else if (!find.isSelf()) { 8.43 - assert mh.type().returnType().equals(returnType) : "returntype mismatch for getter " + mh.type().returnType() + " != " + returnType; 8.44 - if (!property.hasGetterFunction(owner)) { 8.45 + assert mh.type().returnType().equals(returnType) : 8.46 + "return type mismatch for getter " + mh.type().returnType() + " != " + returnType; 8.47 + if (!(property instanceof UserAccessorProperty)) { 8.48 // Add a filter that replaces the self object with the prototype owning the property. 8.49 mh = addProtoFilter(mh, find.getProtoChainLength()); 8.50 } 8.51 @@ -2167,7 +2168,7 @@ 8.52 } 8.53 } 8.54 8.55 - final GuardedInvocation inv = new SetMethodCreator(this, find, desc, explicitInstanceOfCheck).createGuardedInvocation(); 8.56 + final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation(); 8.57 8.58 final GuardedInvocation cinv = Global.getConstants().findSetMethod(find, this, inv, desc, request); 8.59 if (cinv != null) { 8.60 @@ -2320,13 +2321,13 @@ 8.61 find.isSelf()? 8.62 getKnownFunctionPropertyGuardSelf( 8.63 getMap(), 8.64 - find.getGetter(Object.class, INVALID_PROGRAM_POINT), 8.65 + find.getGetter(Object.class, INVALID_PROGRAM_POINT, request), 8.66 func) 8.67 : 8.68 //TODO this always does a scriptobject check 8.69 getKnownFunctionPropertyGuardProto( 8.70 getMap(), 8.71 - find.getGetter(Object.class, INVALID_PROGRAM_POINT), 8.72 + find.getGetter(Object.class, INVALID_PROGRAM_POINT, request), 8.73 find.getProtoChainLength(), 8.74 func), 8.75 getProtoSwitchPoint(NO_SUCH_PROPERTY_NAME, find.getOwner()),
9.1 --- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Thu Sep 11 17:12:38 2014 +0200 9.2 +++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Thu Sep 11 18:04:54 2014 +0200 9.3 @@ -33,6 +33,7 @@ 9.4 import java.lang.invoke.SwitchPoint; 9.5 import jdk.internal.dynalink.CallSiteDescriptor; 9.6 import jdk.internal.dynalink.linker.GuardedInvocation; 9.7 +import jdk.internal.dynalink.linker.LinkRequest; 9.8 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 9.9 import jdk.nashorn.internal.runtime.linker.NashornGuards; 9.10 9.11 @@ -48,7 +49,7 @@ 9.12 private final FindProperty find; 9.13 private final CallSiteDescriptor desc; 9.14 private final Class<?> type; 9.15 - private final boolean explicitInstanceOfCheck; 9.16 + private final LinkRequest request; 9.17 9.18 /** 9.19 * Creates a new property setter method creator. 9.20 @@ -56,14 +57,15 @@ 9.21 * @param find a result of a {@link ScriptObject#findProperty(String, boolean)} on the object for the property we 9.22 * want to create a setter for. Can be null if the property does not yet exist on the object. 9.23 * @param desc the descriptor of the call site that triggered the property setter lookup 9.24 + * @param request the link request 9.25 */ 9.26 - SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck) { 9.27 - this.sobj = sobj; 9.28 - this.map = sobj.getMap(); 9.29 - this.find = find; 9.30 - this.desc = desc; 9.31 - this.type = desc.getMethodType().parameterType(1); 9.32 - this.explicitInstanceOfCheck = explicitInstanceOfCheck; 9.33 + SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc, final LinkRequest request) { 9.34 + this.sobj = sobj; 9.35 + this.map = sobj.getMap(); 9.36 + this.find = find; 9.37 + this.desc = desc; 9.38 + this.type = desc.getMethodType().parameterType(1); 9.39 + this.request = request; 9.40 9.41 } 9.42 9.43 @@ -111,6 +113,7 @@ 9.44 // getGuard() and getException() either both return null, or neither does. The reason for that is that now 9.45 // getGuard returns a map guard that casts its argument to ScriptObject, and if that fails, we need to 9.46 // relink on ClassCastException. 9.47 + final boolean explicitInstanceOfCheck = NashornGuards.explicitInstanceOfCheck(desc, request); 9.48 return new GuardedInvocation(methodHandle, NashornGuards.getGuard(sobj, property, desc, explicitInstanceOfCheck), 9.49 (SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class); 9.50 } 9.51 @@ -140,6 +143,7 @@ 9.52 9.53 private SetMethod createExistingPropertySetter() { 9.54 final Property property = find.getProperty(); 9.55 + final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc); 9.56 final MethodHandle methodHandle; 9.57 9.58 if (NashornCallSiteDescriptor.isDeclaration(desc)) { 9.59 @@ -152,7 +156,7 @@ 9.60 final PropertyMap oldMap = getMap(); 9.61 final Property newProperty = property.removeFlags(Property.NEEDS_DECLARATION); 9.62 final PropertyMap newMap = oldMap.replaceProperty(property, newProperty); 9.63 - final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, NashornCallSiteDescriptor.isStrict(desc)); 9.64 + final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, isStrict, request); 9.65 final MethodHandle slowSetter = MH.insertArguments(ScriptObject.DECLARE_AND_SET, 1, getName()).asType(fastSetter.type()); 9.66 9.67 // cas map used as guard, if true that means we can do the set fast 9.68 @@ -161,14 +165,14 @@ 9.69 casMap = MH.asType(casMap, casMap.type().changeParameterType(0, Object.class)); 9.70 methodHandle = MH.guardWithTest(casMap, fastSetter, slowSetter); 9.71 } else { 9.72 - methodHandle = find.getSetter(type, NashornCallSiteDescriptor.isStrict(desc)); 9.73 + methodHandle = find.getSetter(type, isStrict, request); 9.74 } 9.75 9.76 assert methodHandle != null; 9.77 assert property != null; 9.78 9.79 final MethodHandle boundHandle; 9.80 - if (!property.hasSetterFunction(find.getOwner()) && find.isInherited()) { 9.81 + if (!(property instanceof UserAccessorProperty) && find.isInherited()) { 9.82 boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength()); 9.83 } else { 9.84 boundHandle = methodHandle;
10.1 --- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Thu Sep 11 17:12:38 2014 +0200 10.2 +++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Thu Sep 11 18:04:54 2014 +0200 10.3 @@ -34,8 +34,8 @@ 10.4 10.5 import java.lang.invoke.MethodHandle; 10.6 import java.lang.invoke.MethodHandles; 10.7 +import java.lang.invoke.MethodType; 10.8 import java.util.concurrent.Callable; 10.9 -import jdk.nashorn.internal.codegen.CompilerConstants; 10.10 import jdk.nashorn.internal.lookup.Lookup; 10.11 import jdk.nashorn.internal.runtime.linker.Bootstrap; 10.12 10.13 @@ -48,7 +48,7 @@ 10.14 10.15 private static final long serialVersionUID = -5928687246526840321L; 10.16 10.17 - static class Accessors { 10.18 + static final class Accessors { 10.19 Object getter; 10.20 Object setter; 10.21 10.22 @@ -67,20 +67,20 @@ 10.23 } 10.24 } 10.25 10.26 + private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); 10.27 + 10.28 /** Getter method handle */ 10.29 - private final static CompilerConstants.Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class, 10.30 - "userAccessorGetter", Object.class, Accessors.class, Object.class); 10.31 + private final static MethodHandle INVOKE_GETTER_ACCESSOR = findOwnMH_S("invokeGetterAccessor", Object.class, Accessors.class, Object.class); 10.32 10.33 /** Setter method handle */ 10.34 - private final static CompilerConstants.Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class, 10.35 - "userAccessorSetter", void.class, Accessors.class, String.class, Object.class, Object.class); 10.36 + private final static MethodHandle INVOKE_SETTER_ACCESSOR = findOwnMH_S("invokeSetterAccessor", void.class, Accessors.class, String.class, Object.class, Object.class); 10.37 10.38 /** Dynamic invoker for getter */ 10.39 - private static final Object INVOKE_UA_GETTER = new Object(); 10.40 + private static final Object GETTER_INVOKER_KEY = new Object(); 10.41 10.42 private static MethodHandle getINVOKE_UA_GETTER() { 10.43 10.44 - return Context.getGlobal().getDynamicInvoker(INVOKE_UA_GETTER, 10.45 + return Context.getGlobal().getDynamicInvoker(GETTER_INVOKER_KEY, 10.46 new Callable<MethodHandle>() { 10.47 @Override 10.48 public MethodHandle call() { 10.49 @@ -91,10 +91,10 @@ 10.50 } 10.51 10.52 /** Dynamic invoker for setter */ 10.53 - private static Object INVOKE_UA_SETTER = new Object(); 10.54 + private static Object SETTER_INVOKER_KEY = new Object(); 10.55 10.56 private static MethodHandle getINVOKE_UA_SETTER() { 10.57 - return Context.getGlobal().getDynamicInvoker(INVOKE_UA_SETTER, 10.58 + return Context.getGlobal().getDynamicInvoker(SETTER_INVOKER_KEY, 10.59 new Callable<MethodHandle>() { 10.60 @Override 10.61 public MethodHandle call() { 10.62 @@ -190,7 +190,7 @@ 10.63 10.64 @Override 10.65 public Object getObjectValue(final ScriptObject self, final ScriptObject owner) { 10.66 - return userAccessorGetter(getAccessors((owner != null) ? owner : self), self); 10.67 + return invokeGetterAccessor(getAccessors((owner != null) ? owner : self), self); 10.68 } 10.69 10.70 @Override 10.71 @@ -210,13 +210,13 @@ 10.72 10.73 @Override 10.74 public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) { 10.75 - userAccessorSetter(getAccessors((owner != null) ? owner : self), strict ? getKey() : null, self, value); 10.76 + invokeSetterAccessor(getAccessors((owner != null) ? owner : self), strict ? getKey() : null, self, value); 10.77 } 10.78 10.79 @Override 10.80 public MethodHandle getGetter(final Class<?> type) { 10.81 //this returns a getter on the format (Accessors, Object receiver) 10.82 - return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type); 10.83 + return Lookup.filterReturnType(INVOKE_GETTER_ACCESSOR, type); 10.84 } 10.85 10.86 @Override 10.87 @@ -260,7 +260,7 @@ 10.88 10.89 @Override 10.90 public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) { 10.91 - return USER_ACCESSOR_SETTER.methodHandle(); 10.92 + return INVOKE_SETTER_ACCESSOR; 10.93 } 10.94 10.95 @Override 10.96 @@ -269,11 +269,21 @@ 10.97 return (value instanceof ScriptFunction) ? (ScriptFunction)value : null; 10.98 } 10.99 10.100 + /** 10.101 + * Get the getter for the {@code Accessors} object. 10.102 + * This is the the super {@code Object} type getter with {@code Accessors} return type. 10.103 + * 10.104 + * @return The getter handle for the Accessors 10.105 + */ 10.106 + MethodHandle getAccessorsGetter() { 10.107 + return super.getGetter(Object.class).asType(MethodType.methodType(Accessors.class, Object.class)); 10.108 + } 10.109 + 10.110 // User defined getter and setter are always called by "dyn:call". Note that the user 10.111 // getter/setter may be inherited. If so, proto is bound during lookup. In either 10.112 // inherited or self case, slot is also bound during lookup. Actual ScriptFunction 10.113 // to be called is retrieved everytime and applied. 10.114 - static Object userAccessorGetter(final Accessors gs, final Object self) { 10.115 + private static Object invokeGetterAccessor(final Accessors gs, final Object self) { 10.116 final Object func = gs.getter; 10.117 if (func instanceof ScriptFunction) { 10.118 try { 10.119 @@ -288,7 +298,7 @@ 10.120 return UNDEFINED; 10.121 } 10.122 10.123 - static void userAccessorSetter(final Accessors gs, final String name, final Object self, final Object value) { 10.124 + private static void invokeSetterAccessor(final Accessors gs, final String name, final Object self, final Object value) { 10.125 final Object func = gs.setter; 10.126 if (func instanceof ScriptFunction) { 10.127 try { 10.128 @@ -303,4 +313,8 @@ 10.129 } 10.130 } 10.131 10.132 + private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) { 10.133 + return MH.findStatic(LOOKUP, UserAccessorProperty.class, name, MH.type(rtype, types)); 10.134 + } 10.135 + 10.136 }
11.1 --- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Thu Sep 11 17:12:38 2014 +0200 11.2 +++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Thu Sep 11 18:04:54 2014 +0200 11.3 @@ -32,11 +32,10 @@ 11.4 import jdk.internal.dynalink.CallSiteDescriptor; 11.5 import jdk.internal.dynalink.linker.GuardedInvocation; 11.6 import jdk.internal.dynalink.linker.LinkRequest; 11.7 -import jdk.internal.dynalink.support.CallSiteDescriptorFactory; 11.8 import jdk.internal.dynalink.support.Guards; 11.9 -import jdk.nashorn.internal.lookup.Lookup; 11.10 import jdk.nashorn.internal.runtime.FindProperty; 11.11 import jdk.nashorn.internal.runtime.ScriptObject; 11.12 +import jdk.nashorn.internal.runtime.UserAccessorProperty; 11.13 11.14 /** 11.15 * Implements lookup of methods to link for dynamic operations on JavaScript primitive values (booleans, strings, and 11.16 @@ -86,15 +85,6 @@ 11.17 final ScriptObject wrappedReceiver, final MethodHandle wrapFilter, 11.18 final MethodHandle protoFilter) { 11.19 final CallSiteDescriptor desc = request.getCallSiteDescriptor(); 11.20 - final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0); 11.21 - if ("setProp".equals(operator) || "setElem".equals(operator)) { 11.22 - final MethodType type = desc.getMethodType(); 11.23 - MethodHandle method = MH.asType(Lookup.EMPTY_SETTER, MH.type(void.class, Object.class, type.parameterType(1))); 11.24 - if (type.parameterCount() == 3) { 11.25 - method = MH.dropArguments(method, 2, type.parameterType(2)); 11.26 - } 11.27 - return new GuardedInvocation(method, guard); 11.28 - } 11.29 11.30 if(desc.getNameTokenCount() > 2) { 11.31 final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); 11.32 @@ -102,7 +92,7 @@ 11.33 if(find == null) { 11.34 // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it. 11.35 return null; 11.36 - } else if (find.isInherited() && !find.getProperty().hasGetterFunction(find.getOwner())) { 11.37 + } else if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) { 11.38 // If property is found in the prototype object bind the method handle directly to 11.39 // the proto filter instead of going through wrapper instantiation below. 11.40 final ScriptObject proto = wrappedReceiver.getProto();
12.1 --- a/test/src/jdk/nashorn/api/scripting/ScopeTest.java Thu Sep 11 17:12:38 2014 +0200 12.2 +++ b/test/src/jdk/nashorn/api/scripting/ScopeTest.java Thu Sep 11 18:04:54 2014 +0200 12.3 @@ -407,6 +407,75 @@ 12.4 Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context"); 12.5 } 12.6 12.7 + 12.8 + /** 12.9 + * Test multi-threaded access to prototype user accessor properties for shared script classes with multiple globals. 12.10 + */ 12.11 + @Test 12.12 + public static void multiThreadedAccessorTest() throws ScriptException, InterruptedException { 12.13 + final ScriptEngineManager m = new ScriptEngineManager(); 12.14 + final ScriptEngine e = m.getEngineByName("nashorn"); 12.15 + final Bindings b = e.createBindings(); 12.16 + final ScriptContext origContext = e.getContext(); 12.17 + final ScriptContext newCtxt = new SimpleScriptContext(); 12.18 + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 12.19 + 12.20 + e.eval("Object.defineProperty(Object.prototype, 'foo', { get: function() 'original context' })", origContext); 12.21 + e.eval("Object.defineProperty(Object.prototype, 'foo', { get: function() 'new context', configurable: true })", newCtxt); 12.22 + final String sharedScript = "({}).foo"; 12.23 + 12.24 + final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 12.25 + final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); 12.26 + t1.start(); 12.27 + t2.start(); 12.28 + t1.join(); 12.29 + t2.join(); 12.30 + 12.31 + final Object obj3 = e.eval("delete Object.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt); 12.32 + assertEquals(obj3, "newer context"); 12.33 + final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 12.34 + final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); 12.35 + 12.36 + t3.start(); 12.37 + t4.start(); 12.38 + t3.join(); 12.39 + t4.join(); 12.40 + } 12.41 + 12.42 + /** 12.43 + * Test multi-threaded access to primitive prototype user accessor properties for shared script classes with multiple globals. 12.44 + */ 12.45 + @Test 12.46 + public static void multiThreadedPrimitiveAccessorTest() throws ScriptException, InterruptedException { 12.47 + final ScriptEngineManager m = new ScriptEngineManager(); 12.48 + final ScriptEngine e = m.getEngineByName("nashorn"); 12.49 + final Bindings b = e.createBindings(); 12.50 + final ScriptContext origContext = e.getContext(); 12.51 + final ScriptContext newCtxt = new SimpleScriptContext(); 12.52 + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 12.53 + 12.54 + e.eval("Object.defineProperty(String.prototype, 'foo', { get: function() 'original context' })", origContext); 12.55 + e.eval("Object.defineProperty(String.prototype, 'foo', { get: function() 'new context' })", newCtxt); 12.56 + final String sharedScript = "''.foo"; 12.57 + 12.58 + final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 12.59 + final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); 12.60 + t1.start(); 12.61 + t2.start(); 12.62 + t1.join(); 12.63 + t2.join(); 12.64 + 12.65 + final Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt); 12.66 + assertEquals(obj3, "newer context"); 12.67 + final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 12.68 + final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); 12.69 + 12.70 + t3.start(); 12.71 + t4.start(); 12.72 + t3.join(); 12.73 + t4.join(); 12.74 + } 12.75 + 12.76 /** 12.77 * Test multi-threaded scope function invocation for shared script classes with multiple globals. 12.78 */