Remove ConcurrentModificationDetector.
ConcurrentModificationDetector was using WASM incompatible jsinterop magic
to track mod count. This was done to hide everything magically behind a flag.
Normally removing the read of the modCount should be enough to remove all other usages however we are hitting JsCompiler bugs there so I also guarded
structureChanged calls.
PiperOrigin-RevId: 373473243
Change-Id: I3f5b2160a2bc34bd02a0d5f7f224b548ac3f3cc7
diff --git a/user/super/com/google/gwt/emul/java/util/AbstractHashMap.java b/user/super/com/google/gwt/emul/java/util/AbstractHashMap.java
index d3ffe81..dec4c91 100644
--- a/user/super/com/google/gwt/emul/java/util/AbstractHashMap.java
+++ b/user/super/com/google/gwt/emul/java/util/AbstractHashMap.java
@@ -15,13 +15,11 @@
*/
package java.util;
-import static java.util.ConcurrentModificationDetector.checkStructuralChange;
-import static java.util.ConcurrentModificationDetector.recordLastKnownStructure;
-import static java.util.ConcurrentModificationDetector.structureChanged;
-
import static javaemul.internal.InternalPreconditions.checkArgument;
+import static javaemul.internal.InternalPreconditions.checkConcurrentModification;
import static javaemul.internal.InternalPreconditions.checkElement;
import static javaemul.internal.InternalPreconditions.checkState;
+import static javaemul.internal.InternalPreconditions.isApiChecked;
import javaemul.internal.JsUtils;
import javaemul.internal.annotations.SpecializeMethod;
@@ -80,10 +78,7 @@
private Iterator<Entry<K, V>> current = stringMapEntries;
private Iterator<Entry<K, V>> last;
private boolean hasNext = computeHasNext();
-
- public EntrySetIterator() {
- recordLastKnownStructure(AbstractHashMap.this, this);
- }
+ private int lastModCount = modCount;
@Override
public boolean hasNext() {
@@ -103,7 +98,7 @@
@Override
public Entry<K, V> next() {
- checkStructuralChange(AbstractHashMap.this, this);
+ checkConcurrentModification(modCount, lastModCount);
checkElement(hasNext());
last = current;
@@ -116,13 +111,13 @@
@Override
public void remove() {
checkState(last != null);
- checkStructuralChange(AbstractHashMap.this, this);
+ checkConcurrentModification(modCount, lastModCount);
last.remove();
last = null;
hasNext = computeHasNext();
- recordLastKnownStructure(AbstractHashMap.this, this);
+ lastModCount = modCount;
}
}
@@ -136,6 +131,8 @@
*/
private transient InternalStringMap<K, V> stringMap;
+ int modCount;
+
public AbstractHashMap() {
reset();
}
@@ -166,7 +163,16 @@
private void reset() {
hashCodeMap = new InternalHashCodeMap<K, V>(this);
stringMap = new InternalStringMap<K, V>(this);
- structureChanged(this);
+ structureChanged();
+ }
+
+ void structureChanged() {
+ if (!isApiChecked()) {
+ // Shouldn't be necessary but JsCompiler chokes on removing modCount so make sure we don't pay
+ // cost for updating the field.
+ return;
+ }
+ this.modCount++;
}
@SpecializeMethod(params = {String.class}, target = "hasStringValue")
diff --git a/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java b/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java
deleted file mode 100644
index 69c8be4..0000000
--- a/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package java.util;
-
-import javaemul.internal.InternalPreconditions;
-
-import jsinterop.annotations.JsPackage;
-import jsinterop.annotations.JsProperty;
-import jsinterop.annotations.JsType;
-
-/**
- * A helper to detect concurrent modifications to collections. This is implemented as a helper
- * utility so that we could remove the checks easily by a flag.
- */
-class ConcurrentModificationDetector {
-
- private static final boolean API_CHECK = InternalPreconditions.isApiChecked();
-
- public static void structureChanged(Object host) {
- if (!API_CHECK) {
- return;
- }
-
- ModCountable modCountable = (ModCountable) host;
- // Ensure that modCount is initialized if it is not already.
- int modCount = modCountable.getModCount() | 0;
- modCountable.setModCount(modCount + 1);
- }
-
- public static void recordLastKnownStructure(Object host, Iterator<?> iterator) {
- if (!API_CHECK) {
- return;
- }
-
- ((ModCountable) iterator).setModCount(((ModCountable) host).getModCount());
- }
-
- public static void checkStructuralChange(Object host, Iterator<?> iterator) {
- if (!API_CHECK) {
- return;
- }
-
- if (((ModCountable) iterator).getModCount() != ((ModCountable) host).getModCount()) {
- throw new ConcurrentModificationException();
- }
- }
-
- @JsType(isNative = true, name = "*", namespace = JsPackage.GLOBAL)
- private interface ModCountable {
- @JsProperty(name = "$modCount")
- void setModCount(int modCount);
-
- @JsProperty(name = "$modCount")
- int getModCount();
- }
-}
diff --git a/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java b/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
index 4b9a251..abefed8 100644
--- a/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
+++ b/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
@@ -15,8 +15,6 @@
*/
package java.util;
-import static java.util.ConcurrentModificationDetector.structureChanged;
-
import java.util.AbstractMap.SimpleEntry;
import java.util.Map.Entry;
import javaemul.internal.ArrayHelper;
@@ -58,7 +56,7 @@
}
chain[chain.length] = new SimpleEntry<K, V>(key, value);
size++;
- structureChanged(host);
+ host.structureChanged();
return null;
}
@@ -77,7 +75,7 @@
ArrayHelper.removeFrom(chain, i, 1);
}
size--;
- structureChanged(host);
+ host.structureChanged();
return entry.getValue();
}
}
diff --git a/user/super/com/google/gwt/emul/java/util/InternalStringMap.java b/user/super/com/google/gwt/emul/java/util/InternalStringMap.java
index 8366f6f..52fe42d 100644
--- a/user/super/com/google/gwt/emul/java/util/InternalStringMap.java
+++ b/user/super/com/google/gwt/emul/java/util/InternalStringMap.java
@@ -15,10 +15,7 @@
*/
package java.util;
-import static java.util.ConcurrentModificationDetector.structureChanged;
-
import java.util.Map.Entry;
-
import javaemul.internal.JsUtils;
/**
@@ -56,7 +53,7 @@
if (JsUtils.isUndefined(oldValue)) {
size++;
- structureChanged(host);
+ host.structureChanged();
} else {
valueMod++;
}
@@ -68,7 +65,7 @@
if (!JsUtils.isUndefined(value)) {
backingMap.delete(key);
size--;
- structureChanged(host);
+ host.structureChanged();
} else {
valueMod++;
}
diff --git a/user/super/com/google/gwt/emul/java/util/LinkedHashMap.java b/user/super/com/google/gwt/emul/java/util/LinkedHashMap.java
index c1f5f6c..5cd2a6d 100644
--- a/user/super/com/google/gwt/emul/java/util/LinkedHashMap.java
+++ b/user/super/com/google/gwt/emul/java/util/LinkedHashMap.java
@@ -15,9 +15,7 @@
*/
package java.util;
-import static java.util.ConcurrentModificationDetector.checkStructuralChange;
-import static java.util.ConcurrentModificationDetector.recordLastKnownStructure;
-
+import static javaemul.internal.InternalPreconditions.checkConcurrentModification;
import static javaemul.internal.InternalPreconditions.checkCriticalElement;
import static javaemul.internal.InternalPreconditions.checkState;
@@ -93,9 +91,11 @@
// The next entry to return from this iterator.
private ChainEntry next;
+ private int lastModCount;
+
public EntryIterator() {
next = head.next;
- recordLastKnownStructure(map, this);
+ lastModCount = map.modCount;
}
@Override
@@ -105,7 +105,7 @@
@Override
public Map.Entry<K, V> next() {
- checkStructuralChange(map, this);
+ checkConcurrentModification(map.modCount, lastModCount);
checkCriticalElement(hasNext());
last = next;
@@ -116,11 +116,11 @@
@Override
public void remove() {
checkState(last != null);
- checkStructuralChange(map, this);
+ checkConcurrentModification(map.modCount, lastModCount);
last.remove();
map.remove(last.getKey());
- recordLastKnownStructure(map, this);
+ lastModCount = map.modCount;
last = null;
}
}
diff --git a/user/super/com/google/gwt/emul/javaemul/internal/InternalPreconditions.java b/user/super/com/google/gwt/emul/javaemul/internal/InternalPreconditions.java
index f41d857..b754266 100644
--- a/user/super/com/google/gwt/emul/javaemul/internal/InternalPreconditions.java
+++ b/user/super/com/google/gwt/emul/javaemul/internal/InternalPreconditions.java
@@ -17,6 +17,7 @@
import static java.lang.System.getProperty;
+import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
/**
@@ -139,7 +140,7 @@
} else if (IS_ASSERTED) {
try {
checkCriticalType(expression, message);
- } catch (Exception e) {
+ } catch (RuntimeException e) {
throw new AssertionError(e);
}
}
@@ -586,6 +587,24 @@
}
}
+ public static void checkConcurrentModification(int currentModCount, int recordedModCount) {
+ if (IS_API_CHECKED) {
+ checkCriticalConcurrentModification(currentModCount, recordedModCount);
+ } else if (IS_ASSERTED) {
+ try {
+ checkCriticalConcurrentModification(currentModCount, recordedModCount);
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ public static void checkCriticalConcurrentModification(
+ double currentModCount, double recordedModCount) {
+ if (currentModCount != recordedModCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
// Hides the constructor for this static utility class.
private InternalPreconditions() { }
}