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() { } }