From 4593fb5e29adc09cd53beaba8777f5656434c08d Mon Sep 17 00:00:00 2001
From: Mike Pall <mike>
Date: Mon, 25 Nov 2013 15:18:31 +0100
Subject: Add table.clear().

---
 src/Makefile.dep  |  2 +-
 src/lib_table.c   | 12 ++++++++++++
 src/lj_ffrecord.c | 10 ++++++++++
 src/lj_ircall.h   |  1 +
 src/lj_opt_mem.c  | 11 ++++++++++-
 src/lj_tab.c      | 11 +++++++++++
 src/lj_tab.h      |  1 +
 7 files changed, 46 insertions(+), 2 deletions(-)

(limited to 'src')

diff --git a/src/Makefile.dep b/src/Makefile.dep
index 97f8125a..9aefb236 100644
--- a/src/Makefile.dep
+++ b/src/Makefile.dep
@@ -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_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
diff --git a/src/lib_table.c b/src/lib_table.c
index 91c022bb..4436ebd7 100644
--- a/src/lib_table.c
+++ b/src/lib_table.c
@@ -273,11 +273,22 @@ LJLIB_NOREG LJLIB_CF(table_new)		LJLIB_REC(.)
   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"
@@ -290,6 +301,7 @@ LUALIB_API int luaopen_table(lua_State *L)
   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;
 }
 
diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c
index de74a3ec..69614d92 100644
--- a/src/lj_ffrecord.c
+++ b/src/lj_ffrecord.c
@@ -1024,6 +1024,16 @@ static void LJ_FASTCALL recff_table_new(jit_State *J, RecordFFData *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 ------------------------------------------ */
 
 /* Get FILE* for I/O function. Any I/O error aborts recording, so there's
diff --git a/src/lj_ircall.h b/src/lj_ircall.h
index 53eb4638..db5ed5ab 100644
--- a/src/lj_ircall.h
+++ b/src/lj_ircall.h
@@ -144,6 +144,7 @@ typedef struct CCallInfo {
   _(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) \
diff --git a/src/lj_opt_mem.c b/src/lj_opt_mem.c
index 7177ce2c..d705bf3d 100644
--- a/src/lj_opt_mem.c
+++ b/src/lj_opt_mem.c
@@ -17,6 +17,7 @@
 #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)])
@@ -308,7 +309,7 @@ int LJ_FASTCALL lj_opt_fwd_href_nokey(jit_State *J)
   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;
@@ -319,6 +320,14 @@ int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim)
       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. */
 }
 
diff --git a/src/lj_tab.c b/src/lj_tab.c
index 37a3c32c..643d0819 100644
--- a/src/lj_tab.c
+++ b/src/lj_tab.c
@@ -204,6 +204,17 @@ GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt)
   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)
 {
diff --git a/src/lj_tab.h b/src/lj_tab.h
index 5ec73286..b6e85579 100644
--- a/src/lj_tab.h
+++ b/src/lj_tab.h
@@ -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);
 #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);
-- 
cgit v1.2.3-55-g6feb