8199443: Nashorn multithread bottleneck with "use strict"
authorhannesw
Fri, 16 Mar 2018 14:56:54 +0100
changeset 49257 82f763a9cc22
parent 49256 ca2780cd2056
child 49259 ff7c335430d4
8199443: Nashorn multithread bottleneck with "use strict" Reviewed-by: jlaskey, sundar
src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/Lookup.java
src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeStrictArguments.java
src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java
src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/Lookup.java	Fri Mar 16 13:02:42 2018 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/Lookup.java	Fri Mar 16 14:56:54 2018 +0100
@@ -56,11 +56,8 @@
     /** Method handle to the empty setter */
     public static final MethodHandle EMPTY_SETTER = findOwnMH("emptySetter", void.class, Object.class, Object.class);
 
-    /** Method handle to a getter that only throws type error */
-    public static final MethodHandle TYPE_ERROR_THROWER_GETTER = findOwnMH("typeErrorThrowerGetter", Object.class, Object.class);
-
-    /** Method handle to a setter that only throws type error */
-    public static final MethodHandle TYPE_ERROR_THROWER_SETTER = findOwnMH("typeErrorThrowerSetter", void.class, Object.class, Object.class);
+    /** Method handle to a getter or setter that only throws type error */
+    public static final MethodHandle TYPE_ERROR_THROWER = findOwnMH("typeErrorThrower", Object.class, Object.class);
 
     /** Method handle to the most generic of getters, the one that returns an Object */
     public static final MethodType GET_OBJECT_TYPE = MH.type(Object.class, Object.class);
@@ -114,17 +111,7 @@
      * @param self  self reference
      * @return undefined (but throws error before return point)
      */
-    public static Object typeErrorThrowerGetter(final Object self) {
-        throw typeError("strict.getter.setter.poison", ScriptRuntime.safeToString(self));
-    }
-
-    /**
-     * Getter function that always throws type error
-     *
-     * @param self  self reference
-     * @param value (ignored)
-     */
-    public static void typeErrorThrowerSetter(final Object self, final Object value) {
+    public static Object typeErrorThrower(final Object self) {
         throw typeError("strict.getter.setter.poison", ScriptRuntime.safeToString(self));
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Fri Mar 16 13:02:42 2018 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Fri Mar 16 14:56:54 2018 +0100
@@ -2978,7 +2978,7 @@
         anon.deleteOwnProperty(anon.getMap().findProperty("prototype"));
 
         // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3
-        this.typeErrorThrower = ScriptFunction.createBuiltin("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER);
+        this.typeErrorThrower = ScriptFunction.createBuiltin("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER);
         typeErrorThrower.preventExtensions();
 
         // now initialize Object
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeStrictArguments.java	Fri Mar 16 13:02:42 2018 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeStrictArguments.java	Fri Mar 16 14:56:54 2018 +0100
@@ -79,9 +79,8 @@
         final ScriptFunction func = Global.instance().getTypeErrorThrower();
         // We have to fill user accessor functions late as these are stored
         // in this object rather than in the PropertyMap of this object.
-        final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
-        initUserAccessors("caller", flags, func, func);
-        initUserAccessors("callee", flags, func, func);
+        initUserAccessors("caller", func, func);
+        initUserAccessors("callee", func, func);
 
         setArray(ArrayData.allocate(values));
         this.length = values.length;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Fri Mar 16 13:02:42 2018 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Fri Mar 16 14:56:54 2018 +0100
@@ -137,8 +137,8 @@
         final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
         PropertyMap newMap = map;
         // Need to add properties directly to map since slots are assigned speculatively by newUserAccessors.
-        newMap = newMap.addPropertyNoHistory(map.newUserAccessors("arguments", flags));
-        newMap = newMap.addPropertyNoHistory(map.newUserAccessors("caller", flags));
+        newMap = newMap.addPropertyNoHistory(newMap.newUserAccessors("arguments", flags));
+        newMap = newMap.addPropertyNoHistory(newMap.newUserAccessors("caller", flags));
         return newMap;
     }
 
@@ -215,8 +215,8 @@
         assert objectSpill == null;
         if (isStrict() || isBoundFunction()) {
             final ScriptFunction typeErrorThrower = global.getTypeErrorThrower();
-            initUserAccessors("arguments", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
-            initUserAccessors("caller", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
+            initUserAccessors("arguments", typeErrorThrower, typeErrorThrower);
+            initUserAccessors("caller", typeErrorThrower, typeErrorThrower);
         }
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Mar 16 13:02:42 2018 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Mar 16 14:56:54 2018 +0100
@@ -962,24 +962,19 @@
     /**
      * Fast initialization functions for ScriptFunctions that are strict, to avoid
      * creating setters that probably aren't used. Inject directly into the spill pool
-     * the defaults for "arguments" and "caller"
+     * the defaults for "arguments" and "caller", asserting the property is already
+     * defined in the map.
      *
-     * @param key           property key
-     * @param propertyFlags flags
-     * @param getter        getter for {@link UserAccessorProperty}, null if not present or N/A
-     * @param setter        setter for {@link UserAccessorProperty}, null if not present or N/A
+     * @param key     property key
+     * @param getter  getter for {@link UserAccessorProperty}
+     * @param setter  setter for {@link UserAccessorProperty}
      */
-    protected final void initUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
-        final PropertyMap oldMap = getMap();
-        final int slot = oldMap.getFreeSpillSlot();
-        ensureSpillSize(slot);
-        objectSpill[slot] = new UserAccessorProperty.Accessors(getter, setter);
-        Property    newProperty;
-        PropertyMap newMap;
-        do {
-            newProperty = new UserAccessorProperty(key, propertyFlags, slot);
-            newMap = oldMap.addProperty(newProperty);
-        } while (!compareAndSetMap(oldMap, newMap));
+    protected final void initUserAccessors(final String key, final ScriptFunction getter, final ScriptFunction setter) {
+        final PropertyMap map = getMap();
+        final Property property = map.findProperty(key);
+        assert property instanceof UserAccessorProperty;
+        ensureSpillSize(property.getSlot());
+        objectSpill[property.getSlot()] = new UserAccessorProperty.Accessors(getter, setter);
     }
 
     /**