8057021: UserAccessorProperty guards fail with multiple globals

Thu, 11 Sep 2014 18:04:54 +0200

author
hannesw
date
Thu, 11 Sep 2014 18:04:54 +0200
changeset 1006
e94bfa3c6c6c
parent 1005
2cad9bf911a4
child 1007
39ba6d257e4c

8057021: UserAccessorProperty guards fail with multiple globals
Reviewed-by: attila, lagergren

src/jdk/nashorn/internal/objects/Global.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeBoolean.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeJSAdapter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeNumber.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeString.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/FindProperty.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/SetMethodCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/UserAccessorProperty.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java file | annotate | diff | comparison | revisions
test/src/jdk/nashorn/api/scripting/ScopeTest.java file | annotate | diff | comparison | revisions
     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       */

mercurial