8057021: UserAccessorProperty guards fail with multiple globals
authorhannesw
Wed, 10 Sep 2014 15:19:26 +0200
changeset 26508 b40ef4386b01
parent 26507 9d6e3ec59878
child 26509 00cc73c2862d
8057021: UserAccessorProperty guards fail with multiple globals Reviewed-by: attila, lagergren
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Wed Sep 10 15:19:26 2014 +0200
@@ -631,6 +631,24 @@
     }
 
     /**
+     * Returns a method handle that creates a wrapper object for a JS primitive value.
+     *
+     * @param self receiver object
+     * @return method handle to create wrapper objects for primitive receiver
+     */
+    public static MethodHandle getPrimitiveWrapFilter(final Object self) {
+        if (self instanceof String || self instanceof ConsString) {
+            return NativeString.WRAPFILTER;
+        } else if (self instanceof Number) {
+            return NativeNumber.WRAPFILTER;
+        } else if (self instanceof Boolean) {
+            return NativeBoolean.WRAPFILTER;
+        }
+        throw new IllegalArgumentException("Unsupported primitive: " + self);
+    }
+
+
+    /**
      * Create a new empty script object
      *
      * @return the new ScriptObject
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java	Wed Sep 10 15:19:26 2014 +0200
@@ -51,9 +51,9 @@
 public final class NativeBoolean extends ScriptObject {
     private final boolean value;
 
-    // Method handle to create an object wrapper for a primitive boolean
-    private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class));
-    // Method handle to retrieve the Boolean prototype object
+    /** Method handle to create an object wrapper for a primitive boolean. */
+    static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class));
+    /** Method handle to retrieve the Boolean prototype object. */
     private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
 
     // initialized by nasgen
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java	Wed Sep 10 15:19:26 2014 +0200
@@ -28,6 +28,7 @@
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -697,7 +698,7 @@
                 if (methodHandle != null) {
                     return new GuardedInvocation(
                             methodHandle,
-                            testJSAdaptor(adaptee, findData.getGetter(Object.class, UnwarrantedOptimismException.INVALID_PROGRAM_POINT), findData.getOwner(), func),
+                            testJSAdaptor(adaptee, findData.getGetter(Object.class, INVALID_PROGRAM_POINT, null), findData.getOwner(), func),
                             adaptee.getProtoSwitchPoint(hook, findData.getOwner()));
                 }
              }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java	Wed Sep 10 15:19:26 2014 +0200
@@ -57,9 +57,9 @@
 @ScriptClass("Number")
 public final class NativeNumber extends ScriptObject {
 
-    // Method handle to create an object wrapper for a primitive number
-    private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class));
-    // Method handle to retrieve the Number prototype object
+    /** Method handle to create an object wrapper for a primitive number. */
+    static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class));
+    /** Method handle to retrieve the Number prototype object. */
     private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
 
     /** ECMA 15.7.3.2 largest positive finite value */
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java	Wed Sep 10 15:19:26 2014 +0200
@@ -71,9 +71,9 @@
 
     private final CharSequence value;
 
-    // Method handle to create an object wrapper for a primitive string
-    private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class));
-    // Method handle to retrieve the String prototype object
+    /** Method handle to create an object wrapper for a primitive string */
+    static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class));
+    /** Method handle to retrieve the String prototype object */
     private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
 
     // initialized by nasgen
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Wed Sep 10 15:19:26 2014 +0200
@@ -196,11 +196,11 @@
         }
 
         @Override
-        public void storeScript(final String classInfoFile, final Source source, final String mainClassName,
+        public void storeScript(final String cacheKey, final Source source, final String mainClassName,
                                 final Map<String,byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers,
                                 final Object[] constants, final int compilationId) {
             if (context.codeStore != null) {
-                context.codeStore.storeScript(classInfoFile, source, mainClassName, classBytes, initializers, constants, compilationId);
+                context.codeStore.storeScript(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId);
             }
         }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java	Wed Sep 10 15:19:26 2014 +0200
@@ -29,7 +29,9 @@
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
 
 import java.lang.invoke.MethodHandle;
+import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
+import jdk.nashorn.internal.objects.Global;
 
 /**
  * This class represents the result from a find property search.
@@ -79,25 +81,17 @@
      * @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic
      * @return method handle for the getter
      */
-    public MethodHandle getGetter(final Class<?> type, final int programPoint) {
+    public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) {
         final MethodHandle getter;
         if (isValid(programPoint)) {
             getter = property.getOptimisticGetter(type, programPoint);
         } else {
             getter = property.getGetter(type);
         }
-        return getGetterInner(getter);
-    }
-
-    private MethodHandle getGetterInner(final MethodHandle getter) {
         if (property instanceof UserAccessorProperty) {
-            final UserAccessorProperty uc        = (UserAccessorProperty)property;
-            final ScriptObject         owner     = getOwner();
-            final ScriptObject         container = (owner != null) ? owner : self;
-            return MH.insertArguments(getter, 0, uc.getAccessors(container));
+            return insertAccessorsGetter((UserAccessorProperty) property, request, getter);
         }
         return getter;
-
     }
 
     /**
@@ -111,18 +105,31 @@
      *
      * @return method handle for the getter
      */
-    public MethodHandle getSetter(final Class<?> type, final boolean strict) {
-        final MethodHandle setter = property.getSetter(type, getOwner().getMap());
+    public MethodHandle getSetter(final Class<?> type, final boolean strict, final LinkRequest request) {
+        MethodHandle setter = property.getSetter(type, getOwner().getMap());
         if (property instanceof UserAccessorProperty) {
-            final UserAccessorProperty uc        = (UserAccessorProperty)property;
-            final ScriptObject         owner     = getOwner();
-            final ScriptObject         container = (owner != null) ? owner : self;
-            return MH.insertArguments(setter, 0, uc.getAccessors(container), strict ? property.getKey() : null);
+            setter =  MH.insertArguments(setter, 1, strict ? property.getKey() : null);
+            return insertAccessorsGetter((UserAccessorProperty) property, request, setter);
         }
 
         return setter;
     }
 
+    // Fold an accessor getter into the method handle of a user accessor property.
+    private MethodHandle insertAccessorsGetter(final UserAccessorProperty uap, final LinkRequest request, final MethodHandle mh) {
+        MethodHandle superGetter = uap.getAccessorsGetter();
+        if (isInherited()) {
+            superGetter = ScriptObject.addProtoFilter(superGetter, getProtoChainLength());
+        }
+        if (request != null && !(request.getReceiver() instanceof ScriptObject)) {
+            final MethodHandle wrapFilter = Global.getPrimitiveWrapFilter(request.getReceiver());
+            superGetter = MH.filterArguments(superGetter, 0, wrapFilter.asType(wrapFilter.type().changeReturnType(superGetter.type().parameterType(0))));
+        }
+        superGetter = MH.asType(superGetter, superGetter.type().changeParameterType(0, Object.class));
+
+        return MH.foldArguments(mh, superGetter);
+    }
+
     /**
      * Return the {@code ScriptObject} owning of the property:  this means the prototype.
      * @return owner of property
@@ -136,7 +143,7 @@
      * @return appropriate receiver
      */
     public ScriptObject getGetterReceiver() {
-        return property != null && property.hasGetterFunction(prototype) ? self : prototype;
+        return property != null && property instanceof UserAccessorProperty ? self : prototype;
     }
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Sep 10 15:19:26 2014 +0200
@@ -1050,7 +1050,7 @@
     }
 
     private static int getIntValue(final FindProperty find, final int programPoint) {
-        final MethodHandle getter = find.getGetter(int.class, programPoint);
+        final MethodHandle getter = find.getGetter(int.class, programPoint, null);
         if (getter != null) {
             try {
                 return (int)getter.invokeExact((Object)find.getGetterReceiver());
@@ -1065,7 +1065,7 @@
     }
 
     private static long getLongValue(final FindProperty find, final int programPoint) {
-        final MethodHandle getter = find.getGetter(long.class, programPoint);
+        final MethodHandle getter = find.getGetter(long.class, programPoint, null);
         if (getter != null) {
             try {
                 return (long)getter.invokeExact((Object)find.getGetterReceiver());
@@ -1080,7 +1080,7 @@
     }
 
     private static double getDoubleValue(final FindProperty find, final int programPoint) {
-        final MethodHandle getter = find.getGetter(double.class, programPoint);
+        final MethodHandle getter = find.getGetter(double.class, programPoint, null);
         if (getter != null) {
             try {
                 return (double)getter.invokeExact((Object)find.getGetterReceiver());
@@ -1983,7 +1983,7 @@
                 NashornCallSiteDescriptor.getProgramPoint(desc) :
                 UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 
-        mh = find.getGetter(returnType, programPoint);
+        mh = find.getGetter(returnType, programPoint, request);
         // Get the appropriate guard for this callsite and property.
         final MethodHandle guard = NashornGuards.getGuard(this, property, desc, explicitInstanceOfCheck);
         final ScriptObject owner = find.getOwner();
@@ -1995,8 +1995,9 @@
             mh = Lookup.emptyGetter(returnType);
             protoSwitchPoint = getProtoSwitchPoint(name, owner);
         } else if (!find.isSelf()) {
-            assert mh.type().returnType().equals(returnType) : "returntype mismatch for getter " + mh.type().returnType() + " != " + returnType;
-            if (!property.hasGetterFunction(owner)) {
+            assert mh.type().returnType().equals(returnType) :
+                    "return type mismatch for getter " + mh.type().returnType() + " != " + returnType;
+            if (!(property instanceof UserAccessorProperty)) {
                 // Add a filter that replaces the self object with the prototype owning the property.
                 mh = addProtoFilter(mh, find.getProtoChainLength());
             }
@@ -2167,7 +2168,7 @@
             }
         }
 
-        final GuardedInvocation inv = new SetMethodCreator(this, find, desc, explicitInstanceOfCheck).createGuardedInvocation();
+        final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation();
 
         final GuardedInvocation cinv = Global.getConstants().findSetMethod(find, this, inv, desc, request);
         if (cinv != null) {
@@ -2320,13 +2321,13 @@
                         find.isSelf()?
                             getKnownFunctionPropertyGuardSelf(
                                 getMap(),
-                                find.getGetter(Object.class, INVALID_PROGRAM_POINT),
+                                find.getGetter(Object.class, INVALID_PROGRAM_POINT, request),
                                 func)
                             :
                             //TODO this always does a scriptobject check
                             getKnownFunctionPropertyGuardProto(
                                 getMap(),
-                                find.getGetter(Object.class, INVALID_PROGRAM_POINT),
+                                find.getGetter(Object.class, INVALID_PROGRAM_POINT, request),
                                 find.getProtoChainLength(),
                                 func),
                         getProtoSwitchPoint(NO_SUCH_PROPERTY_NAME, find.getOwner()),
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java	Wed Sep 10 15:19:26 2014 +0200
@@ -33,6 +33,7 @@
 import java.lang.invoke.SwitchPoint;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import jdk.nashorn.internal.runtime.linker.NashornGuards;
 
@@ -48,7 +49,7 @@
     private final FindProperty       find;
     private final CallSiteDescriptor desc;
     private final Class<?>           type;
-    private final boolean            explicitInstanceOfCheck;
+    private final LinkRequest        request;
 
     /**
      * Creates a new property setter method creator.
@@ -56,14 +57,15 @@
      * @param find a result of a {@link ScriptObject#findProperty(String, boolean)} on the object for the property we
      * want to create a setter for. Can be null if the property does not yet exist on the object.
      * @param desc the descriptor of the call site that triggered the property setter lookup
+     * @param request the link request
      */
-    SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck) {
-        this.sobj = sobj;
-        this.map  = sobj.getMap();
-        this.find = find;
-        this.desc = desc;
-        this.type = desc.getMethodType().parameterType(1);
-        this.explicitInstanceOfCheck = explicitInstanceOfCheck;
+    SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc, final LinkRequest request) {
+        this.sobj    = sobj;
+        this.map     = sobj.getMap();
+        this.find    = find;
+        this.desc    = desc;
+        this.type    = desc.getMethodType().parameterType(1);
+        this.request = request;
 
     }
 
@@ -111,6 +113,7 @@
             // getGuard() and getException() either both return null, or neither does. The reason for that is that now
             // getGuard returns a map guard that casts its argument to ScriptObject, and if that fails, we need to
             // relink on ClassCastException.
+            final boolean explicitInstanceOfCheck = NashornGuards.explicitInstanceOfCheck(desc, request);
             return new GuardedInvocation(methodHandle, NashornGuards.getGuard(sobj, property, desc, explicitInstanceOfCheck),
                     (SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class);
         }
@@ -140,6 +143,7 @@
 
     private SetMethod createExistingPropertySetter() {
         final Property property = find.getProperty();
+        final boolean isStrict  = NashornCallSiteDescriptor.isStrict(desc);
         final MethodHandle methodHandle;
 
         if (NashornCallSiteDescriptor.isDeclaration(desc)) {
@@ -152,7 +156,7 @@
             final PropertyMap oldMap = getMap();
             final Property newProperty = property.removeFlags(Property.NEEDS_DECLARATION);
             final PropertyMap newMap = oldMap.replaceProperty(property, newProperty);
-            final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
+            final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, isStrict, request);
             final MethodHandle slowSetter = MH.insertArguments(ScriptObject.DECLARE_AND_SET, 1, getName()).asType(fastSetter.type());
 
             // cas map used as guard, if true that means we can do the set fast
@@ -161,14 +165,14 @@
             casMap = MH.asType(casMap, casMap.type().changeParameterType(0, Object.class));
             methodHandle = MH.guardWithTest(casMap, fastSetter, slowSetter);
         } else {
-            methodHandle = find.getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
+            methodHandle = find.getSetter(type, isStrict, request);
         }
 
         assert methodHandle != null;
         assert property     != null;
 
         final MethodHandle boundHandle;
-        if (!property.hasSetterFunction(find.getOwner()) && find.isInherited()) {
+        if (!(property instanceof UserAccessorProperty) && find.isInherited()) {
             boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength());
         } else {
             boundHandle = methodHandle;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Wed Sep 10 15:19:26 2014 +0200
@@ -34,8 +34,8 @@
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 import java.util.concurrent.Callable;
-import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.lookup.Lookup;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 
@@ -48,7 +48,7 @@
 
     private static final long serialVersionUID = -5928687246526840321L;
 
-    static class Accessors {
+    static final class Accessors {
         Object getter;
         Object setter;
 
@@ -67,20 +67,20 @@
         }
     }
 
+    private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
     /** Getter method handle */
-    private final static CompilerConstants.Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
-            "userAccessorGetter", Object.class, Accessors.class, Object.class);
+    private final static MethodHandle INVOKE_GETTER_ACCESSOR = findOwnMH_S("invokeGetterAccessor", Object.class, Accessors.class, Object.class);
 
     /** Setter method handle */
-    private final static CompilerConstants.Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
-            "userAccessorSetter", void.class, Accessors.class, String.class, Object.class, Object.class);
+    private final static MethodHandle INVOKE_SETTER_ACCESSOR = findOwnMH_S("invokeSetterAccessor", void.class, Accessors.class, String.class, Object.class, Object.class);
 
     /** Dynamic invoker for getter */
-    private static final Object INVOKE_UA_GETTER = new Object();
+    private static final Object GETTER_INVOKER_KEY = new Object();
 
     private static MethodHandle getINVOKE_UA_GETTER() {
 
-        return Context.getGlobal().getDynamicInvoker(INVOKE_UA_GETTER,
+        return Context.getGlobal().getDynamicInvoker(GETTER_INVOKER_KEY,
                 new Callable<MethodHandle>() {
                     @Override
                     public MethodHandle call() {
@@ -91,10 +91,10 @@
     }
 
     /** Dynamic invoker for setter */
-    private static Object INVOKE_UA_SETTER = new Object();
+    private static Object SETTER_INVOKER_KEY = new Object();
 
     private static MethodHandle getINVOKE_UA_SETTER() {
-        return Context.getGlobal().getDynamicInvoker(INVOKE_UA_SETTER,
+        return Context.getGlobal().getDynamicInvoker(SETTER_INVOKER_KEY,
                 new Callable<MethodHandle>() {
                     @Override
                     public MethodHandle call() {
@@ -190,7 +190,7 @@
 
     @Override
     public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
-        return userAccessorGetter(getAccessors((owner != null) ? owner : self), self);
+        return invokeGetterAccessor(getAccessors((owner != null) ? owner : self), self);
     }
 
     @Override
@@ -210,13 +210,13 @@
 
     @Override
     public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
-        userAccessorSetter(getAccessors((owner != null) ? owner : self), strict ? getKey() : null, self, value);
+        invokeSetterAccessor(getAccessors((owner != null) ? owner : self), strict ? getKey() : null, self, value);
     }
 
     @Override
     public MethodHandle getGetter(final Class<?> type) {
         //this returns a getter on the format (Accessors, Object receiver)
-        return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type);
+        return Lookup.filterReturnType(INVOKE_GETTER_ACCESSOR, type);
     }
 
     @Override
@@ -260,7 +260,7 @@
 
     @Override
     public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
-        return USER_ACCESSOR_SETTER.methodHandle();
+        return INVOKE_SETTER_ACCESSOR;
     }
 
     @Override
@@ -269,11 +269,21 @@
         return (value instanceof ScriptFunction) ? (ScriptFunction)value : null;
     }
 
+    /**
+     * Get the getter for the {@code Accessors} object.
+     * This is the the super {@code Object} type getter with {@code Accessors} return type.
+     *
+     * @return The getter handle for the Accessors
+     */
+    MethodHandle getAccessorsGetter() {
+        return super.getGetter(Object.class).asType(MethodType.methodType(Accessors.class, Object.class));
+    }
+
     // User defined getter and setter are always called by "dyn:call". Note that the user
     // getter/setter may be inherited. If so, proto is bound during lookup. In either
     // inherited or self case, slot is also bound during lookup. Actual ScriptFunction
     // to be called is retrieved everytime and applied.
-    static Object userAccessorGetter(final Accessors gs, final Object self) {
+    private static Object invokeGetterAccessor(final Accessors gs, final Object self) {
         final Object func = gs.getter;
         if (func instanceof ScriptFunction) {
             try {
@@ -288,7 +298,7 @@
         return UNDEFINED;
     }
 
-    static void userAccessorSetter(final Accessors gs, final String name, final Object self, final Object value) {
+    private static void invokeSetterAccessor(final Accessors gs, final String name, final Object self, final Object value) {
         final Object func = gs.setter;
         if (func instanceof ScriptFunction) {
             try {
@@ -303,4 +313,8 @@
         }
     }
 
+    private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
+        return MH.findStatic(LOOKUP, UserAccessorProperty.class, name, MH.type(rtype, types));
+    }
+
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Wed Sep 10 15:19:26 2014 +0200
@@ -32,11 +32,10 @@
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
-import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
 import jdk.internal.dynalink.support.Guards;
-import jdk.nashorn.internal.lookup.Lookup;
 import jdk.nashorn.internal.runtime.FindProperty;
 import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.UserAccessorProperty;
 
 /**
  * Implements lookup of methods to link for dynamic operations on JavaScript primitive values (booleans, strings, and
@@ -86,15 +85,6 @@
                                                     final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
                                                     final MethodHandle protoFilter) {
         final CallSiteDescriptor desc = request.getCallSiteDescriptor();
-        final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
-        if ("setProp".equals(operator) || "setElem".equals(operator)) {
-            final MethodType type = desc.getMethodType();
-            MethodHandle method = MH.asType(Lookup.EMPTY_SETTER, MH.type(void.class, Object.class, type.parameterType(1)));
-            if (type.parameterCount() == 3) {
-                method = MH.dropArguments(method, 2, type.parameterType(2));
-            }
-            return new GuardedInvocation(method, guard);
-        }
 
         if(desc.getNameTokenCount() > 2) {
             final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
@@ -102,7 +92,7 @@
             if(find == null) {
                 // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
                 return null;
-            } else if (find.isInherited() && !find.getProperty().hasGetterFunction(find.getOwner())) {
+            } else if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
                 // If property is found in the prototype object bind the method handle directly to
                 // the proto filter instead of going through wrapper instantiation below.
                 final ScriptObject proto = wrappedReceiver.getProto();
--- a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java	Wed Sep 10 13:08:58 2014 +0200
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java	Wed Sep 10 15:19:26 2014 +0200
@@ -407,6 +407,75 @@
         Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context");
     }
 
+
+    /**
+     * Test multi-threaded access to prototype user accessor properties for shared script classes with multiple globals.
+     */
+    @Test
+    public static void multiThreadedAccessorTest() throws ScriptException, InterruptedException {
+        final ScriptEngineManager m = new ScriptEngineManager();
+        final ScriptEngine e = m.getEngineByName("nashorn");
+        final Bindings b = e.createBindings();
+        final ScriptContext origContext = e.getContext();
+        final ScriptContext newCtxt = new SimpleScriptContext();
+        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+        e.eval("Object.defineProperty(Object.prototype, 'foo', { get: function() 'original context' })", origContext);
+        e.eval("Object.defineProperty(Object.prototype, 'foo', { get: function() 'new context', configurable: true })", newCtxt);
+        final String sharedScript = "({}).foo";
+
+        final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
+        t1.start();
+        t2.start();
+        t1.join();
+        t2.join();
+
+        final Object obj3 = e.eval("delete Object.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt);
+        assertEquals(obj3, "newer context");
+        final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+        final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
+
+        t3.start();
+        t4.start();
+        t3.join();
+        t4.join();
+    }
+
+    /**
+     * Test multi-threaded access to primitive prototype user accessor properties for shared script classes with multiple globals.
+     */
+    @Test
+    public static void multiThreadedPrimitiveAccessorTest() throws ScriptException, InterruptedException {
+        final ScriptEngineManager m = new ScriptEngineManager();
+        final ScriptEngine e = m.getEngineByName("nashorn");
+        final Bindings b = e.createBindings();
+        final ScriptContext origContext = e.getContext();
+        final ScriptContext newCtxt = new SimpleScriptContext();
+        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+        e.eval("Object.defineProperty(String.prototype, 'foo', { get: function() 'original context' })", origContext);
+        e.eval("Object.defineProperty(String.prototype, 'foo', { get: function() 'new context' })", newCtxt);
+        final String sharedScript = "''.foo";
+
+        final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
+        t1.start();
+        t2.start();
+        t1.join();
+        t2.join();
+
+        final Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt);
+        assertEquals(obj3, "newer context");
+        final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+        final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
+
+        t3.start();
+        t4.start();
+        t3.join();
+        t4.join();
+    }
+
     /**
      * Test multi-threaded scope function invocation for shared script classes with multiple globals.
      */