diff --git a/benchmarks/src/jmh/java/org/mozilla/javascript/benchmarks/SlotMapBenchmark.java b/benchmarks/src/jmh/java/org/mozilla/javascript/benchmarks/SlotMapBenchmark.java
index a841daf131..43ee5955cd 100644
--- a/benchmarks/src/jmh/java/org/mozilla/javascript/benchmarks/SlotMapBenchmark.java
+++ b/benchmarks/src/jmh/java/org/mozilla/javascript/benchmarks/SlotMapBenchmark.java
@@ -44,7 +44,7 @@ public void create() {
public Object embeddedInsert1Key(EmbeddedState state) {
Slot newSlot = null;
for (int i = 0; i < 100; i++) {
- newSlot = state.emptyMap.modify(state.randomKeys[i], 0, 0);
+ newSlot = state.emptyMap.modify(null, state.randomKeys[i], 0, 0);
}
if (newSlot == null) {
throw new AssertionError();
@@ -109,7 +109,7 @@ public void create() {
public Object hashInsert1Key(HashState state) {
Slot newSlot = null;
for (int i = 0; i < 100; i++) {
- newSlot = state.emptyMap.modify(state.randomKeys[i], 0, 0);
+ newSlot = state.emptyMap.modify(null, state.randomKeys[i], 0, 0);
}
if (newSlot == null) {
throw new AssertionError();
@@ -156,7 +156,7 @@ private static String makeRandomString() {
/** Insert a random key and value into the map */
private static String insertRandomEntry(SlotMap map) {
String key = makeRandomString();
- Slot slot = map.modify(key, 0, 0);
+ Slot slot = map.modify(null, key, 0, 0);
slot.setValue(key, null, null);
return key;
}
diff --git a/rhino-xml/src/main/java/module-info.java b/rhino-xml/src/main/java/module-info.java
index f88109a202..8ce70d199a 100644
--- a/rhino-xml/src/main/java/module-info.java
+++ b/rhino-xml/src/main/java/module-info.java
@@ -1,6 +1,9 @@
module org.mozilla.javascript.xml {
exports org.mozilla.javascript.xmlimpl;
+ provides org.mozilla.javascript.xml.XMLLoader with
+ org.mozilla.javascript.xmlimpl.XMLLoaderImpl;
+
requires transitive org.mozilla.rhino;
requires transitive java.xml;
}
diff --git a/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLLoaderImpl.java b/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLLoaderImpl.java
new file mode 100644
index 0000000000..553153e280
--- /dev/null
+++ b/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLLoaderImpl.java
@@ -0,0 +1,22 @@
+package org.mozilla.javascript.xmlimpl;
+
+import org.mozilla.javascript.LazilyLoadedCtor;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.xml.XMLLib;
+import org.mozilla.javascript.xml.XMLLoader;
+
+public class XMLLoaderImpl implements XMLLoader {
+ @Override
+ public void load(ScriptableObject scope, boolean sealed) {
+ String implClass = XMLLibImpl.class.getName();
+ new LazilyLoadedCtor(scope, "XML", implClass, sealed, true);
+ new LazilyLoadedCtor(scope, "XMLList", implClass, sealed, true);
+ new LazilyLoadedCtor(scope, "Namespace", implClass, sealed, true);
+ new LazilyLoadedCtor(scope, "QName", implClass, sealed, true);
+ }
+
+ @Override
+ public XMLLib.Factory getFactory() {
+ return XMLLib.Factory.create(XMLLibImpl.class.getName());
+ }
+}
diff --git a/rhino-xml/src/main/resources/META-INF/services/org.mozilla.javascript.xml.XMLLoader b/rhino-xml/src/main/resources/META-INF/services/org.mozilla.javascript.xml.XMLLoader
new file mode 100644
index 0000000000..48091e4ca6
--- /dev/null
+++ b/rhino-xml/src/main/resources/META-INF/services/org.mozilla.javascript.xml.XMLLoader
@@ -0,0 +1 @@
+org.mozilla.javascript.xmlimpl.XMLLoaderImpl
diff --git a/rhino/src/main/java/module-info.java b/rhino/src/main/java/module-info.java
index 1d33d575b7..32b36988d2 100644
--- a/rhino/src/main/java/module-info.java
+++ b/rhino/src/main/java/module-info.java
@@ -13,6 +13,12 @@
exports org.mozilla.javascript.typedarrays;
exports org.mozilla.javascript.xml;
+ uses org.mozilla.javascript.RegExpProxy;
+ uses org.mozilla.javascript.xml.XMLLoader;
+
+ provides org.mozilla.javascript.RegExpProxy with
+ org.mozilla.javascript.regexp.RegExpImpl;
+
requires java.compiler;
requires jdk.dynalink;
requires transitive java.desktop;
diff --git a/rhino/src/main/java/org/mozilla/javascript/Context.java b/rhino/src/main/java/org/mozilla/javascript/Context.java
index e397248502..48a0af3efa 100644
--- a/rhino/src/main/java/org/mozilla/javascript/Context.java
+++ b/rhino/src/main/java/org/mozilla/javascript/Context.java
@@ -35,6 +35,7 @@
import org.mozilla.javascript.debug.DebuggableScript;
import org.mozilla.javascript.debug.Debugger;
import org.mozilla.javascript.xml.XMLLib;
+import org.mozilla.javascript.xml.XMLLoader;
/**
* This class represents the runtime context of an executing script.
@@ -2318,11 +2319,19 @@ public boolean hasFeature(int featureIndex) {
*
The default implementation uses the implementation provided by this Context
's
* {@link ContextFactory}.
*
+ *
This is no longer used in E4X -- an implementation is only provided for backward
+ * compatibility.
+ *
* @return An XMLLib.Factory. Should not return null
if {@link #FEATURE_E4X} is
* enabled. See {@link #hasFeature}.
*/
+ @Deprecated
public XMLLib.Factory getE4xImplementationFactory() {
- return getFactory().getE4xImplementationFactory();
+ XMLLoader loader = ScriptRuntime.loadOneServiceImplementation(XMLLoader.class);
+ if (loader != null) {
+ return loader.getFactory();
+ }
+ return null;
}
/**
@@ -2682,10 +2691,7 @@ private static boolean frameMatches(StackTraceElement e) {
RegExpProxy getRegExpProxy() {
if (regExpProxy == null) {
- Class> cl = Kit.classOrNull("org.mozilla.javascript.regexp.RegExpImpl");
- if (cl != null) {
- regExpProxy = (RegExpProxy) Kit.newInstanceOrNull(cl);
- }
+ regExpProxy = ScriptRuntime.loadOneServiceImplementation(RegExpProxy.class);
}
return regExpProxy;
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/ContextFactory.java b/rhino/src/main/java/org/mozilla/javascript/ContextFactory.java
index 8f5939f47e..43eef0fa4c 100644
--- a/rhino/src/main/java/org/mozilla/javascript/ContextFactory.java
+++ b/rhino/src/main/java/org/mozilla/javascript/ContextFactory.java
@@ -295,42 +295,6 @@ protected boolean hasFeature(Context cx, int featureIndex) {
throw new IllegalArgumentException(String.valueOf(featureIndex));
}
- private static boolean isDom3Present() {
- Class> nodeClass = Kit.classOrNull("org.w3c.dom.Node");
- if (nodeClass == null) return false;
- // Check to see whether DOM3 is present; use a new method defined in
- // DOM3 that is vital to our implementation
- try {
- nodeClass.getMethod("getUserData", String.class);
- return true;
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- /**
- * Provides a default {@link org.mozilla.javascript.xml.XMLLib.Factory XMLLib.Factory} to be
- * used by the Context
instances produced by this factory. See {@link
- * Context#getE4xImplementationFactory} for details.
- *
- *
May return null, in which case E4X functionality is not supported in Rhino.
- *
- *
The default implementation now prefers the DOM3 E4X implementation.
- */
- protected org.mozilla.javascript.xml.XMLLib.Factory getE4xImplementationFactory() {
- // Must provide default implementation, rather than abstract method,
- // so that past implementors of ContextFactory do not fail at runtime
- // upon invocation of this method.
- // Note that the default implementation returns null if we
- // neither have XMLBeans nor a DOM3 implementation present.
-
- if (isDom3Present()) {
- return org.mozilla.javascript.xml.XMLLib.Factory.create(
- "org.mozilla.javascript.xmlimpl.XMLLibImpl");
- }
- return null;
- }
-
/**
* Create class loader for generated classes. This method creates an instance of the default
* implementation of {@link GeneratedClassLoader}. Rhino uses this interface to load generated
diff --git a/rhino/src/main/java/org/mozilla/javascript/EmbeddedSlotMap.java b/rhino/src/main/java/org/mozilla/javascript/EmbeddedSlotMap.java
index 0214341511..6be578ba70 100644
--- a/rhino/src/main/java/org/mozilla/javascript/EmbeddedSlotMap.java
+++ b/rhino/src/main/java/org/mozilla/javascript/EmbeddedSlotMap.java
@@ -94,7 +94,7 @@ public Slot query(Object key, int index) {
* @param index index or 0 if slot holds property name.
*/
@Override
- public Slot modify(Object key, int index, int attributes) {
+ public Slot modify(SlotMapOwner owner, Object key, int index, int attributes) {
final int indexOrHash = (key != null ? key.hashCode() : index);
Slot slot;
@@ -110,13 +110,12 @@ public Slot modify(Object key, int index, int attributes) {
}
}
- // A new slot has to be inserted.
Slot newSlot = new Slot(key, index, attributes);
- createNewSlot(newSlot);
+ createNewSlot(owner, newSlot);
return newSlot;
}
- private void createNewSlot(Slot newSlot) {
+ private void createNewSlot(SlotMapOwner owner, Slot newSlot) {
if (count == 0) {
// Always throw away old slots if any on empty insert.
slots = new Slot[INITIAL_SLOT_SIZE];
@@ -125,6 +124,11 @@ private void createNewSlot(Slot newSlot) {
// Check if the table is not too full before inserting.
if (4 * (count + 1) > 3 * slots.length) {
// table size must be a power of 2 -- always grow by x2!
+ if (count > SlotMapContainer.LARGE_HASH_SIZE) {
+ var newMap = new HashSlotMap(this, newSlot);
+ owner.setMap(newMap);
+ return;
+ }
Slot[] newSlots = new Slot[slots.length * 2];
copyTable(slots, newSlots);
slots = newSlots;
@@ -134,7 +138,8 @@ private void createNewSlot(Slot newSlot) {
}
@Override
- public S compute(Object key, int index, SlotComputer c) {
+ public S compute(
+ SlotMapOwner owner, Object key, int index, SlotComputer c) {
final int indexOrHash = (key != null ? key.hashCode() : index);
if (slots != null) {
@@ -148,54 +153,62 @@ public S compute(Object key, int index, SlotComputer c) {
prev = slot;
}
if (slot != null) {
- // Modify or remove existing slot
- S newSlot = c.compute(key, index, slot);
- if (newSlot == null) {
- // Need to delete this slot actually
- removeSlot(slot, prev, slotIndex, key);
- } else if (!Objects.equals(slot, newSlot)) {
- // Replace slot in hash table
- if (prev == slot) {
- slots[slotIndex] = newSlot;
- } else {
- prev.next = newSlot;
- }
- newSlot.next = slot.next;
- // Replace new slot in linked list, keeping same order
- if (slot == firstAdded) {
- firstAdded = newSlot;
- } else {
- Slot ps = firstAdded;
- while ((ps != null) && (ps.orderedNext != slot)) {
- ps = ps.orderedNext;
- }
- if (ps != null) {
- ps.orderedNext = newSlot;
- }
- }
- newSlot.orderedNext = slot.orderedNext;
- if (slot == lastAdded) {
- lastAdded = newSlot;
- }
- }
- return newSlot;
+ return computeExisting(key, index, c, slot, prev, slotIndex);
}
}
+ return computeNew(owner, key, index, c);
+ }
- // If we get here, we know we are potentially adding a new slot
+ private S computeNew(
+ SlotMapOwner owner, Object key, int index, SlotComputer c) {
S newSlot = c.compute(key, index, null);
if (newSlot != null) {
- createNewSlot(newSlot);
+ createNewSlot(owner, newSlot);
+ }
+ return newSlot;
+ }
+
+ private S computeExisting(
+ Object key, int index, SlotComputer c, Slot slot, Slot prev, int slotIndex) {
+ // Modify or remove existing slot
+ S newSlot = c.compute(key, index, slot);
+ if (newSlot == null) {
+ // Need to delete this slot actually
+ removeSlot(slot, prev, slotIndex, key);
+ } else if (!Objects.equals(slot, newSlot)) {
+ // Replace slot in hash table
+ if (prev == slot) {
+ slots[slotIndex] = newSlot;
+ } else {
+ prev.next = newSlot;
+ }
+ newSlot.next = slot.next;
+ // Replace new slot in linked list, keeping same order
+ if (slot == firstAdded) {
+ firstAdded = newSlot;
+ } else {
+ Slot ps = firstAdded;
+ while ((ps != null) && (ps.orderedNext != slot)) {
+ ps = ps.orderedNext;
+ }
+ if (ps != null) {
+ ps.orderedNext = newSlot;
+ }
+ }
+ newSlot.orderedNext = slot.orderedNext;
+ if (slot == lastAdded) {
+ lastAdded = newSlot;
+ }
}
return newSlot;
}
@Override
- public void add(Slot newSlot) {
+ public void add(SlotMapOwner owner, Slot newSlot) {
if (slots == null) {
slots = new Slot[INITIAL_SLOT_SIZE];
}
- insertNewSlot(newSlot);
+ createNewSlot(owner, newSlot);
}
private void insertNewSlot(Slot newSlot) {
diff --git a/rhino/src/main/java/org/mozilla/javascript/HashSlotMap.java b/rhino/src/main/java/org/mozilla/javascript/HashSlotMap.java
index 542cf8e386..f4b4e308d1 100644
--- a/rhino/src/main/java/org/mozilla/javascript/HashSlotMap.java
+++ b/rhino/src/main/java/org/mozilla/javascript/HashSlotMap.java
@@ -26,10 +26,18 @@ public HashSlotMap() {
public HashSlotMap(SlotMap oldMap) {
map = new LinkedHashMap<>(oldMap.size());
for (Slot n : oldMap) {
- add(n.copySlot());
+ add(null, n.copySlot());
}
}
+ public HashSlotMap(SlotMap oldMap, Slot newSlot) {
+ map = new LinkedHashMap<>(oldMap.dirtySize() + 1);
+ for (Slot n : oldMap) {
+ add(null, n.copySlot());
+ }
+ add(null, newSlot);
+ }
+
@Override
public int size() {
return map.size();
@@ -47,21 +55,22 @@ public Slot query(Object key, int index) {
}
@Override
- public Slot modify(Object key, int index, int attributes) {
+ public Slot modify(SlotMapOwner owner, Object key, int index, int attributes) {
Object name = makeKey(key, index);
return map.computeIfAbsent(name, n -> new Slot(key, index, attributes));
}
@SuppressWarnings("unchecked")
@Override
- public S compute(Object key, int index, SlotComputer c) {
+ public S compute(
+ SlotMapOwner owner, Object key, int index, SlotComputer c) {
Object name = makeKey(key, index);
Slot ret = map.compute(name, (n, existing) -> c.compute(key, index, existing));
return (S) ret;
}
@Override
- public void add(Slot newSlot) {
+ public void add(SlotMapOwner owner, Slot newSlot) {
Object name = makeKey(newSlot);
map.put(name, newSlot);
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java b/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java
index 5b9bbf5012..d85d6e123b 100644
--- a/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java
+++ b/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java
@@ -14,15 +14,18 @@
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Locale;
import java.util.Optional;
import java.util.ResourceBundle;
+import java.util.ServiceLoader;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.mozilla.javascript.ast.FunctionNode;
import org.mozilla.javascript.v8dtoa.DoubleConversion;
import org.mozilla.javascript.v8dtoa.FastDtoa;
import org.mozilla.javascript.xml.XMLLib;
+import org.mozilla.javascript.xml.XMLLoader;
import org.mozilla.javascript.xml.XMLObject;
/**
@@ -194,19 +197,15 @@ public static ScriptableObject initSafeStandardObjects(
NativeJavaObject.init(scope, sealed);
NativeJavaMap.init(scope, sealed);
- boolean withXml =
- cx.hasFeature(Context.FEATURE_E4X) && cx.getE4xImplementationFactory() != null;
-
// define lazy-loaded properties using their class name
new LazilyLoadedCtor(
scope, "Continuation", "org.mozilla.javascript.NativeContinuation", sealed, true);
- if (withXml) {
- String xmlImpl = cx.getE4xImplementationFactory().getImplementationClassName();
- new LazilyLoadedCtor(scope, "XML", xmlImpl, sealed, true);
- new LazilyLoadedCtor(scope, "XMLList", xmlImpl, sealed, true);
- new LazilyLoadedCtor(scope, "Namespace", xmlImpl, sealed, true);
- new LazilyLoadedCtor(scope, "QName", xmlImpl, sealed, true);
+ if (cx.hasFeature(Context.FEATURE_E4X)) {
+ XMLLoader loader = loadOneServiceImplementation(XMLLoader.class);
+ if (loader != null) {
+ loader.load(scope, sealed);
+ }
}
if (((cx.getLanguageVersion() >= Context.VERSION_1_8)
@@ -5626,6 +5625,24 @@ public static void throwDeleteOnSuperPropertyNotAllowed() {
throw referenceError("msg.delete.super");
}
+ /**
+ * Load a single implementation of "serviceClass" using the ServiceLoader. If there are no
+ * implementations, return null. If there is more than one implementation, throw a fatal
+ * exception, since this indicates that the classpath was configured incorrectly.
+ */
+ static T loadOneServiceImplementation(Class serviceClass) {
+ Iterator it = ServiceLoader.load(serviceClass).iterator();
+ if (it.hasNext()) {
+ T result = it.next();
+ if (it.hasNext()) {
+ throw Kit.codeBug(
+ "Invalid configuration: more than one implementation of " + serviceClass);
+ }
+ return result;
+ }
+ return null;
+ }
+
public static final Object[] emptyArgs = new Object[0];
public static final String[] emptyStrings = new String[0];
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java b/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java
index 8d953ea28f..b747942c82 100644
--- a/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java
+++ b/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java
@@ -51,7 +51,7 @@
* @see org.mozilla.javascript.Scriptable
* @author Norris Boyd
*/
-public abstract class ScriptableObject
+public abstract class ScriptableObject extends SlotMapOwner
implements Scriptable, SymbolScriptable, Serializable, DebuggableObject, ConstProperties {
private static final long serialVersionUID = 2829861078851942586L;
@@ -109,12 +109,6 @@ public abstract class ScriptableObject
/** The parent scope of this object. */
private Scriptable parentScopeObject;
- /**
- * This holds all the slots. It may or may not be thread-safe, and may expand itself to a
- * different data structure depending on the size of the object.
- */
- private transient SlotMapContainer slotMap;
-
// Where external array data is stored.
private transient ExternalArrayData externalData;
@@ -157,24 +151,16 @@ static void checkValidAttributes(int attributes) {
}
}
- private static SlotMapContainer createSlotMap(int initialSize) {
- Context cx = Context.getCurrentContext();
- if ((cx != null) && cx.hasFeature(Context.FEATURE_THREAD_SAFE_OBJECTS)) {
- return new ThreadSafeSlotMapContainer(initialSize);
- }
- return new SlotMapContainer(initialSize);
- }
-
public ScriptableObject() {
- slotMap = createSlotMap(0);
+ super(0);
}
public ScriptableObject(Scriptable scope, Scriptable prototype) {
+ super(0);
if (scope == null) throw new IllegalArgumentException();
parentScopeObject = scope;
prototypeObject = prototype;
- slotMap = createSlotMap(0);
}
/**
@@ -205,7 +191,7 @@ public String getTypeOf() {
*/
@Override
public boolean has(String name, Scriptable start) {
- return null != slotMap.query(name, 0);
+ return null != getMap().query(name, 0);
}
/**
@@ -220,13 +206,13 @@ public boolean has(int index, Scriptable start) {
if (externalData != null) {
return (index < externalData.getArrayLength());
}
- return null != slotMap.query(null, index);
+ return null != getMap().query(null, index);
}
/** A version of "has" that supports symbols. */
@Override
public boolean has(Symbol key, Scriptable start) {
- return null != slotMap.query(key, 0);
+ return null != getMap().query(key, 0);
}
/**
@@ -240,7 +226,7 @@ public boolean has(Symbol key, Scriptable start) {
*/
@Override
public Object get(String name, Scriptable start) {
- Slot slot = slotMap.query(name, 0);
+ Slot slot = getMap().query(name, 0);
if (slot == null) {
return Scriptable.NOT_FOUND;
}
@@ -263,7 +249,7 @@ public Object get(int index, Scriptable start) {
return Scriptable.NOT_FOUND;
}
- Slot slot = slotMap.query(null, index);
+ Slot slot = getMap().query(null, index);
if (slot == null) {
return Scriptable.NOT_FOUND;
}
@@ -273,7 +259,7 @@ public Object get(int index, Scriptable start) {
/** Another version of Get that supports Symbol keyed properties. */
@Override
public Object get(Symbol key, Scriptable start) {
- Slot slot = slotMap.query(key, 0);
+ Slot slot = getMap().query(key, 0);
if (slot == null) {
return Scriptable.NOT_FOUND;
}
@@ -384,7 +370,7 @@ protected boolean putOwnProperty(Symbol key, Scriptable start, Object value, boo
@Override
public void delete(String name) {
checkNotSealed(name, 0);
- slotMap.compute(name, 0, ScriptableObject::checkSlotRemoval);
+ getMap().compute(this, name, 0, ScriptableObject::checkSlotRemoval);
}
/**
@@ -397,14 +383,14 @@ public void delete(String name) {
@Override
public void delete(int index) {
checkNotSealed(null, index);
- slotMap.compute(null, index, ScriptableObject::checkSlotRemoval);
+ getMap().compute(this, null, index, ScriptableObject::checkSlotRemoval);
}
/** Removes an object like the others, but using a Symbol as the key. */
@Override
public void delete(Symbol key) {
checkNotSealed(key, 0);
- slotMap.compute(key, 0, ScriptableObject::checkSlotRemoval);
+ getMap().compute(this, key, 0, ScriptableObject::checkSlotRemoval);
}
private static Slot checkSlotRemoval(Object key, int index, Slot slot) {
@@ -458,7 +444,7 @@ public void defineConst(String name, Scriptable start) {
*/
@Override
public boolean isConst(String name) {
- Slot slot = slotMap.query(name, 0);
+ Slot slot = getMap().query(name, 0);
if (slot == null) {
return false;
}
@@ -561,7 +547,7 @@ public int getAttributes(Symbol sym) {
*/
public void setAttributes(String name, int attributes) {
checkNotSealed(name, 0);
- Slot attrSlot = slotMap.modify(name, 0, 0);
+ Slot attrSlot = getMap().modify(this, name, 0, 0);
attrSlot.setAttributes(attributes);
}
@@ -579,14 +565,14 @@ public void setAttributes(String name, int attributes) {
*/
public void setAttributes(int index, int attributes) {
checkNotSealed(null, index);
- Slot attrSlot = slotMap.modify(null, index, 0);
+ Slot attrSlot = getMap().modify(this, null, index, 0);
attrSlot.setAttributes(attributes);
}
/** Set attributes of a Symbol-keyed property. */
public void setAttributes(Symbol key, int attributes) {
checkNotSealed(key, 0);
- Slot attrSlot = slotMap.modify(key, 0, 0);
+ Slot attrSlot = getMap().modify(this, key, 0, 0);
attrSlot.setAttributes(attributes);
}
@@ -599,9 +585,9 @@ public void setGetterOrSetter(
AccessorSlot aSlot;
if (isExtensible()) {
// Create a new AccessorSlot, or cast it if it's already set
- aSlot = slotMap.compute(name, index, ScriptableObject::ensureAccessorSlot);
+ aSlot = getMap().compute(this, name, index, ScriptableObject::ensureAccessorSlot);
} else {
- Slot slot = slotMap.query(name, index);
+ Slot slot = getMap().query(name, index);
if (slot instanceof AccessorSlot) {
aSlot = (AccessorSlot) slot;
} else {
@@ -647,7 +633,7 @@ public void setGetterOrSetter(
*/
public Object getGetterOrSetter(String name, int index, Scriptable scope, boolean isSetter) {
if (name != null && index != 0) throw new IllegalArgumentException(name);
- Slot slot = slotMap.query(name, index);
+ Slot slot = getMap().query(name, index);
if (slot == null) return null;
Function getterOrSetter =
isSetter
@@ -683,14 +669,14 @@ public Object getGetterOrSetter(String name, int index, boolean isSetter) {
* @return whether the property is a getter or a setter
*/
protected boolean isGetterOrSetter(String name, int index, boolean setter) {
- Slot slot = slotMap.query(name, index);
+ Slot slot = getMap().query(name, index);
return (slot != null && slot.isSetterSlot());
}
void addLazilyInitializedValue(String name, int index, LazilyLoadedCtor init, int attributes) {
if (name != null && index != 0) throw new IllegalArgumentException(name);
checkNotSealed(name, index);
- LazyLoadSlot lslot = slotMap.compute(name, index, ScriptableObject::ensureLazySlot);
+ LazyLoadSlot lslot = getMap().compute(this, name, index, ScriptableObject::ensureLazySlot);
lslot.setAttributes(attributes);
lslot.value = init;
}
@@ -1588,7 +1574,8 @@ public void defineProperty(
}
}
- AccessorSlot aSlot = slotMap.compute(propertyName, 0, ScriptableObject::ensureAccessorSlot);
+ AccessorSlot aSlot =
+ getMap().compute(this, propertyName, 0, ScriptableObject::ensureAccessorSlot);
aSlot.setAttributes(attributes);
if (getterBox != null) {
aSlot.getter = new AccessorSlot.MemberBoxGetter(getterBox);
@@ -1658,7 +1645,7 @@ protected boolean defineOwnProperty(
}
}
- // this property lookup cannot happen from inside slotMap.compute lambda
+ // this property lookup cannot happen from inside getMap().compute lambda
// as it risks causing a deadlock if ThreadSafeSlotMapContainer is used
// and `this` is in prototype chain of `desc`
Object enumerable = getProperty(desc, "enumerable");
@@ -1671,69 +1658,70 @@ protected boolean defineOwnProperty(
// Do some complex stuff depending on whether or not the key
// already exists in a single hash map operation
- slotMap.compute(
- key,
- index,
- (k, ix, existing) -> {
- if (checkValid) {
- checkPropertyChangeForSlot(id, existing, desc);
- }
-
- Slot slot;
- int attributes;
-
- if (existing == null) {
- slot = new Slot(k, ix, 0);
- attributes =
- applyDescriptorToAttributeBitset(
- DONTENUM | READONLY | PERMANENT,
- enumerable,
- writable,
- configurable);
- } else {
- slot = existing;
- attributes =
- applyDescriptorToAttributeBitset(
- existing.getAttributes(),
- enumerable,
- writable,
- configurable);
- }
-
- if (accessorDescriptor) {
- AccessorSlot fslot;
- if (slot instanceof AccessorSlot) {
- fslot = (AccessorSlot) slot;
- } else {
- fslot = new AccessorSlot(slot);
- slot = fslot;
- }
- if (getter != NOT_FOUND) {
- fslot.getter = new AccessorSlot.FunctionGetter(getter);
- }
-
- if (setter != NOT_FOUND) {
- fslot.setter = new AccessorSlot.FunctionSetter(setter);
- }
- fslot.value = Undefined.instance;
- } else {
- if (!slot.isValueSlot() && isDataDescriptor(desc)) {
- // Replace a non-base slot with a regular slot
- slot = new Slot(slot);
- }
-
- if (value != NOT_FOUND) {
- slot.value = value;
- } else if (existing == null) {
- // Ensure we don't get a zombie value if we have switched a lot
- slot.value = Undefined.instance;
- }
- }
-
- // After all that, whatever we return now ends up in the map
- slot.setAttributes(attributes);
- return slot;
- });
+ getMap().compute(
+ this,
+ key,
+ index,
+ (k, ix, existing) -> {
+ if (checkValid) {
+ checkPropertyChangeForSlot(id, existing, desc);
+ }
+
+ Slot slot;
+ int attributes;
+
+ if (existing == null) {
+ slot = new Slot(k, ix, 0);
+ attributes =
+ applyDescriptorToAttributeBitset(
+ DONTENUM | READONLY | PERMANENT,
+ enumerable,
+ writable,
+ configurable);
+ } else {
+ slot = existing;
+ attributes =
+ applyDescriptorToAttributeBitset(
+ existing.getAttributes(),
+ enumerable,
+ writable,
+ configurable);
+ }
+
+ if (accessorDescriptor) {
+ AccessorSlot fslot;
+ if (slot instanceof AccessorSlot) {
+ fslot = (AccessorSlot) slot;
+ } else {
+ fslot = new AccessorSlot(slot);
+ slot = fslot;
+ }
+ if (getter != NOT_FOUND) {
+ fslot.getter = new AccessorSlot.FunctionGetter(getter);
+ }
+
+ if (setter != NOT_FOUND) {
+ fslot.setter = new AccessorSlot.FunctionSetter(setter);
+ }
+ fslot.value = Undefined.instance;
+ } else {
+ if (!slot.isValueSlot() && isDataDescriptor(desc)) {
+ // Replace a non-base slot with a regular slot
+ slot = new Slot(slot);
+ }
+
+ if (value != NOT_FOUND) {
+ slot.value = value;
+ } else if (existing == null) {
+ // Ensure we don't get a zombie value if we have switched a lot
+ slot.value = Undefined.instance;
+ }
+ }
+
+ // After all that, whatever we return now ends up in the map
+ slot.setAttributes(attributes);
+ return slot;
+ });
return true;
}
@@ -1753,7 +1741,7 @@ protected boolean defineOwnProperty(
*/
public void defineProperty(
String name, Supplier