8199443: Nashorn multithread bottleneck with "use strict"

Reviewed-by: jlaskey, sundar
This commit is contained in:
Hannes Wallnöfer 2018-03-16 14:56:54 +01:00
parent 19ea0009a6
commit 2ca067436f
5 changed files with 21 additions and 40 deletions
src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal

@ -56,11 +56,8 @@ public final class Lookup {
/** 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 @@ public final class Lookup {
* @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));
}

@ -2978,7 +2978,7 @@ public final class Global extends Scope {
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

@ -79,9 +79,8 @@ public final class NativeStrictArguments extends ScriptObject {
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;

@ -137,8 +137,8 @@ public class ScriptFunction extends ScriptObject {
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 @@ public class ScriptFunction extends ScriptObject {
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);
}
}

@ -962,24 +962,19 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
/**
* 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);
}
/**