# HG changeset patch # User hannesw # Date 1410451494 -7200 # Node ID e94bfa3c6c6cdab3697555751d17bc2c0aebdd10 # Parent 2cad9bf911a42e9ee17f7b625fb77b3e509985c2 8057021: UserAccessorProperty guards fail with multiple globals Reviewed-by: attila, lagergren diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/objects/Global.java --- a/src/jdk/nashorn/internal/objects/Global.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/Global.java Thu Sep 11 18:04:54 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 diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/objects/NativeBoolean.java --- a/src/jdk/nashorn/internal/objects/NativeBoolean.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeBoolean.java Thu Sep 11 18:04:54 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 diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/objects/NativeJSAdapter.java --- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java Thu Sep 11 18:04:54 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())); } } diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/objects/NativeNumber.java --- a/src/jdk/nashorn/internal/objects/NativeNumber.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeNumber.java Thu Sep 11 18:04:54 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 */ diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/objects/NativeString.java --- a/src/jdk/nashorn/internal/objects/NativeString.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeString.java Thu Sep 11 18:04:54 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 diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/runtime/Context.java --- a/src/jdk/nashorn/internal/runtime/Context.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/Context.java Thu Sep 11 18:04:54 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 classBytes, final Map 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); } } diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/runtime/FindProperty.java --- a/src/jdk/nashorn/internal/runtime/FindProperty.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/FindProperty.java Thu Sep 11 18:04:54 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; } /** diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/runtime/ScriptObject.java --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu Sep 11 18:04:54 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()), diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/runtime/SetMethodCreator.java --- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Thu Sep 11 18:04:54 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; diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/runtime/UserAccessorProperty.java --- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Thu Sep 11 18:04:54 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() { @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() { @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)); + } + } diff -r 2cad9bf911a4 -r e94bfa3c6c6c src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java --- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Thu Sep 11 17:12:38 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Thu Sep 11 18:04:54 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(); diff -r 2cad9bf911a4 -r e94bfa3c6c6c test/src/jdk/nashorn/api/scripting/ScopeTest.java --- a/test/src/jdk/nashorn/api/scripting/ScopeTest.java Thu Sep 11 17:12:38 2014 +0200 +++ b/test/src/jdk/nashorn/api/scripting/ScopeTest.java Thu Sep 11 18:04:54 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. */