lua inbinary strings

Allows saving of ram by reusing strings already stored in the binary
and storing a pointer instead of malloc and copy to get them inside
the lua state

Saves about 1.5K overall

Derivative of work by bogdanm
RAM optimizations: pseudo RO strings, functions in Flash
https://github.com/elua/elua/commit/d54659b5723bcd2b1e3900362398c72c18a9aa0b

Change-Id: I21d6dcfa32523877efd9f70fb0f88f2a02872649
diff --git a/apps/plugins/lua/lauxlib.c b/apps/plugins/lua/lauxlib.c
index 9597f63..5e7c159 100644
--- a/apps/plugins/lua/lauxlib.c
+++ b/apps/plugins/lua/lauxlib.c
@@ -11,10 +11,12 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "lstring.h" /* ROCKLUA ADDED */
 
 
 /* This file uses only the official API of Lua.
 ** Any function declared here could be written as an application function.
+** Note ** luaS_newlloc breaks this guarantee ROCKLUA ADDED
 */
 
 #define lauxlib_c
@@ -239,23 +241,36 @@
 }
 
 
+ /* ROCKLUA ADDED */
+static int libsize_storenames (lua_State *L, const char* libname, const luaL_Reg *l) {
+  int size = 0;
+  if (libname)
+    luaS_newlloc(L, libname, TSTR_INBIN);
+  for (; l->name; l++) {
+    size++;
+    luaS_newlloc(L, l->name, TSTR_INBIN);
+  }
+  return size;
+}
+
+
 LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
                                 const luaL_Reg *l) {
   luaI_openlib(L, libname, l, 0);
 }
 
-
+#if 0
 static int libsize (const luaL_Reg *l) {
   int size = 0;
   for (; l->name; l++) size++;
   return size;
 }
-
+#endif
 
 LUALIB_API void luaI_openlib (lua_State *L, const char *libname,
                               const luaL_Reg *l, int nup) {
+  int size = libsize_storenames(L, libname, l);
   if (libname) {
-    int size = libsize(l);
     /* check whether lib already exists */
     luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);
     lua_getfield(L, -1, libname);  /* get _LOADED[libname] */
diff --git a/apps/plugins/lua/lgc.c b/apps/plugins/lua/lgc.c
index e909c79..98194c1 100644
--- a/apps/plugins/lua/lgc.c
+++ b/apps/plugins/lua/lgc.c
@@ -388,7 +388,7 @@
     }
     case LUA_TSTRING: {
       G(L)->strt.nuse--;
-      luaM_freemem(L, o, sizestring(gco2ts(o)));
+      luaM_freemem(L, o, sizetstring((gco2ts(o))->type, (gco2ts(o))->len));
       break;
     }
     case LUA_TUSERDATA: {
diff --git a/apps/plugins/lua/llex.c b/apps/plugins/lua/llex.c
index 6f78d48..723d46c 100644
--- a/apps/plugins/lua/llex.c
+++ b/apps/plugins/lua/llex.c
@@ -64,8 +64,8 @@
 void luaX_init (lua_State *L) {
   int i;
   for (i=0; i<NUM_RESERVED; i++) {
-    TString *ts = luaS_new(L, luaX_tokens[i]);
-    luaS_fix(ts);  /* reserved words are never collected */
+    /* reserved words are never collected */
+    TString *ts = luaS_newlloc(L, luaX_tokens[i], TSTR_INBIN | TSTR_FIXED);
     lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN);
     ts->tsv.reserved = cast_byte(i+1);  /* reserved word */
   }
diff --git a/apps/plugins/lua/lobject.c b/apps/plugins/lua/lobject.c
index a351ff4..65a23cf 100644
--- a/apps/plugins/lua/lobject.c
+++ b/apps/plugins/lua/lobject.c
@@ -107,6 +107,21 @@
 }
 
 
+/* ROCKLUA ADDED -- Retrieves C string from TString */
+const char *luaO_getstring(const TString * ts){
+  const char *string;
+#ifdef INBINARYSTRINGS
+  if (testbits((ts)->tsv.type, TSTR_INBIN))
+    string = *(cast(const char **, (ts) + 1));
+  else
+#else
+  if (true)
+#endif
+    string = cast(const char *, (ts) + 1);
+  return string;
+}
+
+
 /* this function handles only `%d', `%c', %f, %p, and `%s' formats */
 const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
   int n = 1;
diff --git a/apps/plugins/lua/lobject.h b/apps/plugins/lua/lobject.h
index 93288fe..26d2a81 100644
--- a/apps/plugins/lua/lobject.h
+++ b/apps/plugins/lua/lobject.h
@@ -201,13 +201,14 @@
   struct {
     CommonHeader;
     lu_byte reserved;
+    lu_byte type;
     unsigned int hash;
     size_t len;
   } tsv;
 } TString;
 
 
-#define getstr(ts)	cast(const char *, (ts) + 1)
+#define getstr(ts) (luaO_getstring(ts)) /* ROCKLUA ADDED */
 #define svalue(o)       getstr(rawtsvalue(o))
 
 
@@ -371,6 +372,7 @@
 LUAI_FUNC int luaO_fb2int (int x);
 LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2);
 LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result);
+LUAI_FUNC const char *luaO_getstring(const TString * ts); /* ROCKLUA ADDED */
 LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
                                                        va_list argp);
 LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
diff --git a/apps/plugins/lua/lstring.c b/apps/plugins/lua/lstring.c
index 4911315..bf0536e 100644
--- a/apps/plugins/lua/lstring.c
+++ b/apps/plugins/lua/lstring.c
@@ -2,6 +2,8 @@
 ** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
 ** String table (keeps all strings handled by Lua)
 ** See Copyright Notice in lua.h
+** luaS_newllocstr is adapted from "elua -- pseudo RO strings"
+** by bogdanm, distributed under a MIT license.
 */
 
 
@@ -48,19 +50,26 @@
 
 
 static TString *newlstr (lua_State *L, const char *str, size_t l,
-                                       unsigned int h) {
+                                       unsigned int h, char type) {
   TString *ts;
   stringtable *tb;
-  if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
+  if (l > ((MAX_SIZET - sizeof(TString))/sizeof(char)) - sizeof(""))
     luaM_toobig(L);
-  ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString)));
+  ts = cast(TString *, luaM_malloc(L, sizetstring(type, l)));
   ts->tsv.len = l;
   ts->tsv.hash = h;
   ts->tsv.marked = luaC_white(G(L));
+  if (testbits(type, TSTR_FIXED))
+    luaS_fix(ts);
   ts->tsv.tt = LUA_TSTRING;
   ts->tsv.reserved = 0;
-  memcpy(ts+1, str, l*sizeof(char));
-  ((char *)(ts+1))[l] = '\0';  /* ending 0 */
+  ts->tsv.type = cast_byte(type);
+  if (testbits(type, TSTR_INBIN)) /* ROCKLUA ADDED */
+    *(const char **)(ts+1) = str; /* store a pointer to the string instead */
+  else {
+    memcpy(ts+1, str, l*sizeof(char));
+    ((char *)(ts+1))[l] = '\0';  /* ending 0 */
+  }
   tb = &G(L)->strt;
   h = lmod(h, tb->size);
   ts->tsv.next = tb->hash[h];  /* chain new entry */
@@ -72,8 +81,16 @@
 }
 
 
-TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
+TString *luaS_newllocstr (lua_State *L, const char *str, size_t l, char type) {
   GCObject *o;
+  if (testbits(type, TSTR_CHKSZ))
+    l = strlen(str);
+#ifdef INBINARYSTRINGS
+  else if (!testbits(type, TSTR_ISLIT))
+#else
+  if (true)
+#endif
+    resetbits(type, TSTR_INBIN); /* only whole strings can be used inbin */
   unsigned int h = cast(unsigned int, l);  /* seed */
   size_t step = (l>>5)+1;  /* if string is too long, don't hash all its chars */
   size_t l1;
@@ -86,10 +103,12 @@
     if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {
       /* string may be dead */
       if (isdead(G(L), o)) changewhite(o);
+      if (testbits(type, TSTR_FIXED))
+        luaS_fix(ts);
       return ts;
     }
   }
-  return newlstr(L, str, l, h);  /* not found */
+  return newlstr(L, str, l, h, type);  /* not found */
 }
 
 
diff --git a/apps/plugins/lua/lstring.h b/apps/plugins/lua/lstring.h
index c88e4c1..8ca69b8 100644
--- a/apps/plugins/lua/lstring.h
+++ b/apps/plugins/lua/lstring.h
@@ -12,20 +12,29 @@
 #include "lobject.h"
 #include "lstate.h"
 
-
-#define sizestring(s)	(sizeof(union TString)+((s)->len+1)*sizeof(char))
+/* ROCKLUA ADDED */
+#define TSTR_INBLOB    0 /* string will be allocated at end of tstring struct */
+#define TSTR_INBIN     1 /* string is static within binary, pointer stored    */
+#define TSTR_FIXED     2 /* string won't be collected for duration of L state */
+#define TSTR_CHKSZ     4 /* luaS_newllocstr shall determine size of string    */
+#define TSTR_ISLIT     8 | TSTR_INBIN /* literal string static within binary  */
+#define sizetstring(t, l) (sizeof(union TString) + (testbits((t), TSTR_INBIN) ? \
+                                   sizeof(const char **) : ((l)+1)*sizeof(char)))
 
 #define sizeudata(u)	(sizeof(union Udata)+(u)->len)
 
-#define luaS_new(L, s)	(luaS_newlstr(L, s, strlen(s)))
-#define luaS_newliteral(L, s)	(luaS_newlstr(L, "" s, \
-                                 (sizeof(s)/sizeof(char))-1))
+#define luaS_new(L, s)  (luaS_newllocstr(L, s, 0, TSTR_INBLOB | TSTR_CHKSZ))
+#define luaS_newlstr(L, s, len) (luaS_newllocstr(L, s, len, TSTR_INBLOB))
+#define luaS_newlloc(L, s, t)   (luaS_newllocstr(L, s, 0, ((t) | TSTR_CHKSZ)))
+#define luaS_newliteral(L, s)   (luaS_newllocstr(L, "" s, \
+                                 (sizeof(s)/sizeof(char))-1, TSTR_ISLIT))
 
 #define luaS_fix(s)	l_setbit((s)->tsv.marked, FIXEDBIT)
 
 LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
 LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
-LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
-
+/* ROCKLUA ADDED */
+LUAI_FUNC TString *luaS_newllocstr (lua_State *L,
+                                    const char *str, size_t l, char type);
 
 #endif
diff --git a/apps/plugins/lua/ltm.c b/apps/plugins/lua/ltm.c
index c27f0f6..9460280 100644
--- a/apps/plugins/lua/ltm.c
+++ b/apps/plugins/lua/ltm.c
@@ -36,10 +36,8 @@
     "__concat", "__call"
   };
   int i;
-  for (i=0; i<TM_N; i++) {
-    G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
-    luaS_fix(G(L)->tmname[i]);  /* never collect these names */
-  }
+  for (i=0; i<TM_N; i++) /* never collect these names */
+    G(L)->tmname[i] = luaS_newlloc(L, luaT_eventname[i], TSTR_INBIN | TSTR_FIXED);
 }
 
 
diff --git a/apps/plugins/lua/rockconf.h b/apps/plugins/lua/rockconf.h
index a13146d..89ab82e 100644
--- a/apps/plugins/lua/rockconf.h
+++ b/apps/plugins/lua/rockconf.h
@@ -31,6 +31,7 @@
 
 #undef LUA_PATH_DEFAULT
 #define LUA_PATH_DEFAULT  "$/?.lua;" "$/?/init.lua;" VIEWERS_DIR"/lua/?.lua;" VIEWERS_DIR"/lua/?/init.lua;"
+#define INBINARYSTRINGS /* Static strings stored as pointer rather than copied into lua state */
 
 #include <setjmp.h>
 
diff --git a/apps/plugins/lua/rocklib.c b/apps/plugins/lua/rocklib.c
index 9ad6411..426dd07 100644
--- a/apps/plugins/lua/rocklib.c
+++ b/apps/plugins/lua/rocklib.c
@@ -25,6 +25,7 @@
 #define LUA_LIB
 
 #include "lua.h"
+#include "lstring.h"
 
 #include "lauxlib.h"
 #include "rocklib.h"
@@ -835,6 +836,7 @@
     static const struct lua_int_reg* rlci = rlib_const_int;
     for (; rlci->name; rlci++) {
         lua_pushinteger(L, rlci->value);
+        luaS_newlloc(L, rlci->name, TSTR_INBIN);
         lua_setfield(L, -2, rlci->name);
     }
 
@@ -853,7 +855,9 @@
 
     static const struct lua_str_reg* rlcs = rlib_const_str;
     for (; rlcs->name; rlcs++) {
+        luaS_newlloc(L, rlcs->value, TSTR_INBIN);
         lua_pushstring(L, rlcs->value);
+        luaS_newlloc(L, rlcs->name, TSTR_INBIN);
         lua_setfield(L, -2, rlcs->name);
     }