diff --git a/src/core/org/luaj/vm/LTable.java b/src/core/org/luaj/vm/LTable.java index 630b3d93..adedcb0f 100644 --- a/src/core/org/luaj/vm/LTable.java +++ b/src/core/org/luaj/vm/LTable.java @@ -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; diff --git a/src/core/org/luaj/vm/LUserData.java b/src/core/org/luaj/vm/LUserData.java index adfad40c..21ac2afc 100644 --- a/src/core/org/luaj/vm/LUserData.java +++ b/src/core/org/luaj/vm/LUserData.java @@ -66,4 +66,8 @@ public class LUserData extends LValue { return lhs.equals( this ); return super.luaBinCmpUnknown( opcode, lhs ); } + + public boolean isUserData() { + return true; + } } diff --git a/src/core/org/luaj/vm/LValue.java b/src/core/org/luaj/vm/LValue.java index bcd7496a..a773e26c 100644 --- a/src/core/org/luaj/vm/LValue.java +++ b/src/core/org/luaj/vm/LValue.java @@ -346,4 +346,9 @@ public class LValue { public boolean isFunction() { return false; } + + /** Returns true if this is an LUserData */ + public boolean isUserData() { + return false; + } } diff --git a/src/core/org/luaj/vm/LWeakTable.java b/src/core/org/luaj/vm/LWeakTable.java index c9a1588d..71da6dbc 100644 --- a/src/core/org/luaj/vm/LWeakTable.java +++ b/src/core/org/luaj/vm/LWeakTable.java @@ -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(); + } } diff --git a/version.properties b/version.properties index 1c31e41d..11ccf95f 100644 --- a/version.properties +++ b/version.properties @@ -1 +1 @@ -version: 0.54 +version: 0.55