Add iterator cache to UnsafeList and use it in hotspots

Adds a specialized iterator for the list and a pool of iterators to avoid
object churn. Also optimizes the clear() method to reduce object creation.
Dieser Commit ist enthalten in:
Travis Watkins 2012-08-17 12:55:33 -05:00
Ursprung 6d777ade16
Commit 858d36efc9
4 geänderte Dateien mit 120 neuen und 20 gelöschten Zeilen

Datei anzeigen

@ -57,7 +57,7 @@ public class Chunk {
this.heightMap = new int[256]; this.heightMap = new int[256];
for (int k = 0; k < this.entitySlices.length; ++k) { for (int k = 0; k < this.entitySlices.length; ++k) {
this.entitySlices[k] = new ArrayList(); this.entitySlices[k] = new org.bukkit.craftbukkit.util.UnsafeList(); // CraftBukkit - ArrayList -> UnsafeList
} }
Arrays.fill(this.b, -999); Arrays.fill(this.b, -999);

Datei anzeigen

@ -4,10 +4,14 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.bukkit.craftbukkit.util.UnsafeList; // CraftBukkit
public class PathfinderGoalSelector { public class PathfinderGoalSelector {
private List a = new ArrayList(); // CraftBukkit start - ArrayList -> UnsafeList
private List b = new ArrayList(); private List a = new UnsafeList();
private List b = new UnsafeList();
// CraftBukkit end
private final MethodProfiler c; private final MethodProfiler c;
private int d = 0; private int d = 0;
private int e = 3; private int e = 3;
@ -21,7 +25,7 @@ public class PathfinderGoalSelector {
} }
public void a() { public void a() {
ArrayList arraylist = new ArrayList(); UnsafeList arraylist = new UnsafeList(); // CraftBukkit - ArrayList -> UnsafeList
Iterator iterator; Iterator iterator;
PathfinderGoalSelectorItem pathfindergoalselectoritem; PathfinderGoalSelectorItem pathfindergoalselectoritem;

Datei anzeigen

@ -10,6 +10,7 @@ import java.util.concurrent.Callable;
// CraftBukkit start // CraftBukkit start
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.util.LongHashset; import org.bukkit.craftbukkit.util.LongHashset;
import org.bukkit.craftbukkit.util.UnsafeList;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
@ -54,7 +55,7 @@ public abstract class World implements IBlockAccess {
public final VillageCollection villages = new VillageCollection(this); public final VillageCollection villages = new VillageCollection(this);
protected final VillageSiege siegeManager = new VillageSiege(this); protected final VillageSiege siegeManager = new VillageSiege(this);
public final MethodProfiler methodProfiler; public final MethodProfiler methodProfiler;
private ArrayList d = new ArrayList(); private UnsafeList d = new UnsafeList(); // CraftBukkit - ArrayList -> UnsafeList
private boolean L; private boolean L;
// CraftBukkit start - public, longhashset // CraftBukkit start - public, longhashset
public boolean allowMonsters = true; public boolean allowMonsters = true;
@ -112,7 +113,7 @@ public abstract class World implements IBlockAccess {
this.M = this.random.nextInt(12000); this.M = this.random.nextInt(12000);
this.J = new int['\u8000']; this.J = new int['\u8000'];
this.N = new ArrayList(); this.N = new UnsafeList(); // CraftBukkit - ArrayList -> UnsafeList
this.isStatic = false; this.isStatic = false;
this.dataManager = idatamanager; this.dataManager = idatamanager;
this.methodProfiler = methodprofiler; this.methodProfiler = methodprofiler;

Datei anzeigen

@ -5,26 +5,38 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.AbstractList; import java.util.AbstractList;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException;
import java.util.RandomAccess; import java.util.RandomAccess;
// implementation of an ArrayList that offers a getter without range checks // implementation of an ArrayList that offers a getter without range checks
@SuppressWarnings("unchecked")
public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable { public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
private static final long serialVersionUID = 8683452581112892190L; private static final long serialVersionUID = 8683452581112892190L;
private transient Object[] data; private transient Object[] data;
private int size; private int size;
private int initialCapacity; private int initialCapacity;
private Iterator[] iterPool = new Iterator[3];
private int poolCounter;
public UnsafeList(int capacity) { public UnsafeList(int capacity) {
super(); super();
if (capacity < 0) capacity = 128; if (capacity < 0) capacity = 32;
int rounded = Integer.highestOneBit(capacity - 1) << 1; int rounded = Integer.highestOneBit(capacity - 1) << 1;
data = new Object[rounded]; data = new Object[rounded];
initialCapacity = rounded; initialCapacity = rounded;
for (int i = 0; i < iterPool.length; i++) {
iterPool[i] = new Itr();
}
} }
public UnsafeList() { public UnsafeList() {
this(128); this(32);
} }
public E get(int index) { public E get(int index) {
@ -98,7 +110,15 @@ public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAcc
public void clear() { public void clear() {
// Create new array to reset memory usage to initial capacity // Create new array to reset memory usage to initial capacity
size = 0; size = 0;
data = new Object[initialCapacity];
// If array has grown too large create new one, otherwise just clear it
if (data.length > initialCapacity << 3) {
data = new Object[initialCapacity];
} else {
for (int i = 0; i < data.length; i++) {
data[i] = null;
}
}
} }
// actually rounds up to nearest power of two // actually rounds up to nearest power of two
@ -115,7 +135,39 @@ public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAcc
} }
public boolean isEmpty() { public boolean isEmpty() {
return size != 0; return size == 0;
}
public Object clone() throws CloneNotSupportedException {
UnsafeList<E> copy = (UnsafeList<E>) super.clone();
copy.data = Java15Compat.Arrays_copyOf(data, size);
copy.size = size;
copy.initialCapacity = initialCapacity;
copy.iterPool = new Iterator[iterPool.length];
return copy;
}
public Iterator<E> iterator() {
Itr iterator = null;
poolCounter = poolCounter++ % iterPool.length;
// Try to find an iterator that isn't in use
for (Iterator iter : iterPool) {
if (!((Itr) iter).valid) {
iterator = (Itr) iter;
break;
}
}
// Couldn't find a free one, round robin replace one with a new iterator
// This is done in the hope that the new one finishes so can be reused
if (iterator == null) {
iterPool[poolCounter] = new Itr();
iterator = (Itr) iterPool[poolCounter];
}
iterator.reset();
return iterator;
} }
private void rangeCheck(int index) { private void rangeCheck(int index) {
@ -153,16 +205,59 @@ public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAcc
} }
} }
public UnsafeList<E> clone() { private class Itr implements Iterator<E> {
try { int index;
UnsafeList<E> copy = (UnsafeList<E>) super.clone(); int lastRet = -1;
copy.data = Java15Compat.Arrays_copyOf(data, size); int expectedModCount = modCount;
copy.size = size; boolean valid = true;
copy.initialCapacity = initialCapacity;
return copy; public void reset() {
} catch (CloneNotSupportedException ex) { index = 0;
// This should never happen lastRet = -1;
return null; expectedModCount = modCount;
valid = true;
}
public boolean hasNext() {
valid = index != size;
return valid;
}
public E next() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
int i = index;
if (i >= size) {
throw new NoSuchElementException();
}
if (i >= data.length) {
throw new ConcurrentModificationException();
}
index = i + 1;
return (E) data[lastRet = i];
}
public void remove() {
if (lastRet < 0) {
throw new IllegalStateException();
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
try {
UnsafeList.this.remove(lastRet);
index = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
} }
} }
} }