Fix two problems with weak tables.
(1) User data values would be dropped even if other references
to the wrapped Java instance existed.
(2) Dropped elements were never actually cleaned out of the table.
This commit is contained in:
@@ -51,7 +51,7 @@ public class LTable extends LValue {
|
||||
|
||||
protected Object[] array;
|
||||
protected LValue[] hashKeys;
|
||||
private Object[] hashValues;
|
||||
protected Object[] hashValues;
|
||||
private int hashEntries;
|
||||
private LTable m_metatable;
|
||||
|
||||
@@ -625,7 +625,7 @@ public class LTable extends LValue {
|
||||
}
|
||||
}
|
||||
|
||||
private void hashClearSlot( int i ) {
|
||||
protected void hashClearSlot( int i ) {
|
||||
if ( hashKeys[ i ] != null ) {
|
||||
|
||||
int j = i;
|
||||
@@ -651,14 +651,14 @@ public class LTable extends LValue {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkLoadFactor() {
|
||||
protected boolean checkLoadFactor() {
|
||||
// Using a load factor of 2/3 because that is easy to compute without
|
||||
// overflow or division.
|
||||
final int hashCapacity = hashKeys.length;
|
||||
return ( hashCapacity >> 1 ) >= ( hashCapacity - hashEntries );
|
||||
}
|
||||
|
||||
private void rehash() {
|
||||
protected void rehash() {
|
||||
final int oldCapacity = hashKeys.length;
|
||||
final int newCapacity = ( oldCapacity > 0 ) ? 2 * oldCapacity : MIN_HASH_CAPACITY;
|
||||
|
||||
|
||||
@@ -66,4 +66,8 @@ public class LUserData extends LValue {
|
||||
return lhs.equals( this );
|
||||
return super.luaBinCmpUnknown( opcode, lhs );
|
||||
}
|
||||
|
||||
public boolean isUserData() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,4 +346,9 @@ public class LValue {
|
||||
public boolean isFunction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns true if this is an LUserData */
|
||||
public boolean isUserData() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,15 +48,30 @@ public class LWeakTable extends LTable {
|
||||
}
|
||||
|
||||
protected LValue normalizeGet(Object val) {
|
||||
if ( val != null )
|
||||
if ( val instanceof WeakReference )
|
||||
val = ((WeakReference)val).get();
|
||||
else if ( val != null ) {
|
||||
LUserData ud = (LUserData) val;
|
||||
Object o = ((WeakReference) ud.m_instance).get();
|
||||
if ( o != null )
|
||||
val = new LUserData(o, ud.m_metatable);
|
||||
else
|
||||
val = LNil.NIL;
|
||||
}
|
||||
return val==null? LNil.NIL: (LValue) val;
|
||||
}
|
||||
|
||||
protected Object normalizePut(LValue val) {
|
||||
return val==LNil.NIL? null: new WeakReference(val);
|
||||
if ( val.isNil() ) {
|
||||
return null;
|
||||
} else if ( val.isUserData() ) {
|
||||
LUserData ud = (LUserData) val;
|
||||
return new LUserData(new WeakReference(ud.m_instance), ud.m_metatable);
|
||||
} else {
|
||||
return new WeakReference(val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean next(LuaState vm, LValue key, boolean indexedonly) {
|
||||
while ( super.next(vm, key, indexedonly) ) {
|
||||
if ( ! vm.isnil(-1) )
|
||||
@@ -66,5 +81,32 @@ public class LWeakTable extends LTable {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void rehash() {
|
||||
final LValue[] keys = this.hashKeys;
|
||||
final Object[] values = this.hashValues;
|
||||
final int n = hashKeys.length;
|
||||
|
||||
for ( int i = 0; i < n; ++i ) {
|
||||
if ( keys[i] != null && normalizeGet(values[i]).isNil() ) {
|
||||
// key has dropped out, clear the slot
|
||||
// It's necessary to call hashClearSlot instead of just nulling
|
||||
// out the slot because the table must be left in a consistent
|
||||
// state if an OutOfMemoryError occurs later in the rehash
|
||||
// process.
|
||||
hashClearSlot(i);
|
||||
// If number of hash entries gets to zero, hashClearSlot will
|
||||
// set hashKeys back to an empty array. Check for that so we
|
||||
// don't have an out-of-bounds index operation.
|
||||
if ( hashKeys != keys )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check load factor again since rehash might not be required if enough
|
||||
// entries dropped out.
|
||||
if ( checkLoadFactor() )
|
||||
super.rehash();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
version: 0.54
|
||||
version: 0.55
|
||||
|
||||
Reference in New Issue
Block a user