too expensive.
</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>
<p>
LuaJIT uses a Tausworthe PRNG with period 2^223 to implement
lj_iropt.h lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_snap.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_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_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
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)
{
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"
lua_setfield(L, -2, "unpack");
#endif
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;
}
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 ------------------------------------------ */
/* Get FILE* for I/O function. Any I/O error aborts recording, so there's
_(ANY, lj_tab_new_ah, 3, A, TAB, CCI_L) \
_(ANY, lj_tab_new1, 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_len, 1, FL, INT, 0) \
_(ANY, lj_gc_step_jit, 2, FS, NIL, CCI_L) \
#include "lj_ir.h"
#include "lj_jit.h"
#include "lj_iropt.h"
+#include "lj_ircall.h"
/* Some local macros to save typing. Undef'd at the end. */
#define IR(ref) (&J->cur.ir[(ref)])
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)
{
IRRef ta = fins->op1;
return 0; /* Conflict. */
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 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. */
void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t)
{
LJ_FUNC GCtab * LJ_FASTCALL lj_tab_new1(lua_State *L, uint32_t ahsize);
#endif
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);
#if LJ_HASFFI
LJ_FUNC void lj_tab_rehash(lua_State *L, GCtab *t);