Add table.clear().

This commit is contained in:
Mike Pall 2013-11-25 15:18:31 +01:00
parent c378f7dbb8
commit 4593fb5e29
8 changed files with 62 additions and 2 deletions

View File

@ -217,6 +217,22 @@ tables if the final table size is known and automatic table resizing is
too expensive. too expensive.
</p> </p>
<h3 id="table_clear"><tt>table.clear(tab)</tt> clears a table</h3>
<p>
An extra library function <tt>table.clear()</tt> can be made available
via <tt>require("table.clear")</tt>. This clears all keys and values
from a table, but preserves the allocated array/hash sizes. This is
useful when a table, which is linked from multiple places, needs to be
cleared and/or when recycling a table for use by the same context. This
avoids managing backlinks, saves an allocation and the overhead of
incremental array/hash part growth.
</p>
<p>
Please note this function is meant for very specific situations. In most
cases it's better to replace the (usually single) link with a new table
and let the GC do its work.
</p>
<h3 id="math_random">Enhanced PRNG for <tt>math.random()</tt></h3> <h3 id="math_random">Enhanced PRNG for <tt>math.random()</tt></h3>
<p> <p>
LuaJIT uses a Tausworthe PRNG with period 2^223 to implement LuaJIT uses a Tausworthe PRNG with period 2^223 to implement

View File

@ -155,7 +155,7 @@ lj_opt_loop.o: lj_opt_loop.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_iropt.h lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_snap.h \ lj_iropt.h lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_snap.h \
lj_vm.h lj_vm.h
lj_opt_mem.o: lj_opt_mem.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ lj_opt_mem.o: lj_opt_mem.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_tab.h lj_ir.h lj_jit.h lj_iropt.h lj_tab.h lj_ir.h lj_jit.h lj_iropt.h lj_ircall.h
lj_opt_narrow.o: lj_opt_narrow.c lj_obj.h lua.h luaconf.h lj_def.h \ lj_opt_narrow.o: lj_opt_narrow.c lj_obj.h lua.h luaconf.h lj_def.h \
lj_arch.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h lj_trace.h lj_dispatch.h \ lj_arch.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h lj_trace.h lj_dispatch.h \
lj_traceerr.h lj_vm.h lj_strscan.h lj_traceerr.h lj_vm.h lj_strscan.h

View File

@ -273,11 +273,22 @@ LJLIB_NOREG LJLIB_CF(table_new) LJLIB_REC(.)
return 1; return 1;
} }
LJLIB_NOREG LJLIB_CF(table_clear) LJLIB_REC(.)
{
lj_tab_clear(lj_lib_checktab(L, 1));
return 0;
}
static int luaopen_table_new(lua_State *L) static int luaopen_table_new(lua_State *L)
{ {
return lj_lib_postreg(L, lj_cf_table_new, FF_table_new, "new"); return lj_lib_postreg(L, lj_cf_table_new, FF_table_new, "new");
} }
static int luaopen_table_clear(lua_State *L)
{
return lj_lib_postreg(L, lj_cf_table_clear, FF_table_clear, "clear");
}
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
#include "lj_libdef.h" #include "lj_libdef.h"
@ -290,6 +301,7 @@ LUALIB_API int luaopen_table(lua_State *L)
lua_setfield(L, -2, "unpack"); lua_setfield(L, -2, "unpack");
#endif #endif
lj_lib_prereg(L, LUA_TABLIBNAME ".new", luaopen_table_new, tabV(L->top-1)); lj_lib_prereg(L, LUA_TABLIBNAME ".new", luaopen_table_new, tabV(L->top-1));
lj_lib_prereg(L, LUA_TABLIBNAME ".clear", luaopen_table_clear, tabV(L->top-1));
return 1; return 1;
} }

View File

@ -1024,6 +1024,16 @@ static void LJ_FASTCALL recff_table_new(jit_State *J, RecordFFData *rd)
UNUSED(rd); UNUSED(rd);
} }
static void LJ_FASTCALL recff_table_clear(jit_State *J, RecordFFData *rd)
{
TRef tr = J->base[0];
if (tref_istab(tr)) {
rd->nres = 0;
lj_ir_call(J, IRCALL_lj_tab_clear, tr);
J->needsnap = 1;
} /* else: Interpreter will throw. */
}
/* -- I/O library fast functions ------------------------------------------ */ /* -- I/O library fast functions ------------------------------------------ */
/* Get FILE* for I/O function. Any I/O error aborts recording, so there's /* Get FILE* for I/O function. Any I/O error aborts recording, so there's

View File

@ -144,6 +144,7 @@ typedef struct CCallInfo {
_(ANY, lj_tab_new_ah, 3, A, TAB, CCI_L) \ _(ANY, lj_tab_new_ah, 3, A, TAB, CCI_L) \
_(ANY, lj_tab_new1, 2, FS, TAB, CCI_L) \ _(ANY, lj_tab_new1, 2, FS, TAB, CCI_L) \
_(ANY, lj_tab_dup, 2, FS, TAB, CCI_L) \ _(ANY, lj_tab_dup, 2, FS, TAB, CCI_L) \
_(ANY, lj_tab_clear, 1, FS, NIL, 0) \
_(ANY, lj_tab_newkey, 3, S, P32, CCI_L) \ _(ANY, lj_tab_newkey, 3, S, P32, CCI_L) \
_(ANY, lj_tab_len, 1, FL, INT, 0) \ _(ANY, lj_tab_len, 1, FL, INT, 0) \
_(ANY, lj_gc_step_jit, 2, FS, NIL, CCI_L) \ _(ANY, lj_gc_step_jit, 2, FS, NIL, CCI_L) \

View File

@ -17,6 +17,7 @@
#include "lj_ir.h" #include "lj_ir.h"
#include "lj_jit.h" #include "lj_jit.h"
#include "lj_iropt.h" #include "lj_iropt.h"
#include "lj_ircall.h"
/* Some local macros to save typing. Undef'd at the end. */ /* Some local macros to save typing. Undef'd at the end. */
#define IR(ref) (&J->cur.ir[(ref)]) #define IR(ref) (&J->cur.ir[(ref)])
@ -308,7 +309,7 @@ int LJ_FASTCALL lj_opt_fwd_href_nokey(jit_State *J)
return 1; /* No conflict. Can fold to niltv. */ return 1; /* No conflict. Can fold to niltv. */
} }
/* Check whether there's no aliasing NEWREF for the left operand. */ /* Check whether there's no aliasing NEWREF/table.clear for the left operand. */
int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim) int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim)
{ {
IRRef ta = fins->op1; IRRef ta = fins->op1;
@ -319,6 +320,14 @@ int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim)
return 0; /* Conflict. */ return 0; /* Conflict. */
ref = newref->prev; ref = newref->prev;
} }
ref = J->chain[IR_CALLS];
while (ref > lim) {
IRIns *calls = IR(ref);
if (calls->op2 == IRCALL_lj_tab_clear &&
(ta == calls->op1 || aa_table(J, ta, calls->op1) != ALIAS_NO))
return 0; /* Conflict. */
ref = calls->prev;
}
return 1; /* No conflict. Can safely FOLD/CSE. */ return 1; /* No conflict. Can safely FOLD/CSE. */
} }

View File

@ -204,6 +204,17 @@ GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt)
return t; return t;
} }
/* Clear a table. */
void LJ_FASTCALL lj_tab_clear(GCtab *t)
{
clearapart(t);
if (t->hmask > 0) {
Node *node = noderef(t->node);
setmref(node->freetop, &node[t->hmask+1]);
clearhpart(t);
}
}
/* Free a table. */ /* Free a table. */
void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t) void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t)
{ {

View File

@ -39,6 +39,7 @@ LJ_FUNC GCtab *lj_tab_new_ah(lua_State *L, int32_t a, int32_t h);
LJ_FUNC GCtab * LJ_FASTCALL lj_tab_new1(lua_State *L, uint32_t ahsize); LJ_FUNC GCtab * LJ_FASTCALL lj_tab_new1(lua_State *L, uint32_t ahsize);
#endif #endif
LJ_FUNCA GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt); LJ_FUNCA GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt);
LJ_FUNC void LJ_FASTCALL lj_tab_clear(GCtab *t);
LJ_FUNC void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t); LJ_FUNC void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t);
#if LJ_HASFFI #if LJ_HASFFI
LJ_FUNC void lj_tab_rehash(lua_State *L, GCtab *t); LJ_FUNC void lj_tab_rehash(lua_State *L, GCtab *t);