Unverified Commit 5f67de8d authored by Terry Ellison's avatar Terry Ellison Committed by GitHub
Browse files

Optimise ROTable accesses and interface (#2505)

-  Optimise ROTable accesses and interface

This includes some refinements to the ROTable cache which remove the linker cludges on the CROSS_COMPILE builds.  Also keyhole tweaks to some of the Lua VM code to implrove runtimes.

I also noticed some compile time warnings during the build; the change to uz_unzip.c doesn't impact the compiled code, but does remove the compiler warnings.
parent ff44b2f0
...@@ -57,18 +57,8 @@ ...@@ -57,18 +57,8 @@
const LOCK_IN_SECTION(libs) \ const LOCK_IN_SECTION(libs) \
luaL_Reg MODULE_PASTE_(lua_lib_,cfgname) = { luaname, initfunc }; \ luaL_Reg MODULE_PASTE_(lua_lib_,cfgname) = { luaname, initfunc }; \
const LOCK_IN_SECTION(rotable) \ const LOCK_IN_SECTION(rotable) \
luaR_table MODULE_EXPAND_PASTE_(cfgname,MODULE_EXPAND_PASTE_(_module_selected,MODULE_PASTE_(LUA_USE_MODULES_,cfgname))) \ luaR_entry MODULE_EXPAND_PASTE_(cfgname,MODULE_EXPAND_PASTE_(_module_selected,MODULE_PASTE_(LUA_USE_MODULES_,cfgname))) \
= { luaname, map } = {LSTRKEY(luaname), LROVAL(map)}
/* System module registration support, not using LUA_USE_MODULES_XYZ. */
#define BUILTIN_LIB_INIT(name, luaname, initfunc) \
const LOCK_IN_SECTION(libs) \
luaL_Reg MODULE_PASTE_(lua_lib_,name) = { luaname, initfunc }
#define BUILTIN_LIB(name, luaname, map) \
const LOCK_IN_SECTION(rotable) \
luaR_table MODULE_PASTE_(lua_rotable_,name) = { luaname, map }
#if !defined(LUA_CROSS_COMPILER) && !(MIN_OPT_LEVEL==2 && LUA_OPTIMIZE_MEMORY==2) #if !defined(LUA_CROSS_COMPILER) && !(MIN_OPT_LEVEL==2 && LUA_OPTIMIZE_MEMORY==2)
# error "NodeMCU modules must be built with LTR enabled (MIN_OPT_LEVEL=2 and LUA_OPTIMIZE_MEMORY=2)" # error "NodeMCU modules must be built with LTR enabled (MIN_OPT_LEVEL=2 and LUA_OPTIMIZE_MEMORY=2)"
......
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
#define lauxlib_c #define lauxlib_c
#define LUA_LIB #define LUA_LIB
#include "lrotable.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lgc.h" #include "lgc.h"
#include "ldo.h" #include "ldo.h"
...@@ -555,14 +553,7 @@ LUALIB_API const char *luaL_findtable (lua_State *L, int idx, ...@@ -555,14 +553,7 @@ LUALIB_API const char *luaL_findtable (lua_State *L, int idx,
if (e == NULL) e = fname + c_strlen(fname); if (e == NULL) e = fname + c_strlen(fname);
lua_pushlstring(L, fname, e - fname); lua_pushlstring(L, fname, e - fname);
lua_rawget(L, -2); lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
/* If looking for a global variable, check the rotables too */
void *ptable = luaR_findglobal(fname, e - fname);
if (ptable) {
lua_pop(L, 1);
lua_pushrotable(L, ptable);
}
}
if (lua_isnil(L, -1)) { /* no such field? */ if (lua_isnil(L, -1)) { /* no such field? */
lua_pop(L, 1); /* remove this nil */ lua_pop(L, 1); /* remove this nil */
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include C_HEADER_STDLIB #include C_HEADER_STDLIB
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
#include "lrotable.h" #include "lrodefs.h"
...@@ -462,71 +462,62 @@ static int luaB_newproxy (lua_State *L) { ...@@ -462,71 +462,62 @@ static int luaB_newproxy (lua_State *L) {
return 1; return 1;
} }
#define LUA_BASELIB_FUNCLIST\
{LSTRKEY("assert"), LFUNCVAL(luaB_assert)},\
{LSTRKEY("collectgarbage"), LFUNCVAL(luaB_collectgarbage)},\
{LSTRKEY("dofile"), LFUNCVAL(luaB_dofile)},\
{LSTRKEY("error"), LFUNCVAL(luaB_error)},\
{LSTRKEY("gcinfo"), LFUNCVAL(luaB_gcinfo)},\
{LSTRKEY("getfenv"), LFUNCVAL(luaB_getfenv)},\
{LSTRKEY("getmetatable"), LFUNCVAL(luaB_getmetatable)},\
{LSTRKEY("loadfile"), LFUNCVAL(luaB_loadfile)},\
{LSTRKEY("load"), LFUNCVAL(luaB_load)},\
{LSTRKEY("loadstring"), LFUNCVAL(luaB_loadstring)},\
{LSTRKEY("next"), LFUNCVAL(luaB_next)},\
{LSTRKEY("pcall"), LFUNCVAL(luaB_pcall)},\
{LSTRKEY("print"), LFUNCVAL(luaB_print)},\
{LSTRKEY("rawequal"), LFUNCVAL(luaB_rawequal)},\
{LSTRKEY("rawget"), LFUNCVAL(luaB_rawget)},\
{LSTRKEY("rawset"), LFUNCVAL(luaB_rawset)},\
{LSTRKEY("select"), LFUNCVAL(luaB_select)},\
{LSTRKEY("setfenv"), LFUNCVAL(luaB_setfenv)},\
{LSTRKEY("setmetatable"), LFUNCVAL(luaB_setmetatable)},\
{LSTRKEY("tonumber"), LFUNCVAL(luaB_tonumber)},\
{LSTRKEY("tostring"), LFUNCVAL(luaB_tostring)},\
{LSTRKEY("type"), LFUNCVAL(luaB_type)},\
{LSTRKEY("unpack"), LFUNCVAL(luaB_unpack)},\
{LSTRKEY("xpcall"), LFUNCVAL(luaB_xpcall)}
#if LUA_OPTIMIZE_MEMORY == 2
#undef MIN_OPT_LEVEL
#define MIN_OPT_LEVEL 2
#include "lrodefs.h" #include "lrodefs.h"
const LUA_REG_TYPE base_funcs_list[] = {
LUA_BASELIB_FUNCLIST,
{LNILKEY, LNILVAL}
};
#endif
extern const luaR_entry lua_rotable_base[];
static int luaB_index(lua_State *L) { /*
#if LUA_OPTIMIZE_MEMORY == 2 * ESP builds use specific linker directives to marshal all ROTable declarations
int fres; * into a single ROTable in the PSECT ".lua_rotable".
if ((fres = luaR_findfunction(L, base_funcs_list)) != 0) *
return fres; * This is not practical on Posix builds using a standard link so for cross
#endif * compiler builds, separate ROTables are used for the base functions and library
const char *keyname = luaL_checkstring(L, 2); * ROTables, with the latter chained from the former using its __index meta-method.
if (!c_strcmp(keyname, "_VERSION")) { * In this case all library ROTables are defined in linit.c.
lua_pushliteral(L, LUA_VERSION); */
return 1; #ifdef LUA_CROSS_COMPILER
} #define BASE_ROTABLE base_func_map
void *res = luaR_findglobal(keyname, c_strlen(keyname)); #define LOCK_IN_ROTABLE
if (!res) static const LUA_REG_TYPE base_func_meta[] = {
return 0; LROT_TABENTRY(__index, lua_rotable_base),
else { LROT_END};
lua_pushrotable(L, res); #else
return 1; #define BASE_ROTABLE lua_rotable_base
} #define LOCK_IN_ROTABLE __attribute__((used,unused,section(".lua_rotable")))
} #endif
static const luaL_Reg base_funcs[] = { static const LUA_REG_TYPE LOCK_IN_ROTABLE base_func_map[] = {
#if LUA_OPTIMIZE_MEMORY != 2 LROT_FUNCENTRY(assert, luaB_assert),
#undef MIN_OPT_LEVEL LROT_FUNCENTRY(collectgarbage, luaB_collectgarbage),
#define MIN_OPT_LEVEL 0 LROT_FUNCENTRY(dofile, luaB_dofile),
#include "lrodefs.h" LROT_FUNCENTRY(error, luaB_error),
LUA_BASELIB_FUNCLIST, LROT_FUNCENTRY(gcinfo, luaB_gcinfo),
LROT_FUNCENTRY(getfenv, luaB_getfenv),
LROT_FUNCENTRY(getmetatable, luaB_getmetatable),
LROT_FUNCENTRY(loadfile, luaB_loadfile),
LROT_FUNCENTRY(load, luaB_load),
LROT_FUNCENTRY(loadstring, luaB_loadstring),
LROT_FUNCENTRY(next, luaB_next),
LROT_FUNCENTRY(pcall, luaB_pcall),
LROT_FUNCENTRY(print, luaB_print),
LROT_FUNCENTRY(rawequal, luaB_rawequal),
LROT_FUNCENTRY(rawget, luaB_rawget),
LROT_FUNCENTRY(rawset, luaB_rawset),
LROT_FUNCENTRY(select, luaB_select),
LROT_FUNCENTRY(setfenv, luaB_setfenv),
LROT_FUNCENTRY(setmetatable, luaB_setmetatable),
LROT_FUNCENTRY(tonumber, luaB_tonumber),
LROT_FUNCENTRY(tostring, luaB_tostring),
LROT_FUNCENTRY(type, luaB_type),
LROT_FUNCENTRY(unpack, luaB_unpack),
LROT_FUNCENTRY(xpcall, luaB_xpcall)
#ifdef LUA_CROSS_COMPILER
,LROT_TABENTRY(__metatable, base_func_meta),
LROT_END
#endif #endif
{"__index", luaB_index}, };
static const luaL_Reg base_funcs[] = {
{NULL, NULL} {NULL, NULL}
}; };
...@@ -661,7 +652,6 @@ static int luaB_corunning (lua_State *L) { ...@@ -661,7 +652,6 @@ static int luaB_corunning (lua_State *L) {
#undef MIN_OPT_LEVEL #undef MIN_OPT_LEVEL
#define MIN_OPT_LEVEL 1 #define MIN_OPT_LEVEL 1
#include "lrodefs.h"
const LUA_REG_TYPE co_funcs[] = { const LUA_REG_TYPE co_funcs[] = {
{LSTRKEY("create"), LFUNCVAL(luaB_cocreate)}, {LSTRKEY("create"), LFUNCVAL(luaB_cocreate)},
{LSTRKEY("resume"), LFUNCVAL(luaB_coresume)}, {LSTRKEY("resume"), LFUNCVAL(luaB_coresume)},
...@@ -682,7 +672,6 @@ static void auxopen (lua_State *L, const char *name, ...@@ -682,7 +672,6 @@ static void auxopen (lua_State *L, const char *name,
lua_setfield(L, -2, name); lua_setfield(L, -2, name);
} }
static void base_open (lua_State *L) { static void base_open (lua_State *L) {
/* set global _G */ /* set global _G */
lua_pushvalue(L, LUA_GLOBALSINDEX); lua_pushvalue(L, LUA_GLOBALSINDEX);
...@@ -691,11 +680,12 @@ static void base_open (lua_State *L) { ...@@ -691,11 +680,12 @@ static void base_open (lua_State *L) {
luaL_register_light(L, "_G", base_funcs); luaL_register_light(L, "_G", base_funcs);
#if LUA_OPTIMIZE_MEMORY > 0 #if LUA_OPTIMIZE_MEMORY > 0
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
#else lua_pushrotable(L, (void *)BASE_ROTABLE);
lua_setglobal(L, "__index");
#endif
lua_pushliteral(L, LUA_VERSION); lua_pushliteral(L, LUA_VERSION);
lua_setglobal(L, "_VERSION"); /* set global _VERSION */ lua_setglobal(L, "_VERSION"); /* set global _VERSION */
#endif
/* `ipairs' and `pairs' need auxliliary functions as upvalues */ /* `ipairs' and `pairs' need auxliliary functions as upvalues */
auxopen(L, "ipairs", luaB_ipairs, ipairsaux); auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
auxopen(L, "pairs", luaB_pairs, luaB_next); auxopen(L, "pairs", luaB_pairs, luaB_next);
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
#include "lrotable.h"
#include "lstring.h" #include "lstring.h"
#include "lflash.h" #include "lflash.h"
#include "user_modules.h" #include "user_modules.h"
......
...@@ -168,10 +168,14 @@ static int traversetable (global_State *g, Table *h) { ...@@ -168,10 +168,14 @@ static int traversetable (global_State *g, Table *h) {
int i; int i;
int weakkey = 0; int weakkey = 0;
int weakvalue = 0; int weakvalue = 0;
const TValue *mode; const TValue *mode = luaO_nilobject;
if (h->metatable && !luaR_isrotable(h->metatable))
markobject(g, h->metatable); if (h->metatable) {
mode = gfasttm(g, h->metatable, TM_MODE); if (!luaR_isrotable(h->metatable))
markobject(g, h->metatable);
mode = gfasttm(g, h->metatable, TM_MODE);
}
if (mode && ttisstring(mode)) { /* is there a weak mode? */ if (mode && ttisstring(mode)) { /* is there a weak mode? */
weakkey = (c_strchr(svalue(mode), 'k') != NULL); weakkey = (c_strchr(svalue(mode), 'k') != NULL);
weakvalue = (c_strchr(svalue(mode), 'v') != NULL); weakvalue = (c_strchr(svalue(mode), 'v') != NULL);
......
...@@ -15,60 +15,71 @@ ...@@ -15,60 +15,71 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "luaconf.h" #include "luaconf.h"
#include "module.h" #include "module.h"
#if defined(LUA_CROSS_COMPILER)
BUILTIN_LIB( start_list, NULL, NULL); #if !defined(LUA_CROSS_COMPILER) && !(MIN_OPT_LEVEL==2 && LUA_OPTIMIZE_MEMORY==2)
BUILTIN_LIB_INIT( start_list, NULL, NULL); # error "NodeMCU modules must be built with LTR enabled (MIN_OPT_LEVEL=2 and LUA_OPTIMIZE_MEMORY=2)"
#endif #endif
extern const luaR_entry strlib[], tab_funcs[], dblib[], extern const luaR_entry strlib[], tab_funcs[], dblib[],
co_funcs[], math_map[], syslib[]; co_funcs[], math_map[], syslib[];
extern const luaR_entry syslib[], io_funcs[]; // Only used on cross-compile builds
BUILTIN_LIB_INIT( BASE, "", luaopen_base);
BUILTIN_LIB_INIT( LOADLIB, LUA_LOADLIBNAME, luaopen_package);
BUILTIN_LIB( STRING, LUA_STRLIBNAME, strlib);
BUILTIN_LIB_INIT( STRING, LUA_STRLIBNAME, luaopen_string);
BUILTIN_LIB( TABLE, LUA_TABLIBNAME, tab_funcs);
BUILTIN_LIB_INIT( TABLE, LUA_TABLIBNAME, luaopen_table);
BUILTIN_LIB( DBG, LUA_DBLIBNAME, dblib);
BUILTIN_LIB_INIT( DBG, LUA_DBLIBNAME, luaopen_debug);
BUILTIN_LIB( CO, LUA_COLIBNAME, co_funcs);
BUILTIN_LIB( MATH, LUA_MATHLIBNAME, math_map);
#if defined(LUA_CROSS_COMPILER)
extern const luaR_entry syslib[], iolib[];
BUILTIN_LIB( OS, LUA_OSLIBNAME, syslib);
BUILTIN_LIB_INIT( IO, LUA_IOLIBNAME, luaopen_io);
BUILTIN_LIB( end_list, NULL, NULL);
BUILTIN_LIB_INIT( end_list, NULL, NULL);
/* /*
* These base addresses are internal to this module for cross compile builds * The NodeMCU Lua initalisation has been adapted to use linker-based module
* This also exploits feature of the GCC code generator that the variables are * registration. This uses a PSECT naming convention to allow the lib and rotab
* emitted in either normal OR reverse order within PSECT. * entries to be collected by the linker into consoliated tables. The linker
* defines lua_libs_base and lua_rotable_base.
*
* This is not practical on Posix builds which use a standard loader declaration
* so for cross compiler builds, separate ROTables are used for the base functions
* and library ROTables, with the latter chained from the former using its __index
* meta-method. In this case all library ROTables are defined here, avoiding the
* need for linker magic is avoided on host builds.
*/ */
#define isascending(n) ((&(n ## _end_list)-&(n ## _start_list))>0)
static const luaL_Reg *lua_libs; #if defined(LUA_CROSS_COMPILER)
const luaR_table *lua_rotable; #define LUA_ROTABLES lua_rotable_base
#else #define LUA_LIBS lua_libs_base
/* These base addresses are Xtensa toolchain linker constants for Firmware builds */ #else /* declare Xtensa toolchain linker defined constants */
extern const luaL_Reg lua_libs_base[]; extern const luaL_Reg lua_libs_base[];
extern const luaR_table lua_rotable_base[]; extern const luaR_entry lua_rotable_base[];
static const luaL_Reg *lua_libs = lua_libs_base; #define LUA_ROTABLES lua_rotable_core
const luaR_table *lua_rotable = lua_rotable_base; #define LUA_LIBS lua_libs_core
#endif #endif
static const LOCK_IN_SECTION(libs) luaL_reg LUA_LIBS[] = {
{"", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_STRLIBNAME, luaopen_string},
{LUA_TABLIBNAME, luaopen_table},
{LUA_DBLIBNAME, luaopen_debug}
#if defined(LUA_CROSS_COMPILER)
,{LUA_IOLIBNAME, luaopen_io},
{NULL, NULL}
#endif
};
void luaL_openlibs (lua_State *L) { #define ENTRY(n,t) {LSTRKEY(n), LRO_ROVAL(t)}
const LOCK_IN_SECTION(rotable) ROTable LUA_ROTABLES[] = {
ENTRY("ROM", LUA_ROTABLES),
ENTRY(LUA_STRLIBNAME, strlib),
ENTRY(LUA_TABLIBNAME, tab_funcs),
ENTRY(LUA_DBLIBNAME, dblib),
ENTRY(LUA_COLIBNAME, co_funcs),
ENTRY(LUA_MATHLIBNAME, math_map)
#if defined(LUA_CROSS_COMPILER) #if defined(LUA_CROSS_COMPILER)
lua_libs = (isascending(lua_lib) ? &lua_lib_start_list : &lua_lib_end_list) + 1; ,ENTRY(LUA_OSLIBNAME, syslib),
lua_rotable = (isascending(lua_rotable) ? &lua_rotable_start_list : &lua_rotable_end_list) + 1; LROT_END
#endif #endif
const luaL_Reg *lib = lua_libs; };
void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib = lua_libs_base;
/* loop round and open libraries */
for (; lib->name; lib++) { for (; lib->name; lib++) {
if (lib->func) if (lib->func) {
{
lua_pushcfunction(L, lib->func); lua_pushcfunction(L, lib->func);
lua_pushstring(L, lib->name); lua_pushstring(L, lib->name);
lua_call(L, 1, 0); lua_call(L, 1, 0);
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
#include "lrotable.h"
#undef PI #undef PI
#define PI (3.14159265358979323846) #define PI (3.14159265358979323846)
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
#include "lrotable.h"
/* prefix for open functions in C libraries */ /* prefix for open functions in C libraries */
#define LUA_POF "luaopen_" #define LUA_POF "luaopen_"
...@@ -474,10 +473,11 @@ static int ll_require (lua_State *L) { ...@@ -474,10 +473,11 @@ static int ll_require (lua_State *L) {
return 1; /* package is already loaded */ return 1; /* package is already loaded */
} }
/* Is this a readonly table? */ /* Is this a readonly table? */
void *res = luaR_findglobal(name, c_strlen(name)); lua_getfield(L, LUA_GLOBALSINDEX, name);
if (res) { if(lua_isrotable(L,-1)) {
lua_pushrotable(L, res);
return 1; return 1;
} else {
lua_pop(L, 1);
} }
/* else must load it; iterate over available loaders */ /* else must load it; iterate over available loaders */
lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
...@@ -563,8 +563,13 @@ static void modinit (lua_State *L, const char *modname) { ...@@ -563,8 +563,13 @@ static void modinit (lua_State *L, const char *modname) {
static int ll_module (lua_State *L) { static int ll_module (lua_State *L) {
const char *modname = luaL_checkstring(L, 1); const char *modname = luaL_checkstring(L, 1);
if (luaR_findglobal(modname, c_strlen(modname))) /* Is this a readonly table? */
lua_getfield(L, LUA_GLOBALSINDEX, modname);
if(lua_isrotable(L,-1)) {
return 0; return 0;
} else {
lua_pop(L, 1);
}
int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ int loaded = lua_gettop(L) + 1; /* index of _LOADED table */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ lua_getfield(L, loaded, modname); /* get _LOADED[modname] */
......
...@@ -405,6 +405,7 @@ typedef struct Table { ...@@ -405,6 +405,7 @@ typedef struct Table {
int sizearray; /* size of `array' array */ int sizearray; /* size of `array' array */
} Table; } Table;
typedef const struct luaR_entry ROTable;
/* /*
** `module' operation for hashing (size is always a power of 2) ** `module' operation for hashing (size is always a power of 2)
......
...@@ -38,5 +38,10 @@ ...@@ -38,5 +38,10 @@
return 1 return 1
#endif #endif
#define LROT_TABENTRY(n,t) {LSTRKEY(#n), LRO_ROVAL(t)}
#define LROT_FUNCENTRY(n,f) {LSTRKEY(#n), LRO_FUNCVAL(f)}
#define LROT_NUMENTRY(n,x) {LSTRKEY(#n), LRO_NUMVAL(x)}
#define LROT_END {LNILKEY, LNILVAL}
#endif /* lrodefs_h */ #endif /* lrodefs_h */
...@@ -9,77 +9,139 @@ ...@@ -9,77 +9,139 @@
#include "lobject.h" #include "lobject.h"
#include "lapi.h" #include "lapi.h"
/* Local defines */ #define ALIGNED_STRING (__attribute__((aligned(4))) char *)
#define LUAR_FINDFUNCTION 0 #define LA_LINES 16
#define LUAR_FINDVALUE 1 #define LA_SLOTS 4
//#define COLLECT_STATS
/* Externally defined read-only table array */
extern const luaR_table *lua_rotable; /*
* All keyed ROtable access passes through luaR_findentry(). ROTables
/* Find a global "read only table" in the constant lua_rotable array */ * are simply a list of <key><TValue value> pairs. The existing algo
void* luaR_findglobal(const char *name, unsigned len) { * did a linear scan of this vector of pairs looking for a match.
unsigned i; *
* A N×M lookaside cache has been added, with a simple hash on the key's
if (c_strlen(name) > LUA_MAX_ROTABLE_NAME) * TString addr and the ROTable addr to identify one of N lines. Each
return NULL; * line has M slots which are scanned. This is all done in RAM and is
for (i=0; lua_rotable[i].name; i ++) * perhaps 20x faster than the corresponding random Flash accesses which
if (*lua_rotable[i].name != '\0' && c_strlen(lua_rotable[i].name) == len && !c_strncmp(lua_rotable[i].name, name, len)) { * will cause flash faults.
return (void*)(lua_rotable[i].pentries); *
* If a match is found and the table addresses match, then this entry is
* probed first. In practice the hit-rate here is over 99% so the code
* rarely fails back to doing the linear scan in ROM.
*
* Note that this hash does a couple of prime multiples and a modulus 2^X
* with is all evaluated in H/W, and adequately randomizes the lookup.
*/
#define HASH(a,b) (519*((size_t)(a)>>4) + 17*((size_t)(b)>>4))
static struct {
unsigned hash;
unsigned addr:24;
unsigned ndx:8;
} cache[LA_LINES][LA_SLOTS];
#ifdef COLLECT_STATS
unsigned cache_stats[3];
#define COUNT(i) cache_stats[i]++
#else
#define COUNT(i)
#endif
static int lookup_cache(unsigned hash, ROTable *rotable) {
int i = (hash>>2) & (LA_LINES-1), j;
for (j = 0; j<LA_SLOTS; j++) {
if (cache[i][j].hash == hash &&
((size_t)rotable & 0xffffffu) == cache[i][j].addr) {
COUNT(0);
return cache[i][j].ndx;
} }
return NULL; }
COUNT(1);
return -1;
} }
/* Find an entry in a rotable and return it */ static void update_cache(unsigned hash, ROTable *rotable, unsigned ndx) {
static const TValue* luaR_auxfind(const luaR_entry *pentry, const char *strkey, luaR_numkey numkey, unsigned *ppos) { int i = (hash)>>2 & (LA_LINES-1), j;
const TValue *res = NULL; COUNT(2);
unsigned i = 0; if (ndx>0xffu)
return;
if (pentry == NULL) for (j = LA_SLOTS-1; j>0; j--)
return NULL; cache[i][j] = cache[i][j-1];
while(pentry->key.type != LUA_TNIL) { cache[i][0].hash = hash;
if ((strkey && (pentry->key.type == LUA_TSTRING) && (!c_strcmp(pentry->key.id.strkey, strkey))) || cache[i][0].addr = (size_t) rotable;
(!strkey && (pentry->key.type == LUA_TNUMBER) && ((luaR_numkey)pentry->key.id.numkey == numkey))) { cache[i][0].ndx = ndx;
res = &pentry->value; }
break; /*
* Find a string key entry in a rotable and return it. Note that this internally
* uses a null key to denote a metatable search.
*/
const TValue* luaR_findentry(ROTable *rotable, TString *key, unsigned *ppos) {
const luaR_entry *pentry = rotable;
const char *strkey = key ? getstr(key) : ALIGNED_STRING "__metatable" ;
size_t hash = HASH(rotable, key);
unsigned i = 0;
int j = lookup_cache(hash, rotable);
if (pentry) {
if (j >= 0){
if ((pentry[j].key.type == LUA_TSTRING) &&
!c_strcmp(pentry[j].key.id.strkey, strkey)) {
if (ppos)
*ppos = j;
return &pentry[j].value;
}
}
/*
* The invariants for 1st word comparison are deferred to here since they
* aren't needed if there is a cache hit. Note that the termination null
* is included so a "on\0" has a mask of 0xFFFFFF and "a\0" has 0xFFFF.
*/
unsigned name4 = *(unsigned *)strkey;
unsigned l = key ? key->tsv.len : sizeof("__metatable")-1;
unsigned mask4 = l > 2 ? (~0u) : (~0u)>>((3-l)*8);
for(;pentry->key.type != LUA_TNIL; i++, pentry++) {
if ((pentry->key.type == LUA_TSTRING) &&
((*(unsigned *)pentry->key.id.strkey ^ name4) & mask4) == 0 &&
!c_strcmp(pentry->key.id.strkey, strkey)) {
if (ppos)
*ppos = i;
if (j==-1) {
update_cache(hash, rotable, pentry - rotable);
} else if (j != (pentry - rotable)) {
j = 0;
}
return &pentry->value;
}
} }
i ++; pentry ++;
} }
if (res && ppos) return luaO_nilobject;
*ppos = i;
return res;
} }
int luaR_findfunction(lua_State *L, const luaR_entry *ptable) { const TValue* luaR_findentryN(ROTable *rotable, luaR_numkey numkey, unsigned *ppos) {
const TValue *res = NULL; unsigned i = 0;
const char *key = luaL_checkstring(L, 2); const luaR_entry *pentry = rotable;
if (pentry) {
res = luaR_auxfind(ptable, key, 0, NULL); for ( ;pentry->key.type != LUA_TNIL; i++, pentry++) {
if (res && ttislightfunction(res)) { if (pentry->key.type == LUA_TNUMBER && (luaR_numkey) pentry->key.id.numkey == numkey) {
luaA_pushobject(L, res); if (ppos)
return 1; *ppos = i;
return &pentry->value;
}
}
} }
else return NULL;
return 0;
} }
/* Find an entry in a rotable and return its type
If "strkey" is not NULL, the function will look for a string key,
otherwise it will look for a number key */
const TValue* luaR_findentry(void *data, const char *strkey, luaR_numkey numkey, unsigned *ppos) {
return luaR_auxfind((const luaR_entry*)data, strkey, numkey, ppos);
}
/* Find the metatable of a given table */ /* Find the metatable of a given table */
void* luaR_getmeta(void *data) { void* luaR_getmeta(ROTable *rotable) {
#ifdef LUA_META_ROTABLES const TValue *res = luaR_findentry(rotable, NULL, NULL);
const TValue *res = luaR_auxfind((const luaR_entry*)data, "__metatable", 0, NULL);
return res && ttisrotable(res) ? rvalue(res) : NULL; return res && ttisrotable(res) ? rvalue(res) : NULL;
#else
return NULL;
#endif
} }
static void luaR_next_helper(lua_State *L, const luaR_entry *pentries, int pos, TValue *key, TValue *val) { static void luaR_next_helper(lua_State *L, ROTable *pentries, int pos,
TValue *key, TValue *val) {
setnilvalue(key); setnilvalue(key);
setnilvalue(val); setnilvalue(val);
if (pentries[pos].key.type != LUA_TNIL) { if (pentries[pos].key.type != LUA_TNIL) {
...@@ -91,56 +153,24 @@ static void luaR_next_helper(lua_State *L, const luaR_entry *pentries, int pos, ...@@ -91,56 +153,24 @@ static void luaR_next_helper(lua_State *L, const luaR_entry *pentries, int pos,
setobj2s(L, val, &pentries[pos].value); setobj2s(L, val, &pentries[pos].value);
} }
} }
/* next (used for iteration) */ /* next (used for iteration) */
void luaR_next(lua_State *L, void *data, TValue *key, TValue *val) { void luaR_next(lua_State *L, ROTable *rotable, TValue *key, TValue *val) {
const luaR_entry* pentries = (const luaR_entry*)data;
char strkey[LUA_MAX_ROTABLE_NAME + 1], *pstrkey = NULL;
luaR_numkey numkey = 0;
unsigned keypos; unsigned keypos;
/* Special case: if key is nil, return the first element of the rotable */ /* Special case: if key is nil, return the first element of the rotable */
if (ttisnil(key)) if (ttisnil(key))
luaR_next_helper(L, pentries, 0, key, val); luaR_next_helper(L, rotable, 0, key, val);
else if (ttisstring(key) || ttisnumber(key)) { else if (ttisstring(key) || ttisnumber(key)) {
/* Find the previoud key again */ /* Find the previous key again */
if (ttisstring(key)) { if (ttisstring(key)) {
luaR_getcstr(strkey, rawtsvalue(key), LUA_MAX_ROTABLE_NAME); luaR_findentry(rotable, rawtsvalue(key), &keypos);
pstrkey = strkey; } else {
} else luaR_findentryN(rotable, (luaR_numkey)nvalue(key), &keypos);
numkey = (luaR_numkey)nvalue(key); }
luaR_findentry(data, pstrkey, numkey, &keypos);
/* Advance to next key */ /* Advance to next key */
keypos ++; keypos ++;
luaR_next_helper(L, pentries, keypos, key, val); luaR_next_helper(L, rotable, keypos, key, val);
} }
} }
/* Convert a Lua string to a C string */
void luaR_getcstr(char *dest, const TString *src, size_t maxsize) {
if (src->tsv.len+1 > maxsize)
dest[0] = '\0';
else {
c_memcpy(dest, getstr(src), src->tsv.len);
dest[src->tsv.len] = '\0';
}
}
#ifdef LUA_META_ROTABLES
/* Set in RO check depending on platform */
#if defined(LUA_CROSS_COMPILER) && defined(__CYGWIN__)
extern char __end__[];
#define IN_RO_AREA(p) ((p) < __end__)
#elif defined(LUA_CROSS_COMPILER)
extern char _edata[];
#define IN_RO_AREA(p) ((p) < _edata)
#else /* xtensa tool chain for ESP target */
extern char _irom0_text_start[];
extern char _irom0_text_end[];
#define IN_RO_AREA(p) ((p) >= _irom0_text_start && (p) <= _irom0_text_end)
#endif
/* Return 1 if the given pointer is a rotable */
int luaR_isrotable(void *p) {
return IN_RO_AREA((char *)p);
}
#endif
...@@ -14,7 +14,11 @@ ...@@ -14,7 +14,11 @@
#define LRO_NUMVAL(v) {{.n = v}, LUA_TNUMBER} #define LRO_NUMVAL(v) {{.n = v}, LUA_TNUMBER}
#define LRO_ROVAL(v) {{.p = (void*)v}, LUA_TROTABLE} #define LRO_ROVAL(v) {{.p = (void*)v}, LUA_TROTABLE}
#define LRO_NILVAL {{.p = NULL}, LUA_TNIL} #define LRO_NILVAL {{.p = NULL}, LUA_TNIL}
#ifdef LUA_CROSS_COMPILER
#define LRO_STRKEY(k) {LUA_TSTRING, {.strkey = k}} #define LRO_STRKEY(k) {LUA_TSTRING, {.strkey = k}}
#else
#define LRO_STRKEY(k) {LUA_TSTRING, {.strkey = (STORE_ATTR char *) k}}
#endif
#define LRO_NUMKEY(k) {LUA_TNUMBER, {.numkey = k}} #define LRO_NUMKEY(k) {LUA_TNUMBER, {.numkey = k}}
#define LRO_NILKEY {LUA_TNIL, {.strkey=NULL}} #define LRO_NILKEY {LUA_TNIL, {.strkey=NULL}}
...@@ -25,40 +29,58 @@ ...@@ -25,40 +29,58 @@
typedef int luaR_numkey; typedef int luaR_numkey;
/* The next structure defines the type of a key */ /* The next structure defines the type of a key */
typedef struct typedef struct {
{
int type; int type;
union union {
{
const char* strkey; const char* strkey;
luaR_numkey numkey; luaR_numkey numkey;
} id; } id;
} luaR_key; } luaR_key;
/* An entry in the read only table */ /* An entry in the read only table */
typedef struct typedef struct luaR_entry {
{
const luaR_key key; const luaR_key key;
const TValue value; const TValue value;
} luaR_entry; } luaR_entry;
/* A rotable */ /*
typedef struct * The current ROTable implmentation is a vector of luaR_entry terminated by a
{ * nil record. The convention is to use ROtable * to refer to the entire vector
const char *name; * as a logical ROTable.
const luaR_entry *pentries; */
} luaR_table; typedef const struct luaR_entry ROTable;
void* luaR_findglobal(const char *key, unsigned len); const TValue* luaR_findentry(ROTable *tab, TString *key, unsigned *ppos);
int luaR_findfunction(lua_State *L, const luaR_entry *ptable); const TValue* luaR_findentryN(ROTable *tab, luaR_numkey numkey, unsigned *ppos);
const TValue* luaR_findentry(void *data, const char *strkey, luaR_numkey numkey, unsigned *ppos); void luaR_next(lua_State *L, ROTable *tab, TValue *key, TValue *val);
void luaR_getcstr(char *dest, const TString *src, size_t maxsize); void* luaR_getmeta(ROTable *tab);
void luaR_next(lua_State *L, void *data, TValue *key, TValue *val);
void* luaR_getmeta(void *data);
#ifdef LUA_META_ROTABLES
int luaR_isrotable(void *p); int luaR_isrotable(void *p);
/*
* Set inRO check depending on platform. Note that this implementation needs
* to work on both the host (luac.cross) and ESP targets. The luac.cross
* VM is used for the -e option, and is primarily used to be able to debug
* VM changes on the more developer-friendly hot gdb environment.
*/
#if defined(LUA_CROSS_COMPILER)
#if defined(__CYGWIN__)
#define _RODATA_END __end__
#else #else
#define luaR_isrotable(p) (0) #define _RODATA_END _edata
#endif
extern const char _RODATA_END[];
#define IN_RODATA_AREA(p) (((const char *)(p)) < _RODATA_END)
#else /* xtensa tool chain for ESP target */
extern const char _irom0_text_start[];
extern const char _irom0_text_end[];
#define IN_RODATA_AREA(p) (((const char *)(p)) >= _irom0_text_start && ((const char *)(p)) <= _irom0_text_end)
#endif #endif
/* Return 1 if the given pointer is a rotable */
#define luaR_isrotable(p) IN_RODATA_AREA(p)
#endif #endif
...@@ -80,16 +80,12 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, ...@@ -80,16 +80,12 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
return ts; return ts;
} }
#ifdef LUA_CROSS_COMPILER static int lua_is_ptr_in_ro_area(const char *p) {
#define IN_RO_AREA(p) (0) #ifdef LUA_CROSS_COMPILER
#else /* xtensa tool chain for ESP */ return 0; // TStrings are never in RO in luac.cross
extern char _irom0_text_start[]; #else
extern char _irom0_text_end[]; return IN_RODATA_AREA(p);
#define IN_RO_AREA(p) ((p) >= _irom0_text_start && (p) <= _irom0_text_end)
#endif #endif
int lua_is_ptr_in_ro_area(const char *p) {
return IN_RO_AREA(p);
} }
/* /*
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
#include "lrotable.h"
/* macro to `unsign' a character */ /* macro to `unsign' a character */
#define uchar(c) ((unsigned char)(c)) #define uchar(c) ((unsigned char)(c))
......
...@@ -580,7 +580,7 @@ const TValue *luaH_getnum (Table *t, int key) { ...@@ -580,7 +580,7 @@ const TValue *luaH_getnum (Table *t, int key) {
/* same thing for rotables */ /* same thing for rotables */
const TValue *luaH_getnum_ro (void *t, int key) { const TValue *luaH_getnum_ro (void *t, int key) {
const TValue *res = luaR_findentry(t, NULL, key, NULL); const TValue *res = luaR_findentryN(t, key, NULL);
return res ? res : luaO_nilobject; return res ? res : luaO_nilobject;
} }
...@@ -599,14 +599,10 @@ const TValue *luaH_getstr (Table *t, TString *key) { ...@@ -599,14 +599,10 @@ const TValue *luaH_getstr (Table *t, TString *key) {
} }
/* same thing for rotables */ /* same thing for rotables */
const TValue *luaH_getstr_ro (void *t, TString *key) { const TValue *luaH_getstr_ro (void *t, TString *key) {
char keyname[LUA_MAX_ROTABLE_NAME + 1]; if (!t || key->tsv.len>LUA_MAX_ROTABLE_NAME)
const TValue *res;
if (!t)
return luaO_nilobject; return luaO_nilobject;
luaR_getcstr(keyname, key, LUA_MAX_ROTABLE_NAME); return luaR_findentry(t, key, NULL);
res = luaR_findentry(t, keyname, 0, NULL);
return res ? res : luaO_nilobject;
} }
...@@ -745,7 +741,7 @@ int luaH_getn (Table *t) { ...@@ -745,7 +741,7 @@ int luaH_getn (Table *t) {
int luaH_getn_ro (void *t) { int luaH_getn_ro (void *t) {
int i = 1, len=0; int i = 1, len=0;
while(luaR_findentry(t, NULL, i ++, NULL)) while(luaR_findentryN(t, i ++, NULL))
len ++; len ++;
return len; return len;
} }
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
#include "lrotable.h"
#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) #define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n))
......
...@@ -50,14 +50,22 @@ void luaT_init (lua_State *L) { ...@@ -50,14 +50,22 @@ void luaT_init (lua_State *L) {
** tag methods ** tag methods
*/ */
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
const TValue *tm = luaR_isrotable(events) ? luaH_getstr_ro(events, ename) : luaH_getstr(events, ename); const TValue *tm;
lua_assert(event <= TM_EQ); lua_assert(event <= TM_EQ);
if (ttisnil(tm)) { /* no tag method? */
if (!luaR_isrotable(events)) if (luaR_isrotable(events)) {
tm = luaH_getstr_ro(events, ename);
if (ttisnil(tm)) { /* no tag method? */
return NULL;
}
} else {
tm = luaH_getstr(events, ename);
if (ttisnil(tm)) { /* no tag method? */
events->flags |= cast_byte(1u<<event); /* cache this fact */ events->flags |= cast_byte(1u<<event); /* cache this fact */
return NULL; return NULL;
} }
else return tm; }
return tm;
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "lobject.h" #include "lobject.h"
#include "lrotable.h"
/* /*
* WARNING: if you change the order of this enumeration, * WARNING: if you change the order of this enumeration,
...@@ -36,12 +36,10 @@ typedef enum { ...@@ -36,12 +36,10 @@ typedef enum {
TM_N /* number of elements in the enum */ TM_N /* number of elements in the enum */
} TMS; } TMS;
#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ #define gfasttm(g,et,e) ((et) == NULL ? NULL : \
!luaR_isrotable(et) && ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) (!luaR_isrotable(et) && ((et)->flags & (1u<<(e)))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
#define fasttm(l,et,e) gfasttm(G(l), et, e) #define fasttm(l,et,e) gfasttm(G(l), et, e)
LUAI_DATA const char *const luaT_typenames[]; LUAI_DATA const char *const luaT_typenames[];
......
...@@ -18,6 +18,7 @@ TARGET = host ...@@ -18,6 +18,7 @@ TARGET = host
ifeq ($(FLAVOR),debug) ifeq ($(FLAVOR),debug)
CCFLAGS += -O0 -g CCFLAGS += -O0 -g
TARGET_LDFLAGS += -O0 -g TARGET_LDFLAGS += -O0 -g
DEFINES += -DLUA_DEBUG_BUILD
else else
FLAVOR = release FLAVOR = release
CCFLAGS += -O2 CCFLAGS += -O2
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
#include "lrotable.h"
#define IO_INPUT 1 #define IO_INPUT 1
#define IO_OUTPUT 2 #define IO_OUTPUT 2
...@@ -28,7 +27,11 @@ ...@@ -28,7 +27,11 @@
#define LUA_IO_SETFIELD(f) lua_rawseti(L, LUA_REGISTRYINDEX,(int)(liolib_keys[f])) #define LUA_IO_SETFIELD(f) lua_rawseti(L, LUA_REGISTRYINDEX,(int)(liolib_keys[f]))
/* "Pseudo-random" keys for the registry */ /* "Pseudo-random" keys for the registry */
static const size_t liolib_keys[] = {(size_t)&luaL_callmeta, (size_t)&luaL_typerror, (size_t)&luaL_argerror}; static const size_t liolib_keys[] = {
(size_t)&luaL_callmeta,
(size_t)&luaL_typerror,
(size_t)&luaL_argerror
};
static const char *const fnames[] = {"input", "output"}; static const char *const fnames[] = {"input", "output"};
...@@ -452,20 +455,6 @@ const LUA_REG_TYPE iolib_funcs[] = { ...@@ -452,20 +455,6 @@ const LUA_REG_TYPE iolib_funcs[] = {
{LNILKEY, LNILVAL} {LNILKEY, LNILVAL}
}; };
/* Note that IO objects use a RAM metatable created to allow extensibility */
static int io_index(lua_State *L)
{
return luaR_findfunction(L, iolib_funcs);
}
const luaL_Reg iolib[] = {
{"__index", io_index},
{NULL, NULL}
};
#undef MIN_OPT_LEVEL
#define MIN_OPT_LEVEL 1
#include "lrodefs.h" #include "lrodefs.h"
const LUA_REG_TYPE flib[] = { const LUA_REG_TYPE flib[] = {
{LSTRKEY("close"), LFUNCVAL(io_close)}, {LSTRKEY("close"), LFUNCVAL(io_close)},
...@@ -481,6 +470,7 @@ const LUA_REG_TYPE flib[] = { ...@@ -481,6 +470,7 @@ const LUA_REG_TYPE flib[] = {
{LNILKEY, LNILVAL} {LNILKEY, LNILVAL}
}; };
static const luaL_Reg io_base[] = {{NULL, NULL}};
static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
*newfile(L) = f; *newfile(L) = f;
...@@ -490,14 +480,18 @@ static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { ...@@ -490,14 +480,18 @@ static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
lua_setfield(L, -2, fname); lua_setfield(L, -2, fname);
} }
LUALIB_API int luaopen_io (lua_State *L) { LUALIB_API int luaopen_io(lua_State *L) {
luaL_rometatable(L, LUA_FILEHANDLE, (void*)flib); /* create metatable for file handles */ luaL_rometatable(L, LUA_FILEHANDLE, (void*) flib); /* create metatable for file handles */
luaL_register_light(L, LUA_IOLIBNAME, iolib); luaL_register_light(L, LUA_IOLIBNAME, io_base);
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
lua_pushliteral(L, "__index");
lua_pushrotable(L, (void *)iolib_funcs);
lua_rawset(L, -3);
/* create (and set) default files */ /* create (and set) default files */
createstdfile(L, stdin, IO_INPUT, "stdin"); createstdfile(L, stdin, IO_INPUT, "stdin");
createstdfile(L, stdout, IO_OUTPUT, "stdout"); createstdfile(L, stdout, IO_OUTPUT, "stdout");
createstdfile(L, stderr, 0, "stderr"); createstdfile(L, stderr, IO_STDERR, "stderr");
return 1; return 1;
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment