Unverified Commit eaac369d authored by Johny Mattsson's avatar Johny Mattsson Committed by GitHub
Browse files

LFS support for ESP32 NodeMCU (#2801)

* Port LFS from ESP8266 to ESP32
parent 7cb61a27
/*
** $Id: lflash.c
** See Copyright Notice in lua.h
*/
#define lflash_c
#define LUA_CORE
#define LUAC_CROSS_FILE
#include "lua.h"
#include "lobject.h"
#include "lauxlib.h"
#include "lstate.h"
#include "lfunc.h"
#include "lflash.h"
#include "platform.h"
#include "vfs.h"
#include "uzlib.h"
#include "platform_wdt.h"
#include "esp_partition.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Flash memory is a fixed memory addressable block that is serially allocated by the
* luac build process and the out image can be downloaded into SPIFSS and loaded into
* flash with a node.flash.load() command. See luac_cross/lflashimg.c for the build
* process.
*/
static const char *flashAddr;
static uint32_t flashSize;
static uint32_t flashAddrPhys;
static uint32_t flashSector;
static uint32_t curOffset;
#define ALIGN(s) (((s)+sizeof(size_t)-1) & ((size_t) (- (signed) sizeof(size_t))))
#define ALIGN_BITS(s) (((uint32_t)s) & (sizeof(size_t)-1))
#define ALL_SET (~0)
#define FLASH_PAGE_SIZE INTERNAL_FLASH_SECTOR_SIZE
#define FLASH_PAGES (flashSize/FLASH_PAGE_SIZE)
#define READ_BLOCKSIZE 1024
#define WRITE_BLOCKSIZE 2048
#define DICTIONARY_WINDOW 16384
#define WORDSIZE (sizeof(int))
#define BITS_PER_WORD 32
#define WRITE_BLOCKS ((DICTIONARY_WINDOW/WRITE_BLOCKSIZE)+1)
#define WRITE_BLOCK_WORDS (WRITE_BLOCKSIZE/WORDSIZE)
struct INPUT {
int fd;
int len;
uint8_t block[READ_BLOCKSIZE];
uint8_t *inPtr;
int bytesRead;
int left;
void *inflate_state;
} *in;
typedef struct {
uint8_t byte[WRITE_BLOCKSIZE];
} outBlock;
struct OUTPUT {
lua_State *L;
lu_int32 flash_sig;
int len;
outBlock *block[WRITE_BLOCKS];
outBlock buffer;
int ndx;
uint32_t crc;
int (*fullBlkCB) (void);
int flashLen;
int flagsLen;
int flagsNdx;
uint32_t *flags;
const char *error;
} *out;
#ifdef CONFIG_LUA_EMBEDDED_FLASH_STORE
extern const char lua_flash_store_reserved[0];
#endif
#ifdef NODE_DEBUG
extern void printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
void dumpStrt(stringtable *tb, const char *type) {
int i,j;
GCObject *o;
NODE_DBG("\nDumping %s String table\n\n========================\n", type);
NODE_DBG("No of elements: %d\nSize of table: %d\n", tb->nuse, tb->size);
for (i=0; i<tb->size; i++)
for(o = tb->hash[i], j=0; o; (o=o->gch.next), j++ ) {
TString *ts =cast(TString *, o);
NODE_DBG("%5d %5d %08x %08x %5d %1s %s\n",
i, j, (size_t) ts, ts->tsv.hash, ts->tsv.len,
ts_isreadonly(ts) ? "R" : " ", getstr(ts));
}
}
LUA_API void dumpStrings(lua_State *L) {
dumpStrt(&G(L)->strt, "RAM");
if (G(L)->ROstrt.hash)
dumpStrt(&G(L)->ROstrt, "ROM");
}
#endif
#ifndef CONFIG_LUA_EMBEDDED_FLASH_STORE
/* =====================================================================================
* The next 4 functions: flashPosition, flashSetPosition, flashBlock and flashErase
* wrap writing to flash. The last two are platform dependent. Also note that any
* writes are suppressed if the global writeToFlash is false. This is used in
* phase I where the pass is used to size the structures in flash.
*/
static void flashSetPosition(uint32_t offset){
NODE_DBG("flashSetPosition(%04x)\n", offset);
curOffset = offset;
}
static void flashBlock(const void* b, size_t size) {
NODE_DBG("flashBlock((%04x),%08x,%04x)\n", curOffset,(unsigned int)b,size);
lua_assert(ALIGN_BITS(b) == 0 && ALIGN_BITS(size) == 0);
platform_flash_write(b, flashAddrPhys+curOffset, size);
curOffset += size;
}
static void flashErase(uint32_t start, uint32_t end){
int i;
if (start == -1) start = FLASH_PAGES - 1;
if (end == -1) end = FLASH_PAGES - 1;
NODE_DBG("flashErase(%04x,%04x)\n", flashSector+start, flashSector+end);
for (i = start; i<=end; i++)
platform_flash_erase_sector( flashSector + i );
}
static int loadLFS (lua_State *L);
static int loadLFSgc (lua_State *L);
static int procFirstPass (void);
#endif
/* =====================================================================================
* luaN_init(), luaN_reload_reboot() and luaN_index() are exported via lflash.h.
* The first is the startup hook used in lstate.c and the last two are
* implementations of the node.flash API calls.
*/
/*
* Hook in lstate.c:f_luaopen() to set up ROstrt and ROpvmain if needed
*/
LUAI_FUNC void luaN_init (lua_State *L) {
#ifdef CONFIG_LUA_EMBEDDED_FLASH_STORE
flashSize = CONFIG_LUA_EMBEDDED_FLASH_STORE;
flashAddr = lua_flash_store_reserved;
flashAddrPhys = spi_flash_cache2phys(lua_flash_store_reserved);
if (flashAddrPhys == SPI_FLASH_CACHE2PHYS_FAIL) {
NODE_ERR("spi_flash_cache2phys failed\n");
return;
}
#else
const esp_partition_t *part = esp_partition_find_first(
PLATFORM_PARTITION_TYPE_NODEMCU,
PLATFORM_PARTITION_SUBTYPE_NODEMCU_LFS,
NULL);
if (!part)
return; // Nothing to do if the size is zero
flashSize = part->size; // in bytes
flashAddrPhys = part->address;
flashAddr = spi_flash_phys2cache(flashAddrPhys, SPI_FLASH_MMAP_DATA);
if (!flashAddr) {
spi_flash_mmap_handle_t ignored;
esp_err_t err = spi_flash_mmap(
flashAddrPhys, flashSize, SPI_FLASH_MMAP_DATA,
cast(const void **, &flashAddr), &ignored);
if (err != ESP_OK) {
NODE_ERR("Unable to access LFS partition - is it 64kB aligned as it needs to be?\n");
return;
}
}
#endif
G(L)->LFSsize = flashSize;
flashSector = platform_flash_get_sector_of_address(flashAddrPhys);
FlashHeader *fh = cast(FlashHeader *, flashAddr);
curOffset = 0;
/*
* For the LFS to be valid, its signature has to be correct for this build
* variant, the ROhash and main proto fields must be defined and the main proto
* address be within the LFS address bounds. (This last check is primarily to
* detect the direct imaging of an absolute LFS with the wrong base address.
*/
if (fh->flash_sig == 0 || fh->flash_sig == ~0 ) {
NODE_ERR("No LFS image loaded\n");
return;
}
if ((fh->flash_sig & (~FLASH_SIG_ABSOLUTE)) != FLASH_SIG ) {
NODE_ERR("Flash sig not correct: %u vs %u\n",
fh->flash_sig & (~FLASH_SIG_ABSOLUTE), FLASH_SIG);
return;
}
if (fh->pROhash == ALL_SET ||
((fh->mainProto - cast(FlashAddr, fh)) >= fh->flash_size)) {
NODE_ERR("Flash size check failed: %x vs 0xFFFFFFFF; size: %u\n",
fh->mainProto - cast(FlashAddr, fh), fh->flash_size);
return;
}
G(L)->ROstrt.hash = cast(GCObject **, fh->pROhash);
G(L)->ROstrt.nuse = fh->nROuse ;
G(L)->ROstrt.size = fh->nROsize;
G(L)->ROpvmain = cast(Proto *,fh->mainProto);
}
/*
* Library function called by node.flashreload(filename).
*/
LUALIB_API int luaN_reload_reboot (lua_State *L) {
#ifdef CONFIG_LUA_EMBEDDED_FLASH_STORE
// Updating the LFS section is disabled for now because any changes to the
// image requires updating its checksum to prevent boot failure.
lua_pushstring(L, "Not allowed to write to LFS section");
return 1;
#else
// luaL_dbgbreak();
const char *fn = lua_tostring(L, 1), *msg = "";
int status;
if (G(L)->LFSsize == 0) {
lua_pushstring(L, "No LFS partition allocated");
return 1;
}
/*
* Do a protected call of loadLFS.
*
* - This will normally rewrite the LFS and reboot, with no return.
* - If an error occurs then it is sent to the UART.
* - If this occured in the 1st pass, the previous LFS is unchanged so it is
* safe to return to the calling Lua.
* - If in the 1st pass, then the ESP is rebooted.
*/
status = lua_cpcall(L, &loadLFS, cast(void *,fn));
if (!out || out->fullBlkCB == procFirstPass) {
/*
* Never entered the 2nd pass, so it is safe to return the error. Note
* that I've gone to some trouble to ensure that all dynamically allocated
* working areas have been freed, so that we have no memory leaks.
*/
if (status == LUA_ERRMEM)
msg = "Memory allocation error";
else if (out && out->error)
msg = out->error;
else
msg = "Unknown Error";
/* We can clean up and return error */
lua_cpcall(L, &loadLFSgc, NULL);
lua_settop(L, 0);
lua_pushstring(L, msg);
return 1;
}
if (status == 0) {
/* Successful LFS rewrite */
msg = "LFS region updated. Restarting.";
} else {
/* We have errored during the second pass so clear the LFS and reboot */
if (status == LUA_ERRMEM)
msg = "Memory allocation error";
else if (out->error)
msg = out->error;
else
msg = "Unknown Error";
flashErase(0,-1);
}
NODE_ERR("%s\n", msg);
esp_restart();
return 0;
#endif // CONFIG_LUA_EMBEDDED_FLASH_STORE
}
/*
* If the arg is a valid LFS module name then return the LClosure
* pointing to it. Otherwise return:
* - The Unix time that the LFS was built
* - The base address and length of the LFS
* - An array of the module names in the LFS
*/
LUAI_FUNC int luaN_index (lua_State *L) {
int n = lua_gettop(L);
/* Return nil + the LFS base address if the LFS size > 0 and it isn't loaded */
if (!(G(L)->ROpvmain)) {
lua_settop(L, 0);
lua_pushnil(L);
if (G(L)->LFSsize) {
lua_pushinteger(L, (lua_Integer) flashAddr);
lua_pushinteger(L, flashAddrPhys);
lua_pushinteger(L, G(L)->LFSsize);
return 4;
} else {
return 1;
}
}
/* Push the LClosure of the LFS index function */
Closure *cl = luaF_newLclosure(L, 0, hvalue(gt(L)));
cl->l.p = G(L)->ROpvmain;
lua_settop(L, n+1);
setclvalue(L, L->top-1, cl);
/* Move it infront of the arguments and call the index function */
lua_insert(L, 1);
lua_call(L, n, LUA_MULTRET);
/* Return it if the response if a single value (the function) */
if (lua_gettop(L) == 1)
return 1;
lua_assert(lua_gettop(L) == 2);
/* Otherwise add the base address of the LFS, and its size bewteen the */
/* Unix time and the module list, then return all 4 params. */
lua_pushinteger(L, (lua_Integer) flashAddr);
lua_insert(L, 2);
lua_pushinteger(L, flashAddrPhys);
lua_insert(L, 3);
lua_pushinteger(L, cast(FlashHeader *, flashAddr)->flash_size);
lua_insert(L, 4);
return 5;
}
#ifndef CONFIG_LUA_EMBEDDED_FLASH_STORE
/* =====================================================================================
* The following routines use my uzlib which was based on pfalcon's inflate and
* deflate routines. The standard NodeMCU make also makes two host tools uz_zip
* and uz_unzip which also use these and luac.cross uses the deflate. As discussed
* below, The main action routine loadLFS() calls uzlib_inflate() to do the actual
* stream inflation but uses three supplied CBs to abstract input and output
* stream handling.
*
* ESP8266 RAM limitations and heap fragmentation are a key implementation
* constraint and hence these routines use a number of ~2K buffers (11) as
* working storage.
*
* The inflate is done twice, in order to limit storage use and avoid forward /
* backward reference issues. However this has a major advantage that the LFS
* is scanned with the headers, CRC, etc. validated BEFORE the write to flash
* is started, so the only real chance of failure during the second pass
* write is if a power fail occurs during the pass.
*/
static void flash_error(const char *err) {
if (out)
out->error = err;
if (in && in->inflate_state)
uz_free(in->inflate_state);
lua_pushnil(out->L); /* can't use it on a cpcall anyway */
lua_error(out->L);
}
/*
* uzlib_inflate does a stream inflate on an RFC 1951 encoded data stream.
* It uses three application-specific CBs passed in the call to do the work:
*
* - get_byte() CB to return next byte in input stream
* - put_byte() CB to output byte to output buffer
* - recall_byte() CB to output byte to retrieve a historic byte from
* the output buffer.
*
* Note that put_byte() also triggers secondary CBs to do further processing.
*/
static uint8_t get_byte (void) {
if (--in->left < 0) {
/* Read next input block */
int remaining = in->len - in->bytesRead;
int wanted = remaining >= READ_BLOCKSIZE ? READ_BLOCKSIZE : remaining;
if (vfs_read(in->fd, in->block, wanted) != wanted)
flash_error("read error on LFS image file");
platform_wdt_feed();
in->bytesRead += wanted;
in->inPtr = in->block;
in->left = wanted-1;
}
return *in->inPtr++;
}
static void put_byte (uint8_t value) {
int offset = out->ndx % WRITE_BLOCKSIZE; /* counts from 0 */
out->block[0]->byte[offset++] = value;
out->ndx++;
if (offset == WRITE_BLOCKSIZE || out->ndx == out->len) {
if (out->fullBlkCB)
out->fullBlkCB();
/* circular shift the block pointers (redundant on last block, but so what) */
outBlock *nextBlock = out->block[WRITE_BLOCKS - 1];
memmove(out->block+1, out->block, (WRITE_BLOCKS-1)*sizeof(void*));
out->block[0] = nextBlock ;
}
}
static uint8_t recall_byte (uint offset) {
if(offset > DICTIONARY_WINDOW || offset >= out->ndx)
flash_error("invalid dictionary offset on inflate");
/* ndx starts at 1. Need relative to 0 */
uint n = out->ndx - offset;
uint pos = n % WRITE_BLOCKSIZE;
uint blockNo = out->ndx / WRITE_BLOCKSIZE - n / WRITE_BLOCKSIZE;
return out->block[blockNo]->byte[pos];
}
/*
* On the first pass the break index is set to call this process at the end
* of each completed output buffer.
* - On the first call, the Flash Header is checked.
* - On each call the CRC is rolled up for that buffer.
* - Once the flags array is in-buffer this is also captured.
* This logic is slightly complicated by the last buffer is typically short.
*/
int procFirstPass (void) {
int len = (out->ndx % WRITE_BLOCKSIZE) ?
out->ndx % WRITE_BLOCKSIZE : WRITE_BLOCKSIZE;
if (out->ndx <= WRITE_BLOCKSIZE) {
/* Process the flash header and cache the FlashHeader fields we need */
FlashHeader *fh = cast(FlashHeader *, out->block[0]);
out->flashLen = fh->flash_size; /* in bytes */
out->flagsLen = (out->len-fh->flash_size)/WORDSIZE; /* in words */
out->flash_sig = fh->flash_sig;
if ((fh->flash_sig & FLASH_FORMAT_MASK) != FLASH_FORMAT_VERSION)
flash_error("Incorrect LFS header version");
if ((fh->flash_sig & FLASH_SIG_B2_MASK) != FLASH_SIG_B2)
flash_error("Incorrect LFS build type");
if ((fh->flash_sig & ~FLASH_SIG_ABSOLUTE) != FLASH_SIG)
flash_error("incorrect LFS header signature");
if (fh->flash_size > flashSize)
flash_error("LFS Image too big for configured LFS region");
if ((fh->flash_size & 0x3) ||
fh->flash_size > flashSize ||
out->flagsLen != 1 + (out->flashLen/WORDSIZE - 1) / BITS_PER_WORD)
flash_error("LFS length mismatch");
out->flags = luaM_newvector(out->L, out->flagsLen, uint);
}
/* update running CRC */
out->crc = uzlib_crc32(out->block[0], len, out->crc);
/* copy out any flag vector */
if (out->ndx > out->flashLen) {
int start = out->flashLen - (out->ndx - len);
if (start < 0) start = 0;
memcpy(out->flags + out->flagsNdx, out->block[0]->byte + start, len - start);
out->flagsNdx += (len -start) / WORDSIZE; /* flashLen and len are word aligned */
}
return 1;
}
int procSecondPass (void) {
/*
* The length rules are different for the second pass since this only processes
* upto the flashLen and not the full image. This also works in word units.
* (We've already validated these are word multiples.)
*/
int i, len = (out->ndx > out->flashLen) ?
(out->flashLen % WRITE_BLOCKSIZE) / WORDSIZE :
WRITE_BLOCKSIZE / WORDSIZE;
uint32_t *buf = (uint32_t *) out->buffer.byte;
uint32_t flags = 0;
/*
* Relocate all the addresses tagged in out->flags. This can't be done in
* place because the out->blocks are still in use as dictionary content so
* first copy the block to a working buffer and do the relocation in this.
*/
memcpy(out->buffer.byte, out->block[0]->byte, WRITE_BLOCKSIZE);
for (i=0; i<len; i++,flags>>=1 ) {
if ((i&31)==0)
flags = out->flags[out->flagsNdx++];
if (flags&1)
buf[i] = WORDSIZE*buf[i] + cast(uint32_t, flashAddr); // mapped, not phys
}
/*
* On first block, set the flash_sig has the in progress bit set and this
* is not cleared until end.
*/
if (out->ndx <= WRITE_BLOCKSIZE)
buf[0] = out->flash_sig | FLASH_SIG_IN_PROGRESS;
flashBlock(buf, len*WORDSIZE);
if (out->ndx >= out->flashLen) {
/* we're done so disable CB and rewrite flash sig to complete flash */
flashSetPosition(0);
flashBlock(&out->flash_sig, WORDSIZE);
out->fullBlkCB = NULL;
}
return 1;
}
/*
* loadLFS)() is protected called from luaN_reload_reboot so that it can recover
* from out of memory and other thrown errors. loadLFSgc() GCs any resources.
*/
static int loadLFS (lua_State *L) {
const char *fn = cast(const char *, lua_touserdata(L, 1));
int i, res;
uint32_t crc;
/* Allocate and zero in and out structures */
in = NULL; out = NULL;
in = luaM_new(L, struct INPUT);
memset(in, 0, sizeof(*in));
out = luaM_new(L, struct OUTPUT);
memset(out, 0, sizeof(*out));
out->L = L;
out->fullBlkCB = procFirstPass;
out->crc = ~0;
/* Open LFS image/ file, read unpacked length from last 4 byte and rewind */
if (!(in->fd = vfs_open(fn, "r")))
flash_error("LFS image file not found");
in->len = vfs_size(in->fd);
if (in->len <= 200 || /* size of an empty luac output */
vfs_lseek(in->fd, in->len-4, VFS_SEEK_SET) != in->len-4 ||
vfs_read(in->fd, &out->len, sizeof(uint)) != sizeof(uint))
flash_error("read error on LFS image file");
vfs_lseek(in->fd, 0, VFS_SEEK_SET);
/* Allocate the out buffers */
for(i = 0; i < WRITE_BLOCKS; i++)
out->block[i] = luaM_new(L, outBlock);
/* first inflate pass */
if (uzlib_inflate (get_byte, put_byte, recall_byte,
in->len, &crc, &in->inflate_state) < 0)
flash_error("read error on LFS image file");
if (crc != ~out->crc)
flash_error("checksum error on LFS image file");
out->fullBlkCB = procSecondPass;
out->flagsNdx = 0;
out->ndx = 0;
in->bytesRead = in->left = 0;
/*
* Once we have completed the 1st pass then the LFS image has passed the
* basic signature, crc and length checks, so now we can reset the counts
* to do the actual write to flash on the second pass.
*/
vfs_lseek(in->fd, 0, VFS_SEEK_SET);
flashErase(0,(out->flashLen - 1)/FLASH_PAGE_SIZE);
flashSetPosition(0);
res = uzlib_inflate(get_byte, put_byte, recall_byte,
in->len, &crc, &in->inflate_state);
if (res < 0) { // UZLIB_OK == 0, UZLIB_DONE == 1
const char *err[] = {"Data_error during decompression",
"Chksum_error during decompression",
"Dictionary error during decompression",
"Memory_error during decompression"};
flash_error(err[UZLIB_DATA_ERROR - res]);
}
return 0;
}
static int loadLFSgc (lua_State *L) {
int i;
if (out) {
for (i = 0; i < WRITE_BLOCKS; i++)
if (out->block[i])
luaM_free(L, out->block[i]);
if (out->flags)
luaM_freearray(L, out->flags, out->flagsLen, uint32_t);
luaM_free(L, out);
}
if (in) {
if (in->fd)
vfs_close(in->fd);
luaM_free(L, in);
}
return 0;
}
#endif
/*
** lflashe.h
** See Copyright Notice in lua.h
*/
#ifndef lflash_h
#define lflash_h
#include "lobject.h"
#include "lstate.h"
#include "lzio.h"
#ifdef LUA_NUMBER_INTEGRAL
# define FLASH_SIG_B1 0x02
#else
# define FLASH_SIG_B1 0x00
#endif
#define FLASH_FORMAT_VERSION (1 << 8)
#define FLASH_FORMAT_MASK 0xF00
#ifdef LUA_PACK_TVALUES
#ifdef LUA_NUMBER_INTEGRAL
#error "LUA_PACK_TVALUES is only valid for Floating point builds"
#endif
# define FLASH_SIG_B2 0x04
#else
# define FLASH_SIG_B2 0x00
#endif
# define FLASH_SIG_B2_MASK 0x04
#define FLASH_SIG_ABSOLUTE 0x01
#define FLASH_SIG_IN_PROGRESS 0x08
#define FLASH_SIG (0xfafaa050 | FLASH_FORMAT_VERSION |FLASH_SIG_B2 | FLASH_SIG_B1)
typedef lu_int32 FlashAddr;
typedef struct {
lu_int32 flash_sig; /* a stabdard fingerprint identifying an LFS image */
lu_int32 flash_size; /* Size of LFS image */
FlashAddr mainProto; /* address of main Proto in Proto hierarchy */
FlashAddr pROhash; /* address of ROstrt hash */
lu_int32 nROuse; /* number of elements in ROstrt */
int nROsize; /* size of ROstrt */
lu_int32 fill1; /* reserved */
lu_int32 fill2; /* reserved */
} FlashHeader;
LUAI_FUNC void luaN_init (lua_State *L);
LUAI_FUNC int luaN_flashSetup (lua_State *L);
LUAI_FUNC int luaN_reload_reboot (lua_State *L);
LUAI_FUNC int luaN_index (lua_State *L);
#endif
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#define LUAC_CROSS_FILE #define LUAC_CROSS_FILE
#include "lua.h" #include "lua.h"
#include C_HEADER_STRING #include <string.h>
#include "lfunc.h" #include "lfunc.h"
#include "lgc.h" #include "lgc.h"
...@@ -146,7 +146,7 @@ void luaF_freeproto (lua_State *L, Proto *f) { ...@@ -146,7 +146,7 @@ void luaF_freeproto (lua_State *L, Proto *f) {
luaM_freearray(L, f->k, f->sizek, TValue); luaM_freearray(L, f->k, f->sizek, TValue);
luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *);
if (!proto_is_readonly(f)) { if (!proto_isreadonly(f)) {
luaM_freearray(L, f->code, f->sizecode, Instruction); luaM_freearray(L, f->code, f->sizecode, Instruction);
#ifdef LUA_OPTIMIZE_DEBUG #ifdef LUA_OPTIMIZE_DEBUG
if (f->packedlineinfo) { if (f->packedlineinfo) {
......
...@@ -18,9 +18,6 @@ ...@@ -18,9 +18,6 @@
#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ #define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
cast(int, sizeof(TValue *)*((n)-1))) cast(int, sizeof(TValue *)*((n)-1)))
#define proto_readonly(p) l_setbit((p)->marked, READONLYBIT)
#define proto_is_readonly(p) testbit((p)->marked, READONLYBIT)
LUAI_FUNC Proto *luaF_newproto (lua_State *L); LUAI_FUNC Proto *luaF_newproto (lua_State *L);
LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e);
LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#define LUAC_CROSS_FILE #define LUAC_CROSS_FILE
#include "lua.h" #include "lua.h"
#include C_HEADER_STRING #include <string.h>
#include "ldebug.h" #include "ldebug.h"
#include "ldo.h" #include "ldo.h"
...@@ -37,10 +37,10 @@ ...@@ -37,10 +37,10 @@
#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT)
#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) #define stringmark(s) if (!isLFSobject(&(s)->tsv)) {reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT);}
#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) #define isfinalized(u) testbit(getmarked(u), FINALIZEDBIT)
#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) #define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT)
...@@ -61,15 +61,21 @@ ...@@ -61,15 +61,21 @@
static void removeentry (Node *n) { static void removeentry (Node *n) {
lua_assert(ttisnil(gval(n))); lua_assert(ttisnil(gval(n)));
if (iscollectable(gkey(n))) if (ttype(gkey(n)) != LUA_TDEADKEY && iscollectable(gkey(n)))
// The gkey is always in RAM so it can be marked as DEAD even though it
// refers to an LFS object.
setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */
} }
static void reallymarkobject (global_State *g, GCObject *o) { static void reallymarkobject (global_State *g, GCObject *o) {
/* don't mark LFS Protos (or strings) */
if (gettt(&o->gch) == LUA_TPROTO && isLFSobject(&(o->gch)))
return;
lua_assert(iswhite(o) && !isdead(g, o)); lua_assert(iswhite(o) && !isdead(g, o));
white2gray(o); white2gray(o);
switch (o->gch.tt) { switch (gettt(&o->gch)) {
case LUA_TSTRING: { case LUA_TSTRING: {
return; return;
} }
...@@ -159,10 +165,14 @@ static int traversetable (global_State *g, Table *h) { ...@@ -159,10 +165,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 = (strchr(svalue(mode), 'k') != NULL); weakkey = (strchr(svalue(mode), 'k') != NULL);
weakvalue = (strchr(svalue(mode), 'v') != NULL); weakvalue = (strchr(svalue(mode), 'v') != NULL);
...@@ -180,6 +190,8 @@ static int traversetable (global_State *g, Table *h) { ...@@ -180,6 +190,8 @@ static int traversetable (global_State *g, Table *h) {
while (i--) while (i--)
markvalue(g, &h->array[i]); markvalue(g, &h->array[i]);
} }
if (luaH_isdummy (h->node))
return weakkey || weakvalue;
i = sizenode(h); i = sizenode(h);
while (i--) { while (i--) {
Node *n = gnode(h, i); Node *n = gnode(h, i);
...@@ -202,6 +214,8 @@ static int traversetable (global_State *g, Table *h) { ...@@ -202,6 +214,8 @@ static int traversetable (global_State *g, Table *h) {
*/ */
static void traverseproto (global_State *g, Proto *f) { static void traverseproto (global_State *g, Proto *f) {
int i; int i;
if (isLFSobject(f))
return; /* don't traverse Protos in LFS */
if (f->source) stringmark(f->source); if (f->source) stringmark(f->source);
for (i=0; i<f->sizek; i++) /* mark literals */ for (i=0; i<f->sizek; i++) /* mark literals */
markvalue(g, &f->k[i]); markvalue(g, &f->k[i]);
...@@ -282,7 +296,7 @@ static l_mem propagatemark (global_State *g) { ...@@ -282,7 +296,7 @@ static l_mem propagatemark (global_State *g) {
GCObject *o = g->gray; GCObject *o = g->gray;
lua_assert(isgray(o)); lua_assert(isgray(o));
gray2black(o); gray2black(o);
switch (o->gch.tt) { switch (gettt(&o->gch)) {
case LUA_TTABLE: { case LUA_TTABLE: {
Table *h = gco2h(o); Table *h = gco2h(o);
g->gray = h->gclist; g->gray = h->gclist;
...@@ -317,7 +331,7 @@ static l_mem propagatemark (global_State *g) { ...@@ -317,7 +331,7 @@ static l_mem propagatemark (global_State *g) {
sizeof(TValue) * p->sizek + sizeof(TValue) * p->sizek +
sizeof(LocVar) * p->sizelocvars + sizeof(LocVar) * p->sizelocvars +
sizeof(TString *) * p->sizeupvalues + sizeof(TString *) * p->sizeupvalues +
(proto_is_readonly(p) ? 0 : sizeof(Instruction) * p->sizecode + (proto_isreadonly(p) ? 0 : sizeof(Instruction) * p->sizecode +
#ifdef LUA_OPTIMIZE_DEBUG #ifdef LUA_OPTIMIZE_DEBUG
(p->packedlineinfo ? (p->packedlineinfo ?
strlen(cast(char *, p->packedlineinfo))+1 : strlen(cast(char *, p->packedlineinfo))+1 :
...@@ -387,8 +401,11 @@ static void cleartable (GCObject *l) { ...@@ -387,8 +401,11 @@ static void cleartable (GCObject *l) {
static void freeobj (lua_State *L, GCObject *o) { static void freeobj (lua_State *L, GCObject *o) {
switch (o->gch.tt) { switch (gettt(&o->gch)) {
case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TPROTO:
lua_assert(!isLFSobject(&(o->gch)));
luaF_freeproto(L, gco2p(o));
break;
case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
case LUA_TTABLE: luaH_free(L, gco2h(o)); break; case LUA_TTABLE: luaH_free(L, gco2h(o)); break;
...@@ -398,6 +415,7 @@ static void freeobj (lua_State *L, GCObject *o) { ...@@ -398,6 +415,7 @@ static void freeobj (lua_State *L, GCObject *o) {
break; break;
} }
case LUA_TSTRING: { case LUA_TSTRING: {
lua_assert(!isLFSobject(&(o->gch)));
G(L)->strt.nuse--; G(L)->strt.nuse--;
luaM_freemem(L, o, sizestring(gco2ts(o))); luaM_freemem(L, o, sizestring(gco2ts(o)));
break; break;
...@@ -420,6 +438,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { ...@@ -420,6 +438,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
global_State *g = G(L); global_State *g = G(L);
int deadmask = otherwhite(g); int deadmask = otherwhite(g);
while ((curr = *p) != NULL && count-- > 0) { while ((curr = *p) != NULL && count-- > 0) {
lua_assert(!isLFSobject(&(curr->gch)) || curr->gch.tt == LUA_TTHREAD);
if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */
sweepwholelist(L, &gco2th(curr)->openupval); sweepwholelist(L, &gco2th(curr)->openupval);
if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */
...@@ -538,7 +557,7 @@ static void atomic (lua_State *L) { ...@@ -538,7 +557,7 @@ static void atomic (lua_State *L) {
size_t udsize; /* total size of userdata to be finalized */ size_t udsize; /* total size of userdata to be finalized */
/* remark occasional upvalues of (maybe) dead threads */ /* remark occasional upvalues of (maybe) dead threads */
remarkupvals(g); remarkupvals(g);
/* traverse objects cautch by write barrier and by 'remarkupvals' */ /* traverse objects caucht by write barrier and by 'remarkupvals' */
propagateall(g); propagateall(g);
/* remark weak tables */ /* remark weak tables */
g->gray = g->weak; g->gray = g->weak;
...@@ -694,10 +713,10 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { ...@@ -694,10 +713,10 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
global_State *g = G(L); global_State *g = G(L);
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
lua_assert(ttype(&o->gch) != LUA_TTABLE); lua_assert(o->gch.tt != LUA_TTABLE);
/* must keep invariant? */ /* must keep invariant? */
if (g->gcstate == GCSpropagate) if (g->gcstate == GCSpropagate)
reallymarkobject(g, v); /* restore invariant */ reallymarkobject(g, v); /* Restore invariant */
else /* don't mind */ else /* don't mind */
makewhite(g, o); /* mark as white just to avoid other barriers */ makewhite(g, o); /* mark as white just to avoid other barriers */
} }
......
...@@ -79,6 +79,7 @@ ...@@ -79,6 +79,7 @@
#define VALUEWEAKBIT 4 #define VALUEWEAKBIT 4
#define FIXEDBIT 5 #define FIXEDBIT 5
#define SFIXEDBIT 6 #define SFIXEDBIT 6
#define LFSBIT 6
#define READONLYBIT 7 #define READONLYBIT 7
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
...@@ -100,6 +101,13 @@ ...@@ -100,6 +101,13 @@
#define isfixedstack(x) testbit((x)->marked, FIXEDSTACKBIT) #define isfixedstack(x) testbit((x)->marked, FIXEDSTACKBIT)
#define fixedstack(x) l_setbit((x)->marked, FIXEDSTACKBIT) #define fixedstack(x) l_setbit((x)->marked, FIXEDSTACKBIT)
#define unfixedstack(x) resetbit((x)->marked, FIXEDSTACKBIT) #define unfixedstack(x) resetbit((x)->marked, FIXEDSTACKBIT)
#ifndef LUA_CROSS_COMPILER
#define isLFSobject(x) testbit(getmarked(x), LFSBIT)
#define stringfix(s) if (!test2bits(getmarked(&(s)->tsv), FIXEDBIT, LFSBIT)) {l_setbit((s)->tsv.marked, FIXEDBIT);}
#else
#define isLFSobject(x) (0)
#define stringfix(s) {l_setbit((s)->tsv.marked, FIXEDBIT);}
#endif
#define luaC_checkGC(L) { \ #define luaC_checkGC(L) { \
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \
......
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
#define LUAC_CROSS_FILE #define LUAC_CROSS_FILE
#include "lua.h" #include "lua.h"
#include C_HEADER_CTYPE #include <ctype.h>
#include C_HEADER_LOCALE #include <locale.h>
#include C_HEADER_STRING #include <string.h>
#include "ldo.h" #include "ldo.h"
#include "llex.h" #include "llex.h"
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
#define LUAC_CROSS_FILE #define LUAC_CROSS_FILE
#include "lua.h" #include "lua.h"
#include C_HEADER_STDLIB #include <stdlib.h>
#include C_HEADER_MATH #include <math.h>
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
...@@ -309,92 +309,57 @@ static int math_randomseed (lua_State *L) { ...@@ -309,92 +309,57 @@ static int math_randomseed (lua_State *L) {
return 0; return 0;
} }
LROT_PUBLIC_BEGIN(math)
#undef MIN_OPT_LEVEL
#define MIN_OPT_LEVEL 1
#include "lrodefs.h"
const LUA_REG_TYPE math_map[] = {
#ifdef LUA_NUMBER_INTEGRAL #ifdef LUA_NUMBER_INTEGRAL
{LSTRKEY("abs"), LFUNCVAL(math_abs)}, LROT_FUNCENTRY( abs, math_abs )
{LSTRKEY("ceil"), LFUNCVAL(math_identity)}, LROT_FUNCENTRY( ceil, math_identity )
{LSTRKEY("floor"), LFUNCVAL(math_identity)}, LROT_FUNCENTRY( floor, math_identity )
{LSTRKEY("max"), LFUNCVAL(math_max)}, LROT_FUNCENTRY( max, math_max )
{LSTRKEY("min"), LFUNCVAL(math_min)}, LROT_FUNCENTRY( min, math_min )
{LSTRKEY("pow"), LFUNCVAL(math_pow)}, LROT_FUNCENTRY( pow, math_pow )
{LSTRKEY("random"), LFUNCVAL(math_random)}, LROT_FUNCENTRY( random, math_random )
{LSTRKEY("randomseed"), LFUNCVAL(math_randomseed)}, LROT_FUNCENTRY( randomseed, math_randomseed )
{LSTRKEY("sqrt"), LFUNCVAL(math_sqrt)}, LROT_FUNCENTRY( sqrt, math_sqrt )
#if LUA_OPTIMIZE_MEMORY > 0 LROT_NUMENTRY( huge, INT_MAX )
{LSTRKEY("huge"), LNUMVAL(LONG_MAX)},
#endif
#else #else
{LSTRKEY("abs"), LFUNCVAL(math_abs)}, LROT_FUNCENTRY( abs, math_abs )
// {LSTRKEY("acos"), LFUNCVAL(math_acos)}, // LROT_FUNCENTRY( acos, math_acos )
// {LSTRKEY("asin"), LFUNCVAL(math_asin)}, // LROT_FUNCENTRY( asin, math_asin )
// {LSTRKEY("atan2"), LFUNCVAL(math_atan2)}, // LROT_FUNCENTRY( atan2, math_atan2 )
// {LSTRKEY("atan"), LFUNCVAL(math_atan)}, // LROT_FUNCENTRY( atan, math_atan )
{LSTRKEY("ceil"), LFUNCVAL(math_ceil)}, LROT_FUNCENTRY( ceil, math_ceil )
// {LSTRKEY("cosh"), LFUNCVAL(math_cosh)}, // LROT_FUNCENTRY( cosh, math_cosh )
// {LSTRKEY("cos"), LFUNCVAL(math_cos)}, // LROT_FUNCENTRY( cos, math_cos )
// {LSTRKEY("deg"), LFUNCVAL(math_deg)}, // LROT_FUNCENTRY( deg, math_deg )
// {LSTRKEY("exp"), LFUNCVAL(math_exp)}, // LROT_FUNCENTRY( exp, math_exp )
{LSTRKEY("floor"), LFUNCVAL(math_floor)}, LROT_FUNCENTRY( floor, math_floor )
// {LSTRKEY("fmod"), LFUNCVAL(math_fmod)}, // LROT_FUNCENTRY( fmod, math_fmod )
#if LUA_OPTIMIZE_MEMORY > 0 && defined(LUA_COMPAT_MOD) // LROT_FUNCENTRY( mod, math_fmod )
// {LSTRKEY("mod"), LFUNCVAL(math_fmod)}, // LROT_FUNCENTRY( frexp, math_frexp )
#endif // LROT_FUNCENTRY( ldexp, math_ldexp )
// {LSTRKEY("frexp"), LFUNCVAL(math_frexp)}, // LROT_FUNCENTRY( log10, math_log10 )
// {LSTRKEY("ldexp"), LFUNCVAL(math_ldexp)}, // LROT_FUNCENTRY( log, math_log )
// {LSTRKEY("log10"), LFUNCVAL(math_log10)}, LROT_FUNCENTRY( max, math_max )
// {LSTRKEY("log"), LFUNCVAL(math_log)}, LROT_FUNCENTRY( min, math_min )
{LSTRKEY("max"), LFUNCVAL(math_max)}, // LROT_FUNCENTRY( modf, math_modf )
{LSTRKEY("min"), LFUNCVAL(math_min)}, LROT_FUNCENTRY( pow, math_pow )
// {LSTRKEY("modf"), LFUNCVAL(math_modf)}, // LROT_FUNCENTRY( rad, math_rad )
{LSTRKEY("pow"), LFUNCVAL(math_pow)}, LROT_FUNCENTRY( random, math_random )
// {LSTRKEY("rad"), LFUNCVAL(math_rad)}, LROT_FUNCENTRY( randomseed, math_randomseed )
{LSTRKEY("random"), LFUNCVAL(math_random)}, // LROT_FUNCENTRY( sinh, math_sinh )
{LSTRKEY("randomseed"), LFUNCVAL(math_randomseed)}, // LROT_FUNCENTRY( sin, math_sin )
// {LSTRKEY("sinh"), LFUNCVAL(math_sinh)}, LROT_FUNCENTRY( sqrt, math_sqrt )
// {LSTRKEY("sin"), LFUNCVAL(math_sin)}, // LROT_FUNCENTRY( tanh, math_tanh )
{LSTRKEY("sqrt"), LFUNCVAL(math_sqrt)}, // LROT_FUNCENTRY( tan, math_tan )
// {LSTRKEY("tanh"), LFUNCVAL(math_tanh)}, LROT_NUMENTRY( pi, PI )
// {LSTRKEY("tan"), LFUNCVAL(math_tan)}, LROT_NUMENTRY( huge, HUGE_VAL )
#if LUA_OPTIMIZE_MEMORY > 0
{LSTRKEY("pi"), LNUMVAL(PI)},
{LSTRKEY("huge"), LNUMVAL(HUGE_VAL)},
#endif // #if LUA_OPTIMIZE_MEMORY > 0
#endif // #ifdef LUA_NUMBER_INTEGRAL #endif // #ifdef LUA_NUMBER_INTEGRAL
{LNILKEY, LNILVAL} LROT_END(math, NULL, 0)
};
/* /*
** Open math library ** Open math library
*/ */
#if defined LUA_NUMBER_INTEGRAL
# include <limits.h> /* for LONG_MAX */
#endif
LUALIB_API int luaopen_math (lua_State *L) { LUALIB_API int luaopen_math (lua_State *L) {
#if LUA_OPTIMIZE_MEMORY > 0
return 0; return 0;
#else
luaL_register(L, LUA_MATHLIBNAME, math_map);
# if defined LUA_NUMBER_INTEGRAL
lua_pushnumber(L, LONG_MAX);
lua_setfield(L, -2, "huge");
# else
lua_pushnumber(L, PI);
lua_setfield(L, -2, "pi");
lua_pushnumber(L, HUGE_VAL);
lua_setfield(L, -2, "huge");
# if defined(LUA_COMPAT_MOD)
lua_getfield(L, -1, "fmod");
lua_setfield(L, -2, "mod");
# endif
# endif
return 1;
#endif
} }
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#ifndef LUA_CROSS_COMPILER #ifndef LUA_CROSS_COMPILER
#include "vfs.h" #include "vfs.h"
#include "c_stdlib.h" // for c_getenv
#endif #endif
#include "lauxlib.h" #include "lauxlib.h"
...@@ -334,9 +333,9 @@ static int ll_loadlib (lua_State *L) { ...@@ -334,9 +333,9 @@ static int ll_loadlib (lua_State *L) {
*/ */
#ifdef LUA_CROSS_COMPILER #ifdef LUA_CROSS_COMPILER
static int readable (const char *filename) { static int readable (const char *filename) {
FILE *f = c_fopen(filename, "r"); /* try to open file */ FILE *f = fopen(filename, "r"); /* try to open file */
if (f == NULL) return 0; /* open failed */ if (f == NULL) return 0; /* open failed */
c_fclose(f); fclose(f);
return 1; return 1;
} }
#else #else
...@@ -363,7 +362,9 @@ static const char * findfile (lua_State *L, const char *name, ...@@ -363,7 +362,9 @@ static const char * findfile (lua_State *L, const char *name,
const char *pname) { const char *pname) {
const char *path; const char *path;
name = luaL_gsub(L, name, ".", LUA_DIRSEP); name = luaL_gsub(L, name, ".", LUA_DIRSEP);
lua_getfield(L, LUA_ENVIRONINDEX, pname); lua_getfield(L, LUA_GLOBALSINDEX, "package");
lua_getfield(L, -1, pname);
lua_remove(L, -2);
path = lua_tostring(L, -1); path = lua_tostring(L, -1);
if (path == NULL) if (path == NULL)
luaL_error(L, LUA_QL("package.%s") " must be a string", pname); luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
...@@ -449,7 +450,9 @@ static int loader_Croot (lua_State *L) { ...@@ -449,7 +450,9 @@ static int loader_Croot (lua_State *L) {
static int loader_preload (lua_State *L) { static int loader_preload (lua_State *L) {
const char *name = luaL_checkstring(L, 1); const char *name = luaL_checkstring(L, 1);
lua_getfield(L, LUA_ENVIRONINDEX, "preload"); lua_getfield(L, LUA_GLOBALSINDEX, "package");
lua_getfield(L, -1, "preload");
lua_remove(L, -2);
if (!lua_istable(L, -1)) if (!lua_istable(L, -1))
luaL_error(L, LUA_QL("package.preload") " must be a table"); luaL_error(L, LUA_QL("package.preload") " must be a table");
lua_getfield(L, -1, name); lua_getfield(L, -1, name);
...@@ -475,13 +478,16 @@ static int ll_require (lua_State *L) { ...@@ -475,13 +478,16 @@ 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, 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_GLOBALSINDEX, "package");
lua_getfield(L, -1, "loaders");
lua_remove(L, -2);
if (!lua_istable(L, -1)) if (!lua_istable(L, -1))
luaL_error(L, LUA_QL("package.loaders") " must be a table"); luaL_error(L, LUA_QL("package.loaders") " must be a table");
lua_pushliteral(L, ""); /* error message accumulator */ lua_pushliteral(L, ""); /* error message accumulator */
...@@ -564,8 +570,13 @@ static void modinit (lua_State *L, const char *modname) { ...@@ -564,8 +570,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, 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] */
...@@ -614,7 +625,7 @@ static int ll_seeall (lua_State *L) { ...@@ -614,7 +625,7 @@ static int ll_seeall (lua_State *L) {
static void setpath (lua_State *L, const char *fieldname, const char *envname, static void setpath (lua_State *L, const char *fieldname, const char *envname,
const char *def) { const char *def) {
const char *path = c_getenv(envname); const char *path = NULL; /* getenv(envname) not used in NodeMCU */;
if (path == NULL) /* no environment variable? */ if (path == NULL) /* no environment variable? */
lua_pushstring(L, def); /* use default */ lua_pushstring(L, def); /* use default */
else { else {
...@@ -646,34 +657,20 @@ static const luaL_Reg ll_funcs[] = { ...@@ -646,34 +657,20 @@ static const luaL_Reg ll_funcs[] = {
static const lua_CFunction loaders[] = static const lua_CFunction loaders[] =
{loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; {loader_preload, loader_Lua, loader_C, loader_Croot, NULL};
#if LUA_OPTIMIZE_MEMORY > 0 LROT_PUBLIC_BEGIN(lmt)
#undef MIN_OPT_LEVEL LROT_FUNCENTRY(__gc,gctm)
#define MIN_OPT_LEVEL 1 LROT_END(lmt,lmt, LROT_MASK_GC)
#include "lrodefs.h"
const LUA_REG_TYPE lmt[] = {
{LRO_STRKEY("__gc"), LRO_FUNCVAL(gctm)},
{LRO_NILKEY, LRO_NILVAL}
};
#endif
LUALIB_API int luaopen_package (lua_State *L) { LUALIB_API int luaopen_package (lua_State *L) {
int i; int i;
/* create new type _LOADLIB */ /* create new type _LOADLIB */
#if LUA_OPTIMIZE_MEMORY == 0 luaL_rometatable(L, "_LOADLIB",LROT_TABLEREF(lmt));
luaL_newmetatable(L, "_LOADLIB");
lua_pushlightfunction(L, gctm);
lua_setfield(L, -2, "__gc");
#else
luaL_rometatable(L, "_LOADLIB", (void*)lmt);
#endif
/* create `package' table */ /* create `package' table */
luaL_register_light(L, LUA_LOADLIBNAME, pk_funcs); luaL_register_light(L, LUA_LOADLIBNAME, pk_funcs);
#if defined(LUA_COMPAT_LOADLIB) #if defined(LUA_COMPAT_LOADLIB)
lua_getfield(L, -1, "loadlib"); lua_getfield(L, -1, "loadlib");
lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); lua_setfield(L, LUA_GLOBALSINDEX, "loadlib");
#endif #endif
lua_pushvalue(L, -1);
lua_replace(L, LUA_ENVIRONINDEX);
/* create `loaders' table */ /* create `loaders' table */
lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0); lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0);
/* fill it with pre-defined loaders */ /* fill it with pre-defined loaders */
......
...@@ -54,6 +54,7 @@ int luaO_fb2int (int x) { ...@@ -54,6 +54,7 @@ int luaO_fb2int (int x) {
int luaO_log2 (unsigned int x) { int luaO_log2 (unsigned int x) {
#ifdef LUA_CROSS_COMPILER
static const lu_byte log_2[256] = { static const lu_byte log_2[256] = {
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
...@@ -67,6 +68,12 @@ int luaO_log2 (unsigned int x) { ...@@ -67,6 +68,12 @@ int luaO_log2 (unsigned int x) {
int l = -1; int l = -1;
while (x >= 256) { l += 8; x >>= 8; } while (x >= 256) { l += 8; x >>= 8; }
return l + log_2[x]; return l + log_2[x];
#else
/* Use Normalization Shift Amount Unsigned: 0x1=>31 up to 0xffffffff =>0
* See Xtensa Instruction Set Architecture (ISA) Refman P 462 */
asm volatile ("nsau %0, %1;" :"=r"(x) : "r"(x));
return 31 - x;
#endif
} }
......
...@@ -19,10 +19,8 @@ ...@@ -19,10 +19,8 @@
#define NUM_TAGS (LAST_TAG+1) #define NUM_TAGS (LAST_TAG+1)
/* mask for 'read-only' objects. must match READONLYBIT in lgc.h' */ #define READONLYMASK (1<<7) /* denormalised bitmask for READONLYBIT and */
#define READONLYMASK 128 #define LFSMASK (1<<6) /* LFSBIT to avoid include proliferation */
/* /*
** Extra tags for non-values ** Extra tags for non-values
*/ */
...@@ -30,6 +28,21 @@ ...@@ -30,6 +28,21 @@
#define LUA_TUPVAL (LAST_TAG+2) #define LUA_TUPVAL (LAST_TAG+2)
#define LUA_TDEADKEY (LAST_TAG+3) #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 ** Union of all collectable objects
...@@ -51,86 +64,46 @@ typedef struct GCheader { ...@@ -51,86 +64,46 @@ typedef struct GCheader {
CommonHeader; CommonHeader;
} GCheader; } 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 ** Union of all Lua values
*/ */
#if defined( LUA_PACK_VALUE ) && defined( ELUA_ENDIAN_BIG )
typedef union {
struct {
int _pad0;
GCObject *gc;
};
struct {
int _pad1;
void *p;
};
lua_Number n;
struct {
int _pad2;
int b;
};
} Value;
#else // #if defined( LUA_PACK_VALUE ) && defined( ELUA_ENDIAN_BIG )
typedef union { typedef union {
GCObject *gc; GCObject *gc;
void *p; void *p;
lua_Number n; lua_Number n;
int b; int b;
} Value; } Value;
#endif // #if defined( LUA_PACK_VALUE ) && defined( ELUA_ENDIAN_BIG )
/* /*
** Tagged Values ** Tagged Values
*/ */
#ifndef LUA_PACK_VALUE
#define TValuefields Value value; int tt #define TValuefields Value value; int tt
#define LUA_TVALUE_NIL {NULL}, LUA_TNIL #define LUA_TVALUE_NIL {NULL}, LUA_TNIL
#if defined(LUA_PACK_TVALUES) && !defined(LUA_CROSS_COMPILER)
#pragma pack(4)
#endif
typedef struct lua_TValue { typedef struct lua_TValue {
TValuefields; TValuefields;
} TValue; } TValue;
#else // #ifndef LUA_PACK_VALUE #if defined(LUA_PACK_TVALUES) && !defined(LUA_CROSS_COMPILER)
#ifdef ELUA_ENDIAN_LITTLE #pragma pack()
#define TValuefields union { \ #endif
struct { \
int _pad0; \
int tt_sig; \
} _ts; \
struct { \
int _pad; \
short tt; \
short sig; \
} _t; \
Value value; \
}
#define LUA_TVALUE_NIL {0, add_sig(LUA_TNIL)}
#else // #ifdef ELUA_ENDIAN_LITTLE
#define TValuefields union { \
struct { \
int tt_sig; \
int _pad0; \
} _ts; \
struct { \
short sig; \
short tt; \
int _pad; \
} _t; \
Value value; \
}
#define LUA_TVALUE_NIL {add_sig(LUA_TNIL), 0}
#endif // #ifdef ELUA_ENDIAN_LITTLE
#define LUA_NOTNUMBER_SIG (-1)
#define add_sig(tt) ( 0xffff0000 | (tt) )
typedef TValuefields TValue;
#endif // #ifndef LUA_PACK_VALUE
/* Macros to test type */ /* Macros to test type */
#ifndef LUA_PACK_VALUE
#define ttisnil(o) (ttype(o) == LUA_TNIL) #define ttisnil(o) (ttype(o) == LUA_TNIL)
#define ttisnumber(o) (ttype(o) == LUA_TNUMBER) #define ttisnumber(o) (ttype(o) == LUA_TNUMBER)
#define ttisstring(o) (ttype(o) == LUA_TSTRING) #define ttisstring(o) (ttype(o) == LUA_TSTRING)
...@@ -142,27 +115,11 @@ typedef TValuefields TValue; ...@@ -142,27 +115,11 @@ typedef TValuefields TValue;
#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) #define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA)
#define ttisrotable(o) (ttype(o) == LUA_TROTABLE) #define ttisrotable(o) (ttype(o) == LUA_TROTABLE)
#define ttislightfunction(o) (ttype(o) == LUA_TLIGHTFUNCTION) #define ttislightfunction(o) (ttype(o) == LUA_TLIGHTFUNCTION)
#else // #ifndef LUA_PACK_VALUE
#define ttisnil(o) (ttype_sig(o) == add_sig(LUA_TNIL))
#define ttisnumber(o) ((o)->_t.sig != LUA_NOTNUMBER_SIG)
#define ttisstring(o) (ttype_sig(o) == add_sig(LUA_TSTRING))
#define ttistable(o) (ttype_sig(o) == add_sig(LUA_TTABLE))
#define ttisfunction(o) (ttype_sig(o) == add_sig(LUA_TFUNCTION))
#define ttisboolean(o) (ttype_sig(o) == add_sig(LUA_TBOOLEAN))
#define ttisuserdata(o) (ttype_sig(o) == add_sig(LUA_TUSERDATA))
#define ttisthread(o) (ttype_sig(o) == add_sig(LUA_TTHREAD))
#define ttislightuserdata(o) (ttype_sig(o) == add_sig(LUA_TLIGHTUSERDATA))
#define ttisrotable(o) (ttype_sig(o) == add_sig(LUA_TROTABLE))
#define ttislightfunction(o) (ttype_sig(o) == add_sig(LUA_TLIGHTFUNCTION))
#endif // #ifndef LUA_PACK_VALUE
/* Macros to access values */ /* Macros to access values */
#ifndef LUA_PACK_VALUE
#define ttype(o) ((o)->tt) #define ttype(o) ((void) (o)->value, (o)->tt)
#else // #ifndef LUA_PACK_VALUE
#define ttype(o) ((o)->_t.sig == LUA_NOTNUMBER_SIG ? (o)->_t.tt : LUA_TNUMBER)
#define ttype_sig(o) ((o)->_ts.tt_sig)
#endif // #ifndef LUA_PACK_VALUE
#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc) #define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc)
#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p) #define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p)
#define rvalue(o) check_exp(ttisrotable(o), (o)->value.p) #define rvalue(o) check_exp(ttisrotable(o), (o)->value.p)
...@@ -182,24 +139,15 @@ typedef TValuefields TValue; ...@@ -182,24 +139,15 @@ typedef TValuefields TValue;
/* /*
** for internal debug only ** for internal debug only
*/ */
#ifndef LUA_PACK_VALUE
#define checkconsistency(obj) \ #define checkconsistency(obj) \
lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt))
#define checkliveness(g,obj) \ #define checkliveness(g,obj) \
lua_assert(!iscollectable(obj) || \ lua_assert(!iscollectable(obj) || \
((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc)))
#else // #ifndef LUA_PACK_VALUE
#define checkconsistency(obj) \
lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch._t.tt))
#define checkliveness(g,obj) \
lua_assert(!iscollectable(obj) || \
((ttype(obj) == (obj)->value.gc->gch._t.tt) && !isdead(g, (obj)->value.gc)))
#endif // #ifndef LUA_PACK_VALUE
/* Macros to set values */ /* Macros to set values */
#ifndef LUA_PACK_VALUE
#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) #define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
#define setnvalue(obj,x) \ #define setnvalue(obj,x) \
...@@ -253,69 +201,10 @@ typedef TValuefields TValue; ...@@ -253,69 +201,10 @@ typedef TValuefields TValue;
i_o->value.gc=i_x; i_o->tt=LUA_TPROTO; \ i_o->value.gc=i_x; i_o->tt=LUA_TPROTO; \
checkliveness(G(L),i_o); } checkliveness(G(L),i_o); }
#define setobj(L,obj1,obj2) \ #define setobj(L,obj1,obj2) \
{ const TValue *o2=(obj2); TValue *o1=(obj1); \ { const TValue *o2=(obj2); TValue *o1=(obj1); \
o1->value = o2->value; o1->tt=o2->tt; \ o1->value = o2->value; o1->tt=o2->tt; \
checkliveness(G(L),o1); } checkliveness(G(L),o1); }
#else // #ifndef LUA_PACK_VALUE
#define setnilvalue(obj) ( ttype_sig(obj) = add_sig(LUA_TNIL) )
#define setnvalue(obj,x) \
{ TValue *i_o=(obj); i_o->value.n=(x); }
#define setpvalue(obj,x) \
{ TValue *i_o=(obj); i_o->value.p=(x); i_o->_ts.tt_sig=add_sig(LUA_TLIGHTUSERDATA);}
#define setrvalue(obj,x) \
{ TValue *i_o=(obj); i_o->value.p=(x); i_o->_ts.tt_sig=add_sig(LUA_TROTABLE);}
#define setfvalue(obj,x) \
{ TValue *i_o=(obj); i_o->value.p=(x); i_o->_ts.tt_sig=add_sig(LUA_TLIGHTFUNCTION);}
#define setbvalue(obj,x) \
{ TValue *i_o=(obj); i_o->value.b=(x); i_o->_ts.tt_sig=add_sig(LUA_TBOOLEAN);}
#define setsvalue(L,obj,x) \
{ TValue *i_o=(obj); \
i_o->value.gc=cast(GCObject *, (x)); i_o->_ts.tt_sig=add_sig(LUA_TSTRING); \
checkliveness(G(L),i_o); }
#define setuvalue(L,obj,x) \
{ TValue *i_o=(obj); \
i_o->value.gc=cast(GCObject *, (x)); i_o->_ts.tt_sig=add_sig(LUA_TUSERDATA); \
checkliveness(G(L),i_o); }
#define setthvalue(L,obj,x) \
{ TValue *i_o=(obj); \
i_o->value.gc=cast(GCObject *, (x)); i_o->_ts.tt_sig=add_sig(LUA_TTHREAD); \
checkliveness(G(L),i_o); }
#define setclvalue(L,obj,x) \
{ TValue *i_o=(obj); \
i_o->value.gc=cast(GCObject *, (x)); i_o->_ts.tt_sig=add_sig(LUA_TFUNCTION); \
checkliveness(G(L),i_o); }
#define sethvalue(L,obj,x) \
{ TValue *i_o=(obj); \
i_o->value.gc=cast(GCObject *, (x)); i_o->_ts.tt_sig=add_sig(LUA_TTABLE); \
checkliveness(G(L),i_o); }
#define setptvalue(L,obj,x) \
{ TValue *i_o=(obj); \
i_o->value.gc=cast(GCObject *, (x)); i_o->_ts.tt_sig=add_sig(LUA_TPROTO); \
checkliveness(G(L),i_o); }
#define setobj(L,obj1,obj2) \
{ const TValue *o2=(obj2); TValue *o1=(obj1); \
o1->value = o2->value; \
checkliveness(G(L),o1); }
#endif // #ifndef LUA_PACK_VALUE
/* /*
** different types of sets, according to destination ** different types of sets, according to destination
...@@ -336,18 +225,11 @@ typedef TValuefields TValue; ...@@ -336,18 +225,11 @@ typedef TValuefields TValue;
#define setobj2n setobj #define setobj2n setobj
#define setsvalue2n setsvalue #define setsvalue2n setsvalue
#ifndef LUA_PACK_VALUE #define setttype(obj, stt) ((void) (obj)->value, (obj)->tt = (stt))
#define setttype(obj, tt) (ttype(obj) = (tt))
#else // #ifndef LUA_PACK_VALUE
/* considering it used only in lgc to set LUA_TDEADKEY */
/* we could define it this way */
#define setttype(obj, _tt) ( ttype_sig(obj) = add_sig(_tt) )
#endif // #ifndef LUA_PACK_VALUE
#define iscollectable(o) (ttype(o) >= LUA_TSTRING) #define iscollectable(o) (ttype(o) >= LUA_TSTRING)
typedef TValue *StkId; /* index to stack elements */ typedef TValue *StkId; /* index to stack elements */
...@@ -363,9 +245,16 @@ typedef union TString { ...@@ -363,9 +245,16 @@ typedef union TString {
} tsv; } tsv;
} TString; } TString;
#ifdef LUA_CROSS_COMPILER
#define getstr(ts) (((ts)->tsv.marked & READONLYMASK) ? cast(const char *, *(const char**)((ts) + 1)) : cast(const char *, (ts) + 1)) #define isreadonly(o) (0)
#define svalue(o) getstr(rawtsvalue(o)) #else
#define isreadonly(o) ((o).marked & READONLYMASK)
#endif
#define ts_isreadonly(ts) isreadonly((ts)->tsv)
#define getstr(ts) (ts_isreadonly(ts) ? \
cast(const char *, *(const char**)((ts) + 1)) : \
cast(const char *, (ts) + 1))
#define svalue(o) getstr(rawtsvalue(o))
...@@ -414,6 +303,7 @@ typedef struct Proto { ...@@ -414,6 +303,7 @@ typedef struct Proto {
lu_byte is_vararg; lu_byte is_vararg;
lu_byte maxstacksize; lu_byte maxstacksize;
} Proto; } Proto;
#define proto_isreadonly(p) isreadonly(*(p))
/* masks for new-style vararg */ /* masks for new-style vararg */
...@@ -483,7 +373,6 @@ typedef union Closure { ...@@ -483,7 +373,6 @@ typedef union Closure {
** Tables ** Tables
*/ */
#ifndef LUA_PACK_VALUE
typedef union TKey { typedef union TKey {
struct { struct {
TValuefields; TValuefields;
...@@ -493,16 +382,6 @@ typedef union TKey { ...@@ -493,16 +382,6 @@ typedef union TKey {
} TKey; } TKey;
#define LUA_TKEY_NIL {LUA_TVALUE_NIL, NULL} #define LUA_TKEY_NIL {LUA_TVALUE_NIL, NULL}
#else // #ifndef LUA_PACK_VALUE
typedef struct TKey {
TValue tvk;
struct {
struct Node *next; /* for chaining */
} nk;
} TKey;
#define LUA_TKEY_NIL {LUA_TVALUE_NIL}, {NULL}
#endif // #ifndef LUA_PACK_VALUE
typedef struct Node { typedef struct Node {
TValue i_val; TValue i_val;
...@@ -522,6 +401,7 @@ typedef struct Table { ...@@ -522,6 +401,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)
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#define LUAC_CROSS_FILE #define LUAC_CROSS_FILE
#include "lua.h" #include "lua.h"
#include C_HEADER_STRING #include <string.h>
#include "lcode.h" #include "lcode.h"
#include "ldebug.h" #include "ldebug.h"
...@@ -916,12 +916,11 @@ static int block_follow (int token) { ...@@ -916,12 +916,11 @@ static int block_follow (int token) {
static void block (LexState *ls) { static void block (LexState *ls) {
/* block -> chunk */ /* block -> chunk */
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
BlockCnt *pbl = (BlockCnt*)luaM_malloc(ls->L,sizeof(BlockCnt)); BlockCnt bl;
enterblock(fs, pbl, 0); enterblock(fs, &bl, 0);
chunk(ls); chunk(ls);
lua_assert(pbl->breaklist == NO_JUMP); lua_assert(bl.breaklist == NO_JUMP);
leaveblock(fs); leaveblock(fs);
luaM_free(ls->L,pbl);
} }
...@@ -1081,13 +1080,13 @@ static int exp1 (LexState *ls) { ...@@ -1081,13 +1080,13 @@ static int exp1 (LexState *ls) {
static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
/* forbody -> DO block */ /* forbody -> DO block */
BlockCnt *pbl = (BlockCnt*)luaM_malloc(ls->L,sizeof(BlockCnt)); BlockCnt bl;
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
int prep, endfor; int prep, endfor;
adjustlocalvars(ls, 3); /* control variables */ adjustlocalvars(ls, 3); /* control variables */
checknext(ls, TK_DO); checknext(ls, TK_DO);
prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
enterblock(fs, pbl, 0); /* scope for declared variables */ enterblock(fs, &bl, 0); /* scope for declared variables */
adjustlocalvars(ls, nvars); adjustlocalvars(ls, nvars);
luaK_reserveregs(fs, nvars); luaK_reserveregs(fs, nvars);
block(ls); block(ls);
...@@ -1097,7 +1096,6 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { ...@@ -1097,7 +1096,6 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars);
luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */
luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1);
luaM_free(ls->L,pbl);
} }
......
/* Read-only tables helper */
#ifndef lrodefs_h
#define lrodefs_h
#include "lrotable.h"
#undef LUA_REG_TYPE
#undef LSTRKEY
#undef LNILKEY
#undef LNUMKEY
#undef LFUNCVAL
#undef LNUMVAL
#undef LROVAL
#undef LNILVAL
#undef LREGISTER
#if (MIN_OPT_LEVEL > 0) && (LUA_OPTIMIZE_MEMORY >= MIN_OPT_LEVEL)
#define LUA_REG_TYPE luaR_entry
#define LSTRKEY LRO_STRKEY
#define LNUMKEY LRO_NUMKEY
#define LNILKEY LRO_NILKEY
#define LFUNCVAL LRO_FUNCVAL
#define LUDATA LRO_LUDATA
#define LNUMVAL LRO_NUMVAL
#define LROVAL LRO_ROVAL
#define LNILVAL LRO_NILVAL
#define LREGISTER(L, name, table)\
return 0
#else
#define LUA_REG_TYPE luaL_reg
#define LSTRKEY(x) x
#define LNILKEY NULL
#define LFUNCVAL(x) x
#define LNILVAL NULL
#define LREGISTER(L, name, table)\
luaL_register(L, name, table);\
return 1
#endif
#endif /* lrodefs_h */
...@@ -2,135 +2,157 @@ ...@@ -2,135 +2,157 @@
#define LUAC_CROSS_FILE #define LUAC_CROSS_FILE
#include "lua.h" #include "lua.h"
#include C_HEADER_STRING #include <string.h>
#include "lrotable.h" #include "lrotable.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lstring.h" #include "lstring.h"
#include "lobject.h" #include "lobject.h"
#include "lapi.h" #include "lapi.h"
/* Local defines */ #ifdef _MSC_VER
#define LUAR_FINDFUNCTION 0 #define ALIGNED_STRING (__declspec( align( 4 ) ) char*)
#define LUAR_FINDVALUE 1 #else
#define ALIGNED_STRING (__attribute__((aligned(4))) char *)
#endif
#define LA_LINES 32
#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
* 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) + ((b) ? (b)->tsv.hash: 0))
/* Find a global "read only table" in the constant lua_rotable array */ static struct {
void* luaR_findglobal(const char *name, unsigned len) { unsigned hash;
unsigned i; unsigned addr:24;
unsigned ndx:8;
} cache[LA_LINES][LA_SLOTS];
if (strlen(name) > LUA_MAX_ROTABLE_NAME) #ifdef COLLECT_STATS
return NULL; unsigned cache_stats[3];
for (i=0; lua_rotable[i].name; i ++) #define COUNT(i) cache_stats[i]++
if (*lua_rotable[i].name != '\0' && strlen(lua_rotable[i].name) == len && !strncmp(lua_rotable[i].name, name, len)) { #else
return (void*)(lua_rotable[i].pentries); #define COUNT(i)
} #endif
return NULL;
} static int lookup_cache(unsigned hash, ROTable *rotable) {
int i = (hash>>2) & (LA_LINES-1), j;
/* Find an entry in a rotable and return it */ for (j = 0; j<LA_SLOTS; j++) {
static const TValue* luaR_auxfind(const luaR_entry *pentry, const char *strkey, luaR_numkey numkey, unsigned *ppos) { if (cache[i][j].hash == hash &&
const TValue *res = NULL; ((size_t)rotable & 0xffffffu) == cache[i][j].addr) {
unsigned i = 0; COUNT(0);
return cache[i][j].ndx;
if (pentry == NULL)
return NULL;
while(pentry->key.type != LUA_TNIL) {
if ((strkey && (pentry->key.type == LUA_TSTRING) && (!strcmp(pentry->key.id.strkey, strkey))) ||
(!strkey && (pentry->key.type == LUA_TNUMBER) && ((luaR_numkey)pentry->key.id.numkey == numkey))) {
res = &pentry->value;
break;
} }
i ++; pentry ++;
} }
if (res && ppos) COUNT(1);
*ppos = i; return -1;
return res;
} }
int luaR_findfunction(lua_State *L, const luaR_entry *ptable) { static void update_cache(unsigned hash, ROTable *rotable, unsigned ndx) {
const TValue *res = NULL; int i = (hash)>>2 & (LA_LINES-1), j;
const char *key = luaL_checkstring(L, 2); COUNT(2);
if (ndx>0xffu)
res = luaR_auxfind(ptable, key, 0, NULL); return;
if (res && ttislightfunction(res)) { for (j = LA_SLOTS-1; j>0; j--)
luaA_pushobject(L, res); cache[i][j] = cache[i][j-1];
return 1; cache[i][0].hash = hash;
} cache[i][0].addr = (size_t) rotable;
else cache[i][0].ndx = ndx;
return 0;
} }
/*
* 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" ;
unsigned hash = HASH(rotable, key);
unsigned i = 0;
int j = lookup_cache(hash, rotable);
unsigned l = key ? key->tsv.len : sizeof("__metatable")-1;
if (pentry) {
if (j >= 0 && !strcmp(pentry[j].key, strkey)) {
if (ppos)
*ppos = j;
//printf("%3d hit %p %s\n", (hash>>2) & (LA_LINES-1), rotable, strkey);
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, mask4 = l > 2 ? (~0u) : (~0u)>>((3-l)*8);
memcpy(&name4, strkey, sizeof(name4));
/* Find an entry in a rotable and return its type for(;pentry->key != NULL; i++, pentry++) {
If "strkey" is not NULL, the function will look for a string key, if (((*(unsigned *)pentry->key ^ name4) & mask4) == 0 &&
otherwise it will look for a number key */ !strcmp(pentry->key, strkey)) {
const TValue* luaR_findentry(void *data, const char *strkey, luaR_numkey numkey, unsigned *ppos) { //printf("%p %s hit after %d probes \n", rotable, strkey, (int)(pentry-rotable));
return luaR_auxfind((const luaR_entry*)data, strkey, numkey, ppos); if (ppos)
*ppos = i;
update_cache(hash, rotable, pentry - rotable);
//printf("%3d %3d %p %s\n", (hash>>2) & (LA_LINES-1), (int)(pentry-rotable), rotable, strkey);
return &pentry->value;
}
}
}
//printf("%p %s miss after %d probes \n", rotable, strkey, (int)(pentry-rotable));
return luaO_nilobject;
} }
/* 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,
setnilvalue(key); TValue *key, TValue *val) {
setnilvalue(val); if (pentries[pos].key) {
if (pentries[pos].key.type != LUA_TNIL) {
/* Found an entry */ /* Found an entry */
if (pentries[pos].key.type == LUA_TSTRING) setsvalue(L, key, luaS_new(L, pentries[pos].key));
setsvalue(L, key, luaS_newro(L, pentries[pos].key.id.strkey)) setobj2s(L, val, &pentries[pos].value);
else } else {
setnvalue(key, (lua_Number)pentries[pos].key.id.numkey) setnilvalue(key);
setobj2s(L, val, &pentries[pos].value); setnilvalue(val);
} }
} }
/* 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)) {
/* 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
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 {
memcpy(dest, getstr(src), src->tsv.len);
dest[src->tsv.len] = '\0';
}
}
/* Return 1 if the given pointer is a rotable */
#ifdef LUA_META_ROTABLES
#include "compiler.h"
int luaR_isrotable(void *p) {
return RODATA_START_ADDRESS <= (char*)p && (char*)p <= RODATA_END_ADDRESS;
}
#endif
...@@ -4,35 +4,38 @@ ...@@ -4,35 +4,38 @@
#define lrotable_h #define lrotable_h
#include "lua.h" #include "lua.h"
#include "llimits.h"
#include "lobject.h"
#include "luaconf.h" #include "luaconf.h"
#include "lobject.h"
#include "llimits.h"
/* Macros one can use to define rotable entries */ /* Macros one can use to define rotable entries */
#ifndef LUA_PACK_VALUE
#define LRO_FUNCVAL(v) {{.p = v}, LUA_TLIGHTFUNCTION} #define LRO_FUNCVAL(v) {{.p = v}, LUA_TLIGHTFUNCTION}
#define LRO_LUDATA(v) {{.p = v}, LUA_TLIGHTUSERDATA} #define LRO_LUDATA(v) {{.p = v}, LUA_TLIGHTUSERDATA}
#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}
#else // #ifndef LUA_PACK_VALUE
#define LRO_NUMVAL(v) {.value.n = v} #ifdef LUA_CROSS_COMPILER
#ifdef ELUA_ENDIAN_LITTLE #define LRO_STRKEY(k) k
#define LRO_FUNCVAL(v) {{(int)v, add_sig(LUA_TLIGHTFUNCTION)}} #else
#define LRO_LUDATA(v) {{(int)v, add_sig(LUA_TLIGHTUSERDATA)}} #define LRO_STRKEY(k) ((__attribute__((aligned(4))) char *) k)
#define LRO_ROVAL(v) {{(int)v, add_sig(LUA_TROTABLE)}} #endif
#define LRO_NILVAL {{0, add_sig(LUA_TNIL)}}
#else // #ifdef ELUA_ENDIAN_LITTLE #define LROT_TABLE(t) static const LUA_REG_TYPE t ## _map[];
#define LRO_FUNCVAL(v) {{add_sig(LUA_TLIGHTFUNCTION), (int)v}} #define LROT_PUBLIC_TABLE(t) const LUA_REG_TYPE t ## _map[];
#define LRO_LUDATA(v) {{add_sig(LUA_TLIGHTUSERDATA), (int)v}} #define LROT_TABLEREF(t) ((void *) t ## _map)
#define LRO_ROVAL(v) {{add_sig(LUA_TROTABLE), (int)v}} #define LROT_BEGIN(t) static const LUA_REG_TYPE t ## _map [] = {
#define LRO_NILVAL {{add_sig(LUA_TNIL), 0}} #define LROT_PUBLIC_BEGIN(t) const LUA_REG_TYPE t ## _map[] = {
#endif // #ifdef ELUA_ENDIAN_LITTLE #define LROT_EXTERN(t) extern const LUA_REG_TYPE t ## _map[]
#endif // #ifndef LUA_PACK_VALUE #define LROT_TABENTRY(n,t) {LRO_STRKEY(#n), LRO_ROVAL(t ## _map)},
#define LROT_FUNCENTRY(n,f) {LRO_STRKEY(#n), LRO_FUNCVAL(f)},
#define LRO_STRKEY(k) {LUA_TSTRING, {.strkey = k}} #define LROT_NUMENTRY(n,x) {LRO_STRKEY(#n), LRO_NUMVAL(x)},
#define LRO_NUMKEY(k) {LUA_TNUMBER, {.numkey = k}} #define LROT_LUDENTRY(n,x) {LRO_STRKEY(#n), LRO_LUDATA((void *) x)},
#define LRO_NILKEY {LUA_TNIL, {.strkey=NULL}} #define LROT_END(t,mt, f) {NULL, LRO_NILVAL} };
#define LROT_BREAK(t) };
#define LUA_REG_TYPE luaR_entry
#define LREGISTER(L, name, table) return 0
/* Maximum length of a rotable name and of a string key*/ /* Maximum length of a rotable name and of a string key*/
#define LUA_MAX_ROTABLE_NAME 32 #define LUA_MAX_ROTABLE_NAME 32
...@@ -40,41 +43,57 @@ ...@@ -40,41 +43,57 @@
/* Type of a numeric key in a rotable */ /* Type of a numeric key in a rotable */
typedef int luaR_numkey; typedef int luaR_numkey;
/* The next structure defines the type of a key */
typedef struct
{
int type;
union
{
const char* strkey;
luaR_numkey numkey;
} id;
} luaR_key;
/* An entry in the read only table */ /* An entry in the read only table */
typedef struct typedef struct luaR_entry {
{ const char *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(_MSC_VER)
//msvc build uses these dummy vars to locate the beginning and ending addresses of the RO data
extern const char _ro_start[], _ro_end[];
#define IN_RODATA_AREA(p) (((const char*)(p)) >= _ro_start && ((const char *)(p)) <= _ro_end)
#else /* one of the POSIX variants */
#if defined(__CYGWIN__)
#define _RODATA_END __end__
#elif defined(__MINGW32__)
#define _RODATA_END end
#else #else
#define luaR_isrotable(p) (0) #define _RODATA_END _edata
#endif #endif
extern const char _RODATA_END[];
#define IN_RODATA_AREA(p) (((const char *)(p)) < _RODATA_END)
#endif /* defined(_MSC_VER) */
#else /* xtensa tool chain for ESP32 target */
#include "compiler.h"
#define IN_RODATA_AREA(p) (((const char *)p) >= RODATA_START_ADDRESS && ((const char *)p) <= RODATA_END_ADDRESS)
#endif /* defined(LUA_CROSS_COMPILER) */
/* Return 1 if the given pointer is a rotable */
#define luaR_isrotable(p) IN_RODATA_AREA(p)
#endif #endif
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ldebug.h" #include "ldebug.h"
#include "ldo.h" #include "ldo.h"
#include "lflash.h"
#include "lfunc.h" #include "lfunc.h"
#include "lgc.h" #include "lgc.h"
#include "llex.h" #include "llex.h"
...@@ -72,9 +73,12 @@ static void f_luaopen (lua_State *L, void *ud) { ...@@ -72,9 +73,12 @@ static void f_luaopen (lua_State *L, void *ud) {
sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */
sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
#ifndef LUA_CROSS_COMPILER
luaN_init(L); /* optionally map RO string table */
#endif
luaT_init(L); luaT_init(L);
luaX_init(L); luaX_init(L);
luaS_fix(luaS_newliteral(L, MEMERRMSG)); stringfix(luaS_newliteral(L, MEMERRMSG));
g->GCthreshold = 4*g->totalbytes; g->GCthreshold = 4*g->totalbytes;
} }
...@@ -191,6 +195,13 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { ...@@ -191,6 +195,13 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->memlimit = EGC_INITIAL_MEMLIMIT; g->memlimit = EGC_INITIAL_MEMLIMIT;
#else #else
g->memlimit = 0; g->memlimit = 0;
#endif
#ifndef LUA_CROSS_COMPILER
g->ROstrt.size = 0;
g->ROstrt.nuse = 0;
g->ROstrt.hash = NULL;
g->ROpvmain = NULL;
g->LFSsize = 0;
#endif #endif
for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL; for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
......
...@@ -82,7 +82,7 @@ typedef struct global_State { ...@@ -82,7 +82,7 @@ typedef struct global_State {
Mbuffer buff; /* temporary buffer for string concatentation */ Mbuffer buff; /* temporary buffer for string concatentation */
lu_mem GCthreshold; lu_mem GCthreshold;
lu_mem totalbytes; /* number of bytes currently allocated */ lu_mem totalbytes; /* number of bytes currently allocated */
lu_mem memlimit; /* maximum number of bytes that can be allocated, 0 = no limit. */ l_mem memlimit; /* maximum number of bytes that can be allocated, 0 = no limit. <0 used with EGC_ON_MEM_LIMIT when free heap falls below -memlimit */
lu_mem estimate; /* an estimate of number of bytes actually in use */ lu_mem estimate; /* an estimate of number of bytes actually in use */
lu_mem gcdept; /* how much GC is `behind schedule' */ lu_mem gcdept; /* how much GC is `behind schedule' */
int gcpause; /* size of pause between successive GCs */ int gcpause; /* size of pause between successive GCs */
...@@ -94,6 +94,11 @@ typedef struct global_State { ...@@ -94,6 +94,11 @@ typedef struct global_State {
UpVal uvhead; /* head of double-linked list of all open upvalues */ UpVal uvhead; /* head of double-linked list of all open upvalues */
struct Table *mt[NUM_TAGS]; /* metatables for basic types */ struct Table *mt[NUM_TAGS]; /* metatables for basic types */
TString *tmname[TM_N]; /* array with tag-method names */ TString *tmname[TM_N]; /* array with tag-method names */
#ifndef LUA_CROSS_COMPILER
stringtable ROstrt; /* Flash-based hash table for RO strings */
Proto *ROpvmain; /* Flash-based Proto main */
int LFSsize; /* Size of Lua Flash Store */
#endif
} global_State; } global_State;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#define LUAC_CROSS_FILE #define LUAC_CROSS_FILE
#include "lua.h" #include "lua.h"
#include C_HEADER_STRING #include <string.h>
#include "lmem.h" #include "lmem.h"
#include "lobject.h" #include "lobject.h"
...@@ -61,7 +61,7 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, ...@@ -61,7 +61,7 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
tb = &G(L)->strt; tb = &G(L)->strt;
if ((tb->nuse + 1) > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) if ((tb->nuse + 1) > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
luaS_resize(L, tb->size*2); /* too crowded */ luaS_resize(L, tb->size*2); /* too crowded */
ts = cast(TString *, luaM_malloc(L, readonly ? sizeof(char**)+sizeof(TString) : (l+1)*sizeof(char)+sizeof(TString))); ts = cast(TString *, luaM_malloc(L, sizeof(TString) + (readonly ? sizeof(char**) : (l+1)*sizeof(char))));
ts->tsv.len = l; ts->tsv.len = l;
ts->tsv.hash = h; ts->tsv.hash = h;
ts->tsv.marked = luaC_white(G(L)); ts->tsv.marked = luaC_white(G(L));
...@@ -71,7 +71,7 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, ...@@ -71,7 +71,7 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
((char *)(ts+1))[l] = '\0'; /* ending 0 */ ((char *)(ts+1))[l] = '\0'; /* ending 0 */
} else { } else {
*(char **)(ts+1) = (char *)str; *(char **)(ts+1) = (char *)str;
luaS_readonly(ts); l_setbit((ts)->tsv.marked, READONLYBIT);
} }
h = lmod(h, tb->size); h = lmod(h, tb->size);
ts->tsv.next = tb->hash[h]; /* chain new entry */ ts->tsv.next = tb->hash[h]; /* chain new entry */
...@@ -80,14 +80,28 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, ...@@ -80,14 +80,28 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
return ts; return ts;
} }
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
}
/*
* The string algorithm has been modified to be LFS-friendly. The previous eLua
* algo used the address of the string was in flash and the string was >4 bytes
* This creates miminal savings and prevents the use of LFS based strings
*/
static TString *luaS_newlstr_helper (lua_State *L, const char *str, size_t l, int readonly) { LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
GCObject *o; GCObject *o;
unsigned int h = cast(unsigned int, l); /* seed */ 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 step = (l>>5)+1; /* if string is too long, don't hash all its chars */
size_t l1; size_t l1;
for (l1=l; l1>=step; l1-=step) /* compute hash */ for (l1=l; l1>=step; l1-=step) /* compute hash */
h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
o != NULL; o != NULL;
o = o->gch.next) { o = o->gch.next) {
...@@ -98,35 +112,27 @@ static TString *luaS_newlstr_helper (lua_State *L, const char *str, size_t l, in ...@@ -98,35 +112,27 @@ static TString *luaS_newlstr_helper (lua_State *L, const char *str, size_t l, in
return ts; return ts;
} }
} }
return newlstr(L, str, l, h, readonly); /* not found */ #ifndef LUA_CROSS_COMPILER
} /*
* The RAM strt is searched first since RAM access is faster tham Flash access.
static int lua_is_ptr_in_ro_area(const char *p) { * If a miss, then search the RO string table.
#ifdef LUA_CROSS_COMPILER */
return 0; if (G(L)->ROstrt.hash) {
#else for (o = G(L)->ROstrt.hash[lmod(h, G(L)->ROstrt.size)];
o != NULL;
#include "compiler.h" o = o->gch.next) {
TString *ts = rawgco2ts(o);
return p >= RODATA_START_ADDRESS && p <= RODATA_END_ADDRESS; if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {
return ts;
}
}
}
#endif #endif
} /* New additions to the RAM strt are tagged as readonly if the string address
* is in the CTEXT segment (target only, not luac.cross) */
TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { int readonly = (lua_is_ptr_in_ro_area(str) && l+1 > sizeof(char**) &&
// If the pointer is in a read-only memory and the string is at least 4 chars in length, l == strlen(str) ? LUAS_READONLY_STRING : LUAS_REGULAR_STRING);
// create it as a read-only string instead return newlstr(L, str, l, h, readonly); /* not found */
if(lua_is_ptr_in_ro_area(str) && l+1 > sizeof(char**) && l == strlen(str))
return luaS_newlstr_helper(L, str, l, LUAS_READONLY_STRING);
else
return luaS_newlstr_helper(L, str, l, LUAS_REGULAR_STRING);
}
LUAI_FUNC TString *luaS_newrolstr (lua_State *L, const char *str, size_t l) {
if(l+1 > sizeof(char**) && l == strlen(str))
return luaS_newlstr_helper(L, str, l, LUAS_READONLY_STRING);
else // no point in creating a RO string, as it would actually be larger
return luaS_newlstr_helper(L, str, l, LUAS_REGULAR_STRING);
} }
......
...@@ -13,22 +13,16 @@ ...@@ -13,22 +13,16 @@
#include "lstate.h" #include "lstate.h"
#define sizestring(s) (sizeof(union TString)+(luaS_isreadonly(s) ? 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) #define sizeudata(u) (sizeof(union Udata)+(u)->len)
#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s))) #define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s)))
#define luaS_newro(L, s) (luaS_newrolstr(L, s, strlen(s)))
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
(sizeof(s)/sizeof(char))-1)) (sizeof(s)/sizeof(char))-1))
#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT)
#define luaS_readonly(s) l_setbit((s)->tsv.marked, READONLYBIT)
#define luaS_isreadonly(s) testbit((s)->marked, READONLYBIT)
LUAI_FUNC void luaS_resize (lua_State *L, int newsize); 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 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); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
LUAI_FUNC TString *luaS_newrolstr (lua_State *L, const char *str, size_t l);
#endif #endif
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
#define LUAC_CROSS_FILE #define LUAC_CROSS_FILE
#include "lua.h" #include "lua.h"
#include C_HEADER_STDIO #include <stdio.h>
#include C_HEADER_STRING #include <string.h>
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
...@@ -577,7 +577,7 @@ static int gmatch (lua_State *L) { ...@@ -577,7 +577,7 @@ static int gmatch (lua_State *L) {
return 1; return 1;
} }
#if LUA_OPTIMIZE_MEMORY == 0 || !defined(LUA_COMPAT_GFIND) #ifndef LUA_COMPAT_GFIND
static int gfind_nodef (lua_State *L) { static int gfind_nodef (lua_State *L) {
return luaL_error(L, LUA_QL("string.gfind") " was renamed to " return luaL_error(L, LUA_QL("string.gfind") " was renamed to "
LUA_QL("string.gmatch")); LUA_QL("string.gmatch"));
...@@ -825,67 +825,37 @@ static int str_format (lua_State *L) { ...@@ -825,67 +825,37 @@ static int str_format (lua_State *L) {
return 1; return 1;
} }
#undef MIN_OPT_LEVEL LROT_PUBLIC_BEGIN(strlib)
#define MIN_OPT_LEVEL 1 LROT_FUNCENTRY( byte, str_byte )
#include "lrodefs.h" LROT_FUNCENTRY( char, str_char )
const LUA_REG_TYPE strlib[] = { LROT_FUNCENTRY( dump, str_dump )
{LSTRKEY("byte"), LFUNCVAL(str_byte)}, LROT_FUNCENTRY( find, str_find )
{LSTRKEY("char"), LFUNCVAL(str_char)}, LROT_FUNCENTRY( format, str_format )
{LSTRKEY("dump"), LFUNCVAL(str_dump)}, #ifdef LUA_COMPAT_GFIND
{LSTRKEY("find"), LFUNCVAL(str_find)}, LROT_FUNCENTRY( gfind, gmatch )
{LSTRKEY("format"), LFUNCVAL(str_format)},
#if LUA_OPTIMIZE_MEMORY > 0 && defined(LUA_COMPAT_GFIND)
{LSTRKEY("gfind"), LFUNCVAL(gmatch)},
#else #else
{LSTRKEY("gfind"), LFUNCVAL(gfind_nodef)}, LROT_FUNCENTRY( gfind, gfind_nodef )
#endif
{LSTRKEY("gmatch"), LFUNCVAL(gmatch)},
{LSTRKEY("gsub"), LFUNCVAL(str_gsub)},
{LSTRKEY("len"), LFUNCVAL(str_len)},
{LSTRKEY("lower"), LFUNCVAL(str_lower)},
{LSTRKEY("match"), LFUNCVAL(str_match)},
{LSTRKEY("rep"), LFUNCVAL(str_rep)},
{LSTRKEY("reverse"), LFUNCVAL(str_reverse)},
{LSTRKEY("sub"), LFUNCVAL(str_sub)},
{LSTRKEY("upper"), LFUNCVAL(str_upper)},
#if LUA_OPTIMIZE_MEMORY > 0
{LSTRKEY("__index"), LROVAL(strlib)},
#endif
{LNILKEY, LNILVAL}
};
#if LUA_OPTIMIZE_MEMORY != 2
static void createmetatable (lua_State *L) {
lua_createtable(L, 0, 1); /* create metatable for strings */
lua_pushliteral(L, ""); /* dummy string */
lua_pushvalue(L, -2);
lua_setmetatable(L, -2); /* set string metatable */
lua_pop(L, 1); /* pop dummy string */
lua_pushvalue(L, -2); /* string library... */
lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */
lua_pop(L, 1); /* pop metatable */
}
#endif #endif
LROT_FUNCENTRY( gmatch, gmatch )
LROT_FUNCENTRY( gsub, str_gsub )
LROT_FUNCENTRY( len, str_len )
LROT_FUNCENTRY( lower, str_lower )
LROT_FUNCENTRY( match, str_match )
LROT_FUNCENTRY( rep, str_rep )
LROT_FUNCENTRY( reverse, str_reverse )
LROT_FUNCENTRY( sub, str_sub )
LROT_FUNCENTRY( upper, str_upper )
LROT_TABENTRY( __index, strlib )
LROT_END(strlib, NULL, 0) // OR DO WE NEED LRTO_MASK_INDEX **TODO**
/* /*
** Open string library ** Open string library
*/ */
LUALIB_API int luaopen_string (lua_State *L) { LUALIB_API int luaopen_string (lua_State *L) {
#if LUA_OPTIMIZE_MEMORY == 0
luaL_register(L, LUA_STRLIBNAME, strlib);
#if defined(LUA_COMPAT_GFIND)
lua_getfield(L, -1, "gmatch");
lua_setfield(L, -2, "gfind");
#endif
createmetatable(L);
return 1;
#else
lua_pushliteral(L,""); lua_pushliteral(L,"");
lua_pushrotable(L, (void*)strlib); lua_pushrotable(L, LROT_TABLEREF(strlib));
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
lua_pop(L,1); lua_pop(L,1);
return 0; return 0;
#endif
} }
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