Unverified Commit 11592951 authored by Arnim Läuger's avatar Arnim Läuger Committed by GitHub
Browse files

Merge pull request #2582 from nodemcu/dev

Next master drop
parents 4095c408 61433c44
......@@ -15,7 +15,6 @@
#include "lauxlib.h"
#include "lualib.h"
#include "lrotable.h"
#undef PI
#define PI (3.14159265358979323846)
......
......@@ -24,7 +24,6 @@
#include "lauxlib.h"
#include "lualib.h"
#include "lrotable.h"
/* prefix for open functions in C libraries */
#define LUA_POF "luaopen_"
......@@ -474,10 +473,11 @@ static int ll_require (lua_State *L) {
return 1; /* package is already loaded */
}
/* Is this a readonly table? */
void *res = luaR_findglobal(name, c_strlen(name));
if (res) {
lua_pushrotable(L, res);
lua_getfield(L, LUA_GLOBALSINDEX, name);
if(lua_isrotable(L,-1)) {
return 1;
} else {
lua_pop(L, 1);
}
/* else must load it; iterate over available loaders */
lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
......@@ -563,8 +563,13 @@ static void modinit (lua_State *L, const char *modname) {
static int ll_module (lua_State *L) {
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;
} else {
lua_pop(L, 1);
}
int loaded = lua_gettop(L) + 1; /* index of _LOADED table */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, loaded, modname); /* get _LOADED[modname] */
......
......@@ -34,20 +34,33 @@
#define LUA_TUPVAL (LAST_TAG+2)
#define LUA_TDEADKEY (LAST_TAG+3)
#ifdef __XTENSA__
/*
** force aligned access to critical fields in Flash-based structures
** wo is the offset of aligned word in bytes 0,4,8,..
** bo is the field within the word in bits 0..31
*/
#define GET_BYTE_FN(name,t,wo,bo) \
static inline lu_byte get ## name(void *o) { \
lu_byte res; /* extract named field */ \
asm ("l32i %0, %1, " #wo "; extui %0, %0, " #bo ", 8;" : "=r"(res) : "r"(o) : );\
return res; }
#else
#define GET_BYTE_FN(name,t,wo,bo) \
static inline lu_byte get ## name(void *o) { return ((t *)o)->name; }
#endif
/*
** Union of all collectable objects
*/
typedef union GCObject GCObject;
/*
** Common Header for all collectable objects (in macro form, to be
** included in other objects)
*/
#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
/*
** Common header in struct form
*/
......@@ -55,11 +68,18 @@ typedef struct GCheader {
CommonHeader;
} GCheader;
/*
** Word aligned inline access functions for the CommonHeader tt and marked fields.
** Note that these MUST be consistent with the CommonHeader definition above. Arg
** 3 is a word offset (4 bytes in this case) and arg 4 the bit offset in the word.
*/
GET_BYTE_FN(tt,GCheader,4,0)
GET_BYTE_FN(marked,GCheader,4,8)
#if defined(LUA_PACK_VALUE) || defined(ELUA_ENDIAN_BIG) || defined(ELUA_ENDIAN_SMALL)
# error "NodeMCU does not support the eLua LUA_PACK_VALUE and ELUA_ENDIAN defines"
#endif
/*
** Union of all Lua values
*/
......@@ -214,7 +234,6 @@ typedef struct lua_TValue {
#define iscollectable(o) (ttype(o) >= LUA_TSTRING)
typedef TValue *StkId; /* index to stack elements */
......@@ -386,6 +405,7 @@ typedef struct Table {
int sizearray; /* size of `array' array */
} Table;
typedef const struct luaR_entry ROTable;
/*
** `module' operation for hashing (size is always a power of 2)
......
......@@ -38,5 +38,10 @@
return 1
#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 */
......@@ -9,77 +9,139 @@
#include "lobject.h"
#include "lapi.h"
/* Local defines */
#define LUAR_FINDFUNCTION 0
#define LUAR_FINDVALUE 1
/* Externally defined read-only table array */
extern const luaR_table *lua_rotable;
/* Find a global "read only table" in the constant lua_rotable array */
void* luaR_findglobal(const char *name, unsigned len) {
unsigned i;
if (c_strlen(name) > LUA_MAX_ROTABLE_NAME)
return NULL;
for (i=0; lua_rotable[i].name; i ++)
if (*lua_rotable[i].name != '\0' && c_strlen(lua_rotable[i].name) == len && !c_strncmp(lua_rotable[i].name, name, len)) {
return (void*)(lua_rotable[i].pentries);
#define ALIGNED_STRING (__attribute__((aligned(4))) char *)
#define LA_LINES 16
#define LA_SLOTS 4
//#define COLLECT_STATS
/*
* All keyed ROtable access passes through luaR_findentry(). ROTables
* are simply a list of <key><TValue value> pairs. The existing algo
* did a linear scan of this vector of pairs looking for a match.
*
* A N×M lookaside cache has been added, with a simple hash on the key's
* TString addr and the ROTable addr to identify one of N lines. Each
* line has M slots which are scanned. This is all done in RAM and is
* perhaps 20x faster than the corresponding random Flash accesses which
* will cause flash faults.
*
* 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 const TValue* luaR_auxfind(const luaR_entry *pentry, const char *strkey, luaR_numkey numkey, unsigned *ppos) {
const TValue *res = NULL;
unsigned i = 0;
if (pentry == NULL)
return NULL;
while(pentry->key.type != LUA_TNIL) {
if ((strkey && (pentry->key.type == LUA_TSTRING) && (!c_strcmp(pentry->key.id.strkey, strkey))) ||
(!strkey && (pentry->key.type == LUA_TNUMBER) && ((luaR_numkey)pentry->key.id.numkey == numkey))) {
res = &pentry->value;
break;
static void update_cache(unsigned hash, ROTable *rotable, unsigned ndx) {
int i = (hash)>>2 & (LA_LINES-1), j;
COUNT(2);
if (ndx>0xffu)
return;
for (j = LA_SLOTS-1; j>0; j--)
cache[i][j] = cache[i][j-1];
cache[i][0].hash = hash;
cache[i][0].addr = (size_t) rotable;
cache[i][0].ndx = ndx;
}
/*
* 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)
*ppos = i;
return res;
return luaO_nilobject;
}
int luaR_findfunction(lua_State *L, const luaR_entry *ptable) {
const TValue *res = NULL;
const char *key = luaL_checkstring(L, 2);
res = luaR_auxfind(ptable, key, 0, NULL);
if (res && ttislightfunction(res)) {
luaA_pushobject(L, res);
return 1;
const TValue* luaR_findentryN(ROTable *rotable, luaR_numkey numkey, unsigned *ppos) {
unsigned i = 0;
const luaR_entry *pentry = rotable;
if (pentry) {
for ( ;pentry->key.type != LUA_TNIL; i++, pentry++) {
if (pentry->key.type == LUA_TNUMBER && (luaR_numkey) pentry->key.id.numkey == numkey) {
if (ppos)
*ppos = i;
return &pentry->value;
}
}
}
else
return 0;
return NULL;
}
/* 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 */
void* luaR_getmeta(void *data) {
#ifdef LUA_META_ROTABLES
const TValue *res = luaR_auxfind((const luaR_entry*)data, "__metatable", 0, NULL);
void* luaR_getmeta(ROTable *rotable) {
const TValue *res = luaR_findentry(rotable, NULL, 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(val);
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,
setobj2s(L, val, &pentries[pos].value);
}
}
/* next (used for iteration) */
void luaR_next(lua_State *L, void *data, 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;
void luaR_next(lua_State *L, ROTable *rotable, TValue *key, TValue *val) {
unsigned keypos;
/* Special case: if key is nil, return the first element of the rotable */
if (ttisnil(key))
luaR_next_helper(L, pentries, 0, key, val);
if (ttisnil(key))
luaR_next_helper(L, rotable, 0, key, val);
else if (ttisstring(key) || ttisnumber(key)) {
/* Find the previoud key again */
/* Find the previous key again */
if (ttisstring(key)) {
luaR_getcstr(strkey, rawtsvalue(key), LUA_MAX_ROTABLE_NAME);
pstrkey = strkey;
} else
numkey = (luaR_numkey)nvalue(key);
luaR_findentry(data, pstrkey, numkey, &keypos);
luaR_findentry(rotable, rawtsvalue(key), &keypos);
} else {
luaR_findentryN(rotable, (luaR_numkey)nvalue(key), &keypos);
}
/* Advance to next key */
keypos ++;
luaR_next_helper(L, pentries, keypos, key, val);
keypos ++;
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 @@
#define LRO_NUMVAL(v) {{.n = v}, LUA_TNUMBER}
#define LRO_ROVAL(v) {{.p = (void*)v}, LUA_TROTABLE}
#define LRO_NILVAL {{.p = NULL}, LUA_TNIL}
#ifdef LUA_CROSS_COMPILER
#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_NILKEY {LUA_TNIL, {.strkey=NULL}}
......@@ -25,40 +29,58 @@
typedef int luaR_numkey;
/* The next structure defines the type of a key */
typedef struct
{
typedef struct {
int type;
union
{
union {
const char* strkey;
luaR_numkey numkey;
} id;
} luaR_key;
/* An entry in the read only table */
typedef struct
{
typedef struct luaR_entry {
const luaR_key key;
const TValue value;
} luaR_entry;
/* A rotable */
typedef struct
{
const char *name;
const luaR_entry *pentries;
} luaR_table;
void* luaR_findglobal(const char *key, unsigned len);
int luaR_findfunction(lua_State *L, const luaR_entry *ptable);
const TValue* luaR_findentry(void *data, const char *strkey, luaR_numkey numkey, unsigned *ppos);
void luaR_getcstr(char *dest, const TString *src, size_t maxsize);
void luaR_next(lua_State *L, void *data, TValue *key, TValue *val);
void* luaR_getmeta(void *data);
#ifdef LUA_META_ROTABLES
/*
* 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
* as a logical ROTable.
*/
typedef const struct luaR_entry ROTable;
const TValue* luaR_findentry(ROTable *tab, TString *key, unsigned *ppos);
const TValue* luaR_findentryN(ROTable *tab, luaR_numkey numkey, unsigned *ppos);
void luaR_next(lua_State *L, ROTable *tab, TValue *key, TValue *val);
void* luaR_getmeta(ROTable *tab);
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
#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
/* Return 1 if the given pointer is a rotable */
#define luaR_isrotable(p) IN_RODATA_AREA(p)
#endif
......@@ -80,16 +80,12 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
return ts;
}
#ifdef LUA_CROSS_COMPILER
#define IN_RO_AREA(p) (0)
#else /* xtensa tool chain for ESP */
extern char _irom0_text_start[];
extern char _irom0_text_end[];
#define IN_RO_AREA(p) ((p) >= _irom0_text_start && (p) <= _irom0_text_end)
static int lua_is_ptr_in_ro_area(const char *p) {
#ifdef LUA_CROSS_COMPILER
return 0; // TStrings are never in RO in luac.cross
#else
return IN_RODATA_AREA(p);
#endif
int lua_is_ptr_in_ro_area(const char *p) {
return IN_RO_AREA(p);
}
/*
......
......@@ -13,7 +13,7 @@
#include "lstate.h"
#define sizestring(s) (sizeof(union TString)+(testbit((s)->marked, READONLYBIT) ? sizeof(char **) : ((s)->len+1)*sizeof(char)))
#define sizestring(s) (sizeof(union TString)+(testbit(getmarked(s), READONLYBIT) ? sizeof(char **) : ((s)->len+1)*sizeof(char)))
#define sizeudata(u) (sizeof(union Udata)+(u)->len)
......
......@@ -15,7 +15,6 @@
#include "lauxlib.h"
#include "lualib.h"
#include "lrotable.h"
/* macro to `unsign' a character */
#define uchar(c) ((unsigned char)(c))
......
......@@ -580,7 +580,7 @@ const TValue *luaH_getnum (Table *t, int key) {
/* same thing for rotables */
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;
}
......@@ -599,14 +599,10 @@ const TValue *luaH_getstr (Table *t, TString *key) {
}
/* same thing for rotables */
const TValue *luaH_getstr_ro (void *t, TString *key) {
char keyname[LUA_MAX_ROTABLE_NAME + 1];
const TValue *res;
if (!t)
const TValue *luaH_getstr_ro (void *t, TString *key) {
if (!t || key->tsv.len>LUA_MAX_ROTABLE_NAME)
return luaO_nilobject;
luaR_getcstr(keyname, key, LUA_MAX_ROTABLE_NAME);
res = luaR_findentry(t, keyname, 0, NULL);
return res ? res : luaO_nilobject;
return luaR_findentry(t, key, NULL);
}
......@@ -745,7 +741,7 @@ int luaH_getn (Table *t) {
int luaH_getn_ro (void *t) {
int i = 1, len=0;
while(luaR_findentry(t, NULL, i ++, NULL))
while(luaR_findentryN(t, i ++, NULL))
len ++;
return len;
}
......
......@@ -13,7 +13,6 @@
#include "lauxlib.h"
#include "lualib.h"
#include "lrotable.h"
#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) {
** tag methods
*/
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);
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 */
return NULL;
}
else return tm;
return NULL;
}
}
return tm;
}
......
......@@ -9,7 +9,7 @@
#include "lobject.h"
#include "lrotable.h"
/*
* WARNING: if you change the order of this enumeration,
......@@ -36,12 +36,10 @@ typedef enum {
TM_N /* number of elements in the enum */
} TMS;
#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[];
......
#
# This Make file is called from the core Makefile hierarchy which is a hierarchical
# make which uses parent callbacks to implement inheritance. However if luac_cross
# build stands outside this it uses the host toolchain to implement a separate
# This Make file is called from the core Makefile hierarchy with is a hierarchical
# make wwhich uses parent callbacks to implement inheritance. However is luac_cross
# build stands outside this and uses the host toolchain to implement a separate
# host build of the luac.cross image.
#
.NOTPARALLEL:
CCFLAGS:= -I.. -I../../include -I../../../include -I ../../libc
CCFLAGS:= -I.. -I../../include -I../../libc -I../../uzlib
LDFLAGS:= -L$(SDK_DIR)/lib -L$(SDK_DIR)/ld -lm -ldl -Wl,-Map=mapfile
CCFLAGS += -Wall
......@@ -18,6 +18,7 @@ TARGET = host
ifeq ($(FLAVOR),debug)
CCFLAGS += -O0 -g
TARGET_LDFLAGS += -O0 -g
DEFINES += -DLUA_DEBUG_BUILD
else
FLAVOR = release
CCFLAGS += -O2
......@@ -31,13 +32,13 @@ LUASRC := lapi.c lauxlib.c lbaselib.c lcode.c ldblib.c ldebug.c
lrotable.c lstate.c lstring.c lstrlib.c ltable.c ltablib.c \
ltm.c lundump.c lvm.c lzio.c
LIBCSRC := c_stdlib.c
UZSRC := uzlib_deflate.c crc32.c
#
# This relies on the files being unique on the vpath
#
SRC := $(LUACSRC) $(LUASRC) $(LIBCSRC)
vpath %.c .:..:../../libc
SRC := $(LUACSRC) $(LUASRC) $(LIBCSRC) $(UZSRC)
vpath %.c .:..:../../libc:../../uzlib
ODIR := .output/$(TARGET)/$(FLAVOR)/obj
......@@ -51,12 +52,7 @@ CC := $(WRAPCC) gcc
ECHO := echo
BUILD_TYPE := $(shell $(CC) $(EXTRA_CCFLAGS) -E -dM - <../../../app/include/user_config.h | grep LUA_NUMBER_INTEGRAL | wc -l)
ifeq ($(BUILD_TYPE),0)
IMAGE := ../../../luac.cross
else
IMAGE := ../../../luac.cross.int
endif
.PHONY: test clean all
......@@ -70,7 +66,6 @@ test :
@echo SRC: $(SRC)
@echo OBJS: $(OBJS)
@echo DEPS: $(DEPS)
@echo IMAGE: $(IMAGE)
clean :
$(RM) -r $(ODIR)
......
/*
/***--
** lflashimg.c
** Dump a compiled Proto hiearchy to a RO (FLash) image file
** See Copyright Notice in lua.h
......@@ -19,6 +19,7 @@
#undef LUA_FLASH_STORE
#define LUA_FLASH_STORE
#include "lflash.h"
#include "uzlib.h"
//#define LOCAL_DEBUG
......@@ -46,18 +47,18 @@ typedef unsigned int uint;
* independent image format, which permits the on-device image loader to load the LFS
* image at an appropriate base within the flash address space. As all objects in the
* LFS can be treated as multiples of 4-byte words, also all address fields are both
* word aligned, and any address references within the LFS are also word-aligned,
* such addresses are stored in a special format, where each PI address is two
* 16-bit unsigned offsets:
* word aligned, and any address references within the LFS are also word-aligned.
*
* Bits 0-15 is the offset into the LFS that this address refers to
* Bits 16-31 is the offset linking to the PIC next address.
* This version adds gzip compression of the generated LFS image for more efficient
* over-the-air (OTA) transfer, so the method of tagging address words has been
* replaced by a scheme which achieves better compression: an additional bitmap
* has been added to the image, with each bit corresponding to a word in the image
* and set if the corresponding work is an address. The addresses are stored as
* signed relative word offsets.
*
* Hence the LFS can be up to 256Kb in length and the flash loader can use the forward
* links to chain down PI address from the mainProto address at offet 3 to all image
* addresses during load and convert them to the corresponding correct absolute memory
* addresses. This reloation process is skipped for absolute addressed images (which
* are identified by the FLASH_SIG_ABSOLUTE bit setting in the flash signature.
* The unloader is documented in lflash.c Note that his relocation process is
* skipped for absolute addressed images (which are identified by the
* FLASH_SIG_ABSOLUTE bit setting in the flash signature).
*
* The flash image has a standard header detailed in lflash.h
*
......@@ -66,7 +67,7 @@ typedef unsigned int uint;
* and int may not have the same size. Hence addresses with the must be declared as
* the FlashAddr type rather than typed C pointers and must be accessed through macros.
*
* ALso note that image built with a given LUA_PACK_TVALUES / LUA_NUNBER_INTEGRAL
* Also note that image built with a given LUA_PACK_TVALUES / LUA_NUNBER_INTEGRAL
* combination must be loaded into a corresponding firmware build. Hence these
* configuration options are also included in the FLash Signature.
*
......@@ -96,8 +97,19 @@ typedef struct flashts { /* This is the fixed 32-bit equivalent of TString
#endif
static uint curOffset = 0;
static uint flashImage[LUA_MAX_FLASH_SIZE];
static unsigned char flashAddrTag[LUA_MAX_FLASH_SIZE/WORDSIZE];
/*
* The flashAddrTag is a bit array, one bit per flashImage word denoting
* whether the corresponding word is a relative address. The defines
* are access methods for this bit array.
*/
static uint flashImage[LUA_MAX_FLASH_SIZE + LUA_MAX_FLASH_SIZE/32];
static uint *flashAddrTag = flashImage + LUA_MAX_FLASH_SIZE;
#define _TW(v) (v)>>5
#define _TB(v) (1<<((v)&0x1F))
#define setFlashAddrTag(v) flashAddrTag[_TW(v)] |= _TB(v)
#define getFlashAddrTag(v) ((flashAddrTag[_TW(v)]&_TB(v)) != 0)
#define fatal luac_fatal
extern void __attribute__((noreturn)) luac_fatal(const char* message);
......@@ -115,7 +127,7 @@ static void *flashAlloc(lua_State* L, size_t n) {
void *p = (void *)(flashImage + curOffset);
curOffset += ALIGN(n)>>WORDSHIFT;
if (curOffset > LUA_MAX_FLASH_SIZE) {
fatal("Out of Flash memmory");
fatal("Out of Flash memory");
}
return p;
}
......@@ -128,8 +140,8 @@ static void *flashAlloc(lua_State* L, size_t n) {
#define toFlashAddr(l, pd, s) _toFlashAddr(l, &(pd), s)
static void _toFlashAddr(lua_State* L, FlashAddr *a, void *p) {
uint doffset = cast(char *, a) - cast(char *,flashImage);
lua_assert(!(doffset & (WORDSIZE-1)));
doffset >>= WORDSHIFT;
lua_assert(!(doffset & (WORDSIZE-1))); // check word aligned
doffset >>= WORDSHIFT; // and convert to a word offset
lua_assert(doffset <= curOffset);
if (p) {
uint poffset = cast(char *, p) - cast(char *,flashImage);
......@@ -137,10 +149,8 @@ static void _toFlashAddr(lua_State* L, FlashAddr *a, void *p) {
poffset >>= WORDSHIFT;
lua_assert(poffset <= curOffset);
flashImage[doffset] = poffset; // Set the pointer to the offset
flashAddrTag[doffset] = 1; // And tag as an address
} else { // Special case for NULL pointer
flashImage[doffset] = 0;
}
setFlashAddrTag(doffset); // And tag as an address
} /* else leave clear */ // Special case for NULL pointer
}
/*
......@@ -231,7 +241,7 @@ static void createROstrt(lua_State *L, FlashHeader *fh) {
fts->marked = bitmask(LFSBIT); // LFS string with no Whitebits set
fts->hash = hash; // add hash
fts->len = len; // and length
memcpy(flashAlloc(L, ALIGN(len+1)), p, ALIGN(len+1)); // copy string
memcpy(flashAlloc(L, len+1), p, len+1); // copy string
// include the trailing null char
lua_pop(L, 1); // Junk the value
lua_pushvalue(L, -1); // Dup the key as rawset dumps its copy
......@@ -308,6 +318,9 @@ static void *flashCopy(lua_State* L, int n, const char *fmt, void *src) {
case 'I':
*d++ = *s++;
break;
case 'H':
*d++ = (*s++) & 0;
break;
case 'S':
newts = resolveTString(L, *cast(TString **, s));
toFlashAddr(L, *d, newts);
......@@ -318,11 +331,15 @@ static void *flashCopy(lua_State* L, int n, const char *fmt, void *src) {
/* This code has to work for both Integer and Float build variants */
memset(d, 0, TARGET_TV_SIZE);
TValue *sv = cast(TValue *, s);
/* The value is 0, 4 or 8 bytes depending on type */
if (ttisstring(sv)) {
toFlashAddr(L, *d, resolveTString(L, rawtsvalue(sv)));
} else { /* non-collectable types all of size lua_Number */
lua_assert(!iscollectable(sv));
} else if (ttisnumber(sv)) {
*cast(lua_Number*,d) = *cast(lua_Number*,s);
} else if (!ttisnil(sv)){
/* all other types are 4 byte */
lua_assert(!iscollectable(sv));
*cast(uint *,d) = *cast(uint *,s);
}
*cast(int *,cast(lua_Number*,d)+1) = ttype(sv);
s += FLASH_WORDS(TValue);
......@@ -338,9 +355,9 @@ static void *flashCopy(lua_State* L, int n, const char *fmt, void *src) {
/* The debug optimised version has a different Proto layout */
#ifdef LUA_OPTIMIZE_DEBUG
#define PROTO_COPY_MASK "AIAAAAAASIIIIIIIAI"
#define PROTO_COPY_MASK "AHAAAAAASIIIIIIIAI"
#else
#define PROTO_COPY_MASK "AIAAAAAASIIIIIIIIAI"
#define PROTO_COPY_MASK "AHAAAAAASIIIIIIIIAI"
#endif
/*
......@@ -378,44 +395,52 @@ static void *functionToFlash(lua_State* L, const Proto* orig) {
return cast(void *, flashCopy(L, 1, PROTO_COPY_MASK, &f));
}
/*
* Scan through the tagged addresses. This operates in one of two modes.
* - If address is non-zero then the offset is converted back into an absolute
* mapped flash address using the specified address base.
*
* - If the address is zero then form a form linked chain with the upper 16 bits
* the link to the last offset. As the scan is backwards, this 'last' address
* becomes forward reference for the on-chip LFS loader.
*/
void linkAddresses(lu_int32 address){
int i, last = 0;
for (i = curOffset-1 ; i >= 0; i--) {
if (flashAddrTag[i]) {
lua_assert(flashImage[i]<curOffset);
if (address) {
flashImage[i] = 4*flashImage[i] + address;
} else {
flashImage[i] |= last<<16;
last = i;
}
}
}
}
uint dumpToFlashImage (lua_State* L, const Proto *main, lua_Writer w,
void* data, int strip, lu_int32 address) {
void* data, int strip,
lu_int32 address, lu_int32 maxSize) {
// parameter strip is ignored for now
lua_newtable(L);
FlashHeader *fh = cast(FlashHeader *, flashAlloc(L, sizeof(FlashHeader)));
int i, status;
lua_newtable(L);
scanProtoStrings(L, main);
createROstrt(L, fh);
toFlashAddr(L, fh->mainProto, functionToFlash(L, main));
fh->flash_sig = FLASH_SIG + (address ? FLASH_SIG_ABSOLUTE : 0);
fh->flash_size = curOffset*WORDSIZE;
linkAddresses(address);
lua_unlock(L);
int status = w(L, flashImage, curOffset * sizeof(uint), data);
if (fh->flash_size>maxSize) {
fatal ("The image is too large for specfied LFS size");
}
if (address) { /* in absolute mode convert addresses to mapped address */
for (i = 0 ; i < curOffset; i++)
if (getFlashAddrTag(i))
flashImage[i] = 4*flashImage[i] + address;
lua_unlock(L);
status = w(L, flashImage, fh->flash_size, data);
} else { /* compressed PI mode */
/*
* In image mode, shift the relocation bitmap down directly above
* the used flashimage. This consolidated array is then gzipped.
*/
uint oLen;
uint8_t *oBuf;
int bmLen = sizeof(uint)*((curOffset+31)/32); /* 32 flags to a word */
memmove(flashImage+curOffset, flashAddrTag, bmLen);
status = uzlib_compress (&oBuf, &oLen,
(const uint8_t *)flashImage, bmLen+fh->flash_size);
if (status != UZLIB_OK) {
luac_fatal("Out of memory during image compression");
}
lua_unlock(L);
#if 0
status = w(L, flashImage, bmLen+fh->flash_size, data);
#else
status = w(L, oBuf, oLen, data);
free(oBuf);
#endif
}
lua_lock(L);
return status;
}
......@@ -18,7 +18,6 @@
#include "lauxlib.h"
#include "lualib.h"
#include "lrotable.h"
#define IO_INPUT 1
#define IO_OUTPUT 2
......@@ -28,7 +27,11 @@
#define LUA_IO_SETFIELD(f) lua_rawseti(L, LUA_REGISTRYINDEX,(int)(liolib_keys[f]))
/* "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"};
......@@ -452,20 +455,6 @@ const LUA_REG_TYPE iolib_funcs[] = {
{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"
const LUA_REG_TYPE flib[] = {
{LSTRKEY("close"), LFUNCVAL(io_close)},
......@@ -481,6 +470,7 @@ const LUA_REG_TYPE flib[] = {
{LNILKEY, LNILVAL}
};
static const luaL_Reg io_base[] = {{NULL, NULL}};
static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
*newfile(L) = f;
......@@ -490,14 +480,18 @@ static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
lua_setfield(L, -2, fname);
}
LUALIB_API int luaopen_io (lua_State *L) {
luaL_rometatable(L, LUA_FILEHANDLE, (void*)flib); /* create metatable for file handles */
luaL_register_light(L, LUA_IOLIBNAME, iolib);
LUALIB_API int luaopen_io(lua_State *L) {
luaL_rometatable(L, LUA_FILEHANDLE, (void*) flib); /* create metatable for file handles */
luaL_register_light(L, LUA_IOLIBNAME, io_base);
lua_pushvalue(L, -1);
lua_setmetatable(L, -2);
lua_pushliteral(L, "__index");
lua_pushrotable(L, (void *)iolib_funcs);
lua_rawset(L, -3);
/* create (and set) default files */
createstdfile(L, stdin, IO_INPUT, "stdin");
createstdfile(L, stdout, IO_OUTPUT, "stdout");
createstdfile(L, stderr, 0, "stderr");
createstdfile(L, stderr, IO_STDERR, "stderr");
return 1;
}
......@@ -20,8 +20,6 @@
#include "lauxlib.h"
#include "lualib.h"
#include "lrotable.h"
static int os_pushresult (lua_State *L, int i, const char *filename) {
int en = errno; /* calls to Lua API may change this value */
......
......@@ -35,6 +35,7 @@ static int dumping=1; /* dump bytecodes? */
static int stripping=0; /* strip debug information? */
static int flash=0; /* output flash image */
static lu_int32 address=0; /* output flash image at absolute location */
static lu_int32 maxSize=0x40000; /* maximuum uncompressed image size */
static int lookup=0; /* output lookup-style master combination header */
static char Output[]={ OUTPUT }; /* default output file name */
static const char* output=Output; /* actual output file name */
......@@ -72,6 +73,7 @@ static void usage(const char* message)
" -f output a flash image file\n"
" -a addr generate an absolute, rather than position independent flash image file\n"
" -i generate lookup combination master (default with option -f)\n"
" -m size maximum LFS image in bytes\n"
" -p parse only\n"
" -s strip debug information\n"
" -v show version information\n"
......@@ -123,6 +125,13 @@ static int doargs(int argc, char* argv[])
lookup = 1;
else if (IS("-l")) /* list */
++listing;
else if (IS("-m")) /* specify a maximum image size */
{
flash=lookup=1;
maxSize=strtol(argv[++i],NULL,0);
if (maxSize & 0xFFF)
usage(LUA_QL("-e") " maximum size must be a multiple of 4,096");
}
else if (IS("-o")) /* output file */
{
output=argv[++i];
......@@ -264,7 +273,8 @@ struct Smain {
};
extern uint dumpToFlashImage (lua_State* L,const Proto *main, lua_Writer w,
void* data, int strip, lu_int32 address);
void* data, int strip,
lu_int32 address, lu_int32 maxSize);
static int pmain(lua_State* L)
{
......@@ -302,7 +312,7 @@ static int pmain(lua_State* L)
lua_lock(L);
if (flash)
{
result=dumpToFlashImage(L,f,writer, D, stripping, address);
result=dumpToFlashImage(L,f,writer, D, stripping, address, maxSize);
} else
{
result=luaU_dump_crosscompile(L,f,writer,D,stripping,target);
......
......@@ -896,13 +896,6 @@ union luai_Cast { double l_d; long l_l; };
** without modifying the main part of the file.
*/
/* If you define the next macro you'll get the ability to set rotables as
metatables for tables/userdata/types (but the VM might run slower)
*/
#if (LUA_OPTIMIZE_MEMORY == 2)
#define LUA_META_ROTABLES
#endif
#if LUA_OPTIMIZE_MEMORY == 2 && defined(LUA_USE_POPEN)
#error "Pipes not supported in aggresive optimization mode (LUA_OPTIMIZE_MEMORY=2)"
#endif
......
......@@ -130,18 +130,29 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
TValue temp;
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t) || ttisrotable(t)) { /* `t' is a table? */
void *h = ttistable(t) ? hvalue(t) : rvalue(t);
const TValue *res = ttistable(t) ? luaH_get((Table*)h, key) : luaH_get_ro(h, key); /* do a primitive get */
if (ttistable(t)) { /* `t' is a table? */
Table *h = hvalue(t);
const TValue *res = luaH_get(h, key); /* do a primitive get */
if (!ttisnil(res) || /* result is no nil? */
(tm = fasttm(L, ttistable(t) ? ((Table*)h)->metatable : (Table*)luaR_getmeta(h), TM_INDEX)) == NULL) { /* or no TM? */
(tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
setobj2s(L, val, res);
return;
}
}
/* else will try the tag method */
} else if (ttisrotable(t)) { /* `t' is a table? */
void *h = rvalue(t);
const TValue *res = luaH_get_ro(h, key); /* do a primitive get */
if (!ttisnil(res) || /* result is no nil? */
(tm = fasttm(L, (Table*)luaR_getmeta(h), TM_INDEX)) == NULL) { /* or no TM? */
setobj2s(L, val, res);
return;
}
/* else will try the tag method */
}
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
luaG_typeerror(L, t, "index");
if (ttisfunction(tm) || ttislightfunction(tm)) {
callTMres(L, val, tm, t, key);
return;
......@@ -161,25 +172,27 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
L->top++;
fixedstack(L);
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t) || ttisrotable(t)) { /* `t' is a table? */
void *h = ttistable(t) ? hvalue(t) : rvalue(t);
TValue *oldval = ttistable(t) ? luaH_set(L, (Table*)h, key) : NULL; /* do a primitive set */
if ((oldval && !ttisnil(oldval)) || /* result is no nil? */
(tm = fasttm(L, ttistable(t) ? ((Table*)h)->metatable : (Table*)luaR_getmeta(h), TM_NEWINDEX)) == NULL) { /* or no TM? */
if(oldval) {
L->top--;
unfixedstack(L);
setobj2t(L, oldval, val);
((Table *)h)->flags = 0;
luaC_barriert(L, (Table*)h, val);
}
const TValue *tm = NULL;
if (ttistable(t)) { /* `t' is a table? */
Table *h = hvalue(t);
TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
if ((!ttisnil(oldval)) || /* result is no nil? */
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) {
L->top--;
unfixedstack(L);
setobj2t(L, oldval, val);
((Table *)h)->flags = 0;
luaC_barriert(L, (Table*)h, val);
return;
}
/* else will try the tag method */
}
else if (ttisrotable(t)) {
luaG_runerror(L, "invalid write to ROM variable");
}
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
luaG_typeerror(L, t, "index");
if (ttisfunction(tm) || ttislightfunction(tm)) {
L->top--;
unfixedstack(L);
......@@ -294,7 +307,7 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
case LUA_TROTABLE:
return rvalue(t1) == rvalue(t2);
case LUA_TLIGHTUSERDATA:
case LUA_TLIGHTUSERDATA:
case LUA_TLIGHTFUNCTION:
return pvalue(t1) == pvalue(t2);
case LUA_TUSERDATA: {
......@@ -321,7 +334,7 @@ void luaV_concat (lua_State *L, int total, int last) {
if (G(L)->memlimit < max_sizet) max_sizet = G(L)->memlimit;
do {
/* Any call which does a memory allocation may trim the stack,
invalidating top unless the stack is fixed duri ng the allocation */
invalidating top unless the stack is fixed during the allocation */
StkId top = L->base + last + 1;
fixedstack(L);
int n = 2; /* number of elements handled in this pass (at least 2) */
......@@ -570,7 +583,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
case OP_LEN: {
const TValue *rb = RB(i);
switch (ttype(rb)) {
case LUA_TTABLE:
case LUA_TTABLE:
case LUA_TROTABLE: {
setnvalue(ra, ttistable(rb) ? cast_num(luaH_getn(hvalue(rb))) : cast_num(luaH_getn_ro(rvalue(rb))));
break;
......
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