1
0
Fork 0

Switch to upstream LuaJIT

This does not yet handle the patching, but should build without issue
This commit is contained in:
Ryan 2021-01-21 06:23:28 -05:00 committed by Ryan Lucia
parent 48c3acd3aa
commit ef64307ba1
181 changed files with 18 additions and 107186 deletions

1
.gitignore vendored
View File

@ -31,6 +31,7 @@ subprojects/icu
subprojects/libass
subprojects/libffi*
subprojects/libpng-*
subprojects/luajit
subprojects/nasm-*
subprojects/packagecache
subprojects/proxy-libintl*

View File

@ -277,7 +277,7 @@ endif
if not deps.contains(luajit)
luajit_sp = subproject('luajit')
luajit_inc = luajit_sp.get_variable('incdir')
luajit_inc = luajit_sp.get_variable('src_inc')
deps += luajit_sp.get_variable('luajit_dep')
else
luajit_inc = include_directories(luajit.get_pkgconfig_variable('includedir'))

8
subprojects/luajit.wrap Normal file
View File

@ -0,0 +1,8 @@
[wrap-git]
directory = luajit
url = https://github.com/LuaJIT/LuaJIT.git
revision = v2.1
patch_directory = luajit
[provide]
luajit = luajit_dep

View File

@ -1,56 +0,0 @@
===============================================================================
LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/
Copyright (C) 2005-2015 Mike Pall. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
[ MIT license: http://www.opensource.org/licenses/mit-license.php ]
===============================================================================
[ LuaJIT includes code from Lua 5.1/5.2, which has this license statement: ]
Copyright (C) 1994-2012 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================================================
[ LuaJIT includes code from dlmalloc, which has this license statement: ]
This is a version (aka dlmalloc) of malloc/free/realloc written by
Doug Lea and released to the public domain, as explained at
http://creativecommons.org/licenses/publicdomain
===============================================================================

View File

@ -1,16 +0,0 @@
README for LuaJIT 2.0.4
-----------------------
LuaJIT is a Just-In-Time (JIT) compiler for the Lua programming language.
Project Homepage: http://luajit.org/
LuaJIT is Copyright (C) 2005-2015 Mike Pall.
LuaJIT is free software, released under the MIT license.
See full Copyright Notice in the COPYRIGHT file or in luajit.h.
Documentation for LuaJIT is available in HTML format.
Please point your favorite browser to:
doc/luajit.html

View File

@ -1,456 +0,0 @@
/*
** DynASM ARM encoding engine.
** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define DASM_ARCH "arm"
#ifndef DASM_EXTERN
#define DASM_EXTERN(a,b,c,d) 0
#endif
/* Action definitions. */
enum {
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
/* The following actions need a buffer position. */
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
/* The following actions also have an argument. */
DASM_REL_PC, DASM_LABEL_PC,
DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8,
DASM__MAX
};
/* Maximum number of section buffer positions for a single dasm_put() call. */
#define DASM_MAXSECPOS 25
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
#define DASM_S_OK 0x00000000
#define DASM_S_NOMEM 0x01000000
#define DASM_S_PHASE 0x02000000
#define DASM_S_MATCH_SEC 0x03000000
#define DASM_S_RANGE_I 0x11000000
#define DASM_S_RANGE_SEC 0x12000000
#define DASM_S_RANGE_LG 0x13000000
#define DASM_S_RANGE_PC 0x14000000
#define DASM_S_RANGE_REL 0x15000000
#define DASM_S_UNDEF_LG 0x21000000
#define DASM_S_UNDEF_PC 0x22000000
/* Macros to convert positions (8 bit section + 24 bit index). */
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
#define DASM_SEC2POS(sec) ((sec)<<24)
#define DASM_POS2SEC(pos) ((pos)>>24)
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
/* Action list type. */
typedef const unsigned int *dasm_ActList;
/* Per-section structure. */
typedef struct dasm_Section {
int *rbuf; /* Biased buffer pointer (negative section bias). */
int *buf; /* True buffer pointer. */
size_t bsize; /* Buffer size in bytes. */
int pos; /* Biased buffer position. */
int epos; /* End of biased buffer position - max single put. */
int ofs; /* Byte offset into section. */
} dasm_Section;
/* Core structure holding the DynASM encoding state. */
struct dasm_State {
size_t psize; /* Allocated size of this structure. */
dasm_ActList actionlist; /* Current actionlist pointer. */
int *lglabels; /* Local/global chain/pos ptrs. */
size_t lgsize;
int *pclabels; /* PC label chains/pos ptrs. */
size_t pcsize;
void **globals; /* Array of globals (bias -10). */
dasm_Section *section; /* Pointer to active section. */
size_t codesize; /* Total size of all code sections. */
int maxsection; /* 0 <= sectionidx < maxsection. */
int status; /* Status code. */
dasm_Section sections[1]; /* All sections. Alloc-extended. */
};
/* The size of the core structure depends on the max. number of sections. */
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
/* Initialize DynASM state. */
void dasm_init(Dst_DECL, int maxsection)
{
dasm_State *D;
size_t psz = 0;
int i;
Dst_REF = NULL;
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
D = Dst_REF;
D->psize = psz;
D->lglabels = NULL;
D->lgsize = 0;
D->pclabels = NULL;
D->pcsize = 0;
D->globals = NULL;
D->maxsection = maxsection;
for (i = 0; i < maxsection; i++) {
D->sections[i].buf = NULL; /* Need this for pass3. */
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
D->sections[i].bsize = 0;
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
}
}
/* Free DynASM state. */
void dasm_free(Dst_DECL)
{
dasm_State *D = Dst_REF;
int i;
for (i = 0; i < D->maxsection; i++)
if (D->sections[i].buf)
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
DASM_M_FREE(Dst, D, D->psize);
}
/* Setup global label array. Must be called before dasm_setup(). */
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
{
dasm_State *D = Dst_REF;
D->globals = gl - 10; /* Negative bias to compensate for locals. */
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
}
/* Grow PC label array. Can be called after dasm_setup(), too. */
void dasm_growpc(Dst_DECL, unsigned int maxpc)
{
dasm_State *D = Dst_REF;
size_t osz = D->pcsize;
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
}
/* Setup encoder. */
void dasm_setup(Dst_DECL, const void *actionlist)
{
dasm_State *D = Dst_REF;
int i;
D->actionlist = (dasm_ActList)actionlist;
D->status = DASM_S_OK;
D->section = &D->sections[0];
memset((void *)D->lglabels, 0, D->lgsize);
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
for (i = 0; i < D->maxsection; i++) {
D->sections[i].pos = DASM_SEC2POS(i);
D->sections[i].ofs = 0;
}
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) { \
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
#define CKPL(kind, st) \
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
#else
#define CK(x, st) ((void)0)
#define CKPL(kind, st) ((void)0)
#endif
static int dasm_imm12(unsigned int n)
{
int i;
for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30))
if (n <= 255) return (int)(n + (i << 8));
return -1;
}
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
void dasm_put(Dst_DECL, int start, ...)
{
va_list ap;
dasm_State *D = Dst_REF;
dasm_ActList p = D->actionlist + start;
dasm_Section *sec = D->section;
int pos = sec->pos, ofs = sec->ofs;
int *b;
if (pos >= sec->epos) {
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
}
b = sec->rbuf;
b[pos++] = start;
va_start(ap, start);
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
if (action >= DASM__MAX) {
ofs += 4;
} else {
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
switch (action) {
case DASM_STOP: goto stop;
case DASM_SECTION:
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
D->section = &D->sections[n]; goto stop;
case DASM_ESC: p++; ofs += 4; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
case DASM_REL_LG:
n = (ins & 2047) - 10; pl = D->lglabels + n;
/* Bkwd rel or global. */
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
pl += 10; n = *pl;
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
goto linkrel;
case DASM_REL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putrel:
n = *pl;
if (n < 0) { /* Label exists. Get label pos and store it. */
b[pos] = -n;
} else {
linkrel:
b[pos] = n; /* Else link to rel chain, anchored at label. */
*pl = pos;
}
pos++;
break;
case DASM_LABEL_LG:
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
case DASM_LABEL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putlabel:
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
}
*pl = -pos; /* Label exists now. */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_IMM:
case DASM_IMM16:
#ifdef DASM_CHECKS
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
if ((ins & 0x8000))
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
else
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
#endif
b[pos++] = n;
break;
case DASM_IMMV8:
CK((n & 3) == 0, RANGE_I);
n >>= 2;
case DASM_IMML8:
case DASM_IMML12:
CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) :
(((-n)>>((ins>>5)&31)) == 0), RANGE_I);
b[pos++] = n;
break;
case DASM_IMM12:
CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
b[pos++] = n;
break;
}
}
}
stop:
va_end(ap);
sec->pos = pos;
sec->ofs = ofs;
}
#undef CK
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
int dasm_link(Dst_DECL, size_t *szp)
{
dasm_State *D = Dst_REF;
int secnum;
int ofs = 0;
#ifdef DASM_CHECKS
*szp = 0;
if (D->status != DASM_S_OK) return D->status;
{
int pc;
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
}
#endif
{ /* Handle globals not defined in this translation unit. */
int idx;
for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
int n = D->lglabels[idx];
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
}
}
/* Combine all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->rbuf;
int pos = DASM_SEC2POS(secnum);
int lastpos = sec->pos;
while (pos != lastpos) {
dasm_ActList p = D->actionlist + b[pos++];
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: p++; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
case DASM_IMM: case DASM_IMM12: case DASM_IMM16:
case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break;
}
}
stop: (void)0;
}
ofs += sec->ofs; /* Next section starts right after current section. */
}
D->codesize = ofs; /* Total size of all code sections */
*szp = ofs;
return DASM_S_OK;
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
#else
#define CK(x, st) ((void)0)
#endif
/* Pass 3: Encode sections. */
int dasm_encode(Dst_DECL, void *buffer)
{
dasm_State *D = Dst_REF;
char *base = (char *)buffer;
unsigned int *cp = (unsigned int *)buffer;
int secnum;
/* Encode all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->buf;
int *endb = sec->rbuf + sec->pos;
while (b != endb) {
dasm_ActList p = D->actionlist + *b++;
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: *cp++ = *p++; break;
case DASM_REL_EXT:
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
goto patchrel;
case DASM_ALIGN:
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
break;
case DASM_REL_LG:
CK(n >= 0, UNDEF_LG);
case DASM_REL_PC:
CK(n >= 0, UNDEF_PC);
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4;
patchrel:
if ((ins & 0x800) == 0) {
CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL);
cp[-1] |= ((n >> 2) & 0x00ffffff);
} else if ((ins & 0x1000)) {
CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL);
goto patchimml8;
} else if ((ins & 0x2000) == 0) {
CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL);
goto patchimml;
} else {
CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL);
n >>= 2;
goto patchimml;
}
break;
case DASM_LABEL_LG:
ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
break;
case DASM_LABEL_PC: break;
case DASM_IMM:
cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31);
break;
case DASM_IMM12:
cp[-1] |= dasm_imm12((unsigned int)n);
break;
case DASM_IMM16:
cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff);
break;
case DASM_IMML8: patchimml8:
cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) :
((-n & 0x0f) | ((-n & 0xf0) << 4));
break;
case DASM_IMML12: case DASM_IMMV8: patchimml:
cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n);
break;
default: *cp++ = ins; break;
}
}
stop: (void)0;
}
}
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
return DASM_S_PHASE;
return DASM_S_OK;
}
#undef CK
/* Get PC label offset. */
int dasm_getpclabel(Dst_DECL, unsigned int pc)
{
dasm_State *D = Dst_REF;
if (pc*sizeof(int) < D->pcsize) {
int pos = D->pclabels[pc];
if (pos < 0) return *DASM_POS2PTR(D, -pos);
if (pos > 0) return -1; /* Undefined. */
}
return -2; /* Unused or out of range. */
}
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
int dasm_checkstep(Dst_DECL, int secmatch)
{
dasm_State *D = Dst_REF;
if (D->status == DASM_S_OK) {
int i;
for (i = 1; i <= 9; i++) {
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
D->lglabels[i] = 0;
}
}
if (D->status == DASM_S_OK && secmatch >= 0 &&
D->section != &D->sections[secmatch])
D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
return D->status;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,416 +0,0 @@
/*
** DynASM MIPS encoding engine.
** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define DASM_ARCH "mips"
#ifndef DASM_EXTERN
#define DASM_EXTERN(a,b,c,d) 0
#endif
/* Action definitions. */
enum {
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
/* The following actions need a buffer position. */
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
/* The following actions also have an argument. */
DASM_REL_PC, DASM_LABEL_PC, DASM_IMM,
DASM__MAX
};
/* Maximum number of section buffer positions for a single dasm_put() call. */
#define DASM_MAXSECPOS 25
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
#define DASM_S_OK 0x00000000
#define DASM_S_NOMEM 0x01000000
#define DASM_S_PHASE 0x02000000
#define DASM_S_MATCH_SEC 0x03000000
#define DASM_S_RANGE_I 0x11000000
#define DASM_S_RANGE_SEC 0x12000000
#define DASM_S_RANGE_LG 0x13000000
#define DASM_S_RANGE_PC 0x14000000
#define DASM_S_RANGE_REL 0x15000000
#define DASM_S_UNDEF_LG 0x21000000
#define DASM_S_UNDEF_PC 0x22000000
/* Macros to convert positions (8 bit section + 24 bit index). */
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
#define DASM_SEC2POS(sec) ((sec)<<24)
#define DASM_POS2SEC(pos) ((pos)>>24)
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
/* Action list type. */
typedef const unsigned int *dasm_ActList;
/* Per-section structure. */
typedef struct dasm_Section {
int *rbuf; /* Biased buffer pointer (negative section bias). */
int *buf; /* True buffer pointer. */
size_t bsize; /* Buffer size in bytes. */
int pos; /* Biased buffer position. */
int epos; /* End of biased buffer position - max single put. */
int ofs; /* Byte offset into section. */
} dasm_Section;
/* Core structure holding the DynASM encoding state. */
struct dasm_State {
size_t psize; /* Allocated size of this structure. */
dasm_ActList actionlist; /* Current actionlist pointer. */
int *lglabels; /* Local/global chain/pos ptrs. */
size_t lgsize;
int *pclabels; /* PC label chains/pos ptrs. */
size_t pcsize;
void **globals; /* Array of globals (bias -10). */
dasm_Section *section; /* Pointer to active section. */
size_t codesize; /* Total size of all code sections. */
int maxsection; /* 0 <= sectionidx < maxsection. */
int status; /* Status code. */
dasm_Section sections[1]; /* All sections. Alloc-extended. */
};
/* The size of the core structure depends on the max. number of sections. */
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
/* Initialize DynASM state. */
void dasm_init(Dst_DECL, int maxsection)
{
dasm_State *D;
size_t psz = 0;
int i;
Dst_REF = NULL;
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
D = Dst_REF;
D->psize = psz;
D->lglabels = NULL;
D->lgsize = 0;
D->pclabels = NULL;
D->pcsize = 0;
D->globals = NULL;
D->maxsection = maxsection;
for (i = 0; i < maxsection; i++) {
D->sections[i].buf = NULL; /* Need this for pass3. */
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
D->sections[i].bsize = 0;
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
}
}
/* Free DynASM state. */
void dasm_free(Dst_DECL)
{
dasm_State *D = Dst_REF;
int i;
for (i = 0; i < D->maxsection; i++)
if (D->sections[i].buf)
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
DASM_M_FREE(Dst, D, D->psize);
}
/* Setup global label array. Must be called before dasm_setup(). */
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
{
dasm_State *D = Dst_REF;
D->globals = gl - 10; /* Negative bias to compensate for locals. */
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
}
/* Grow PC label array. Can be called after dasm_setup(), too. */
void dasm_growpc(Dst_DECL, unsigned int maxpc)
{
dasm_State *D = Dst_REF;
size_t osz = D->pcsize;
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
}
/* Setup encoder. */
void dasm_setup(Dst_DECL, const void *actionlist)
{
dasm_State *D = Dst_REF;
int i;
D->actionlist = (dasm_ActList)actionlist;
D->status = DASM_S_OK;
D->section = &D->sections[0];
memset((void *)D->lglabels, 0, D->lgsize);
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
for (i = 0; i < D->maxsection; i++) {
D->sections[i].pos = DASM_SEC2POS(i);
D->sections[i].ofs = 0;
}
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) { \
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
#define CKPL(kind, st) \
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
#else
#define CK(x, st) ((void)0)
#define CKPL(kind, st) ((void)0)
#endif
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
void dasm_put(Dst_DECL, int start, ...)
{
va_list ap;
dasm_State *D = Dst_REF;
dasm_ActList p = D->actionlist + start;
dasm_Section *sec = D->section;
int pos = sec->pos, ofs = sec->ofs;
int *b;
if (pos >= sec->epos) {
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
}
b = sec->rbuf;
b[pos++] = start;
va_start(ap, start);
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16) - 0xff00;
if (action >= DASM__MAX) {
ofs += 4;
} else {
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
switch (action) {
case DASM_STOP: goto stop;
case DASM_SECTION:
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
D->section = &D->sections[n]; goto stop;
case DASM_ESC: p++; ofs += 4; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
case DASM_REL_LG:
n = (ins & 2047) - 10; pl = D->lglabels + n;
/* Bkwd rel or global. */
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
pl += 10; n = *pl;
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
goto linkrel;
case DASM_REL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putrel:
n = *pl;
if (n < 0) { /* Label exists. Get label pos and store it. */
b[pos] = -n;
} else {
linkrel:
b[pos] = n; /* Else link to rel chain, anchored at label. */
*pl = pos;
}
pos++;
break;
case DASM_LABEL_LG:
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
case DASM_LABEL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putlabel:
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
}
*pl = -pos; /* Label exists now. */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_IMM:
#ifdef DASM_CHECKS
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
#endif
n >>= ((ins>>10)&31);
#ifdef DASM_CHECKS
if (ins & 0x8000)
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
else
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
#endif
b[pos++] = n;
break;
}
}
}
stop:
va_end(ap);
sec->pos = pos;
sec->ofs = ofs;
}
#undef CK
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
int dasm_link(Dst_DECL, size_t *szp)
{
dasm_State *D = Dst_REF;
int secnum;
int ofs = 0;
#ifdef DASM_CHECKS
*szp = 0;
if (D->status != DASM_S_OK) return D->status;
{
int pc;
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
}
#endif
{ /* Handle globals not defined in this translation unit. */
int idx;
for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
int n = D->lglabels[idx];
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
}
}
/* Combine all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->rbuf;
int pos = DASM_SEC2POS(secnum);
int lastpos = sec->pos;
while (pos != lastpos) {
dasm_ActList p = D->actionlist + b[pos++];
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16) - 0xff00;
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: p++; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
case DASM_IMM: pos++; break;
}
}
stop: (void)0;
}
ofs += sec->ofs; /* Next section starts right after current section. */
}
D->codesize = ofs; /* Total size of all code sections */
*szp = ofs;
return DASM_S_OK;
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
#else
#define CK(x, st) ((void)0)
#endif
/* Pass 3: Encode sections. */
int dasm_encode(Dst_DECL, void *buffer)
{
dasm_State *D = Dst_REF;
char *base = (char *)buffer;
unsigned int *cp = (unsigned int *)buffer;
int secnum;
/* Encode all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->buf;
int *endb = sec->rbuf + sec->pos;
while (b != endb) {
dasm_ActList p = D->actionlist + *b++;
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16) - 0xff00;
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: *cp++ = *p++; break;
case DASM_REL_EXT:
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1);
goto patchrel;
case DASM_ALIGN:
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
break;
case DASM_REL_LG:
CK(n >= 0, UNDEF_LG);
case DASM_REL_PC:
CK(n >= 0, UNDEF_PC);
n = *DASM_POS2PTR(D, n);
if (ins & 2048)
n = n - (int)((char *)cp - base);
else
n = (n + (int)base) & 0x0fffffff;
patchrel:
CK((n & 3) == 0 &&
((n + ((ins & 2048) ? 0x00020000 : 0)) >>
((ins & 2048) ? 18 : 28)) == 0, RANGE_REL);
cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff));
break;
case DASM_LABEL_LG:
ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
break;
case DASM_LABEL_PC: break;
case DASM_IMM:
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
break;
default: *cp++ = ins; break;
}
}
stop: (void)0;
}
}
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
return DASM_S_PHASE;
return DASM_S_OK;
}
#undef CK
/* Get PC label offset. */
int dasm_getpclabel(Dst_DECL, unsigned int pc)
{
dasm_State *D = Dst_REF;
if (pc*sizeof(int) < D->pcsize) {
int pos = D->pclabels[pc];
if (pos < 0) return *DASM_POS2PTR(D, -pos);
if (pos > 0) return -1; /* Undefined. */
}
return -2; /* Unused or out of range. */
}
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
int dasm_checkstep(Dst_DECL, int secmatch)
{
dasm_State *D = Dst_REF;
if (D->status == DASM_S_OK) {
int i;
for (i = 1; i <= 9; i++) {
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
D->lglabels[i] = 0;
}
}
if (D->status == DASM_S_OK && secmatch >= 0 &&
D->section != &D->sections[secmatch])
D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
return D->status;
}
#endif

View File

@ -1,953 +0,0 @@
------------------------------------------------------------------------------
-- DynASM MIPS module.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- See dynasm.lua for full copyright notice.
------------------------------------------------------------------------------
-- Module information:
local _info = {
arch = "mips",
description = "DynASM MIPS module",
version = "1.3.0",
vernum = 10300,
release = "2012-01-23",
author = "Mike Pall",
license = "MIT",
}
-- Exported glue functions for the arch-specific module.
local _M = { _info = _info }
-- Cache library functions.
local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
local assert, setmetatable = assert, setmetatable
local _s = string
local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
local match, gmatch = _s.match, _s.gmatch
local concat, sort = table.concat, table.sort
local bit = bit or require("bit")
local band, shl, sar, tohex = bit.band, bit.lshift, bit.arshift, bit.tohex
-- Inherited tables and callbacks.
local g_opt, g_arch
local wline, werror, wfatal, wwarn
-- Action name list.
-- CHECK: Keep this in sync with the C code!
local action_names = {
"STOP", "SECTION", "ESC", "REL_EXT",
"ALIGN", "REL_LG", "LABEL_LG",
"REL_PC", "LABEL_PC", "IMM",
}
-- Maximum number of section buffer positions for dasm_put().
-- CHECK: Keep this in sync with the C code!
local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
-- Action name -> action number.
local map_action = {}
for n,name in ipairs(action_names) do
map_action[name] = n-1
end
-- Action list buffer.
local actlist = {}
-- Argument list for next dasm_put(). Start with offset 0 into action list.
local actargs = { 0 }
-- Current number of section buffer positions for dasm_put().
local secpos = 1
------------------------------------------------------------------------------
-- Dump action names and numbers.
local function dumpactions(out)
out:write("DynASM encoding engine action codes:\n")
for n,name in ipairs(action_names) do
local num = map_action[name]
out:write(format(" %-10s %02X %d\n", name, num, num))
end
out:write("\n")
end
-- Write action list buffer as a huge static C array.
local function writeactions(out, name)
local nn = #actlist
if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
out:write("static const unsigned int ", name, "[", nn, "] = {\n")
for i = 1,nn-1 do
assert(out:write("0x", tohex(actlist[i]), ",\n"))
end
assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
end
------------------------------------------------------------------------------
-- Add word to action list.
local function wputxw(n)
assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
actlist[#actlist+1] = n
end
-- Add action to list with optional arg. Advance buffer pos, too.
local function waction(action, val, a, num)
local w = assert(map_action[action], "bad action name `"..action.."'")
wputxw(0xff000000 + w * 0x10000 + (val or 0))
if a then actargs[#actargs+1] = a end
if a or num then secpos = secpos + (num or 1) end
end
-- Flush action list (intervening C code or buffer pos overflow).
local function wflush(term)
if #actlist == actargs[1] then return end -- Nothing to flush.
if not term then waction("STOP") end -- Terminate action list.
wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
secpos = 1 -- The actionlist offset occupies a buffer position, too.
end
-- Put escaped word.
local function wputw(n)
if n >= 0xff000000 then waction("ESC") end
wputxw(n)
end
-- Reserve position for word.
local function wpos()
local pos = #actlist+1
actlist[pos] = ""
return pos
end
-- Store word to reserved position.
local function wputpos(pos, n)
assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
actlist[pos] = n
end
------------------------------------------------------------------------------
-- Global label name -> global label number. With auto assignment on 1st use.
local next_global = 20
local map_global = setmetatable({}, { __index = function(t, name)
if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
local n = next_global
if n > 2047 then werror("too many global labels") end
next_global = n + 1
t[name] = n
return n
end})
-- Dump global labels.
local function dumpglobals(out, lvl)
local t = {}
for name, n in pairs(map_global) do t[n] = name end
out:write("Global labels:\n")
for i=20,next_global-1 do
out:write(format(" %s\n", t[i]))
end
out:write("\n")
end
-- Write global label enum.
local function writeglobals(out, prefix)
local t = {}
for name, n in pairs(map_global) do t[n] = name end
out:write("enum {\n")
for i=20,next_global-1 do
out:write(" ", prefix, t[i], ",\n")
end
out:write(" ", prefix, "_MAX\n};\n")
end
-- Write global label names.
local function writeglobalnames(out, name)
local t = {}
for name, n in pairs(map_global) do t[n] = name end
out:write("static const char *const ", name, "[] = {\n")
for i=20,next_global-1 do
out:write(" \"", t[i], "\",\n")
end
out:write(" (const char *)0\n};\n")
end
------------------------------------------------------------------------------
-- Extern label name -> extern label number. With auto assignment on 1st use.
local next_extern = 0
local map_extern_ = {}
local map_extern = setmetatable({}, { __index = function(t, name)
-- No restrictions on the name for now.
local n = next_extern
if n > 2047 then werror("too many extern labels") end
next_extern = n + 1
t[name] = n
map_extern_[n] = name
return n
end})
-- Dump extern labels.
local function dumpexterns(out, lvl)
out:write("Extern labels:\n")
for i=0,next_extern-1 do
out:write(format(" %s\n", map_extern_[i]))
end
out:write("\n")
end
-- Write extern label names.
local function writeexternnames(out, name)
out:write("static const char *const ", name, "[] = {\n")
for i=0,next_extern-1 do
out:write(" \"", map_extern_[i], "\",\n")
end
out:write(" (const char *)0\n};\n")
end
------------------------------------------------------------------------------
-- Arch-specific maps.
local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name.
local map_type = {} -- Type name -> { ctype, reg }
local ctypenum = 0 -- Type number (for Dt... macros).
-- Reverse defines for registers.
function _M.revdef(s)
if s == "r29" then return "sp"
elseif s == "r31" then return "ra" end
return s
end
------------------------------------------------------------------------------
-- Template strings for MIPS instructions.
local map_op = {
-- First-level opcodes.
j_1 = "08000000J",
jal_1 = "0c000000J",
b_1 = "10000000B",
beqz_2 = "10000000SB",
beq_3 = "10000000STB",
bnez_2 = "14000000SB",
bne_3 = "14000000STB",
blez_2 = "18000000SB",
bgtz_2 = "1c000000SB",
addi_3 = "20000000TSI",
li_2 = "24000000TI",
addiu_3 = "24000000TSI",
slti_3 = "28000000TSI",
sltiu_3 = "2c000000TSI",
andi_3 = "30000000TSU",
lu_2 = "34000000TU",
ori_3 = "34000000TSU",
xori_3 = "38000000TSU",
lui_2 = "3c000000TU",
beqzl_2 = "50000000SB",
beql_3 = "50000000STB",
bnezl_2 = "54000000SB",
bnel_3 = "54000000STB",
blezl_2 = "58000000SB",
bgtzl_2 = "5c000000SB",
lb_2 = "80000000TO",
lh_2 = "84000000TO",
lwl_2 = "88000000TO",
lw_2 = "8c000000TO",
lbu_2 = "90000000TO",
lhu_2 = "94000000TO",
lwr_2 = "98000000TO",
sb_2 = "a0000000TO",
sh_2 = "a4000000TO",
swl_2 = "a8000000TO",
sw_2 = "ac000000TO",
swr_2 = "b8000000TO",
cache_2 = "bc000000NO",
ll_2 = "c0000000TO",
lwc1_2 = "c4000000HO",
pref_2 = "cc000000NO",
ldc1_2 = "d4000000HO",
sc_2 = "e0000000TO",
swc1_2 = "e4000000HO",
sdc1_2 = "f4000000HO",
-- Opcode SPECIAL.
nop_0 = "00000000",
sll_3 = "00000000DTA",
movf_2 = "00000001DS",
movf_3 = "00000001DSC",
movt_2 = "00010001DS",
movt_3 = "00010001DSC",
srl_3 = "00000002DTA",
rotr_3 = "00200002DTA",
sra_3 = "00000003DTA",
sllv_3 = "00000004DTS",
srlv_3 = "00000006DTS",
rotrv_3 = "00000046DTS",
srav_3 = "00000007DTS",
jr_1 = "00000008S",
jalr_1 = "0000f809S",
jalr_2 = "00000009DS",
movz_3 = "0000000aDST",
movn_3 = "0000000bDST",
syscall_0 = "0000000c",
syscall_1 = "0000000cY",
break_0 = "0000000d",
break_1 = "0000000dY",
sync_0 = "0000000f",
mfhi_1 = "00000010D",
mthi_1 = "00000011S",
mflo_1 = "00000012D",
mtlo_1 = "00000013S",
mult_2 = "00000018ST",
multu_2 = "00000019ST",
div_2 = "0000001aST",
divu_2 = "0000001bST",
add_3 = "00000020DST",
move_2 = "00000021DS",
addu_3 = "00000021DST",
sub_3 = "00000022DST",
negu_2 = "00000023DT",
subu_3 = "00000023DST",
and_3 = "00000024DST",
or_3 = "00000025DST",
xor_3 = "00000026DST",
not_2 = "00000027DS",
nor_3 = "00000027DST",
slt_3 = "0000002aDST",
sltu_3 = "0000002bDST",
tge_2 = "00000030ST",
tge_3 = "00000030STZ",
tgeu_2 = "00000031ST",
tgeu_3 = "00000031STZ",
tlt_2 = "00000032ST",
tlt_3 = "00000032STZ",
tltu_2 = "00000033ST",
tltu_3 = "00000033STZ",
teq_2 = "00000034ST",
teq_3 = "00000034STZ",
tne_2 = "00000036ST",
tne_3 = "00000036STZ",
-- Opcode REGIMM.
bltz_2 = "04000000SB",
bgez_2 = "04010000SB",
bltzl_2 = "04020000SB",
bgezl_2 = "04030000SB",
tgei_2 = "04080000SI",
tgeiu_2 = "04090000SI",
tlti_2 = "040a0000SI",
tltiu_2 = "040b0000SI",
teqi_2 = "040c0000SI",
tnei_2 = "040e0000SI",
bltzal_2 = "04100000SB",
bal_1 = "04110000B",
bgezal_2 = "04110000SB",
bltzall_2 = "04120000SB",
bgezall_2 = "04130000SB",
synci_1 = "041f0000O",
-- Opcode SPECIAL2.
madd_2 = "70000000ST",
maddu_2 = "70000001ST",
mul_3 = "70000002DST",
msub_2 = "70000004ST",
msubu_2 = "70000005ST",
clz_2 = "70000020DS=",
clo_2 = "70000021DS=",
sdbbp_0 = "7000003f",
sdbbp_1 = "7000003fY",
-- Opcode SPECIAL3.
ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1
ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1
wsbh_2 = "7c0000a0DT",
seb_2 = "7c000420DT",
seh_2 = "7c000620DT",
rdhwr_2 = "7c00003bTD",
-- Opcode COP0.
mfc0_2 = "40000000TD",
mfc0_3 = "40000000TDW",
mtc0_2 = "40800000TD",
mtc0_3 = "40800000TDW",
rdpgpr_2 = "41400000DT",
di_0 = "41606000",
di_1 = "41606000T",
ei_0 = "41606020",
ei_1 = "41606020T",
wrpgpr_2 = "41c00000DT",
tlbr_0 = "42000001",
tlbwi_0 = "42000002",
tlbwr_0 = "42000006",
tlbp_0 = "42000008",
eret_0 = "42000018",
deret_0 = "4200001f",
wait_0 = "42000020",
-- Opcode COP1.
mfc1_2 = "44000000TG",
cfc1_2 = "44400000TG",
mfhc1_2 = "44600000TG",
mtc1_2 = "44800000TG",
ctc1_2 = "44c00000TG",
mthc1_2 = "44e00000TG",
bc1f_1 = "45000000B",
bc1f_2 = "45000000CB",
bc1t_1 = "45010000B",
bc1t_2 = "45010000CB",
bc1fl_1 = "45020000B",
bc1fl_2 = "45020000CB",
bc1tl_1 = "45030000B",
bc1tl_2 = "45030000CB",
["add.s_3"] = "46000000FGH",
["sub.s_3"] = "46000001FGH",
["mul.s_3"] = "46000002FGH",
["div.s_3"] = "46000003FGH",
["sqrt.s_2"] = "46000004FG",
["abs.s_2"] = "46000005FG",
["mov.s_2"] = "46000006FG",
["neg.s_2"] = "46000007FG",
["round.l.s_2"] = "46000008FG",
["trunc.l.s_2"] = "46000009FG",
["ceil.l.s_2"] = "4600000aFG",
["floor.l.s_2"] = "4600000bFG",
["round.w.s_2"] = "4600000cFG",
["trunc.w.s_2"] = "4600000dFG",
["ceil.w.s_2"] = "4600000eFG",
["floor.w.s_2"] = "4600000fFG",
["movf.s_2"] = "46000011FG",
["movf.s_3"] = "46000011FGC",
["movt.s_2"] = "46010011FG",
["movt.s_3"] = "46010011FGC",
["movz.s_3"] = "46000012FGT",
["movn.s_3"] = "46000013FGT",
["recip.s_2"] = "46000015FG",
["rsqrt.s_2"] = "46000016FG",
["cvt.d.s_2"] = "46000021FG",
["cvt.w.s_2"] = "46000024FG",
["cvt.l.s_2"] = "46000025FG",
["cvt.ps.s_3"] = "46000026FGH",
["c.f.s_2"] = "46000030GH",
["c.f.s_3"] = "46000030VGH",
["c.un.s_2"] = "46000031GH",
["c.un.s_3"] = "46000031VGH",
["c.eq.s_2"] = "46000032GH",
["c.eq.s_3"] = "46000032VGH",
["c.ueq.s_2"] = "46000033GH",
["c.ueq.s_3"] = "46000033VGH",
["c.olt.s_2"] = "46000034GH",
["c.olt.s_3"] = "46000034VGH",
["c.ult.s_2"] = "46000035GH",
["c.ult.s_3"] = "46000035VGH",
["c.ole.s_2"] = "46000036GH",
["c.ole.s_3"] = "46000036VGH",
["c.ule.s_2"] = "46000037GH",
["c.ule.s_3"] = "46000037VGH",
["c.sf.s_2"] = "46000038GH",
["c.sf.s_3"] = "46000038VGH",
["c.ngle.s_2"] = "46000039GH",
["c.ngle.s_3"] = "46000039VGH",
["c.seq.s_2"] = "4600003aGH",
["c.seq.s_3"] = "4600003aVGH",
["c.ngl.s_2"] = "4600003bGH",
["c.ngl.s_3"] = "4600003bVGH",
["c.lt.s_2"] = "4600003cGH",
["c.lt.s_3"] = "4600003cVGH",
["c.nge.s_2"] = "4600003dGH",
["c.nge.s_3"] = "4600003dVGH",
["c.le.s_2"] = "4600003eGH",
["c.le.s_3"] = "4600003eVGH",
["c.ngt.s_2"] = "4600003fGH",
["c.ngt.s_3"] = "4600003fVGH",
["add.d_3"] = "46200000FGH",
["sub.d_3"] = "46200001FGH",
["mul.d_3"] = "46200002FGH",
["div.d_3"] = "46200003FGH",
["sqrt.d_2"] = "46200004FG",
["abs.d_2"] = "46200005FG",
["mov.d_2"] = "46200006FG",
["neg.d_2"] = "46200007FG",
["round.l.d_2"] = "46200008FG",
["trunc.l.d_2"] = "46200009FG",
["ceil.l.d_2"] = "4620000aFG",
["floor.l.d_2"] = "4620000bFG",
["round.w.d_2"] = "4620000cFG",
["trunc.w.d_2"] = "4620000dFG",
["ceil.w.d_2"] = "4620000eFG",
["floor.w.d_2"] = "4620000fFG",
["movf.d_2"] = "46200011FG",
["movf.d_3"] = "46200011FGC",
["movt.d_2"] = "46210011FG",
["movt.d_3"] = "46210011FGC",
["movz.d_3"] = "46200012FGT",
["movn.d_3"] = "46200013FGT",
["recip.d_2"] = "46200015FG",
["rsqrt.d_2"] = "46200016FG",
["cvt.s.d_2"] = "46200020FG",
["cvt.w.d_2"] = "46200024FG",
["cvt.l.d_2"] = "46200025FG",
["c.f.d_2"] = "46200030GH",
["c.f.d_3"] = "46200030VGH",
["c.un.d_2"] = "46200031GH",
["c.un.d_3"] = "46200031VGH",
["c.eq.d_2"] = "46200032GH",
["c.eq.d_3"] = "46200032VGH",
["c.ueq.d_2"] = "46200033GH",
["c.ueq.d_3"] = "46200033VGH",
["c.olt.d_2"] = "46200034GH",
["c.olt.d_3"] = "46200034VGH",
["c.ult.d_2"] = "46200035GH",
["c.ult.d_3"] = "46200035VGH",
["c.ole.d_2"] = "46200036GH",
["c.ole.d_3"] = "46200036VGH",
["c.ule.d_2"] = "46200037GH",
["c.ule.d_3"] = "46200037VGH",
["c.sf.d_2"] = "46200038GH",
["c.sf.d_3"] = "46200038VGH",
["c.ngle.d_2"] = "46200039GH",
["c.ngle.d_3"] = "46200039VGH",
["c.seq.d_2"] = "4620003aGH",
["c.seq.d_3"] = "4620003aVGH",
["c.ngl.d_2"] = "4620003bGH",
["c.ngl.d_3"] = "4620003bVGH",
["c.lt.d_2"] = "4620003cGH",
["c.lt.d_3"] = "4620003cVGH",
["c.nge.d_2"] = "4620003dGH",
["c.nge.d_3"] = "4620003dVGH",
["c.le.d_2"] = "4620003eGH",
["c.le.d_3"] = "4620003eVGH",
["c.ngt.d_2"] = "4620003fGH",
["c.ngt.d_3"] = "4620003fVGH",
["add.ps_3"] = "46c00000FGH",
["sub.ps_3"] = "46c00001FGH",
["mul.ps_3"] = "46c00002FGH",
["abs.ps_2"] = "46c00005FG",
["mov.ps_2"] = "46c00006FG",
["neg.ps_2"] = "46c00007FG",
["movf.ps_2"] = "46c00011FG",
["movf.ps_3"] = "46c00011FGC",
["movt.ps_2"] = "46c10011FG",
["movt.ps_3"] = "46c10011FGC",
["movz.ps_3"] = "46c00012FGT",
["movn.ps_3"] = "46c00013FGT",
["cvt.s.pu_2"] = "46c00020FG",
["cvt.s.pl_2"] = "46c00028FG",
["pll.ps_3"] = "46c0002cFGH",
["plu.ps_3"] = "46c0002dFGH",
["pul.ps_3"] = "46c0002eFGH",
["puu.ps_3"] = "46c0002fFGH",
["c.f.ps_2"] = "46c00030GH",
["c.f.ps_3"] = "46c00030VGH",
["c.un.ps_2"] = "46c00031GH",
["c.un.ps_3"] = "46c00031VGH",
["c.eq.ps_2"] = "46c00032GH",
["c.eq.ps_3"] = "46c00032VGH",
["c.ueq.ps_2"] = "46c00033GH",
["c.ueq.ps_3"] = "46c00033VGH",
["c.olt.ps_2"] = "46c00034GH",
["c.olt.ps_3"] = "46c00034VGH",
["c.ult.ps_2"] = "46c00035GH",
["c.ult.ps_3"] = "46c00035VGH",
["c.ole.ps_2"] = "46c00036GH",
["c.ole.ps_3"] = "46c00036VGH",
["c.ule.ps_2"] = "46c00037GH",
["c.ule.ps_3"] = "46c00037VGH",
["c.sf.ps_2"] = "46c00038GH",
["c.sf.ps_3"] = "46c00038VGH",
["c.ngle.ps_2"] = "46c00039GH",
["c.ngle.ps_3"] = "46c00039VGH",
["c.seq.ps_2"] = "46c0003aGH",
["c.seq.ps_3"] = "46c0003aVGH",
["c.ngl.ps_2"] = "46c0003bGH",
["c.ngl.ps_3"] = "46c0003bVGH",
["c.lt.ps_2"] = "46c0003cGH",
["c.lt.ps_3"] = "46c0003cVGH",
["c.nge.ps_2"] = "46c0003dGH",
["c.nge.ps_3"] = "46c0003dVGH",
["c.le.ps_2"] = "46c0003eGH",
["c.le.ps_3"] = "46c0003eVGH",
["c.ngt.ps_2"] = "46c0003fGH",
["c.ngt.ps_3"] = "46c0003fVGH",
["cvt.s.w_2"] = "46800020FG",
["cvt.d.w_2"] = "46800021FG",
["cvt.s.l_2"] = "46a00020FG",
["cvt.d.l_2"] = "46a00021FG",
-- Opcode COP1X.
lwxc1_2 = "4c000000FX",
ldxc1_2 = "4c000001FX",
luxc1_2 = "4c000005FX",
swxc1_2 = "4c000008FX",
sdxc1_2 = "4c000009FX",
suxc1_2 = "4c00000dFX",
prefx_2 = "4c00000fMX",
["alnv.ps_4"] = "4c00001eFGHS",
["madd.s_4"] = "4c000020FRGH",
["madd.d_4"] = "4c000021FRGH",
["madd.ps_4"] = "4c000026FRGH",
["msub.s_4"] = "4c000028FRGH",
["msub.d_4"] = "4c000029FRGH",
["msub.ps_4"] = "4c00002eFRGH",
["nmadd.s_4"] = "4c000030FRGH",
["nmadd.d_4"] = "4c000031FRGH",
["nmadd.ps_4"] = "4c000036FRGH",
["nmsub.s_4"] = "4c000038FRGH",
["nmsub.d_4"] = "4c000039FRGH",
["nmsub.ps_4"] = "4c00003eFRGH",
}
------------------------------------------------------------------------------
local function parse_gpr(expr)
local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$")
local tp = map_type[tname or expr]
if tp then
local reg = ovreg or tp.reg
if not reg then
werror("type `"..(tname or expr).."' needs a register override")
end
expr = reg
end
local r = match(expr, "^r([1-3]?[0-9])$")
if r then
r = tonumber(r)
if r <= 31 then return r, tp end
end
werror("bad register name `"..expr.."'")
end
local function parse_fpr(expr)
local r = match(expr, "^f([1-3]?[0-9])$")
if r then
r = tonumber(r)
if r <= 31 then return r end
end
werror("bad register name `"..expr.."'")
end
local function parse_imm(imm, bits, shift, scale, signed)
local n = tonumber(imm)
if n then
local m = sar(n, scale)
if shl(m, scale) == n then
if signed then
local s = sar(m, bits-1)
if s == 0 then return shl(m, shift)
elseif s == -1 then return shl(m + shl(1, bits), shift) end
else
if sar(m, bits) == 0 then return shl(m, shift) end
end
end
werror("out of range immediate `"..imm.."'")
elseif match(imm, "^[rf]([1-3]?[0-9])$") or
match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then
werror("expected immediate operand, got register")
else
waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
return 0
end
end
local function parse_disp(disp)
local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
if imm then
local r = shl(parse_gpr(reg), 21)
local extname = match(imm, "^extern%s+(%S+)$")
if extname then
waction("REL_EXT", map_extern[extname], nil, 1)
return r
else
return r + parse_imm(imm, 16, 0, 0, true)
end
end
local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
if reg and tailr ~= "" then
local r, tp = parse_gpr(reg)
if tp then
waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr))
return shl(r, 21)
end
end
werror("bad displacement `"..disp.."'")
end
local function parse_index(idx)
local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$")
if rt then
rt = parse_gpr(rt)
rs = parse_gpr(rs)
return shl(rt, 16) + shl(rs, 21)
end
werror("bad index `"..idx.."'")
end
local function parse_label(label, def)
local prefix = sub(label, 1, 2)
-- =>label (pc label reference)
if prefix == "=>" then
return "PC", 0, sub(label, 3)
end
-- ->name (global label reference)
if prefix == "->" then
return "LG", map_global[sub(label, 3)]
end
if def then
-- [1-9] (local label definition)
if match(label, "^[1-9]$") then
return "LG", 10+tonumber(label)
end
else
-- [<>][1-9] (local label reference)
local dir, lnum = match(label, "^([<>])([1-9])$")
if dir then -- Fwd: 1-9, Bkwd: 11-19.
return "LG", lnum + (dir == ">" and 0 or 10)
end
-- extern label (extern label reference)
local extname = match(label, "^extern%s+(%S+)$")
if extname then
return "EXT", map_extern[extname]
end
end
werror("bad label `"..label.."'")
end
------------------------------------------------------------------------------
-- Handle opcodes defined with template strings.
map_op[".template__"] = function(params, template, nparams)
if not params then return sub(template, 9) end
local op = tonumber(sub(template, 1, 8), 16)
local n = 1
-- Limit number of section buffer positions used by a single dasm_put().
-- A single opcode needs a maximum of 2 positions (ins/ext).
if secpos+2 > maxsecpos then wflush() end
local pos = wpos()
-- Process each character.
for p in gmatch(sub(template, 9), ".") do
if p == "D" then
op = op + shl(parse_gpr(params[n]), 11); n = n + 1
elseif p == "T" then
op = op + shl(parse_gpr(params[n]), 16); n = n + 1
elseif p == "S" then
op = op + shl(parse_gpr(params[n]), 21); n = n + 1
elseif p == "F" then
op = op + shl(parse_fpr(params[n]), 6); n = n + 1
elseif p == "G" then
op = op + shl(parse_fpr(params[n]), 11); n = n + 1
elseif p == "H" then
op = op + shl(parse_fpr(params[n]), 16); n = n + 1
elseif p == "R" then
op = op + shl(parse_fpr(params[n]), 21); n = n + 1
elseif p == "I" then
op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1
elseif p == "U" then
op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1
elseif p == "O" then
op = op + parse_disp(params[n]); n = n + 1
elseif p == "X" then
op = op + parse_index(params[n]); n = n + 1
elseif p == "B" or p == "J" then
local mode, n, s = parse_label(params[n], false)
if p == "B" then n = n + 2048 end
waction("REL_"..mode, n, s, 1)
n = n + 1
elseif p == "A" then
op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1
elseif p == "M" then
op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1
elseif p == "N" then
op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1
elseif p == "C" then
op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1
elseif p == "V" then
op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1
elseif p == "W" then
op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1
elseif p == "Y" then
op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1
elseif p == "Z" then
op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1
elseif p == "=" then
op = op + shl(band(op, 0xf800), 5) -- Copy D to T for clz, clo.
else
assert(false)
end
end
wputpos(pos, op)
end
------------------------------------------------------------------------------
-- Pseudo-opcode to mark the position where the action list is to be emitted.
map_op[".actionlist_1"] = function(params)
if not params then return "cvar" end
local name = params[1] -- No syntax check. You get to keep the pieces.
wline(function(out) writeactions(out, name) end)
end
-- Pseudo-opcode to mark the position where the global enum is to be emitted.
map_op[".globals_1"] = function(params)
if not params then return "prefix" end
local prefix = params[1] -- No syntax check. You get to keep the pieces.
wline(function(out) writeglobals(out, prefix) end)
end
-- Pseudo-opcode to mark the position where the global names are to be emitted.
map_op[".globalnames_1"] = function(params)
if not params then return "cvar" end
local name = params[1] -- No syntax check. You get to keep the pieces.
wline(function(out) writeglobalnames(out, name) end)
end
-- Pseudo-opcode to mark the position where the extern names are to be emitted.
map_op[".externnames_1"] = function(params)
if not params then return "cvar" end
local name = params[1] -- No syntax check. You get to keep the pieces.
wline(function(out) writeexternnames(out, name) end)
end
------------------------------------------------------------------------------
-- Label pseudo-opcode (converted from trailing colon form).
map_op[".label_1"] = function(params)
if not params then return "[1-9] | ->global | =>pcexpr" end
if secpos+1 > maxsecpos then wflush() end
local mode, n, s = parse_label(params[1], true)
if mode == "EXT" then werror("bad label definition") end
waction("LABEL_"..mode, n, s, 1)
end
------------------------------------------------------------------------------
-- Pseudo-opcodes for data storage.
map_op[".long_*"] = function(params)
if not params then return "imm..." end
for _,p in ipairs(params) do
local n = tonumber(p)
if not n then werror("bad immediate `"..p.."'") end
if n < 0 then n = n + 2^32 end
wputw(n)
if secpos+2 > maxsecpos then wflush() end
end
end
-- Alignment pseudo-opcode.
map_op[".align_1"] = function(params)
if not params then return "numpow2" end
if secpos+1 > maxsecpos then wflush() end
local align = tonumber(params[1])
if align then
local x = align
-- Must be a power of 2 in the range (2 ... 256).
for i=1,8 do
x = x / 2
if x == 1 then
waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
return
end
end
end
werror("bad alignment")
end
------------------------------------------------------------------------------
-- Pseudo-opcode for (primitive) type definitions (map to C types).
map_op[".type_3"] = function(params, nparams)
if not params then
return nparams == 2 and "name, ctype" or "name, ctype, reg"
end
local name, ctype, reg = params[1], params[2], params[3]
if not match(name, "^[%a_][%w_]*$") then
werror("bad type name `"..name.."'")
end
local tp = map_type[name]
if tp then
werror("duplicate type `"..name.."'")
end
-- Add #type to defines. A bit unclean to put it in map_archdef.
map_archdef["#"..name] = "sizeof("..ctype..")"
-- Add new type and emit shortcut define.
local num = ctypenum + 1
map_type[name] = {
ctype = ctype,
ctypefmt = format("Dt%X(%%s)", num),
reg = reg,
}
wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
ctypenum = num
end
map_op[".type_2"] = map_op[".type_3"]
-- Dump type definitions.
local function dumptypes(out, lvl)
local t = {}
for name in pairs(map_type) do t[#t+1] = name end
sort(t)
out:write("Type definitions:\n")
for _,name in ipairs(t) do
local tp = map_type[name]
local reg = tp.reg or ""
out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
end
out:write("\n")
end
------------------------------------------------------------------------------
-- Set the current section.
function _M.section(num)
waction("SECTION", num)
wflush(true) -- SECTION is a terminal action.
end
------------------------------------------------------------------------------
-- Dump architecture description.
function _M.dumparch(out)
out:write(format("DynASM %s version %s, released %s\n\n",
_info.arch, _info.version, _info.release))
dumpactions(out)
end
-- Dump all user defined elements.
function _M.dumpdef(out, lvl)
dumptypes(out, lvl)
dumpglobals(out, lvl)
dumpexterns(out, lvl)
end
------------------------------------------------------------------------------
-- Pass callbacks from/to the DynASM core.
function _M.passcb(wl, we, wf, ww)
wline, werror, wfatal, wwarn = wl, we, wf, ww
return wflush
end
-- Setup the arch-specific module.
function _M.setup(arch, opt)
g_arch, g_opt = arch, opt
end
-- Merge the core maps and the arch-specific maps.
function _M.mergemaps(map_coreop, map_def)
setmetatable(map_op, { __index = map_coreop })
setmetatable(map_def, { __index = map_archdef })
return map_op, map_def
end
return _M
------------------------------------------------------------------------------

View File

@ -1,412 +0,0 @@
/*
** DynASM PPC encoding engine.
** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define DASM_ARCH "ppc"
#ifndef DASM_EXTERN
#define DASM_EXTERN(a,b,c,d) 0
#endif
/* Action definitions. */
enum {
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
/* The following actions need a buffer position. */
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
/* The following actions also have an argument. */
DASM_REL_PC, DASM_LABEL_PC, DASM_IMM,
DASM__MAX
};
/* Maximum number of section buffer positions for a single dasm_put() call. */
#define DASM_MAXSECPOS 25
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
#define DASM_S_OK 0x00000000
#define DASM_S_NOMEM 0x01000000
#define DASM_S_PHASE 0x02000000
#define DASM_S_MATCH_SEC 0x03000000
#define DASM_S_RANGE_I 0x11000000
#define DASM_S_RANGE_SEC 0x12000000
#define DASM_S_RANGE_LG 0x13000000
#define DASM_S_RANGE_PC 0x14000000
#define DASM_S_RANGE_REL 0x15000000
#define DASM_S_UNDEF_LG 0x21000000
#define DASM_S_UNDEF_PC 0x22000000
/* Macros to convert positions (8 bit section + 24 bit index). */
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
#define DASM_SEC2POS(sec) ((sec)<<24)
#define DASM_POS2SEC(pos) ((pos)>>24)
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
/* Action list type. */
typedef const unsigned int *dasm_ActList;
/* Per-section structure. */
typedef struct dasm_Section {
int *rbuf; /* Biased buffer pointer (negative section bias). */
int *buf; /* True buffer pointer. */
size_t bsize; /* Buffer size in bytes. */
int pos; /* Biased buffer position. */
int epos; /* End of biased buffer position - max single put. */
int ofs; /* Byte offset into section. */
} dasm_Section;
/* Core structure holding the DynASM encoding state. */
struct dasm_State {
size_t psize; /* Allocated size of this structure. */
dasm_ActList actionlist; /* Current actionlist pointer. */
int *lglabels; /* Local/global chain/pos ptrs. */
size_t lgsize;
int *pclabels; /* PC label chains/pos ptrs. */
size_t pcsize;
void **globals; /* Array of globals (bias -10). */
dasm_Section *section; /* Pointer to active section. */
size_t codesize; /* Total size of all code sections. */
int maxsection; /* 0 <= sectionidx < maxsection. */
int status; /* Status code. */
dasm_Section sections[1]; /* All sections. Alloc-extended. */
};
/* The size of the core structure depends on the max. number of sections. */
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
/* Initialize DynASM state. */
void dasm_init(Dst_DECL, int maxsection)
{
dasm_State *D;
size_t psz = 0;
int i;
Dst_REF = NULL;
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
D = Dst_REF;
D->psize = psz;
D->lglabels = NULL;
D->lgsize = 0;
D->pclabels = NULL;
D->pcsize = 0;
D->globals = NULL;
D->maxsection = maxsection;
for (i = 0; i < maxsection; i++) {
D->sections[i].buf = NULL; /* Need this for pass3. */
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
D->sections[i].bsize = 0;
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
}
}
/* Free DynASM state. */
void dasm_free(Dst_DECL)
{
dasm_State *D = Dst_REF;
int i;
for (i = 0; i < D->maxsection; i++)
if (D->sections[i].buf)
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
DASM_M_FREE(Dst, D, D->psize);
}
/* Setup global label array. Must be called before dasm_setup(). */
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
{
dasm_State *D = Dst_REF;
D->globals = gl - 10; /* Negative bias to compensate for locals. */
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
}
/* Grow PC label array. Can be called after dasm_setup(), too. */
void dasm_growpc(Dst_DECL, unsigned int maxpc)
{
dasm_State *D = Dst_REF;
size_t osz = D->pcsize;
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
}
/* Setup encoder. */
void dasm_setup(Dst_DECL, const void *actionlist)
{
dasm_State *D = Dst_REF;
int i;
D->actionlist = (dasm_ActList)actionlist;
D->status = DASM_S_OK;
D->section = &D->sections[0];
memset((void *)D->lglabels, 0, D->lgsize);
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
for (i = 0; i < D->maxsection; i++) {
D->sections[i].pos = DASM_SEC2POS(i);
D->sections[i].ofs = 0;
}
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) { \
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
#define CKPL(kind, st) \
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
#else
#define CK(x, st) ((void)0)
#define CKPL(kind, st) ((void)0)
#endif
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
void dasm_put(Dst_DECL, int start, ...)
{
va_list ap;
dasm_State *D = Dst_REF;
dasm_ActList p = D->actionlist + start;
dasm_Section *sec = D->section;
int pos = sec->pos, ofs = sec->ofs;
int *b;
if (pos >= sec->epos) {
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
}
b = sec->rbuf;
b[pos++] = start;
va_start(ap, start);
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
if (action >= DASM__MAX) {
ofs += 4;
} else {
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
switch (action) {
case DASM_STOP: goto stop;
case DASM_SECTION:
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
D->section = &D->sections[n]; goto stop;
case DASM_ESC: p++; ofs += 4; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
case DASM_REL_LG:
n = (ins & 2047) - 10; pl = D->lglabels + n;
/* Bkwd rel or global. */
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
pl += 10; n = *pl;
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
goto linkrel;
case DASM_REL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putrel:
n = *pl;
if (n < 0) { /* Label exists. Get label pos and store it. */
b[pos] = -n;
} else {
linkrel:
b[pos] = n; /* Else link to rel chain, anchored at label. */
*pl = pos;
}
pos++;
break;
case DASM_LABEL_LG:
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
case DASM_LABEL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putlabel:
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
}
*pl = -pos; /* Label exists now. */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_IMM:
#ifdef DASM_CHECKS
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
#endif
n >>= ((ins>>10)&31);
#ifdef DASM_CHECKS
if (ins & 0x8000)
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
else
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
#endif
b[pos++] = n;
break;
}
}
}
stop:
va_end(ap);
sec->pos = pos;
sec->ofs = ofs;
}
#undef CK
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
int dasm_link(Dst_DECL, size_t *szp)
{
dasm_State *D = Dst_REF;
int secnum;
int ofs = 0;
#ifdef DASM_CHECKS
*szp = 0;
if (D->status != DASM_S_OK) return D->status;
{
int pc;
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
}
#endif
{ /* Handle globals not defined in this translation unit. */
int idx;
for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
int n = D->lglabels[idx];
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
}
}
/* Combine all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->rbuf;
int pos = DASM_SEC2POS(secnum);
int lastpos = sec->pos;
while (pos != lastpos) {
dasm_ActList p = D->actionlist + b[pos++];
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: p++; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
case DASM_IMM: pos++; break;
}
}
stop: (void)0;
}
ofs += sec->ofs; /* Next section starts right after current section. */
}
D->codesize = ofs; /* Total size of all code sections */
*szp = ofs;
return DASM_S_OK;
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
#else
#define CK(x, st) ((void)0)
#endif
/* Pass 3: Encode sections. */
int dasm_encode(Dst_DECL, void *buffer)
{
dasm_State *D = Dst_REF;
char *base = (char *)buffer;
unsigned int *cp = (unsigned int *)buffer;
int secnum;
/* Encode all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->buf;
int *endb = sec->rbuf + sec->pos;
while (b != endb) {
dasm_ActList p = D->actionlist + *b++;
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: *cp++ = *p++; break;
case DASM_REL_EXT:
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4;
goto patchrel;
case DASM_ALIGN:
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
break;
case DASM_REL_LG:
CK(n >= 0, UNDEF_LG);
case DASM_REL_PC:
CK(n >= 0, UNDEF_PC);
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base);
patchrel:
CK((n & 3) == 0 &&
(((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >>
((ins & 2048) ? 16 : 26)) == 0, RANGE_REL);
cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc));
break;
case DASM_LABEL_LG:
ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
break;
case DASM_LABEL_PC: break;
case DASM_IMM:
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
break;
default: *cp++ = ins; break;
}
}
stop: (void)0;
}
}
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
return DASM_S_PHASE;
return DASM_S_OK;
}
#undef CK
/* Get PC label offset. */
int dasm_getpclabel(Dst_DECL, unsigned int pc)
{
dasm_State *D = Dst_REF;
if (pc*sizeof(int) < D->pcsize) {
int pos = D->pclabels[pc];
if (pos < 0) return *DASM_POS2PTR(D, -pos);
if (pos > 0) return -1; /* Undefined. */
}
return -2; /* Unused or out of range. */
}
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
int dasm_checkstep(Dst_DECL, int secmatch)
{
dasm_State *D = Dst_REF;
if (D->status == DASM_S_OK) {
int i;
for (i = 1; i <= 9; i++) {
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
D->lglabels[i] = 0;
}
}
if (D->status == DASM_S_OK && secmatch >= 0 &&
D->section != &D->sections[secmatch])
D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
return D->status;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,83 +0,0 @@
/*
** DynASM encoding engine prototypes.
** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#ifndef _DASM_PROTO_H
#define _DASM_PROTO_H
#include <stddef.h>
#include <stdarg.h>
#define DASM_IDENT "DynASM 1.3.0"
#define DASM_VERSION 10300 /* 1.3.0 */
#ifndef Dst_DECL
#define Dst_DECL dasm_State **Dst
#endif
#ifndef Dst_REF
#define Dst_REF (*Dst)
#endif
#ifndef DASM_FDEF
#define DASM_FDEF extern
#endif
#ifndef DASM_M_GROW
#define DASM_M_GROW(ctx, t, p, sz, need) \
do { \
size_t _sz = (sz), _need = (need); \
if (_sz < _need) { \
if (_sz < 16) _sz = 16; \
while (_sz < _need) _sz += _sz; \
(p) = (t *)realloc((p), _sz); \
if ((p) == NULL) exit(1); \
(sz) = _sz; \
} \
} while(0)
#endif
#ifndef DASM_M_FREE
#define DASM_M_FREE(ctx, p, sz) free(p)
#endif
/* Internal DynASM encoder state. */
typedef struct dasm_State dasm_State;
/* Initialize and free DynASM state. */
DASM_FDEF void dasm_init(Dst_DECL, int maxsection);
DASM_FDEF void dasm_free(Dst_DECL);
/* Setup global array. Must be called before dasm_setup(). */
DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl);
/* Grow PC label array. Can be called after dasm_setup(), too. */
DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc);
/* Setup encoder. */
DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist);
/* Feed encoder with actions. Calls are generated by pre-processor. */
DASM_FDEF void dasm_put(Dst_DECL, int start, ...);
/* Link sections and return the resulting size. */
DASM_FDEF int dasm_link(Dst_DECL, size_t *szp);
/* Encode sections into buffer. */
DASM_FDEF int dasm_encode(Dst_DECL, void *buffer);
/* Get PC label offset. */
DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc);
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch);
#else
#define dasm_checkstep(a, b) 0
#endif
#endif /* _DASM_PROTO_H */

View File

@ -1,12 +0,0 @@
------------------------------------------------------------------------------
-- DynASM x64 module.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- See dynasm.lua for full copyright notice.
------------------------------------------------------------------------------
-- This module just sets 64 bit mode for the combined x86/x64 module.
-- All the interesting stuff is there.
------------------------------------------------------------------------------
x64 = true -- Using a global is an ugly, but effective solution.
return require("dasm_x86")

View File

@ -1,472 +0,0 @@
/*
** DynASM x86 encoding engine.
** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define DASM_ARCH "x86"
#ifndef DASM_EXTERN
#define DASM_EXTERN(a,b,c,d) 0
#endif
/* Action definitions. DASM_STOP must be 255. */
enum {
DASM_DISP = 233,
DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB,
DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC,
DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN,
DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP
};
/* Maximum number of section buffer positions for a single dasm_put() call. */
#define DASM_MAXSECPOS 25
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
#define DASM_S_OK 0x00000000
#define DASM_S_NOMEM 0x01000000
#define DASM_S_PHASE 0x02000000
#define DASM_S_MATCH_SEC 0x03000000
#define DASM_S_RANGE_I 0x11000000
#define DASM_S_RANGE_SEC 0x12000000
#define DASM_S_RANGE_LG 0x13000000
#define DASM_S_RANGE_PC 0x14000000
#define DASM_S_RANGE_VREG 0x15000000
#define DASM_S_UNDEF_L 0x21000000
#define DASM_S_UNDEF_PC 0x22000000
/* Macros to convert positions (8 bit section + 24 bit index). */
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
#define DASM_SEC2POS(sec) ((sec)<<24)
#define DASM_POS2SEC(pos) ((pos)>>24)
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
/* Action list type. */
typedef const unsigned char *dasm_ActList;
/* Per-section structure. */
typedef struct dasm_Section {
int *rbuf; /* Biased buffer pointer (negative section bias). */
int *buf; /* True buffer pointer. */
size_t bsize; /* Buffer size in bytes. */
int pos; /* Biased buffer position. */
int epos; /* End of biased buffer position - max single put. */
int ofs; /* Byte offset into section. */
} dasm_Section;
/* Core structure holding the DynASM encoding state. */
struct dasm_State {
size_t psize; /* Allocated size of this structure. */
dasm_ActList actionlist; /* Current actionlist pointer. */
int *lglabels; /* Local/global chain/pos ptrs. */
size_t lgsize;
int *pclabels; /* PC label chains/pos ptrs. */
size_t pcsize;
void **globals; /* Array of globals (bias -10). */
dasm_Section *section; /* Pointer to active section. */
size_t codesize; /* Total size of all code sections. */
int maxsection; /* 0 <= sectionidx < maxsection. */
int status; /* Status code. */
dasm_Section sections[1]; /* All sections. Alloc-extended. */
};
/* The size of the core structure depends on the max. number of sections. */
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
/* Initialize DynASM state. */
void dasm_init(Dst_DECL, int maxsection)
{
dasm_State *D;
size_t psz = 0;
int i;
Dst_REF = NULL;
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
D = Dst_REF;
D->psize = psz;
D->lglabels = NULL;
D->lgsize = 0;
D->pclabels = NULL;
D->pcsize = 0;
D->globals = NULL;
D->maxsection = maxsection;
for (i = 0; i < maxsection; i++) {
D->sections[i].buf = NULL; /* Need this for pass3. */
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
D->sections[i].bsize = 0;
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
}
}
/* Free DynASM state. */
void dasm_free(Dst_DECL)
{
dasm_State *D = Dst_REF;
int i;
for (i = 0; i < D->maxsection; i++)
if (D->sections[i].buf)
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
DASM_M_FREE(Dst, D, D->psize);
}
/* Setup global label array. Must be called before dasm_setup(). */
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
{
dasm_State *D = Dst_REF;
D->globals = gl - 10; /* Negative bias to compensate for locals. */
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
}
/* Grow PC label array. Can be called after dasm_setup(), too. */
void dasm_growpc(Dst_DECL, unsigned int maxpc)
{
dasm_State *D = Dst_REF;
size_t osz = D->pcsize;
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
}
/* Setup encoder. */
void dasm_setup(Dst_DECL, const void *actionlist)
{
dasm_State *D = Dst_REF;
int i;
D->actionlist = (dasm_ActList)actionlist;
D->status = DASM_S_OK;
D->section = &D->sections[0];
memset((void *)D->lglabels, 0, D->lgsize);
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
for (i = 0; i < D->maxsection; i++) {
D->sections[i].pos = DASM_SEC2POS(i);
D->sections[i].ofs = 0;
}
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) { \
D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0)
#define CKPL(kind, st) \
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0)
#else
#define CK(x, st) ((void)0)
#define CKPL(kind, st) ((void)0)
#endif
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
void dasm_put(Dst_DECL, int start, ...)
{
va_list ap;
dasm_State *D = Dst_REF;
dasm_ActList p = D->actionlist + start;
dasm_Section *sec = D->section;
int pos = sec->pos, ofs = sec->ofs, mrm = 4;
int *b;
if (pos >= sec->epos) {
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
}
b = sec->rbuf;
b[pos++] = start;
va_start(ap, start);
while (1) {
int action = *p++;
if (action < DASM_DISP) {
ofs++;
} else if (action <= DASM_REL_A) {
int n = va_arg(ap, int);
b[pos++] = n;
switch (action) {
case DASM_DISP:
if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; }
case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob;
case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */
case DASM_IMM_D: ofs += 4; break;
case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob;
case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break;
case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob;
case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break;
case DASM_SPACE: p++; ofs += n; break;
case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */
case DASM_VREG: CK((n&-8) == 0 && (n != 4 || (*p&1) == 0), RANGE_VREG);
if (*p++ == 1 && *p == DASM_DISP) mrm = n;
continue;
}
mrm = 4;
} else {
int *pl, n;
switch (action) {
case DASM_REL_LG:
case DASM_IMM_LG:
n = *p++; pl = D->lglabels + n;
/* Bkwd rel or global. */
if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
pl -= 246; n = *pl;
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
goto linkrel;
case DASM_REL_PC:
case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
putrel:
n = *pl;
if (n < 0) { /* Label exists. Get label pos and store it. */
b[pos] = -n;
} else {
linkrel:
b[pos] = n; /* Else link to rel chain, anchored at label. */
*pl = pos;
}
pos++;
ofs += 4; /* Maximum offset needed. */
if (action == DASM_REL_LG || action == DASM_REL_PC)
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel;
case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
putlabel:
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; }
*pl = -pos; /* Label exists now. */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_ALIGN:
ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_EXTERN: p += 2; ofs += 4; break;
case DASM_ESC: p++; ofs++; break;
case DASM_MARK: mrm = p[-2]; break;
case DASM_SECTION:
n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n];
case DASM_STOP: goto stop;
}
}
}
stop:
va_end(ap);
sec->pos = pos;
sec->ofs = ofs;
}
#undef CK
/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */
int dasm_link(Dst_DECL, size_t *szp)
{
dasm_State *D = Dst_REF;
int secnum;
int ofs = 0;
#ifdef DASM_CHECKS
*szp = 0;
if (D->status != DASM_S_OK) return D->status;
{
int pc;
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
}
#endif
{ /* Handle globals not defined in this translation unit. */
int idx;
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
int n = D->lglabels[idx];
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
}
}
/* Combine all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->rbuf;
int pos = DASM_SEC2POS(secnum);
int lastpos = sec->pos;
while (pos != lastpos) {
dasm_ActList p = D->actionlist + b[pos++];
while (1) {
int op, action = *p++;
switch (action) {
case DASM_REL_LG: p++; op = p[-3]; goto rel_pc;
case DASM_REL_PC: op = p[-2]; rel_pc: {
int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0);
if (shrink) { /* Shrinkable branch opcode? */
int lofs, lpos = b[pos];
if (lpos < 0) goto noshrink; /* Ext global? */
lofs = *DASM_POS2PTR(D, lpos);
if (lpos > pos) { /* Fwd label: add cumulative section offsets. */
int i;
for (i = secnum; i < DASM_POS2SEC(lpos); i++)
lofs += D->sections[i].ofs;
} else {
lofs -= ofs; /* Bkwd label: unfix offset. */
}
lofs -= b[pos+1]; /* Short branch ok? */
if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */
else { noshrink: shrink = 0; } /* No, cannot shrink op. */
}
b[pos+1] = shrink;
pos += 2;
break;
}
case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++;
case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W:
case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB:
case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break;
case DASM_LABEL_LG: p++;
case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */
case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */
case DASM_EXTERN: p += 2; break;
case DASM_ESC: p++; break;
case DASM_MARK: break;
case DASM_SECTION: case DASM_STOP: goto stop;
}
}
stop: (void)0;
}
ofs += sec->ofs; /* Next section starts right after current section. */
}
D->codesize = ofs; /* Total size of all code sections */
*szp = ofs;
return DASM_S_OK;
}
#define dasmb(x) *cp++ = (unsigned char)(x)
#ifndef DASM_ALIGNED_WRITES
#define dasmw(x) \
do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0)
#define dasmd(x) \
do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0)
#else
#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0)
#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0)
#endif
/* Pass 3: Encode sections. */
int dasm_encode(Dst_DECL, void *buffer)
{
dasm_State *D = Dst_REF;
unsigned char *base = (unsigned char *)buffer;
unsigned char *cp = base;
int secnum;
/* Encode all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->buf;
int *endb = sec->rbuf + sec->pos;
while (b != endb) {
dasm_ActList p = D->actionlist + *b++;
unsigned char *mark = NULL;
while (1) {
int action = *p++;
int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0;
switch (action) {
case DASM_DISP: if (!mark) mark = cp; {
unsigned char *mm = mark;
if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL;
if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7;
if (mrm != 5) { mm[-1] -= 0x80; break; } }
if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40;
}
case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break;
case DASM_IMM_DB: if (((n+128)&-256) == 0) {
db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb;
} else mark = NULL;
case DASM_IMM_D: wd: dasmd(n); break;
case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL;
case DASM_IMM_W: dasmw(n); break;
case DASM_VREG: { int t = *p++; if (t >= 2) n<<=3; cp[-1] |= n; break; }
case DASM_REL_LG: p++; if (n >= 0) goto rel_pc;
b++; n = (int)(ptrdiff_t)D->globals[-n];
case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */
case DASM_REL_PC: rel_pc: {
int shrink = *b++;
int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; }
n = *pb - ((int)(cp-base) + 4-shrink);
if (shrink == 0) goto wd;
if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb;
goto wb;
}
case DASM_IMM_LG:
p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; }
case DASM_IMM_PC: {
int *pb = DASM_POS2PTR(D, n);
n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base);
goto wd;
}
case DASM_LABEL_LG: {
int idx = *p++;
if (idx >= 10)
D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n));
break;
}
case DASM_LABEL_PC: case DASM_SETLABEL: break;
case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; }
case DASM_ALIGN:
n = *p++;
while (((cp-base) & n)) *cp++ = 0x90; /* nop */
break;
case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd;
case DASM_MARK: mark = cp; break;
case DASM_ESC: action = *p++;
default: *cp++ = action; break;
case DASM_SECTION: case DASM_STOP: goto stop;
}
}
stop: (void)0;
}
}
if (base + D->codesize != cp) /* Check for phase errors. */
return DASM_S_PHASE;
return DASM_S_OK;
}
/* Get PC label offset. */
int dasm_getpclabel(Dst_DECL, unsigned int pc)
{
dasm_State *D = Dst_REF;
if (pc*sizeof(int) < D->pcsize) {
int pos = D->pclabels[pc];
if (pos < 0) return *DASM_POS2PTR(D, -pos);
if (pos > 0) return -1; /* Undefined. */
}
return -2; /* Unused or out of range. */
}
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
int dasm_checkstep(Dst_DECL, int secmatch)
{
dasm_State *D = Dst_REF;
if (D->status == DASM_S_OK) {
int i;
for (i = 1; i <= 9; i++) {
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; }
D->lglabels[i] = 0;
}
}
if (D->status == DASM_S_OK && secmatch >= 0 &&
D->section != &D->sections[secmatch])
D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections);
return D->status;
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,167 +0,0 @@
/*
** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#ifndef lauxlib_h
#define lauxlib_h
#include <stddef.h>
#include <stdio.h>
#include "lua.h"
#define luaL_getn(L,i) ((int)lua_objlen(L, i))
#define luaL_setn(L,i,j) ((void)0) /* no op! */
/* extra error code for `luaL_load' */
#define LUA_ERRFILE (LUA_ERRERR+1)
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
const luaL_Reg *l);
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
const char *def, size_t *l);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
lua_Integer def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
const char *const lst[]);
LUALIB_API int (luaL_ref) (lua_State *L, int t);
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
const char *name);
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);
LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
const char *fname, int szhint);
/* From Lua 5.2. */
LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname);
LUALIB_API int luaL_execresult(lua_State *L, int stat);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
const char *name, const char *mode);
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
int level);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define luaL_argcheck(L, cond,numarg,extramsg) \
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
typedef struct luaL_Buffer {
char *p; /* current position in buffer */
int lvl; /* number of strings in the stack (level) */
lua_State *L;
char buffer[LUAL_BUFFERSIZE];
} luaL_Buffer;
#define luaL_addchar(B,c) \
((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
(*(B)->p++ = (char)(c)))
/* compatibility only */
#define luaL_putchar(B,c) luaL_addchar(B,c)
#define luaL_addsize(B,n) ((B)->p += (n))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
/* }====================================================== */
/* compatibility with ref system */
/* pre-defined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
(lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))
#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref))
#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref))
#define luaL_reg luaL_Reg
#endif

View File

@ -1,393 +0,0 @@
/*
** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $
** Lua - An Extensible Extension Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
*/
#ifndef lua_h
#define lua_h
#include <stdarg.h>
#include <stddef.h>
#include "luaconf.h"
#define LUA_VERSION "Lua 5.1"
#define LUA_RELEASE "Lua 5.1.4"
#define LUA_VERSION_NUM 501
#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
/* mark for precompiled code (`<esc>Lua') */
#define LUA_SIGNATURE "\033Lua"
/* option for multiple returns in `lua_pcall' and `lua_call' */
#define LUA_MULTRET (-1)
/*
** pseudo-indices
*/
#define LUA_REGISTRYINDEX (-10000)
#define LUA_ENVIRONINDEX (-10001)
#define LUA_GLOBALSINDEX (-10002)
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))
/* thread status; 0 is OK */
#define LUA_YIELD 1
#define LUA_ERRRUN 2
#define LUA_ERRSYNTAX 3
#define LUA_ERRMEM 4
#define LUA_ERRERR 5
typedef struct lua_State lua_State;
typedef int (*lua_CFunction) (lua_State *L);
/*
** functions that read/write blocks when loading/dumping Lua chunks
*/
typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
/*
** prototype for memory-allocation functions
*/
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
/*
** basic types
*/
#define LUA_TNONE (-1)
#define LUA_TNIL 0
#define LUA_TBOOLEAN 1
#define LUA_TLIGHTUSERDATA 2
#define LUA_TNUMBER 3
#define LUA_TSTRING 4
#define LUA_TTABLE 5
#define LUA_TFUNCTION 6
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
/* minimum Lua stack available to a C function */
#define LUA_MINSTACK 20
/*
** generic extra include file
*/
#if defined(LUA_USER_H)
#include LUA_USER_H
#endif
/* type of numbers in Lua */
typedef LUA_NUMBER lua_Number;
/* type for integer functions */
typedef LUA_INTEGER lua_Integer;
/*
** state manipulation
*/
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
/*
** basic stack manipulation
*/
LUA_API int (lua_gettop) (lua_State *L);
LUA_API void (lua_settop) (lua_State *L, int idx);
LUA_API void (lua_pushvalue) (lua_State *L, int idx);
LUA_API void (lua_remove) (lua_State *L, int idx);
LUA_API void (lua_insert) (lua_State *L, int idx);
LUA_API void (lua_replace) (lua_State *L, int idx);
LUA_API int (lua_checkstack) (lua_State *L, int sz);
LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
/*
** access functions (stack -> C)
*/
LUA_API int (lua_isnumber) (lua_State *L, int idx);
LUA_API int (lua_isstring) (lua_State *L, int idx);
LUA_API int (lua_iscfunction) (lua_State *L, int idx);
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
LUA_API int (lua_type) (lua_State *L, int idx);
LUA_API const char *(lua_typename) (lua_State *L, int tp);
LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2);
LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2);
LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx);
LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx);
LUA_API int (lua_toboolean) (lua_State *L, int idx);
LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
LUA_API size_t (lua_objlen) (lua_State *L, int idx);
LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
LUA_API void *(lua_touserdata) (lua_State *L, int idx);
LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
LUA_API const void *(lua_topointer) (lua_State *L, int idx);
/*
** push functions (C -> stack)
*/
LUA_API void (lua_pushnil) (lua_State *L);
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l);
LUA_API void (lua_pushstring) (lua_State *L, const char *s);
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
va_list argp);
LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
LUA_API void (lua_pushboolean) (lua_State *L, int b);
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
LUA_API int (lua_pushthread) (lua_State *L);
/*
** get functions (Lua -> stack)
*/
LUA_API void (lua_gettable) (lua_State *L, int idx);
LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_rawget) (lua_State *L, int idx);
LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n);
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
LUA_API void (lua_getfenv) (lua_State *L, int idx);
/*
** set functions (stack -> Lua)
*/
LUA_API void (lua_settable) (lua_State *L, int idx);
LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_rawset) (lua_State *L, int idx);
LUA_API void (lua_rawseti) (lua_State *L, int idx, int n);
LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
LUA_API int (lua_setfenv) (lua_State *L, int idx);
/*
** `load' and `call' functions (load and run Lua code)
*/
LUA_API void (lua_call) (lua_State *L, int nargs, int nresults);
LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
const char *chunkname);
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
/*
** coroutine functions
*/
LUA_API int (lua_yield) (lua_State *L, int nresults);
LUA_API int (lua_resume) (lua_State *L, int narg);
LUA_API int (lua_status) (lua_State *L);
/*
** garbage-collection function and options
*/
#define LUA_GCSTOP 0
#define LUA_GCRESTART 1
#define LUA_GCCOLLECT 2
#define LUA_GCCOUNT 3
#define LUA_GCCOUNTB 4
#define LUA_GCSTEP 5
#define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7
LUA_API int (lua_gc) (lua_State *L, int what, int data);
/*
** miscellaneous functions
*/
LUA_API int (lua_error) (lua_State *L);
LUA_API int (lua_next) (lua_State *L, int idx);
LUA_API void (lua_concat) (lua_State *L, int n);
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define lua_pop(L,n) lua_settop(L, -(n)-1)
#define lua_newtable(L) lua_createtable(L, 0, 0)
#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
#define lua_strlen(L,i) lua_objlen(L, (i))
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
#define lua_pushliteral(L, s) \
lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s))
#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
/*
** compatibility macros and functions
*/
#define lua_open() luaL_newstate()
#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX)
#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0)
#define lua_Chunkreader lua_Reader
#define lua_Chunkwriter lua_Writer
/* hack */
LUA_API void lua_setlevel (lua_State *from, lua_State *to);
/*
** {======================================================================
** Debug API
** =======================================================================
*/
/*
** Event codes
*/
#define LUA_HOOKCALL 0
#define LUA_HOOKRET 1
#define LUA_HOOKLINE 2
#define LUA_HOOKCOUNT 3
#define LUA_HOOKTAILRET 4
/*
** Event masks
*/
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
#define LUA_MASKRET (1 << LUA_HOOKRET)
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debuger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar);
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n);
LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n);
LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
LUA_API lua_Hook lua_gethook (lua_State *L);
LUA_API int lua_gethookmask (lua_State *L);
LUA_API int lua_gethookcount (lua_State *L);
/* From Lua 5.2. */
LUA_API void *lua_upvalueid (lua_State *L, int idx, int n);
LUA_API void lua_upvaluejoin (lua_State *L, int idx1, int n1, int idx2, int n2);
LUA_API int lua_loadx (lua_State *L, lua_Reader reader, void *dt,
const char *chunkname, const char *mode);
struct lua_Debug {
int event;
const char *name; /* (n) */
const char *namewhat; /* (n) `global', `local', `field', `method' */
const char *what; /* (S) `Lua', `C', `main', `tail' */
const char *source; /* (S) */
int currentline; /* (l) */
int nups; /* (u) number of upvalues */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
char short_src[LUA_IDSIZE]; /* (S) */
/* private part */
int i_ci; /* active function */
};
/* }====================================================================== */
/******************************************************************************
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#endif

View File

@ -1,9 +0,0 @@
// C++ wrapper for LuaJIT header files.
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "luajit.h"
}

View File

@ -1,156 +0,0 @@
/*
** Configuration header.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef luaconf_h
#define luaconf_h
#ifndef WINVER
#define WINVER 0x0501
#endif
#include <limits.h>
#include <stddef.h>
/* Default path for loading Lua and C modules with require(). */
#if defined(_WIN32)
/*
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
*/
#define LUA_LDIR "!\\lua\\"
#define LUA_CDIR "!\\"
#define LUA_PATH_DEFAULT \
".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;"
#define LUA_CPATH_DEFAULT \
".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
#else
/*
** Note to distribution maintainers: do NOT patch the following lines!
** Please read ../doc/install.html#distro and pass PREFIX=/usr instead.
*/
#ifndef LUA_MULTILIB
#define LUA_MULTILIB "lib"
#endif
#ifndef LUA_LMULTILIB
#define LUA_LMULTILIB "lib"
#endif
#define LUA_LROOT "/usr/local"
#define LUA_LUADIR "/lua/5.1/"
#define LUA_LJDIR "/luajit-2.0.5/"
#ifdef LUA_ROOT
#define LUA_JROOT LUA_ROOT
#define LUA_RLDIR LUA_ROOT "/share" LUA_LUADIR
#define LUA_RCDIR LUA_ROOT "/" LUA_MULTILIB LUA_LUADIR
#define LUA_RLPATH ";" LUA_RLDIR "?.lua;" LUA_RLDIR "?/init.lua"
#define LUA_RCPATH ";" LUA_RCDIR "?.so"
#else
#define LUA_JROOT LUA_LROOT
#define LUA_RLPATH
#define LUA_RCPATH
#endif
#define LUA_JPATH ";" LUA_JROOT "/share" LUA_LJDIR "?.lua"
#define LUA_LLDIR LUA_LROOT "/share" LUA_LUADIR
#define LUA_LCDIR LUA_LROOT "/" LUA_LMULTILIB LUA_LUADIR
#define LUA_LLPATH ";" LUA_LLDIR "?.lua;" LUA_LLDIR "?/init.lua"
#define LUA_LCPATH1 ";" LUA_LCDIR "?.so"
#define LUA_LCPATH2 ";" LUA_LCDIR "loadall.so"
#define LUA_PATH_DEFAULT "./?.lua" LUA_JPATH LUA_LLPATH LUA_RLPATH
#define LUA_CPATH_DEFAULT "./?.so" LUA_LCPATH1 LUA_RCPATH LUA_LCPATH2
#endif
/* Environment variable names for path overrides and initialization code. */
#define LUA_PATH "LUA_PATH"
#define LUA_CPATH "LUA_CPATH"
#define LUA_INIT "LUA_INIT"
/* Special file system characters. */
#if defined(_WIN32)
#define LUA_DIRSEP "\\"
#else
#define LUA_DIRSEP "/"
#endif
#define LUA_PATHSEP ";"
#define LUA_PATH_MARK "?"
#define LUA_EXECDIR "!"
#define LUA_IGMARK "-"
#define LUA_PATH_CONFIG \
LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" \
LUA_EXECDIR "\n" LUA_IGMARK
/* Quoting in error messages. */
#define LUA_QL(x) "'" x "'"
#define LUA_QS LUA_QL("%s")
/* Various tunables. */
#define LUAI_MAXSTACK 65500 /* Max. # of stack slots for a thread (<64K). */
#define LUAI_MAXCSTACK 8000 /* Max. # of stack slots for a C func (<10K). */
#define LUAI_GCPAUSE 200 /* Pause GC until memory is at 200%. */
#define LUAI_GCMUL 200 /* Run GC at 200% of allocation speed. */
#define LUA_MAXCAPTURES 32 /* Max. pattern captures. */
/* Compatibility with older library function names. */
#define LUA_COMPAT_MOD /* OLD: math.mod, NEW: math.fmod */
#define LUA_COMPAT_GFIND /* OLD: string.gfind, NEW: string.gmatch */
/* Configuration for the frontend (the luajit executable). */
#if defined(luajit_c)
#define LUA_PROGNAME "luajit" /* Fallback frontend name. */
#define LUA_PROMPT "> " /* Interactive prompt. */
#define LUA_PROMPT2 ">> " /* Continuation prompt. */
#define LUA_MAXINPUT 512 /* Max. input line length. */
#endif
/* Note: changing the following defines breaks the Lua 5.1 ABI. */
#define LUA_INTEGER ptrdiff_t
#define LUA_IDSIZE 60 /* Size of lua_Debug.short_src. */
/*
** Size of lauxlib and io.* on-stack buffers. Weird workaround to avoid using
** unreasonable amounts of stack space, but still retain ABI compatibility.
** Blame Lua for depending on BUFSIZ in the ABI, blame **** for wrecking it.
*/
#define LUAL_BUFFERSIZE (BUFSIZ > 16384 ? 8192 : BUFSIZ)
/* The following defines are here only for compatibility with luaconf.h
** from the standard Lua distribution. They must not be changed for LuaJIT.
*/
#define LUA_NUMBER_DOUBLE
#define LUA_NUMBER double
#define LUAI_UACNUMBER double
#define LUA_NUMBER_SCAN "%lf"
#define LUA_NUMBER_FMT "%.14g"
#define lua_number2str(s, n) sprintf((s), LUA_NUMBER_FMT, (n))
#define LUAI_MAXNUMBER2STR 32
#define LUA_INTFRMLEN "l"
#define LUA_INTFRM_T long
/* Linkage of public API functions. */
#if defined(LUA_BUILD_AS_DLL)
#if defined(LUA_CORE) || defined(LUA_LIB)
#define LUA_API __declspec(dllexport)
#else
#define LUA_API __declspec(dllimport)
#endif
#else
#define LUA_API extern
#endif
#define LUALIB_API LUA_API
/* Support for internal assertions. */
#if defined(LUA_USE_ASSERT) || defined(LUA_USE_APICHECK)
#include <assert.h>
#endif
#ifdef LUA_USE_ASSERT
#define lua_assert(x) assert(x)
#endif
#ifdef LUA_USE_APICHECK
#define luai_apicheck(L, o) { (void)L; assert(o); }
#else
#define luai_apicheck(L, o) { (void)L; }
#endif
#endif

View File

@ -1,70 +0,0 @@
/*
** LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/
**
** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
** "Software"), to deal in the Software without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Software, and to
** permit persons to whom the Software is furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**
** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
*/
#ifndef _LUAJIT_H
#define _LUAJIT_H
#include "lua.h"
#define LUAJIT_VERSION "LuaJIT 2.0.5"
#define LUAJIT_VERSION_NUM 20005 /* Version 2.0.5 = 02.00.05. */
#define LUAJIT_VERSION_SYM luaJIT_version_2_0_5
#define LUAJIT_COPYRIGHT "Copyright (C) 2005-2017 Mike Pall"
#define LUAJIT_URL "http://luajit.org/"
/* Modes for luaJIT_setmode. */
#define LUAJIT_MODE_MASK 0x00ff
enum {
LUAJIT_MODE_ENGINE, /* Set mode for whole JIT engine. */
LUAJIT_MODE_DEBUG, /* Set debug mode (idx = level). */
LUAJIT_MODE_FUNC, /* Change mode for a function. */
LUAJIT_MODE_ALLFUNC, /* Recurse into subroutine protos. */
LUAJIT_MODE_ALLSUBFUNC, /* Change only the subroutines. */
LUAJIT_MODE_TRACE, /* Flush a compiled trace. */
LUAJIT_MODE_WRAPCFUNC = 0x10, /* Set wrapper mode for C function calls. */
LUAJIT_MODE_MAX
};
/* Flags or'ed in to the mode. */
#define LUAJIT_MODE_OFF 0x0000 /* Turn feature off. */
#define LUAJIT_MODE_ON 0x0100 /* Turn feature on. */
#define LUAJIT_MODE_FLUSH 0x0200 /* Flush JIT-compiled code. */
/* LuaJIT public C API. */
/* Control the JIT engine. */
LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode);
/* Enforce (dynamic) linker error for version mismatches. Call from main. */
LUA_API void LUAJIT_VERSION_SYM(void);
#endif

View File

@ -1,43 +0,0 @@
/*
** Standard library header.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LUALIB_H
#define _LUALIB_H
#include "lua.h"
#define LUA_FILEHANDLE "FILE*"
#define LUA_COLIBNAME "coroutine"
#define LUA_MATHLIBNAME "math"
#define LUA_STRLIBNAME "string"
#define LUA_TABLIBNAME "table"
#define LUA_IOLIBNAME "io"
#define LUA_OSLIBNAME "os"
#define LUA_LOADLIBNAME "package"
#define LUA_DBLIBNAME "debug"
#define LUA_BITLIBNAME "bit"
#define LUA_JITLIBNAME "jit"
#define LUA_FFILIBNAME "ffi"
LUALIB_API int luaopen_base(lua_State *L);
LUALIB_API int luaopen_math(lua_State *L);
LUALIB_API int luaopen_string(lua_State *L);
LUALIB_API int luaopen_table(lua_State *L);
LUALIB_API int luaopen_io(lua_State *L);
LUALIB_API int luaopen_os(lua_State *L);
LUALIB_API int luaopen_package(lua_State *L);
LUALIB_API int luaopen_debug(lua_State *L);
LUALIB_API int luaopen_bit(lua_State *L);
LUALIB_API int luaopen_jit(lua_State *L);
LUALIB_API int luaopen_ffi(lua_State *L);
LUALIB_API void luaL_openlibs(lua_State *L);
#ifndef lua_assert
#define lua_assert(x) ((void)0)
#endif
#endif

View File

@ -1,4 +0,0 @@
The files in this directory are only used during the build process of LuaJIT.
For cross-compilation, they must be executed on the host, not on the target.
These files should NOT be installed!

View File

@ -1,516 +0,0 @@
/*
** LuaJIT VM builder.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** This is a tool to build the hand-tuned assembler code required for
** LuaJIT's bytecode interpreter. It supports a variety of output formats
** to feed different toolchains (see usage() below).
**
** This tool is not particularly optimized because it's only used while
** _building_ LuaJIT. There's no point in distributing or installing it.
** Only the object code generated by this tool is linked into LuaJIT.
**
** Caveat: some memory is not free'd, error handling is lazy.
** It's a one-shot tool -- any effort fixing this would be wasted.
*/
#include "buildvm.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_bc.h"
#include "lj_ir.h"
#include "lj_ircall.h"
#include "lj_frame.h"
#include "lj_dispatch.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_ccall.h"
#endif
#include "luajit.h"
#if defined(_WIN32)
#include <fcntl.h>
#include <io.h>
#endif
/* ------------------------------------------------------------------------ */
/* DynASM glue definitions. */
#define Dst ctx
#define Dst_DECL BuildCtx *ctx
#define Dst_REF (ctx->D)
#define DASM_CHECKS 1
#include "../dynasm/dasm_proto.h"
/* Glue macros for DynASM. */
static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type);
#define DASM_EXTERN(ctx, addr, idx, type) \
collect_reloc(ctx, addr, idx, type)
/* ------------------------------------------------------------------------ */
/* Avoid trouble if cross-compiling for an x86 target. Speed doesn't matter. */
#define DASM_ALIGNED_WRITES 1
/* Embed architecture-specific DynASM encoder. */
#if LJ_TARGET_X86ORX64
#include "../dynasm/dasm_x86.h"
#elif LJ_TARGET_ARM
#include "../dynasm/dasm_arm.h"
#elif LJ_TARGET_PPC
#include "../dynasm/dasm_ppc.h"
#elif LJ_TARGET_PPCSPE
#include "../dynasm/dasm_ppc.h"
#elif LJ_TARGET_MIPS
#include "../dynasm/dasm_mips.h"
#else
#error "No support for this architecture (yet)"
#endif
/* Embed generated architecture-specific backend. */
#include "buildvm_arch.h"
/* ------------------------------------------------------------------------ */
void owrite(BuildCtx *ctx, const void *ptr, size_t sz)
{
if (fwrite(ptr, 1, sz, ctx->fp) != sz) {
fprintf(stderr, "Error: cannot write to output file: %s\n",
strerror(errno));
exit(1);
}
}
/* ------------------------------------------------------------------------ */
/* Emit code as raw bytes. Only used for DynASM debugging. */
static void emit_raw(BuildCtx *ctx)
{
owrite(ctx, ctx->code, ctx->codesz);
}
/* -- Build machine code -------------------------------------------------- */
static const char *sym_decorate(BuildCtx *ctx,
const char *prefix, const char *suffix)
{
char name[256];
char *p;
#if LJ_64
const char *symprefix = ctx->mode == BUILD_machasm ? "_" : "";
#elif LJ_TARGET_XBOX360
const char *symprefix = "";
#else
const char *symprefix = ctx->mode != BUILD_elfasm ? "_" : "";
#endif
sprintf(name, "%s%s%s", symprefix, prefix, suffix);
p = strchr(name, '@');
if (p) {
#if LJ_TARGET_X86ORX64
if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj))
name[0] = '@';
else
*p = '\0';
#elif (LJ_TARGET_PPC || LJ_TARGET_PPCSPE) && !LJ_TARGET_CONSOLE
/* Keep @plt. */
#else
*p = '\0';
#endif
}
p = (char *)malloc(strlen(name)+1); /* MSVC doesn't like strdup. */
strcpy(p, name);
return p;
}
#define NRELOCSYM (sizeof(extnames)/sizeof(extnames[0])-1)
static int relocmap[NRELOCSYM];
/* Collect external relocations. */
static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type)
{
if (ctx->nreloc >= BUILD_MAX_RELOC) {
fprintf(stderr, "Error: too many relocations, increase BUILD_MAX_RELOC.\n");
exit(1);
}
if (relocmap[idx] < 0) {
relocmap[idx] = ctx->nrelocsym;
ctx->relocsym[ctx->nrelocsym] = sym_decorate(ctx, "", extnames[idx]);
ctx->nrelocsym++;
}
ctx->reloc[ctx->nreloc].ofs = (int32_t)(addr - ctx->code);
ctx->reloc[ctx->nreloc].sym = relocmap[idx];
ctx->reloc[ctx->nreloc].type = type;
ctx->nreloc++;
#if LJ_TARGET_XBOX360
return (int)(ctx->code - addr) + 4; /* Encode symbol offset of .text. */
#else
return 0; /* Encode symbol offset of 0. */
#endif
}
/* Naive insertion sort. Performance doesn't matter here. */
static void sym_insert(BuildCtx *ctx, int32_t ofs,
const char *prefix, const char *suffix)
{
ptrdiff_t i = ctx->nsym++;
while (i > 0) {
if (ctx->sym[i-1].ofs <= ofs)
break;
ctx->sym[i] = ctx->sym[i-1];
i--;
}
ctx->sym[i].ofs = ofs;
ctx->sym[i].name = sym_decorate(ctx, prefix, suffix);
}
/* Build the machine code. */
static int build_code(BuildCtx *ctx)
{
int status;
int i;
/* Initialize DynASM structures. */
ctx->nglob = GLOB__MAX;
ctx->glob = (void **)malloc(ctx->nglob*sizeof(void *));
memset(ctx->glob, 0, ctx->nglob*sizeof(void *));
ctx->nreloc = 0;
ctx->globnames = globnames;
ctx->relocsym = (const char **)malloc(NRELOCSYM*sizeof(const char *));
ctx->nrelocsym = 0;
for (i = 0; i < (int)NRELOCSYM; i++) relocmap[i] = -1;
ctx->dasm_ident = DASM_IDENT;
ctx->dasm_arch = DASM_ARCH;
dasm_init(Dst, DASM_MAXSECTION);
dasm_setupglobal(Dst, ctx->glob, ctx->nglob);
dasm_setup(Dst, build_actionlist);
/* Call arch-specific backend to emit the code. */
ctx->npc = build_backend(ctx);
/* Finalize the code. */
(void)dasm_checkstep(Dst, -1);
if ((status = dasm_link(Dst, &ctx->codesz))) return status;
ctx->code = (uint8_t *)malloc(ctx->codesz);
if ((status = dasm_encode(Dst, (void *)ctx->code))) return status;
/* Allocate symbol table and bytecode offsets. */
ctx->beginsym = sym_decorate(ctx, "", LABEL_PREFIX "vm_asm_begin");
ctx->sym = (BuildSym *)malloc((ctx->npc+ctx->nglob+1)*sizeof(BuildSym));
ctx->nsym = 0;
ctx->bc_ofs = (int32_t *)malloc(ctx->npc*sizeof(int32_t));
/* Collect the opcodes (PC labels). */
for (i = 0; i < ctx->npc; i++) {
int32_t ofs = dasm_getpclabel(Dst, i);
if (ofs < 0) return 0x22000000|i;
ctx->bc_ofs[i] = ofs;
if ((LJ_HASJIT ||
!(i == BC_JFORI || i == BC_JFORL || i == BC_JITERL || i == BC_JLOOP ||
i == BC_IFORL || i == BC_IITERL || i == BC_ILOOP)) &&
(LJ_HASFFI || i != BC_KCDATA))
sym_insert(ctx, ofs, LABEL_PREFIX_BC, bc_names[i]);
}
/* Collect the globals (named labels). */
for (i = 0; i < ctx->nglob; i++) {
const char *gl = globnames[i];
int len = (int)strlen(gl);
if (!ctx->glob[i]) {
fprintf(stderr, "Error: undefined global %s\n", gl);
exit(2);
}
/* Skip the _Z symbols. */
if (!(len >= 2 && gl[len-2] == '_' && gl[len-1] == 'Z'))
sym_insert(ctx, (int32_t)((uint8_t *)(ctx->glob[i]) - ctx->code),
LABEL_PREFIX, globnames[i]);
}
/* Close the address range. */
sym_insert(ctx, (int32_t)ctx->codesz, "", "");
ctx->nsym--;
dasm_free(Dst);
return 0;
}
/* -- Generate VM enums --------------------------------------------------- */
const char *const bc_names[] = {
#define BCNAME(name, ma, mb, mc, mt) #name,
BCDEF(BCNAME)
#undef BCNAME
NULL
};
const char *const ir_names[] = {
#define IRNAME(name, m, m1, m2) #name,
IRDEF(IRNAME)
#undef IRNAME
NULL
};
const char *const irt_names[] = {
#define IRTNAME(name, size) #name,
IRTDEF(IRTNAME)
#undef IRTNAME
NULL
};
const char *const irfpm_names[] = {
#define FPMNAME(name) #name,
IRFPMDEF(FPMNAME)
#undef FPMNAME
NULL
};
const char *const irfield_names[] = {
#define FLNAME(name, ofs) #name,
IRFLDEF(FLNAME)
#undef FLNAME
NULL
};
const char *const ircall_names[] = {
#define IRCALLNAME(cond, name, nargs, kind, type, flags) #name,
IRCALLDEF(IRCALLNAME)
#undef IRCALLNAME
NULL
};
static const char *const trace_errors[] = {
#define TREDEF(name, msg) msg,
#include "lj_traceerr.h"
NULL
};
static const char *lower(char *buf, const char *s)
{
char *p = buf;
while (*s) {
*p++ = (*s >= 'A' && *s <= 'Z') ? *s+0x20 : *s;
s++;
}
*p = '\0';
return buf;
}
/* Emit C source code for bytecode-related definitions. */
static void emit_bcdef(BuildCtx *ctx)
{
int i;
fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_ofs[] = {\n");
for (i = 0; i < ctx->npc; i++) {
if (i != 0)
fprintf(ctx->fp, ",\n");
fprintf(ctx->fp, "%d", ctx->bc_ofs[i]);
}
}
/* Emit VM definitions as Lua code for debug modules. */
static void emit_vmdef(BuildCtx *ctx)
{
char buf[80];
int i;
fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n");
fprintf(ctx->fp, "module(...)\n\n");
fprintf(ctx->fp, "bcnames = \"");
for (i = 0; bc_names[i]; i++) fprintf(ctx->fp, "%-6s", bc_names[i]);
fprintf(ctx->fp, "\"\n\n");
fprintf(ctx->fp, "irnames = \"");
for (i = 0; ir_names[i]; i++) fprintf(ctx->fp, "%-6s", ir_names[i]);
fprintf(ctx->fp, "\"\n\n");
fprintf(ctx->fp, "irfpm = { [0]=");
for (i = 0; irfpm_names[i]; i++)
fprintf(ctx->fp, "\"%s\", ", lower(buf, irfpm_names[i]));
fprintf(ctx->fp, "}\n\n");
fprintf(ctx->fp, "irfield = { [0]=");
for (i = 0; irfield_names[i]; i++) {
char *p;
lower(buf, irfield_names[i]);
p = strchr(buf, '_');
if (p) *p = '.';
fprintf(ctx->fp, "\"%s\", ", buf);
}
fprintf(ctx->fp, "}\n\n");
fprintf(ctx->fp, "ircall = {\n[0]=");
for (i = 0; ircall_names[i]; i++)
fprintf(ctx->fp, "\"%s\",\n", ircall_names[i]);
fprintf(ctx->fp, "}\n\n");
fprintf(ctx->fp, "traceerr = {\n[0]=");
for (i = 0; trace_errors[i]; i++)
fprintf(ctx->fp, "\"%s\",\n", trace_errors[i]);
fprintf(ctx->fp, "}\n\n");
}
/* -- Argument parsing ---------------------------------------------------- */
/* Build mode names. */
static const char *const modenames[] = {
#define BUILDNAME(name) #name,
BUILDDEF(BUILDNAME)
#undef BUILDNAME
NULL
};
/* Print usage information and exit. */
static void usage(void)
{
int i;
fprintf(stderr, LUAJIT_VERSION " VM builder.\n");
fprintf(stderr, LUAJIT_COPYRIGHT ", " LUAJIT_URL "\n");
fprintf(stderr, "Target architecture: " LJ_ARCH_NAME "\n\n");
fprintf(stderr, "Usage: buildvm -m mode [-o outfile] [infiles...]\n\n");
fprintf(stderr, "Available modes:\n");
for (i = 0; i < BUILD__MAX; i++)
fprintf(stderr, " %s\n", modenames[i]);
exit(1);
}
/* Parse the output mode name. */
static BuildMode parsemode(const char *mode)
{
int i;
for (i = 0; modenames[i]; i++)
if (!strcmp(mode, modenames[i]))
return (BuildMode)i;
usage();
return (BuildMode)-1;
}
/* Parse arguments. */
static void parseargs(BuildCtx *ctx, char **argv)
{
const char *a;
int i;
ctx->mode = (BuildMode)-1;
ctx->outname = "-";
for (i = 1; (a = argv[i]) != NULL; i++) {
if (a[0] != '-')
break;
switch (a[1]) {
case '-':
if (a[2]) goto err;
i++;
goto ok;
case '\0':
goto ok;
case 'm':
i++;
if (a[2] || argv[i] == NULL) goto err;
ctx->mode = parsemode(argv[i]);
break;
case 'o':
i++;
if (a[2] || argv[i] == NULL) goto err;
ctx->outname = argv[i];
break;
default: err:
usage();
break;
}
}
ok:
ctx->args = argv+i;
if (ctx->mode == (BuildMode)-1) goto err;
}
int main(int argc, char **argv)
{
BuildCtx ctx_;
BuildCtx *ctx = &ctx_;
int status, binmode;
if (sizeof(void *) != 4*LJ_32+8*LJ_64) {
fprintf(stderr,"Error: pointer size mismatch in cross-build.\n");
fprintf(stderr,"Try: make HOST_CC=\"gcc -m32\" CROSS=...\n\n");
return 1;
}
UNUSED(argc);
parseargs(ctx, argv);
if ((status = build_code(ctx))) {
fprintf(stderr,"Error: DASM error %08x\n", status);
return 1;
}
switch (ctx->mode) {
case BUILD_peobj:
case BUILD_raw:
binmode = 1;
break;
default:
binmode = 0;
break;
}
if (ctx->outname[0] == '-' && ctx->outname[1] == '\0') {
ctx->fp = stdout;
#if defined(_WIN32)
if (binmode)
_setmode(_fileno(stdout), _O_BINARY); /* Yuck. */
#endif
} else if (!(ctx->fp = fopen(ctx->outname, binmode ? "wb" : "w"))) {
fprintf(stderr, "Error: cannot open output file '%s': %s\n",
ctx->outname, strerror(errno));
exit(1);
}
switch (ctx->mode) {
case BUILD_elfasm:
case BUILD_coffasm:
case BUILD_machasm:
emit_asm(ctx);
emit_asm_debug(ctx);
break;
case BUILD_peobj:
emit_peobj(ctx);
break;
case BUILD_raw:
emit_raw(ctx);
break;
case BUILD_bcdef:
emit_bcdef(ctx);
emit_lib(ctx);
break;
case BUILD_vmdef:
emit_vmdef(ctx);
emit_lib(ctx);
break;
case BUILD_ffdef:
case BUILD_libdef:
case BUILD_recdef:
emit_lib(ctx);
break;
case BUILD_folddef:
emit_fold(ctx);
break;
default:
break;
}
fflush(ctx->fp);
if (ferror(ctx->fp)) {
fprintf(stderr, "Error: cannot write to output file: %s\n",
strerror(errno));
exit(1);
}
fclose(ctx->fp);
return 0;
}

View File

@ -1,104 +0,0 @@
/*
** LuaJIT VM builder.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _BUILDVM_H
#define _BUILDVM_H
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "lj_def.h"
#include "lj_arch.h"
/* Hardcoded limits. Increase as needed. */
#define BUILD_MAX_RELOC 200 /* Max. number of relocations. */
#define BUILD_MAX_FOLD 4096 /* Max. number of fold rules. */
/* Prefix for scanned library definitions. */
#define LIBDEF_PREFIX "LJLIB_"
/* Prefix for scanned fold definitions. */
#define FOLDDEF_PREFIX "LJFOLD"
/* Prefixes for generated labels. */
#define LABEL_PREFIX "lj_"
#define LABEL_PREFIX_BC LABEL_PREFIX "BC_"
#define LABEL_PREFIX_FF LABEL_PREFIX "ff_"
#define LABEL_PREFIX_CF LABEL_PREFIX "cf_"
#define LABEL_PREFIX_FFH LABEL_PREFIX "ffh_"
#define LABEL_PREFIX_LIBCF LABEL_PREFIX "lib_cf_"
#define LABEL_PREFIX_LIBINIT LABEL_PREFIX "lib_init_"
/* Forward declaration. */
struct dasm_State;
/* Build modes. */
#define BUILDDEF(_) \
_(elfasm) _(coffasm) _(machasm) _(peobj) _(raw) \
_(bcdef) _(ffdef) _(libdef) _(recdef) _(vmdef) \
_(folddef)
typedef enum {
#define BUILDENUM(name) BUILD_##name,
BUILDDEF(BUILDENUM)
#undef BUILDENUM
BUILD__MAX
} BuildMode;
/* Code relocation. */
typedef struct BuildReloc {
int32_t ofs;
int sym;
int type;
} BuildReloc;
typedef struct BuildSym {
const char *name;
int32_t ofs;
} BuildSym;
/* Build context structure. */
typedef struct BuildCtx {
/* DynASM state pointer. Should be first member. */
struct dasm_State *D;
/* Parsed command line. */
BuildMode mode;
FILE *fp;
const char *outname;
char **args;
/* Code and symbols generated by DynASM. */
uint8_t *code;
size_t codesz;
int npc, nglob, nsym, nreloc, nrelocsym;
void **glob;
BuildSym *sym;
const char **relocsym;
int32_t *bc_ofs;
const char *beginsym;
/* Strings generated by DynASM. */
const char *const *globnames;
const char *dasm_ident;
const char *dasm_arch;
/* Relocations. */
BuildReloc reloc[BUILD_MAX_RELOC];
} BuildCtx;
extern void owrite(BuildCtx *ctx, const void *ptr, size_t sz);
extern void emit_asm(BuildCtx *ctx);
extern void emit_peobj(BuildCtx *ctx);
extern void emit_lib(BuildCtx *ctx);
extern void emit_fold(BuildCtx *ctx);
extern const char *const bc_names[];
extern const char *const ir_names[];
extern const char *const irt_names[];
extern const char *const irfpm_names[];
extern const char *const irfield_names[];
extern const char *const ircall_names[];
#endif

View File

@ -1,314 +0,0 @@
/*
** LuaJIT VM builder: Assembler source code emitter.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include "buildvm.h"
#include "lj_bc.h"
/* ------------------------------------------------------------------------ */
#if LJ_TARGET_X86ORX64
/* Emit bytes piecewise as assembler text. */
static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n)
{
int i;
for (i = 0; i < n; i++) {
if ((i & 15) == 0)
fprintf(ctx->fp, "\t.byte %d", p[i]);
else
fprintf(ctx->fp, ",%d", p[i]);
if ((i & 15) == 15) putc('\n', ctx->fp);
}
if ((n & 15) != 0) putc('\n', ctx->fp);
}
/* Emit relocation */
static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym)
{
switch (ctx->mode) {
case BUILD_elfasm:
if (type)
fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
else
fprintf(ctx->fp, "\t.long %s\n", sym);
break;
case BUILD_coffasm:
fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", sym);
if (type)
fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
else
fprintf(ctx->fp, "\t.long %s\n", sym);
break;
default: /* BUILD_machasm for relative relocations handled below. */
fprintf(ctx->fp, "\t.long %s\n", sym);
break;
}
}
static const char *const jccnames[] = {
"jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja",
"js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg"
};
/* Emit relocation for the incredibly stupid OSX assembler. */
static void emit_asm_reloc_mach(BuildCtx *ctx, uint8_t *cp, int n,
const char *sym)
{
const char *opname = NULL;
if (--n < 0) goto err;
if (cp[n] == 0xe8) {
opname = "call";
} else if (cp[n] == 0xe9) {
opname = "jmp";
} else if (cp[n] >= 0x80 && cp[n] <= 0x8f && n > 0 && cp[n-1] == 0x0f) {
opname = jccnames[cp[n]-0x80];
n--;
} else {
err:
fprintf(stderr, "Error: unsupported opcode for %s symbol relocation.\n",
sym);
exit(1);
}
emit_asm_bytes(ctx, cp, n);
fprintf(ctx->fp, "\t%s %s\n", opname, sym);
}
#else
/* Emit words piecewise as assembler text. */
static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n)
{
int i;
for (i = 0; i < n; i += 4) {
if ((i & 15) == 0)
fprintf(ctx->fp, "\t.long 0x%08x", *(uint32_t *)(p+i));
else
fprintf(ctx->fp, ",0x%08x", *(uint32_t *)(p+i));
if ((i & 15) == 12) putc('\n', ctx->fp);
}
if ((n & 15) != 0) putc('\n', ctx->fp);
}
/* Emit relocation as part of an instruction. */
static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
const char *sym)
{
uint32_t ins;
emit_asm_words(ctx, p, n-4);
ins = *(uint32_t *)(p+n-4);
#if LJ_TARGET_ARM
if ((ins & 0xff000000u) == 0xfa000000u) {
fprintf(ctx->fp, "\tblx %s\n", sym);
} else if ((ins & 0x0e000000u) == 0x0a000000u) {
fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b",
&"eqnecsccmiplvsvchilsgeltgtle"[2*(ins >> 28)], sym);
} else {
fprintf(stderr,
"Error: unsupported opcode %08x for %s symbol relocation.\n",
ins, sym);
exit(1);
}
#elif LJ_TARGET_PPC || LJ_TARGET_PPCSPE
#if LJ_TARGET_PS3
#define TOCPREFIX "."
#else
#define TOCPREFIX ""
#endif
if ((ins >> 26) == 16) {
fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n",
(ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
} else if ((ins >> 26) == 18) {
fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym);
} else {
fprintf(stderr,
"Error: unsupported opcode %08x for %s symbol relocation.\n",
ins, sym);
exit(1);
}
#elif LJ_TARGET_MIPS
fprintf(stderr,
"Error: unsupported opcode %08x for %s symbol relocation.\n",
ins, sym);
exit(1);
#else
#error "missing relocation support for this architecture"
#endif
}
#endif
#if LJ_TARGET_ARM
#define ELFASM_PX "%%"
#else
#define ELFASM_PX "@"
#endif
/* Emit an assembler label. */
static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
{
switch (ctx->mode) {
case BUILD_elfasm:
#if LJ_TARGET_PS3
if (!strncmp(name, "lj_vm_", 6) &&
strcmp(name, ctx->beginsym) &&
!strstr(name, "hook")) {
fprintf(ctx->fp,
"\n\t.globl %s\n"
"\t.section \".opd\",\"aw\"\n"
"%s:\n"
"\t.long .%s,.TOC.@tocbase32\n"
"\t.size %s,8\n"
"\t.previous\n"
"\t.globl .%s\n"
"\t.hidden .%s\n"
"\t.type .%s, " ELFASM_PX "function\n"
"\t.size .%s, %d\n"
".%s:\n",
name, name, name, name, name, name, name, name, size, name);
break;
}
#endif
fprintf(ctx->fp,
"\n\t.globl %s\n"
"\t.hidden %s\n"
"\t.type %s, " ELFASM_PX "%s\n"
"\t.size %s, %d\n"
"%s:\n",
name, name, name, isfunc ? "function" : "object", name, size, name);
break;
case BUILD_coffasm:
fprintf(ctx->fp, "\n\t.globl %s\n", name);
if (isfunc)
fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
fprintf(ctx->fp, "%s:\n", name);
break;
case BUILD_machasm:
fprintf(ctx->fp,
"\n\t.private_extern %s\n"
"\t.no_dead_strip %s\n"
"%s:\n", name, name, name);
break;
default:
break;
}
}
/* Emit alignment. */
static void emit_asm_align(BuildCtx *ctx, int bits)
{
switch (ctx->mode) {
case BUILD_elfasm:
case BUILD_coffasm:
fprintf(ctx->fp, "\t.p2align %d\n", bits);
break;
case BUILD_machasm:
fprintf(ctx->fp, "\t.align %d\n", bits);
break;
default:
break;
}
}
/* ------------------------------------------------------------------------ */
/* Emit assembler source code. */
void emit_asm(BuildCtx *ctx)
{
int i, rel;
fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
fprintf(ctx->fp, "\t.text\n");
emit_asm_align(ctx, 4);
#if LJ_TARGET_PS3
emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0);
#else
emit_asm_label(ctx, ctx->beginsym, 0, 0);
#endif
if (ctx->mode != BUILD_machasm)
fprintf(ctx->fp, ".Lbegin:\n");
#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
/* This should really be moved into buildvm_arm.dasc. */
fprintf(ctx->fp,
".fnstart\n"
".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
".pad #28\n");
#endif
#if LJ_TARGET_MIPS
fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
#endif
for (i = rel = 0; i < ctx->nsym; i++) {
int32_t ofs = ctx->sym[i].ofs;
int32_t next = ctx->sym[i+1].ofs;
#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI
if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
fprintf(ctx->fp,
".globl lj_err_unwind_arm\n"
".personality lj_err_unwind_arm\n"
".fnend\n"
".fnstart\n"
".save {r4, r5, r11, lr}\n"
".setfp r11, sp\n");
#endif
emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
BuildReloc *r = &ctx->reloc[rel];
int n = r->ofs - ofs;
#if LJ_TARGET_X86ORX64
if (ctx->mode == BUILD_machasm && r->type != 0) {
emit_asm_reloc_mach(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
} else {
emit_asm_bytes(ctx, ctx->code+ofs, n);
emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
}
ofs += n+4;
#else
emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
ofs += n;
#endif
rel++;
}
#if LJ_TARGET_X86ORX64
emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
#else
emit_asm_words(ctx, ctx->code+ofs, next-ofs);
#endif
}
#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
fprintf(ctx->fp,
#if !LJ_HASFFI
".globl lj_err_unwind_arm\n"
".personality lj_err_unwind_arm\n"
#endif
".fnend\n");
#endif
fprintf(ctx->fp, "\n");
switch (ctx->mode) {
case BUILD_elfasm:
#if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA)
fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
#endif
#if LJ_TARGET_PPCSPE
/* Soft-float ABI + SPE. */
fprintf(ctx->fp, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n");
#elif LJ_TARGET_PPC && !LJ_TARGET_PS3
/* Hard-float ABI. */
fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
#endif
/* fallthrough */
case BUILD_coffasm:
fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
break;
case BUILD_machasm:
fprintf(ctx->fp,
"\t.cstring\n"
"\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
break;
default:
break;
}
fprintf(ctx->fp, "\n");
}

View File

@ -1,229 +0,0 @@
/*
** LuaJIT VM builder: IR folding hash table generator.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include "buildvm.h"
#include "lj_obj.h"
#include "lj_ir.h"
/* Context for the folding hash table generator. */
static int lineno;
static uint32_t funcidx;
static uint32_t foldkeys[BUILD_MAX_FOLD];
static uint32_t nkeys;
/* Try to fill the hash table with keys using the hash parameters. */
static int tryhash(uint32_t *htab, uint32_t sz, uint32_t r, int dorol)
{
uint32_t i;
if (dorol && ((r & 31) == 0 || (r>>5) == 0))
return 0; /* Avoid zero rotates. */
memset(htab, 0xff, (sz+1)*sizeof(uint32_t));
for (i = 0; i < nkeys; i++) {
uint32_t key = foldkeys[i];
uint32_t k = key & 0xffffff;
uint32_t h = (dorol ? lj_rol(lj_rol(k, r>>5) - k, r&31) :
(((k << (r>>5)) - k) << (r&31))) % sz;
if (htab[h] != 0xffffffff) { /* Collision on primary slot. */
if (htab[h+1] != 0xffffffff) { /* Collision on secondary slot. */
/* Try to move the colliding key, if possible. */
if (h < sz-1 && htab[h+2] == 0xffffffff) {
uint32_t k2 = htab[h+1] & 0xffffff;
uint32_t h2 = (dorol ? lj_rol(lj_rol(k2, r>>5) - k2, r&31) :
(((k2 << (r>>5)) - k2) << (r&31))) % sz;
if (h2 != h+1) return 0; /* Cannot resolve collision. */
htab[h+2] = htab[h+1]; /* Move colliding key to secondary slot. */
} else {
return 0; /* Collision. */
}
}
htab[h+1] = key;
} else {
htab[h] = key;
}
}
return 1; /* Success, all keys could be stored. */
}
/* Print the generated hash table. */
static void printhash(BuildCtx *ctx, uint32_t *htab, uint32_t sz)
{
uint32_t i;
fprintf(ctx->fp, "static const uint32_t fold_hash[%d] = {\n0x%08x",
sz+1, htab[0]);
for (i = 1; i < sz+1; i++)
fprintf(ctx->fp, ",\n0x%08x", htab[i]);
fprintf(ctx->fp, "\n};\n\n");
}
/* Exhaustive search for the shortest semi-perfect hash table. */
static void makehash(BuildCtx *ctx)
{
uint32_t htab[BUILD_MAX_FOLD*2+1];
uint32_t sz, r;
/* Search for the smallest hash table with an odd size. */
for (sz = (nkeys|1); sz < BUILD_MAX_FOLD*2; sz += 2) {
/* First try all shift hash combinations. */
for (r = 0; r < 32*32; r++) {
if (tryhash(htab, sz, r, 0)) {
printhash(ctx, htab, sz);
fprintf(ctx->fp,
"#define fold_hashkey(k)\t(((((k)<<%u)-(k))<<%u)%%%u)\n\n",
r>>5, r&31, sz);
return;
}
}
/* Then try all rotate hash combinations. */
for (r = 0; r < 32*32; r++) {
if (tryhash(htab, sz, r, 1)) {
printhash(ctx, htab, sz);
fprintf(ctx->fp,
"#define fold_hashkey(k)\t(lj_rol(lj_rol((k),%u)-(k),%u)%%%u)\n\n",
r>>5, r&31, sz);
return;
}
}
}
fprintf(stderr, "Error: search for perfect hash failed\n");
exit(1);
}
/* Parse one token of a fold rule. */
static uint32_t nexttoken(char **pp, int allowlit, int allowany)
{
char *p = *pp;
if (p) {
uint32_t i;
char *q = strchr(p, ' ');
if (q) *q++ = '\0';
*pp = q;
if (allowlit && !strncmp(p, "IRFPM_", 6)) {
for (i = 0; irfpm_names[i]; i++)
if (!strcmp(irfpm_names[i], p+6))
return i;
} else if (allowlit && !strncmp(p, "IRFL_", 5)) {
for (i = 0; irfield_names[i]; i++)
if (!strcmp(irfield_names[i], p+5))
return i;
} else if (allowlit && !strncmp(p, "IRCALL_", 7)) {
for (i = 0; ircall_names[i]; i++)
if (!strcmp(ircall_names[i], p+7))
return i;
} else if (allowlit && !strncmp(p, "IRCONV_", 7)) {
for (i = 0; irt_names[i]; i++) {
const char *r = strchr(p+7, '_');
if (r && !strncmp(irt_names[i], p+7, r-(p+7))) {
uint32_t j;
for (j = 0; irt_names[j]; j++)
if (!strcmp(irt_names[j], r+1))
return (i << 5) + j;
}
}
} else if (allowlit && *p >= '0' && *p <= '9') {
for (i = 0; *p >= '0' && *p <= '9'; p++)
i = i*10 + (*p - '0');
if (*p == '\0')
return i;
} else if (allowany && !strcmp("any", p)) {
return allowany;
} else {
for (i = 0; ir_names[i]; i++)
if (!strcmp(ir_names[i], p))
return i;
}
fprintf(stderr, "Error: bad fold definition token \"%s\" at line %d\n", p, lineno);
exit(1);
}
return 0;
}
/* Parse a fold rule. */
static void foldrule(char *p)
{
uint32_t op = nexttoken(&p, 0, 0);
uint32_t left = nexttoken(&p, 0, 0x7f);
uint32_t right = nexttoken(&p, 1, 0x3ff);
uint32_t key = (funcidx << 24) | (op << 17) | (left << 10) | right;
uint32_t i;
if (nkeys >= BUILD_MAX_FOLD) {
fprintf(stderr, "Error: too many fold rules, increase BUILD_MAX_FOLD.\n");
exit(1);
}
/* Simple insertion sort to detect duplicates. */
for (i = nkeys; i > 0; i--) {
if ((foldkeys[i-1]&0xffffff) < (key & 0xffffff))
break;
if ((foldkeys[i-1]&0xffffff) == (key & 0xffffff)) {
fprintf(stderr, "Error: duplicate fold definition at line %d\n", lineno);
exit(1);
}
foldkeys[i] = foldkeys[i-1];
}
foldkeys[i] = key;
nkeys++;
}
/* Emit C source code for IR folding hash table. */
void emit_fold(BuildCtx *ctx)
{
char buf[256]; /* We don't care about analyzing lines longer than that. */
const char *fname = ctx->args[0];
FILE *fp;
if (fname == NULL) {
fprintf(stderr, "Error: missing input filename\n");
exit(1);
}
if (fname[0] == '-' && fname[1] == '\0') {
fp = stdin;
} else {
fp = fopen(fname, "r");
if (!fp) {
fprintf(stderr, "Error: cannot open input file '%s': %s\n",
fname, strerror(errno));
exit(1);
}
}
fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
fprintf(ctx->fp, "static const FoldFunc fold_func[] = {\n");
lineno = 0;
funcidx = 0;
nkeys = 0;
while (fgets(buf, sizeof(buf), fp) != NULL) {
lineno++;
/* The prefix must be at the start of a line, otherwise it's ignored. */
if (!strncmp(buf, FOLDDEF_PREFIX, sizeof(FOLDDEF_PREFIX)-1)) {
char *p = buf+sizeof(FOLDDEF_PREFIX)-1;
char *q = strchr(p, ')');
if (p[0] == '(' && q) {
p++;
*q = '\0';
foldrule(p);
} else if ((p[0] == 'F' || p[0] == 'X') && p[1] == '(' && q) {
p += 2;
*q = '\0';
if (funcidx)
fprintf(ctx->fp, ",\n");
if (p[-2] == 'X')
fprintf(ctx->fp, " %s", p);
else
fprintf(ctx->fp, " fold_%s", p);
funcidx++;
} else {
buf[strlen(buf)-1] = '\0';
fprintf(stderr, "Error: unknown fold definition tag %s%s at line %d\n",
FOLDDEF_PREFIX, p, lineno);
exit(1);
}
}
}
fclose(fp);
fprintf(ctx->fp, "\n};\n\n");
makehash(ctx);
}

View File

@ -1,398 +0,0 @@
/*
** LuaJIT VM builder: library definition compiler.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include "buildvm.h"
#include "lj_obj.h"
#include "lj_lib.h"
/* Context for library definitions. */
static uint8_t obuf[8192];
static uint8_t *optr;
static char modname[80];
static size_t modnamelen;
static char funcname[80];
static int modstate, regfunc;
static int ffid, recffid, ffasmfunc;
enum {
REGFUNC_OK,
REGFUNC_NOREG,
REGFUNC_NOREGUV
};
static void libdef_name(const char *p, int kind)
{
size_t n = strlen(p);
if (kind != LIBINIT_STRING) {
if (n > modnamelen && p[modnamelen] == '_' &&
!strncmp(p, modname, modnamelen)) {
p += modnamelen+1;
n -= modnamelen+1;
}
}
if (n > LIBINIT_MAXSTR) {
fprintf(stderr, "Error: string too long: '%s'\n", p);
exit(1);
}
if (optr+1+n+2 > obuf+sizeof(obuf)) { /* +2 for caller. */
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
*optr++ = (uint8_t)(n | kind);
memcpy(optr, p, n);
optr += n;
}
static void libdef_endmodule(BuildCtx *ctx)
{
if (modstate != 0) {
char line[80];
const uint8_t *p;
int n;
if (modstate == 1)
fprintf(ctx->fp, " (lua_CFunction)0");
fprintf(ctx->fp, "\n};\n");
fprintf(ctx->fp, "static const uint8_t %s%s[] = {\n",
LABEL_PREFIX_LIBINIT, modname);
line[0] = '\0';
for (n = 0, p = obuf; p < optr; p++) {
n += sprintf(line+n, "%d,", *p);
if (n >= 75) {
fprintf(ctx->fp, "%s\n", line);
n = 0;
line[0] = '\0';
}
}
fprintf(ctx->fp, "%s%d\n};\n#endif\n\n", line, LIBINIT_END);
}
}
static void libdef_module(BuildCtx *ctx, char *p, int arg)
{
UNUSED(arg);
if (ctx->mode == BUILD_libdef) {
libdef_endmodule(ctx);
optr = obuf;
*optr++ = (uint8_t)ffid;
*optr++ = (uint8_t)ffasmfunc;
*optr++ = 0; /* Hash table size. */
modstate = 1;
fprintf(ctx->fp, "#ifdef %sMODULE_%s\n", LIBDEF_PREFIX, p);
fprintf(ctx->fp, "#undef %sMODULE_%s\n", LIBDEF_PREFIX, p);
fprintf(ctx->fp, "static const lua_CFunction %s%s[] = {\n",
LABEL_PREFIX_LIBCF, p);
}
modnamelen = strlen(p);
if (modnamelen > sizeof(modname)-1) {
fprintf(stderr, "Error: module name too long: '%s'\n", p);
exit(1);
}
strcpy(modname, p);
}
static int find_ffofs(BuildCtx *ctx, const char *name)
{
int i;
for (i = 0; i < ctx->nglob; i++) {
const char *gl = ctx->globnames[i];
if (gl[0] == 'f' && gl[1] == 'f' && gl[2] == '_' && !strcmp(gl+3, name)) {
return (int)((uint8_t *)ctx->glob[i] - ctx->code);
}
}
fprintf(stderr, "Error: undefined fast function %s%s\n",
LABEL_PREFIX_FF, name);
exit(1);
}
static void libdef_func(BuildCtx *ctx, char *p, int arg)
{
if (arg != LIBINIT_CF)
ffasmfunc++;
if (ctx->mode == BUILD_libdef) {
if (modstate == 0) {
fprintf(stderr, "Error: no module for function definition %s\n", p);
exit(1);
}
if (regfunc == REGFUNC_NOREG) {
if (optr+1 > obuf+sizeof(obuf)) {
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
*optr++ = LIBINIT_FFID;
} else {
if (arg != LIBINIT_ASM_) {
if (modstate != 1) fprintf(ctx->fp, ",\n");
modstate = 2;
fprintf(ctx->fp, " %s%s", arg ? LABEL_PREFIX_FFH : LABEL_PREFIX_CF, p);
}
if (regfunc != REGFUNC_NOREGUV) obuf[2]++; /* Bump hash table size. */
libdef_name(regfunc == REGFUNC_NOREGUV ? "" : p, arg);
}
} else if (ctx->mode == BUILD_ffdef) {
fprintf(ctx->fp, "FFDEF(%s)\n", p);
} else if (ctx->mode == BUILD_recdef) {
if (strlen(p) > sizeof(funcname)-1) {
fprintf(stderr, "Error: function name too long: '%s'\n", p);
exit(1);
}
strcpy(funcname, p);
} else if (ctx->mode == BUILD_vmdef) {
int i;
for (i = 1; p[i] && modname[i-1]; i++)
if (p[i] == '_') p[i] = '.';
fprintf(ctx->fp, "\"%s\",\n", p);
} else if (ctx->mode == BUILD_bcdef) {
if (arg != LIBINIT_CF)
fprintf(ctx->fp, ",\n%d", find_ffofs(ctx, p));
}
ffid++;
regfunc = REGFUNC_OK;
}
static uint32_t find_rec(char *name)
{
char *p = (char *)obuf;
uint32_t n;
for (n = 2; *p; n++) {
if (strcmp(p, name) == 0)
return n;
p += strlen(p)+1;
}
if (p+strlen(name)+1 >= (char *)obuf+sizeof(obuf)) {
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
strcpy(p, name);
return n;
}
static void libdef_rec(BuildCtx *ctx, char *p, int arg)
{
UNUSED(arg);
if (ctx->mode == BUILD_recdef) {
char *q;
uint32_t n;
for (; recffid+1 < ffid; recffid++)
fprintf(ctx->fp, ",\n0");
recffid = ffid;
if (*p == '.') p = funcname;
q = strchr(p, ' ');
if (q) *q++ = '\0';
n = find_rec(p);
if (q)
fprintf(ctx->fp, ",\n0x%02x00+(%s)", n, q);
else
fprintf(ctx->fp, ",\n0x%02x00", n);
}
}
static void memcpy_endian(void *dst, void *src, size_t n)
{
union { uint8_t b; uint32_t u; } host_endian;
host_endian.u = 1;
if (host_endian.b == LJ_ENDIAN_SELECT(1, 0)) {
memcpy(dst, src, n);
} else {
size_t i;
for (i = 0; i < n; i++)
((uint8_t *)dst)[i] = ((uint8_t *)src)[n-i-1];
}
}
static void libdef_push(BuildCtx *ctx, char *p, int arg)
{
UNUSED(arg);
if (ctx->mode == BUILD_libdef) {
int len = (int)strlen(p);
if (*p == '"') {
if (len > 1 && p[len-1] == '"') {
p[len-1] = '\0';
libdef_name(p+1, LIBINIT_STRING);
return;
}
} else if (*p >= '0' && *p <= '9') {
char *ep;
double d = strtod(p, &ep);
if (*ep == '\0') {
if (optr+1+sizeof(double) > obuf+sizeof(obuf)) {
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
*optr++ = LIBINIT_NUMBER;
memcpy_endian(optr, &d, sizeof(double));
optr += sizeof(double);
return;
}
} else if (!strcmp(p, "lastcl")) {
if (optr+1 > obuf+sizeof(obuf)) {
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
*optr++ = LIBINIT_LASTCL;
return;
} else if (len > 4 && !strncmp(p, "top-", 4)) {
if (optr+2 > obuf+sizeof(obuf)) {
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
*optr++ = LIBINIT_COPY;
*optr++ = (uint8_t)atoi(p+4);
return;
}
fprintf(stderr, "Error: bad value for %sPUSH(%s)\n", LIBDEF_PREFIX, p);
exit(1);
}
}
static void libdef_set(BuildCtx *ctx, char *p, int arg)
{
UNUSED(arg);
if (ctx->mode == BUILD_libdef) {
if (p[0] == '!' && p[1] == '\0') p[0] = '\0'; /* Set env. */
libdef_name(p, LIBINIT_STRING);
*optr++ = LIBINIT_SET;
obuf[2]++; /* Bump hash table size. */
}
}
static void libdef_regfunc(BuildCtx *ctx, char *p, int arg)
{
UNUSED(ctx); UNUSED(p);
regfunc = arg;
}
typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg);
typedef struct LibDefHandler {
const char *suffix;
const char *stop;
const LibDefFunc func;
const int arg;
} LibDefHandler;
static const LibDefHandler libdef_handlers[] = {
{ "MODULE_", " \t\r\n", libdef_module, 0 },
{ "CF(", ")", libdef_func, LIBINIT_CF },
{ "ASM(", ")", libdef_func, LIBINIT_ASM },
{ "ASM_(", ")", libdef_func, LIBINIT_ASM_ },
{ "REC(", ")", libdef_rec, 0 },
{ "PUSH(", ")", libdef_push, 0 },
{ "SET(", ")", libdef_set, 0 },
{ "NOREGUV", NULL, libdef_regfunc, REGFUNC_NOREGUV },
{ "NOREG", NULL, libdef_regfunc, REGFUNC_NOREG },
{ NULL, NULL, (LibDefFunc)0, 0 }
};
/* Emit C source code for library function definitions. */
void emit_lib(BuildCtx *ctx)
{
const char *fname;
if (ctx->mode == BUILD_ffdef || ctx->mode == BUILD_libdef ||
ctx->mode == BUILD_recdef)
fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
else if (ctx->mode == BUILD_vmdef)
fprintf(ctx->fp, "ffnames = {\n[0]=\"Lua\",\n\"C\",\n");
if (ctx->mode == BUILD_recdef)
fprintf(ctx->fp, "static const uint16_t recff_idmap[] = {\n0,\n0x0100");
recffid = ffid = FF_C+1;
ffasmfunc = 0;
while ((fname = *ctx->args++)) {
char buf[256]; /* We don't care about analyzing lines longer than that. */
FILE *fp;
if (fname[0] == '-' && fname[1] == '\0') {
fp = stdin;
} else {
fp = fopen(fname, "r");
if (!fp) {
fprintf(stderr, "Error: cannot open input file '%s': %s\n",
fname, strerror(errno));
exit(1);
}
}
modstate = 0;
regfunc = REGFUNC_OK;
while (fgets(buf, sizeof(buf), fp) != NULL) {
char *p;
/* Simplistic pre-processor. Only handles top-level #if/#endif. */
if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') {
int ok = 1;
if (!strcmp(buf, "#if LJ_52\n"))
ok = LJ_52;
else if (!strcmp(buf, "#if LJ_HASJIT\n"))
ok = LJ_HASJIT;
else if (!strcmp(buf, "#if LJ_HASFFI\n"))
ok = LJ_HASFFI;
if (!ok) {
int lvl = 1;
while (fgets(buf, sizeof(buf), fp) != NULL) {
if (buf[0] == '#' && buf[1] == 'e' && buf[2] == 'n') {
if (--lvl == 0) break;
} else if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') {
lvl++;
}
}
continue;
}
}
for (p = buf; (p = strstr(p, LIBDEF_PREFIX)) != NULL; ) {
const LibDefHandler *ldh;
p += sizeof(LIBDEF_PREFIX)-1;
for (ldh = libdef_handlers; ldh->suffix != NULL; ldh++) {
size_t n, len = strlen(ldh->suffix);
if (!strncmp(p, ldh->suffix, len)) {
p += len;
n = ldh->stop ? strcspn(p, ldh->stop) : 0;
if (!p[n]) break;
p[n] = '\0';
ldh->func(ctx, p, ldh->arg);
p += n+1;
break;
}
}
if (ldh->suffix == NULL) {
buf[strlen(buf)-1] = '\0';
fprintf(stderr, "Error: unknown library definition tag %s%s\n",
LIBDEF_PREFIX, p);
exit(1);
}
}
}
fclose(fp);
if (ctx->mode == BUILD_libdef) {
libdef_endmodule(ctx);
}
}
if (ctx->mode == BUILD_ffdef) {
fprintf(ctx->fp, "\n#undef FFDEF\n\n");
fprintf(ctx->fp,
"#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n",
ffasmfunc);
} else if (ctx->mode == BUILD_vmdef) {
fprintf(ctx->fp, "}\n\n");
} else if (ctx->mode == BUILD_bcdef) {
int i;
fprintf(ctx->fp, "\n};\n\n");
fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_mode[] = {\n");
fprintf(ctx->fp, "BCDEF(BCMODE)\n");
for (i = ffasmfunc-1; i > 0; i--)
fprintf(ctx->fp, "BCMODE_FF,\n");
fprintf(ctx->fp, "BCMODE_FF\n};\n\n");
} else if (ctx->mode == BUILD_recdef) {
char *p = (char *)obuf;
fprintf(ctx->fp, "\n};\n\n");
fprintf(ctx->fp, "static const RecordFunc recff_func[] = {\n"
"recff_nyi,\n"
"recff_c");
while (*p) {
fprintf(ctx->fp, ",\nrecff_%s", p);
p += strlen(p)+1;
}
fprintf(ctx->fp, "\n};\n\n");
}
}

View File

@ -1,368 +0,0 @@
/*
** LuaJIT VM builder: PE object emitter.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** Only used for building on Windows, since we cannot assume the presence
** of a suitable assembler. The host and target byte order must match.
*/
#include "buildvm.h"
#include "lj_bc.h"
#if LJ_TARGET_X86ORX64 || LJ_TARGET_PPC
/* Context for PE object emitter. */
static char *strtab;
static size_t strtabofs;
/* -- PE object definitions ----------------------------------------------- */
/* PE header. */
typedef struct PEheader {
uint16_t arch;
uint16_t nsects;
uint32_t time;
uint32_t symtabofs;
uint32_t nsyms;
uint16_t opthdrsz;
uint16_t flags;
} PEheader;
/* PE section. */
typedef struct PEsection {
char name[8];
uint32_t vsize;
uint32_t vaddr;
uint32_t size;
uint32_t ofs;
uint32_t relocofs;
uint32_t lineofs;
uint16_t nreloc;
uint16_t nline;
uint32_t flags;
} PEsection;
/* PE relocation. */
typedef struct PEreloc {
uint32_t vaddr;
uint32_t symidx;
uint16_t type;
} PEreloc;
/* Cannot use sizeof, because it pads up to the max. alignment. */
#define PEOBJ_RELOC_SIZE (4+4+2)
/* PE symbol table entry. */
typedef struct PEsym {
union {
char name[8];
uint32_t nameref[2];
} n;
uint32_t value;
int16_t sect;
uint16_t type;
uint8_t scl;
uint8_t naux;
} PEsym;
/* PE symbol table auxiliary entry for a section. */
typedef struct PEsymaux {
uint32_t size;
uint16_t nreloc;
uint16_t nline;
uint32_t cksum;
uint16_t assoc;
uint8_t comdatsel;
uint8_t unused[3];
} PEsymaux;
/* Cannot use sizeof, because it pads up to the max. alignment. */
#define PEOBJ_SYM_SIZE (8+4+2+2+1+1)
/* PE object CPU specific defines. */
#if LJ_TARGET_X86
#define PEOBJ_ARCH_TARGET 0x014c
#define PEOBJ_RELOC_REL32 0x14 /* MS: REL32, GNU: DISP32. */
#define PEOBJ_RELOC_DIR32 0x06
#define PEOBJ_RELOC_OFS 0
#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
#elif LJ_TARGET_X64
#define PEOBJ_ARCH_TARGET 0x8664
#define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */
#define PEOBJ_RELOC_DIR32 0x02
#define PEOBJ_RELOC_ADDR32NB 0x03
#define PEOBJ_RELOC_OFS 0
#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
#elif LJ_TARGET_PPC
#define PEOBJ_ARCH_TARGET 0x01f2
#define PEOBJ_RELOC_REL32 0x06
#define PEOBJ_RELOC_DIR32 0x02
#define PEOBJ_RELOC_OFS (-4)
#define PEOBJ_TEXT_FLAGS 0x60400020 /* 60=r+x, 40=align8, 20=code. */
#endif
/* Section numbers (0-based). */
enum {
PEOBJ_SECT_ABS = -2,
PEOBJ_SECT_UNDEF = -1,
PEOBJ_SECT_TEXT,
#if LJ_TARGET_X64
PEOBJ_SECT_PDATA,
PEOBJ_SECT_XDATA,
#endif
PEOBJ_SECT_RDATA_Z,
PEOBJ_NSECTIONS
};
/* Symbol types. */
#define PEOBJ_TYPE_NULL 0
#define PEOBJ_TYPE_FUNC 0x20
/* Symbol storage class. */
#define PEOBJ_SCL_EXTERN 2
#define PEOBJ_SCL_STATIC 3
/* -- PE object emitter --------------------------------------------------- */
/* Emit PE object symbol. */
static void emit_peobj_sym(BuildCtx *ctx, const char *name, uint32_t value,
int sect, int type, int scl)
{
PEsym sym;
size_t len = strlen(name);
if (!strtab) { /* Pass 1: only calculate string table length. */
if (len > 8) strtabofs += len+1;
return;
}
if (len <= 8) {
memcpy(sym.n.name, name, len);
memset(sym.n.name+len, 0, 8-len);
} else {
sym.n.nameref[0] = 0;
sym.n.nameref[1] = (uint32_t)strtabofs;
memcpy(strtab + strtabofs, name, len);
strtab[strtabofs+len] = 0;
strtabofs += len+1;
}
sym.value = value;
sym.sect = (int16_t)(sect+1); /* 1-based section number. */
sym.type = (uint16_t)type;
sym.scl = (uint8_t)scl;
sym.naux = 0;
owrite(ctx, &sym, PEOBJ_SYM_SIZE);
}
/* Emit PE object section symbol. */
static void emit_peobj_sym_sect(BuildCtx *ctx, PEsection *pesect, int sect)
{
PEsym sym;
PEsymaux aux;
if (!strtab) return; /* Pass 1: no output. */
memcpy(sym.n.name, pesect[sect].name, 8);
sym.value = 0;
sym.sect = (int16_t)(sect+1); /* 1-based section number. */
sym.type = PEOBJ_TYPE_NULL;
sym.scl = PEOBJ_SCL_STATIC;
sym.naux = 1;
owrite(ctx, &sym, PEOBJ_SYM_SIZE);
memset(&aux, 0, sizeof(PEsymaux));
aux.size = pesect[sect].size;
aux.nreloc = pesect[sect].nreloc;
owrite(ctx, &aux, PEOBJ_SYM_SIZE);
}
/* Emit Windows PE object file. */
void emit_peobj(BuildCtx *ctx)
{
PEheader pehdr;
PEsection pesect[PEOBJ_NSECTIONS];
uint32_t sofs;
int i, nrsym;
union { uint8_t b; uint32_t u; } host_endian;
sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection);
/* Fill in PE sections. */
memset(&pesect, 0, PEOBJ_NSECTIONS*sizeof(PEsection));
memcpy(pesect[PEOBJ_SECT_TEXT].name, ".text", sizeof(".text")-1);
pesect[PEOBJ_SECT_TEXT].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_TEXT].size = (uint32_t)ctx->codesz);
pesect[PEOBJ_SECT_TEXT].relocofs = sofs;
sofs += (pesect[PEOBJ_SECT_TEXT].nreloc = (uint16_t)ctx->nreloc) * PEOBJ_RELOC_SIZE;
/* Flags: 60 = read+execute, 50 = align16, 20 = code. */
pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS;
#if LJ_TARGET_X64
memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
pesect[PEOBJ_SECT_PDATA].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4);
pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * PEOBJ_RELOC_SIZE;
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;
memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
pesect[PEOBJ_SECT_XDATA].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4+6*2); /* See below. */
pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
pesect[PEOBJ_SECT_XDATA].flags = 0x40300040;
#endif
memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1);
pesect[PEOBJ_SECT_RDATA_Z].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_RDATA_Z].size = (uint32_t)strlen(ctx->dasm_ident)+1);
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
pesect[PEOBJ_SECT_RDATA_Z].flags = 0x40300040;
/* Fill in PE header. */
pehdr.arch = PEOBJ_ARCH_TARGET;
pehdr.nsects = PEOBJ_NSECTIONS;
pehdr.time = 0; /* Timestamp is optional. */
pehdr.symtabofs = sofs;
pehdr.opthdrsz = 0;
pehdr.flags = 0;
/* Compute the size of the symbol table:
** @feat.00 + nsections*2
** + asm_start + nsym
** + nrsym
*/
nrsym = ctx->nrelocsym;
pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym;
#if LJ_TARGET_X64
pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win64. */
#endif
/* Write PE object header and all sections. */
owrite(ctx, &pehdr, sizeof(PEheader));
owrite(ctx, &pesect, sizeof(PEsection)*PEOBJ_NSECTIONS);
/* Write .text section. */
host_endian.u = 1;
if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) {
#if LJ_TARGET_PPC
uint32_t *p = (uint32_t *)ctx->code;
int n = (int)(ctx->codesz >> 2);
for (i = 0; i < n; i++, p++)
*p = lj_bswap(*p); /* Byteswap .text section. */
#else
fprintf(stderr, "Error: different byte order for host and target\n");
exit(1);
#endif
}
owrite(ctx, ctx->code, ctx->codesz);
for (i = 0; i < ctx->nreloc; i++) {
PEreloc reloc;
reloc.vaddr = (uint32_t)ctx->reloc[i].ofs + PEOBJ_RELOC_OFS;
reloc.symidx = 1+2+ctx->reloc[i].sym; /* Reloc syms are after .text sym. */
reloc.type = ctx->reloc[i].type ? PEOBJ_RELOC_REL32 : PEOBJ_RELOC_DIR32;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
#if LJ_TARGET_X64
{ /* Write .pdata section. */
uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */
PEreloc reloc;
pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0;
owrite(ctx, &pdata, sizeof(pdata));
pdata[0] = fcofs; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 20;
owrite(ctx, &pdata, sizeof(pdata));
reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 16; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 20; reloc.symidx = 1+2+nrsym+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
{ /* Write .xdata section. */
uint16_t xdata[8+2+6];
PEreloc reloc;
xdata[0] = 0x01|0x08|0x10; /* Ver. 1, uhandler/ehandler, prolog size 0. */
xdata[1] = 0x0005; /* Number of unwind codes, no frame pointer. */
xdata[2] = 0x4200; /* Stack offset 4*8+8 = aword*5. */
xdata[3] = 0x3000; /* Push rbx. */
xdata[4] = 0x6000; /* Push rsi. */
xdata[5] = 0x7000; /* Push rdi. */
xdata[6] = 0x5000; /* Push rbp. */
xdata[7] = 0; /* Alignment. */
xdata[8] = xdata[9] = 0; /* Relocated address of exception handler. */
xdata[10] = 0x01; /* Ver. 1, no handler, prolog size 0. */
xdata[11] = 0x1504; /* Number of unwind codes, fp = rbp, fpofs = 16. */
xdata[12] = 0x0300; /* set_fpreg. */
xdata[13] = 0x0200; /* stack offset 0*8+8 = aword*1. */
xdata[14] = 0x3000; /* Push rbx. */
xdata[15] = 0x5000; /* Push rbp. */
owrite(ctx, &xdata, sizeof(xdata));
reloc.vaddr = 2*8; reloc.symidx = 1+2+nrsym+2+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
#endif
/* Write .rdata$Z section. */
owrite(ctx, ctx->dasm_ident, strlen(ctx->dasm_ident)+1);
/* Write symbol table. */
strtab = NULL; /* 1st pass: collect string sizes. */
for (;;) {
strtabofs = 4;
/* Mark as SafeSEH compliant. */
emit_peobj_sym(ctx, "@feat.00", 1,
PEOBJ_SECT_ABS, PEOBJ_TYPE_NULL, PEOBJ_SCL_STATIC);
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_TEXT);
for (i = 0; i < nrsym; i++)
emit_peobj_sym(ctx, ctx->relocsym[i], 0,
PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
#if LJ_TARGET_X64
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
emit_peobj_sym(ctx, "lj_err_unwind_win64", 0,
PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
#endif
emit_peobj_sym(ctx, ctx->beginsym, 0,
PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN);
for (i = 0; i < ctx->nsym; i++)
emit_peobj_sym(ctx, ctx->sym[i].name, (uint32_t)ctx->sym[i].ofs,
PEOBJ_SECT_TEXT, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA_Z);
if (strtab)
break;
/* 2nd pass: alloc strtab, write syms and copy strings. */
strtab = (char *)malloc(strtabofs);
*(uint32_t *)strtab = (uint32_t)strtabofs;
}
/* Write string table. */
owrite(ctx, strtab, strtabofs);
}
#else
void emit_peobj(BuildCtx *ctx)
{
UNUSED(ctx);
fprintf(stderr, "Error: no PE object support for this target\n");
exit(1);
}
#endif

View File

@ -1,429 +0,0 @@
----------------------------------------------------------------------------
-- Lua script to generate a customized, minified version of Lua.
-- The resulting 'minilua' is used for the build process of LuaJIT.
----------------------------------------------------------------------------
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
local sub, match, gsub = string.sub, string.match, string.gsub
local LUA_VERSION = "5.1.5"
local LUA_SOURCE
local function usage()
io.stderr:write("Usage: ", arg and arg[0] or "genminilua",
" lua-", LUA_VERSION, "-source-dir\n")
os.exit(1)
end
local function find_sources()
LUA_SOURCE = arg and arg[1]
if not LUA_SOURCE then usage() end
if sub(LUA_SOURCE, -1) ~= "/" then LUA_SOURCE = LUA_SOURCE.."/" end
local fp = io.open(LUA_SOURCE .. "lua.h")
if not fp then
LUA_SOURCE = LUA_SOURCE.."src/"
fp = io.open(LUA_SOURCE .. "lua.h")
if not fp then usage() end
end
local all = fp:read("*a")
fp:close()
if not match(all, 'LUA_RELEASE%s*"Lua '..LUA_VERSION..'"') then
io.stderr:write("Error: version mismatch\n")
usage()
end
end
local LUA_FILES = {
"lmem.c", "lobject.c", "ltm.c", "lfunc.c", "ldo.c", "lstring.c", "ltable.c",
"lgc.c", "lstate.c", "ldebug.c", "lzio.c", "lopcodes.c",
"llex.c", "lcode.c", "lparser.c", "lvm.c", "lapi.c", "lauxlib.c",
"lbaselib.c", "ltablib.c", "liolib.c", "loslib.c", "lstrlib.c", "linit.c",
}
local REMOVE_LIB = {}
gsub([[
collectgarbage dofile gcinfo getfenv getmetatable load print rawequal rawset
select tostring xpcall
foreach foreachi getn maxn setn
popen tmpfile seek setvbuf __tostring
clock date difftime execute getenv rename setlocale time tmpname
dump gfind len reverse
LUA_LOADLIBNAME LUA_MATHLIBNAME LUA_DBLIBNAME
]], "%S+", function(name)
REMOVE_LIB[name] = true
end)
local REMOVE_EXTINC = { ["<assert.h>"] = true, ["<locale.h>"] = true, }
local CUSTOM_MAIN = [[
typedef unsigned int UB;
static UB barg(lua_State *L,int idx){
union{lua_Number n;U64 b;}bn;
bn.n=lua_tonumber(L,idx)+6755399441055744.0;
if (bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number");
return(UB)bn.b;
}
#define BRET(b) lua_pushnumber(L,(lua_Number)(int)(b));return 1;
static int tobit(lua_State *L){
BRET(barg(L,1))}
static int bnot(lua_State *L){
BRET(~barg(L,1))}
static int band(lua_State *L){
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)}
static int bor(lua_State *L){
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)}
static int bxor(lua_State *L){
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)}
static int lshift(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET(b<<n)}
static int rshift(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET(b>>n)}
static int arshift(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)}
static int rol(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET((b<<n)|(b>>(32-n)))}
static int ror(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))}
static int bswap(lua_State *L){
UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)}
static int tohex(lua_State *L){
UB b=barg(L,1);
int n=lua_isnone(L,2)?8:(int)barg(L,2);
const char *hexdigits="0123456789abcdef";
char buf[8];
int i;
if(n<0){n=-n;hexdigits="0123456789ABCDEF";}
if(n>8)n=8;
for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;}
lua_pushlstring(L,buf,(size_t)n);
return 1;
}
static const struct luaL_Reg bitlib[] = {
{"tobit",tobit},
{"bnot",bnot},
{"band",band},
{"bor",bor},
{"bxor",bxor},
{"lshift",lshift},
{"rshift",rshift},
{"arshift",arshift},
{"rol",rol},
{"ror",ror},
{"bswap",bswap},
{"tohex",tohex},
{NULL,NULL}
};
int main(int argc, char **argv){
lua_State *L = luaL_newstate();
int i;
luaL_openlibs(L);
luaL_register(L, "bit", bitlib);
if (argc < 2) return sizeof(void *);
lua_createtable(L, 0, 1);
lua_pushstring(L, argv[1]);
lua_rawseti(L, -2, 0);
lua_setglobal(L, "arg");
if (luaL_loadfile(L, argv[1]))
goto err;
for (i = 2; i < argc; i++)
lua_pushstring(L, argv[i]);
if (lua_pcall(L, argc - 2, 0, 0)) {
err:
fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
return 1;
}
lua_close(L);
return 0;
}
]]
local function read_sources()
local t = {}
for i, name in ipairs(LUA_FILES) do
local fp = assert(io.open(LUA_SOURCE..name, "r"))
t[i] = fp:read("*a")
assert(fp:close())
end
t[#t+1] = CUSTOM_MAIN
return table.concat(t)
end
local includes = {}
local function merge_includes(src)
return gsub(src, '#include%s*"([^"]*)"%s*\n', function(name)
if includes[name] then return "" end
includes[name] = true
local fp = assert(io.open(LUA_SOURCE..name, "r"))
local inc = fp:read("*a")
assert(fp:close())
inc = gsub(inc, "#ifndef%s+%w+_h\n#define%s+%w+_h\n", "")
inc = gsub(inc, "#endif%s*$", "")
return merge_includes(inc)
end)
end
local function get_license(src)
return match(src, "/%*+\n%* Copyright %(.-%*/\n")
end
local function fold_lines(src)
return gsub(src, "\\\n", " ")
end
local strings = {}
local function save_str(str)
local n = #strings+1
strings[n] = str
return "\1"..n.."\2"
end
local function save_strings(src)
src = gsub(src, '"[^"\n]*"', save_str)
return gsub(src, "'[^'\n]*'", save_str)
end
local function restore_strings(src)
return gsub(src, "\1(%d+)\2", function(numstr)
return strings[tonumber(numstr)]
end)
end
local function def_istrue(def)
return def == "INT_MAX > 2147483640L" or
def == "LUAI_BITSINT >= 32" or
def == "SIZE_Bx < LUAI_BITSINT-1" or
def == "cast" or
def == "defined(LUA_CORE)" or
def == "MINSTRTABSIZE" or
def == "LUA_MINBUFFER" or
def == "HARDSTACKTESTS" or
def == "UNUSED"
end
local head, defs = {[[
#ifdef _MSC_VER
typedef unsigned __int64 U64;
#else
typedef unsigned long long U64;
#endif
int _CRT_glob = 0;
]]}, {}
local function preprocess(src)
local t = { match(src, "^(.-)#") }
local lvl, on, oldon = 0, true, {}
for pp, def, txt in string.gmatch(src, "#(%w+) *([^\n]*)\n([^#]*)") do
if pp == "if" or pp == "ifdef" or pp == "ifndef" then
lvl = lvl + 1
oldon[lvl] = on
on = def_istrue(def)
elseif pp == "else" then
if oldon[lvl] then
if on == false then on = true else on = false end
end
elseif pp == "elif" then
if oldon[lvl] then
on = def_istrue(def)
end
elseif pp == "endif" then
on = oldon[lvl]
lvl = lvl - 1
elseif on then
if pp == "include" then
if not head[def] and not REMOVE_EXTINC[def] then
head[def] = true
head[#head+1] = "#include "..def.."\n"
end
elseif pp == "define" then
local k, sp, v = match(def, "([%w_]+)(%s*)(.*)")
if k and not (sp == "" and sub(v, 1, 1) == "(") then
defs[k] = gsub(v, "%a[%w_]*", function(tok)
return defs[tok] or tok
end)
else
t[#t+1] = "#define "..def.."\n"
end
elseif pp ~= "undef" then
error("unexpected directive: "..pp.." "..def)
end
end
if on then t[#t+1] = txt end
end
return gsub(table.concat(t), "%a[%w_]*", function(tok)
return defs[tok] or tok
end)
end
local function merge_header(src, license)
local hdr = string.format([[
/* This is a heavily customized and minimized copy of Lua %s. */
/* It's only used to build LuaJIT. It does NOT have all standard functions! */
]], LUA_VERSION)
return hdr..license..table.concat(head)..src
end
local function strip_unused1(src)
return gsub(src, '( {"?([%w_]+)"?,%s+%a[%w_]*},\n)', function(line, func)
return REMOVE_LIB[func] and "" or line
end)
end
local function strip_unused2(src)
return gsub(src, "Symbolic Execution.-}=", "")
end
local function strip_unused3(src)
src = gsub(src, "extern", "static")
src = gsub(src, "\nstatic([^\n]-)%(([^)]*)%)%(", "\nstatic%1 %2(")
src = gsub(src, "#define lua_assert[^\n]*\n", "")
src = gsub(src, "lua_assert%b();?", "")
src = gsub(src, "default:\n}", "default:;\n}")
src = gsub(src, "lua_lock%b();", "")
src = gsub(src, "lua_unlock%b();", "")
src = gsub(src, "luai_threadyield%b();", "")
src = gsub(src, "luai_userstateopen%b();", "{}")
src = gsub(src, "luai_userstate%w+%b();", "")
src = gsub(src, "%(%(c==.*luaY_parser%)", "luaY_parser")
src = gsub(src, "trydecpoint%(ls,seminfo%)",
"luaX_lexerror(ls,\"malformed number\",TK_NUMBER)")
src = gsub(src, "int c=luaZ_lookahead%b();", "")
src = gsub(src, "luaL_register%(L,[^,]*,co_funcs%);\nreturn 2;",
"return 1;")
src = gsub(src, "getfuncname%b():", "NULL:")
src = gsub(src, "getobjname%b():", "NULL:")
src = gsub(src, "if%([^\n]*hookmask[^\n]*%)\n[^\n]*\n", "")
src = gsub(src, "if%([^\n]*hookmask[^\n]*%)%b{}\n", "")
src = gsub(src, "if%([^\n]*hookmask[^\n]*&&\n[^\n]*%b{}\n", "")
src = gsub(src, "(twoto%b()%()", "%1(size_t)")
src = gsub(src, "i<sizenode", "i<(int)sizenode")
src = gsub(src, "cast%(unsigned int,key%-1%)", "cast(unsigned int,key)-1")
return gsub(src, "\n\n+", "\n")
end
local function strip_comments(src)
return gsub(src, "/%*.-%*/", " ")
end
local function strip_whitespace(src)
src = gsub(src, "^%s+", "")
src = gsub(src, "%s*\n%s*", "\n")
src = gsub(src, "[ \t]+", " ")
src = gsub(src, "(%W) ", "%1")
return gsub(src, " (%W)", "%1")
end
local function rename_tokens1(src)
src = gsub(src, "getline", "getline_")
src = gsub(src, "struct ([%w_]+)", "ZX%1")
return gsub(src, "union ([%w_]+)", "ZY%1")
end
local function rename_tokens2(src)
src = gsub(src, "ZX([%w_]+)", "struct %1")
return gsub(src, "ZY([%w_]+)", "union %1")
end
local function func_gather(src)
local nodes, list = {}, {}
local pos, len = 1, #src
while pos < len do
local d, w = match(src, "^(#define ([%w_]+)[^\n]*\n)", pos)
if d then
local n = #list+1
list[n] = d
nodes[w] = n
else
local s
d, w, s = match(src, "^(([%w_]+)[^\n]*([{;])\n)", pos)
if not d then
d, w, s = match(src, "^(([%w_]+)[^(]*%b()([{;])\n)", pos)
if not d then d = match(src, "^[^\n]*\n", pos) end
end
if s == "{" then
d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
if sub(d, -2) == "{\n" then
d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
end
end
local k, v = nil, d
if w == "typedef" then
if match(d, "^typedef enum") then
head[#head+1] = d
else
k = match(d, "([%w_]+);\n$")
if not k then k = match(d, "^.-%(.-([%w_]+)%)%(") end
end
elseif w == "enum" then
head[#head+1] = v
elseif w ~= nil then
k = match(d, "^[^\n]-([%w_]+)[(%[=]")
if k then
if w ~= "static" and k ~= "main" then v = "static "..d end
else
k = w
end
end
if w and k then
local o = nodes[k]
if o then nodes["*"..k] = o end
local n = #list+1
list[n] = v
nodes[k] = n
end
end
pos = pos + #d
end
return nodes, list
end
local function func_visit(nodes, list, used, n)
local i = nodes[n]
for m in string.gmatch(list[i], "[%w_]+") do
if nodes[m] then
local j = used[m]
if not j then
used[m] = i
func_visit(nodes, list, used, m)
elseif i < j then
used[m] = i
end
end
end
end
local function func_collect(src)
local nodes, list = func_gather(src)
local used = {}
func_visit(nodes, list, used, "main")
for n,i in pairs(nodes) do
local j = used[n]
if j and j < i then used["*"..n] = j end
end
for n,i in pairs(nodes) do
if not used[n] then list[i] = "" end
end
return table.concat(list)
end
find_sources()
local src = read_sources()
src = merge_includes(src)
local license = get_license(src)
src = fold_lines(src)
src = strip_unused1(src)
src = save_strings(src)
src = strip_unused2(src)
src = strip_comments(src)
src = preprocess(src)
src = strip_whitespace(src)
src = strip_unused3(src)
src = rename_tokens1(src)
src = func_collect(src)
src = rename_tokens2(src)
src = restore_strings(src)
src = merge_header(src, license)
io.write(src)

File diff suppressed because it is too large Load Diff

View File

@ -1,191 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT bytecode listing module.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module lists the bytecode of a Lua function. If it's loaded by -jbc
-- it hooks into the parser and lists all functions of a chunk as they
-- are parsed.
--
-- Example usage:
--
-- luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)'
-- luajit -jbc=- foo.lua
-- luajit -jbc=foo.list foo.lua
--
-- Default output is to stderr. To redirect the output to a file, pass a
-- filename as an argument (use '-' for stdout) or set the environment
-- variable LUAJIT_LISTFILE. The file is overwritten every time the module
-- is started.
--
-- This module can also be used programmatically:
--
-- local bc = require("jit.bc")
--
-- local function foo() print("hello") end
--
-- bc.dump(foo) --> -- BYTECODE -- [...]
-- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello"
--
-- local out = {
-- -- Do something with each line:
-- write = function(t, ...) io.write(...) end,
-- close = function(t) end,
-- flush = function(t) end,
-- }
-- bc.dump(foo, out)
--
------------------------------------------------------------------------------
-- Cache some library functions and objects.
local jit = require("jit")
assert(jit.version_num == 20005, "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local vmdef = require("jit.vmdef")
local bit = require("bit")
local sub, gsub, format = string.sub, string.gsub, string.format
local byte, band, shr = string.byte, bit.band, bit.rshift
local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck
local funcuvname = jutil.funcuvname
local bcnames = vmdef.bcnames
local stdout, stderr = io.stdout, io.stderr
------------------------------------------------------------------------------
local function ctlsub(c)
if c == "\n" then return "\\n"
elseif c == "\r" then return "\\r"
elseif c == "\t" then return "\\t"
else return format("\\%03d", byte(c))
end
end
-- Return one bytecode line.
local function bcline(func, pc, prefix)
local ins, m = funcbc(func, pc)
if not ins then return end
local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128)
local a = band(shr(ins, 8), 0xff)
local oidx = 6*band(ins, 0xff)
local op = sub(bcnames, oidx+1, oidx+6)
local s = format("%04d %s %-6s %3s ",
pc, prefix or " ", op, ma == 0 and "" or a)
local d = shr(ins, 16)
if mc == 13*128 then -- BCMjump
return format("%s=> %04d\n", s, pc+d-0x7fff)
end
if mb ~= 0 then
d = band(d, 0xff)
elseif mc == 0 then
return s.."\n"
end
local kc
if mc == 10*128 then -- BCMstr
kc = funck(func, -d-1)
kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub))
elseif mc == 9*128 then -- BCMnum
kc = funck(func, d)
if op == "TSETM " then kc = kc - 2^52 end
elseif mc == 12*128 then -- BCMfunc
local fi = funcinfo(funck(func, -d-1))
if fi.ffid then
kc = vmdef.ffnames[fi.ffid]
else
kc = fi.loc
end
elseif mc == 5*128 then -- BCMuv
kc = funcuvname(func, d)
end
if ma == 5 then -- BCMuv
local ka = funcuvname(func, a)
if kc then kc = ka.." ; "..kc else kc = ka end
end
if mb ~= 0 then
local b = shr(ins, 24)
if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end
return format("%s%3d %3d\n", s, b, d)
end
if kc then return format("%s%3d ; %s\n", s, d, kc) end
if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits
return format("%s%3d\n", s, d)
end
-- Collect branch targets of a function.
local function bctargets(func)
local target = {}
for pc=1,1000000000 do
local ins, m = funcbc(func, pc)
if not ins then break end
if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end
end
return target
end
-- Dump bytecode instructions of a function.
local function bcdump(func, out, all)
if not out then out = stdout end
local fi = funcinfo(func)
if all and fi.children then
for n=-1,-1000000000,-1 do
local k = funck(func, n)
if not k then break end
if type(k) == "proto" then bcdump(k, out, true) end
end
end
out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined))
local target = bctargets(func)
for pc=1,1000000000 do
local s = bcline(func, pc, target[pc] and "=>")
if not s then break end
out:write(s)
end
out:write("\n")
out:flush()
end
------------------------------------------------------------------------------
-- Active flag and output file handle.
local active, out
-- List handler.
local function h_list(func)
return bcdump(func, out)
end
-- Detach list handler.
local function bclistoff()
if active then
active = false
jit.attach(h_list)
if out and out ~= stdout and out ~= stderr then out:close() end
out = nil
end
end
-- Open the output file and attach list handler.
local function bcliston(outfile)
if active then bclistoff() end
if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end
if outfile then
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
else
out = stderr
end
jit.attach(h_list, "bc")
active = true
end
-- Public module functions.
module(...)
line = bcline
dump = bcdump
targets = bctargets
on = bcliston
off = bclistoff
start = bcliston -- For -j command line option.

View File

@ -1,659 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT module to save/list bytecode.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module saves or lists the bytecode for an input file.
-- It's run by the -b command line option.
--
------------------------------------------------------------------------------
local jit = require("jit")
assert(jit.version_num == 20005, "LuaJIT core/library version mismatch")
local bit = require("bit")
-- Symbol name prefix for LuaJIT bytecode.
local LJBC_PREFIX = "luaJIT_BC_"
------------------------------------------------------------------------------
local function usage()
io.stderr:write[[
Save LuaJIT bytecode: luajit -b[options] input output
-l Only list bytecode.
-s Strip debug info (default).
-g Keep debug info.
-n name Set module name (default: auto-detect from input name).
-t type Set output file type (default: auto-detect from output name).
-a arch Override architecture for object files (default: native).
-o os Override OS for object files (default: native).
-e chunk Use chunk string as input.
-- Stop handling options.
- Use stdin as input and/or stdout as output.
File types: c h obj o raw (default)
]]
os.exit(1)
end
local function check(ok, ...)
if ok then return ok, ... end
io.stderr:write("luajit: ", ...)
io.stderr:write("\n")
os.exit(1)
end
local function readfile(input)
if type(input) == "function" then return input end
if input == "-" then input = nil end
return check(loadfile(input))
end
local function savefile(name, mode)
if name == "-" then return io.stdout end
return check(io.open(name, mode))
end
------------------------------------------------------------------------------
local map_type = {
raw = "raw", c = "c", h = "h", o = "obj", obj = "obj",
}
local map_arch = {
x86 = true, x64 = true, arm = true, ppc = true, ppcspe = true,
mips = true, mipsel = true,
}
local map_os = {
linux = true, windows = true, osx = true, freebsd = true, netbsd = true,
openbsd = true, dragonfly = true, solaris = true,
}
local function checkarg(str, map, err)
str = string.lower(str)
local s = check(map[str], "unknown ", err)
return s == true and str or s
end
local function detecttype(str)
local ext = string.match(string.lower(str), "%.(%a+)$")
return map_type[ext] or "raw"
end
local function checkmodname(str)
check(string.match(str, "^[%w_.%-]+$"), "bad module name")
return string.gsub(str, "[%.%-]", "_")
end
local function detectmodname(str)
if type(str) == "string" then
local tail = string.match(str, "[^/\\]+$")
if tail then str = tail end
local head = string.match(str, "^(.*)%.[^.]*$")
if head then str = head end
str = string.match(str, "^[%w_.%-]+")
else
str = nil
end
check(str, "cannot derive module name, use -n name")
return string.gsub(str, "[%.%-]", "_")
end
------------------------------------------------------------------------------
local function bcsave_tail(fp, output, s)
local ok, err = fp:write(s)
if ok and output ~= "-" then ok, err = fp:close() end
check(ok, "cannot write ", output, ": ", err)
end
local function bcsave_raw(output, s)
local fp = savefile(output, "wb")
bcsave_tail(fp, output, s)
end
local function bcsave_c(ctx, output, s)
local fp = savefile(output, "w")
if ctx.type == "c" then
fp:write(string.format([[
#ifdef _cplusplus
extern "C"
#endif
#ifdef _WIN32
__declspec(dllexport)
#endif
const char %s%s[] = {
]], LJBC_PREFIX, ctx.modname))
else
fp:write(string.format([[
#define %s%s_SIZE %d
static const char %s%s[] = {
]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname))
end
local t, n, m = {}, 0, 0
for i=1,#s do
local b = tostring(string.byte(s, i))
m = m + #b + 1
if m > 78 then
fp:write(table.concat(t, ",", 1, n), ",\n")
n, m = 0, #b + 1
end
n = n + 1
t[n] = b
end
bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n")
end
local function bcsave_elfobj(ctx, output, s, ffi)
ffi.cdef[[
typedef struct {
uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
uint16_t type, machine;
uint32_t version;
uint32_t entry, phofs, shofs;
uint32_t flags;
uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
} ELF32header;
typedef struct {
uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
uint16_t type, machine;
uint32_t version;
uint64_t entry, phofs, shofs;
uint32_t flags;
uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
} ELF64header;
typedef struct {
uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize;
} ELF32sectheader;
typedef struct {
uint32_t name, type;
uint64_t flags, addr, ofs, size;
uint32_t link, info;
uint64_t align, entsize;
} ELF64sectheader;
typedef struct {
uint32_t name, value, size;
uint8_t info, other;
uint16_t sectidx;
} ELF32symbol;
typedef struct {
uint32_t name;
uint8_t info, other;
uint16_t sectidx;
uint64_t value, size;
} ELF64symbol;
typedef struct {
ELF32header hdr;
ELF32sectheader sect[6];
ELF32symbol sym[2];
uint8_t space[4096];
} ELF32obj;
typedef struct {
ELF64header hdr;
ELF64sectheader sect[6];
ELF64symbol sym[2];
uint8_t space[4096];
} ELF64obj;
]]
local symname = LJBC_PREFIX..ctx.modname
local is64, isbe = false, false
if ctx.arch == "x64" then
is64 = true
elseif ctx.arch == "ppc" or ctx.arch == "ppcspe" or ctx.arch == "mips" then
isbe = true
end
-- Handle different host/target endianess.
local function f32(x) return x end
local f16, fofs = f32, f32
if ffi.abi("be") ~= isbe then
f32 = bit.bswap
function f16(x) return bit.rshift(bit.bswap(x), 16) end
if is64 then
local two32 = ffi.cast("int64_t", 2^32)
function fofs(x) return bit.bswap(x)*two32 end
else
fofs = f32
end
end
-- Create ELF object and fill in header.
local o = ffi.new(is64 and "ELF64obj" or "ELF32obj")
local hdr = o.hdr
if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi.
local bf = assert(io.open("/bin/ls", "rb"))
local bs = bf:read(9)
bf:close()
ffi.copy(o, bs, 9)
check(hdr.emagic[0] == 127, "no support for writing native object files")
else
hdr.emagic = "\127ELF"
hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0
end
hdr.eclass = is64 and 2 or 1
hdr.eendian = isbe and 2 or 1
hdr.eversion = 1
hdr.type = f16(1)
hdr.machine = f16(({ x86=3, x64=62, arm=40, ppc=20, ppcspe=20, mips=8, mipsel=8 })[ctx.arch])
if ctx.arch == "mips" or ctx.arch == "mipsel" then
hdr.flags = f32(0x50001006)
end
hdr.version = f32(1)
hdr.shofs = fofs(ffi.offsetof(o, "sect"))
hdr.ehsize = f16(ffi.sizeof(hdr))
hdr.shentsize = f16(ffi.sizeof(o.sect[0]))
hdr.shnum = f16(6)
hdr.shstridx = f16(2)
-- Fill in sections and symbols.
local sofs, ofs = ffi.offsetof(o, "space"), 1
for i,name in ipairs{
".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack",
} do
local sect = o.sect[i]
sect.align = fofs(1)
sect.name = f32(ofs)
ffi.copy(o.space+ofs, name)
ofs = ofs + #name+1
end
o.sect[1].type = f32(2) -- .symtab
o.sect[1].link = f32(3)
o.sect[1].info = f32(1)
o.sect[1].align = fofs(8)
o.sect[1].ofs = fofs(ffi.offsetof(o, "sym"))
o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0]))
o.sect[1].size = fofs(ffi.sizeof(o.sym))
o.sym[1].name = f32(1)
o.sym[1].sectidx = f16(4)
o.sym[1].size = fofs(#s)
o.sym[1].info = 17
o.sect[2].type = f32(3) -- .shstrtab
o.sect[2].ofs = fofs(sofs)
o.sect[2].size = fofs(ofs)
o.sect[3].type = f32(3) -- .strtab
o.sect[3].ofs = fofs(sofs + ofs)
o.sect[3].size = fofs(#symname+1)
ffi.copy(o.space+ofs+1, symname)
ofs = ofs + #symname + 2
o.sect[4].type = f32(1) -- .rodata
o.sect[4].flags = fofs(2)
o.sect[4].ofs = fofs(sofs + ofs)
o.sect[4].size = fofs(#s)
o.sect[5].type = f32(1) -- .note.GNU-stack
o.sect[5].ofs = fofs(sofs + ofs + #s)
-- Write ELF object file.
local fp = savefile(output, "wb")
fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
bcsave_tail(fp, output, s)
end
local function bcsave_peobj(ctx, output, s, ffi)
ffi.cdef[[
typedef struct {
uint16_t arch, nsects;
uint32_t time, symtabofs, nsyms;
uint16_t opthdrsz, flags;
} PEheader;
typedef struct {
char name[8];
uint32_t vsize, vaddr, size, ofs, relocofs, lineofs;
uint16_t nreloc, nline;
uint32_t flags;
} PEsection;
typedef struct __attribute((packed)) {
union {
char name[8];
uint32_t nameref[2];
};
uint32_t value;
int16_t sect;
uint16_t type;
uint8_t scl, naux;
} PEsym;
typedef struct __attribute((packed)) {
uint32_t size;
uint16_t nreloc, nline;
uint32_t cksum;
uint16_t assoc;
uint8_t comdatsel, unused[3];
} PEsymaux;
typedef struct {
PEheader hdr;
PEsection sect[2];
// Must be an even number of symbol structs.
PEsym sym0;
PEsymaux sym0aux;
PEsym sym1;
PEsymaux sym1aux;
PEsym sym2;
PEsym sym3;
uint32_t strtabsize;
uint8_t space[4096];
} PEobj;
]]
local symname = LJBC_PREFIX..ctx.modname
local is64 = false
if ctx.arch == "x86" then
symname = "_"..symname
elseif ctx.arch == "x64" then
is64 = true
end
local symexport = " /EXPORT:"..symname..",DATA "
-- The file format is always little-endian. Swap if the host is big-endian.
local function f32(x) return x end
local f16 = f32
if ffi.abi("be") then
f32 = bit.bswap
function f16(x) return bit.rshift(bit.bswap(x), 16) end
end
-- Create PE object and fill in header.
local o = ffi.new("PEobj")
local hdr = o.hdr
hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch])
hdr.nsects = f16(2)
hdr.symtabofs = f32(ffi.offsetof(o, "sym0"))
hdr.nsyms = f32(6)
-- Fill in sections and symbols.
o.sect[0].name = ".drectve"
o.sect[0].size = f32(#symexport)
o.sect[0].flags = f32(0x00100a00)
o.sym0.sect = f16(1)
o.sym0.scl = 3
o.sym0.name = ".drectve"
o.sym0.naux = 1
o.sym0aux.size = f32(#symexport)
o.sect[1].name = ".rdata"
o.sect[1].size = f32(#s)
o.sect[1].flags = f32(0x40300040)
o.sym1.sect = f16(2)
o.sym1.scl = 3
o.sym1.name = ".rdata"
o.sym1.naux = 1
o.sym1aux.size = f32(#s)
o.sym2.sect = f16(2)
o.sym2.scl = 2
o.sym2.nameref[1] = f32(4)
o.sym3.sect = f16(-1)
o.sym3.scl = 2
o.sym3.value = f32(1)
o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant.
ffi.copy(o.space, symname)
local ofs = #symname + 1
o.strtabsize = f32(ofs + 4)
o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs)
ffi.copy(o.space + ofs, symexport)
ofs = ofs + #symexport
o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs)
-- Write PE object file.
local fp = savefile(output, "wb")
fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
bcsave_tail(fp, output, s)
end
local function bcsave_machobj(ctx, output, s, ffi)
ffi.cdef[[
typedef struct
{
uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags;
} mach_header;
typedef struct
{
mach_header; uint32_t reserved;
} mach_header_64;
typedef struct {
uint32_t cmd, cmdsize;
char segname[16];
uint32_t vmaddr, vmsize, fileoff, filesize;
uint32_t maxprot, initprot, nsects, flags;
} mach_segment_command;
typedef struct {
uint32_t cmd, cmdsize;
char segname[16];
uint64_t vmaddr, vmsize, fileoff, filesize;
uint32_t maxprot, initprot, nsects, flags;
} mach_segment_command_64;
typedef struct {
char sectname[16], segname[16];
uint32_t addr, size;
uint32_t offset, align, reloff, nreloc, flags;
uint32_t reserved1, reserved2;
} mach_section;
typedef struct {
char sectname[16], segname[16];
uint64_t addr, size;
uint32_t offset, align, reloff, nreloc, flags;
uint32_t reserved1, reserved2, reserved3;
} mach_section_64;
typedef struct {
uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize;
} mach_symtab_command;
typedef struct {
int32_t strx;
uint8_t type, sect;
int16_t desc;
uint32_t value;
} mach_nlist;
typedef struct {
uint32_t strx;
uint8_t type, sect;
uint16_t desc;
uint64_t value;
} mach_nlist_64;
typedef struct
{
uint32_t magic, nfat_arch;
} mach_fat_header;
typedef struct
{
uint32_t cputype, cpusubtype, offset, size, align;
} mach_fat_arch;
typedef struct {
struct {
mach_header hdr;
mach_segment_command seg;
mach_section sec;
mach_symtab_command sym;
} arch[1];
mach_nlist sym_entry;
uint8_t space[4096];
} mach_obj;
typedef struct {
struct {
mach_header_64 hdr;
mach_segment_command_64 seg;
mach_section_64 sec;
mach_symtab_command sym;
} arch[1];
mach_nlist_64 sym_entry;
uint8_t space[4096];
} mach_obj_64;
typedef struct {
mach_fat_header fat;
mach_fat_arch fat_arch[4];
struct {
mach_header hdr;
mach_segment_command seg;
mach_section sec;
mach_symtab_command sym;
} arch[4];
mach_nlist sym_entry;
uint8_t space[4096];
} mach_fat_obj;
]]
local symname = '_'..LJBC_PREFIX..ctx.modname
local isfat, is64, align, mobj = false, false, 4, "mach_obj"
if ctx.arch == "x64" then
is64, align, mobj = true, 8, "mach_obj_64"
elseif ctx.arch == "arm" then
isfat, mobj = true, "mach_fat_obj"
else
check(ctx.arch == "x86", "unsupported architecture for OSX")
end
local function aligned(v, a) return bit.band(v+a-1, -a) end
local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE.
-- Create Mach-O object and fill in header.
local o = ffi.new(mobj)
local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align)
local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12,12,12} })[ctx.arch]
local cpusubtype = ({ x86={3}, x64={3}, arm={3,6,9,11} })[ctx.arch]
if isfat then
o.fat.magic = be32(0xcafebabe)
o.fat.nfat_arch = be32(#cpusubtype)
end
-- Fill in sections and symbols.
for i=0,#cpusubtype-1 do
local ofs = 0
if isfat then
local a = o.fat_arch[i]
a.cputype = be32(cputype[i+1])
a.cpusubtype = be32(cpusubtype[i+1])
-- Subsequent slices overlap each other to share data.
ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0])
a.offset = be32(ofs)
a.size = be32(mach_size-ofs+#s)
end
local a = o.arch[i]
a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface
a.hdr.cputype = cputype[i+1]
a.hdr.cpusubtype = cpusubtype[i+1]
a.hdr.filetype = 1
a.hdr.ncmds = 2
a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym)
a.seg.cmd = is64 and 0x19 or 0x1
a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)
a.seg.vmsize = #s
a.seg.fileoff = mach_size-ofs
a.seg.filesize = #s
a.seg.maxprot = 1
a.seg.initprot = 1
a.seg.nsects = 1
ffi.copy(a.sec.sectname, "__data")
ffi.copy(a.sec.segname, "__DATA")
a.sec.size = #s
a.sec.offset = mach_size-ofs
a.sym.cmd = 2
a.sym.cmdsize = ffi.sizeof(a.sym)
a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs
a.sym.nsyms = 1
a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs
a.sym.strsize = aligned(#symname+2, align)
end
o.sym_entry.type = 0xf
o.sym_entry.sect = 1
o.sym_entry.strx = 1
ffi.copy(o.space+1, symname)
-- Write Macho-O object file.
local fp = savefile(output, "wb")
fp:write(ffi.string(o, mach_size))
bcsave_tail(fp, output, s)
end
local function bcsave_obj(ctx, output, s)
local ok, ffi = pcall(require, "ffi")
check(ok, "FFI library required to write this file type")
if ctx.os == "windows" then
return bcsave_peobj(ctx, output, s, ffi)
elseif ctx.os == "osx" then
return bcsave_machobj(ctx, output, s, ffi)
else
return bcsave_elfobj(ctx, output, s, ffi)
end
end
------------------------------------------------------------------------------
local function bclist(input, output)
local f = readfile(input)
require("jit.bc").dump(f, savefile(output, "w"), true)
end
local function bcsave(ctx, input, output)
local f = readfile(input)
local s = string.dump(f, ctx.strip)
local t = ctx.type
if not t then
t = detecttype(output)
ctx.type = t
end
if t == "raw" then
bcsave_raw(output, s)
else
if not ctx.modname then ctx.modname = detectmodname(input) end
if t == "obj" then
bcsave_obj(ctx, output, s)
else
bcsave_c(ctx, output, s)
end
end
end
local function docmd(...)
local arg = {...}
local n = 1
local list = false
local ctx = {
strip = true, arch = jit.arch, os = string.lower(jit.os),
type = false, modname = false,
}
while n <= #arg do
local a = arg[n]
if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then
table.remove(arg, n)
if a == "--" then break end
for m=2,#a do
local opt = string.sub(a, m, m)
if opt == "l" then
list = true
elseif opt == "s" then
ctx.strip = true
elseif opt == "g" then
ctx.strip = false
else
if arg[n] == nil or m ~= #a then usage() end
if opt == "e" then
if n ~= 1 then usage() end
arg[1] = check(loadstring(arg[1]))
elseif opt == "n" then
ctx.modname = checkmodname(table.remove(arg, n))
elseif opt == "t" then
ctx.type = checkarg(table.remove(arg, n), map_type, "file type")
elseif opt == "a" then
ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture")
elseif opt == "o" then
ctx.os = checkarg(table.remove(arg, n), map_os, "OS name")
else
usage()
end
end
end
else
n = n + 1
end
end
if list then
if #arg == 0 or #arg > 2 then usage() end
bclist(arg[1], arg[2] or "-")
else
if #arg ~= 2 then usage() end
bcsave(ctx, arg[1], arg[2])
end
end
------------------------------------------------------------------------------
-- Public module functions.
module(...)
start = docmd -- Process -b command line option.

View File

@ -1,689 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT ARM disassembler module.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This is a helper module used by the LuaJIT machine code dumper module.
--
-- It disassembles most user-mode ARMv7 instructions
-- NYI: Advanced SIMD and VFP instructions.
------------------------------------------------------------------------------
local type = type
local sub, byte, format = string.sub, string.byte, string.format
local match, gmatch = string.match, string.gmatch
local concat = table.concat
local bit = require("bit")
local band, bor, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
------------------------------------------------------------------------------
-- Opcode maps
------------------------------------------------------------------------------
local map_loadc = {
shift = 8, mask = 15,
[10] = {
shift = 20, mask = 1,
[0] = {
shift = 23, mask = 3,
[0] = "vmovFmDN", "vstmFNdr",
_ = {
shift = 21, mask = 1,
[0] = "vstrFdl",
{ shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", }
},
},
{
shift = 23, mask = 3,
[0] = "vmovFDNm",
{ shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", },
_ = {
shift = 21, mask = 1,
[0] = "vldrFdl", "vldmdbFNdr",
},
},
},
[11] = {
shift = 20, mask = 1,
[0] = {
shift = 23, mask = 3,
[0] = "vmovGmDN", "vstmGNdr",
_ = {
shift = 21, mask = 1,
[0] = "vstrGdl",
{ shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", }
},
},
{
shift = 23, mask = 3,
[0] = "vmovGDNm",
{ shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", },
_ = {
shift = 21, mask = 1,
[0] = "vldrGdl", "vldmdbGNdr",
},
},
},
_ = {
shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc.
},
}
local map_vfps = {
shift = 6, mask = 0x2c001,
[0] = "vmlaF.dnm", "vmlsF.dnm",
[0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm",
[0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm",
[0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm",
[0x20000] = "vdivF.dnm",
[0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm",
[0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm",
[0x2c000] = "vmovF.dY",
[0x2c001] = {
shift = 7, mask = 0x1e01,
[0] = "vmovF.dm", "vabsF.dm",
[0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm",
[0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm",
[0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d",
[0x0e01] = "vcvtG.dF.m",
[0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm",
[0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm",
[0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm",
},
}
local map_vfpd = {
shift = 6, mask = 0x2c001,
[0] = "vmlaG.dnm", "vmlsG.dnm",
[0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm",
[0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm",
[0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm",
[0x20000] = "vdivG.dnm",
[0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm",
[0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm",
[0x2c000] = "vmovG.dY",
[0x2c001] = {
shift = 7, mask = 0x1e01,
[0] = "vmovG.dm", "vabsG.dm",
[0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm",
[0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm",
[0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d",
[0x0e01] = "vcvtF.dG.m",
[0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm",
[0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m",
[0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m",
},
}
local map_datac = {
shift = 24, mask = 1,
[0] = {
shift = 4, mask = 1,
[0] = {
shift = 8, mask = 15,
[10] = map_vfps,
[11] = map_vfpd,
-- NYI cdp, mcr, mrc.
},
{
shift = 8, mask = 15,
[10] = {
shift = 20, mask = 15,
[0] = "vmovFnD", "vmovFDn",
[14] = "vmsrD",
[15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", },
},
},
},
"svcT",
}
local map_loadcu = {
shift = 0, mask = 0, -- NYI unconditional CP load/store.
}
local map_datacu = {
shift = 0, mask = 0, -- NYI unconditional CP data.
}
local map_simddata = {
shift = 0, mask = 0, -- NYI SIMD data.
}
local map_simdload = {
shift = 0, mask = 0, -- NYI SIMD load/store, preload.
}
local map_preload = {
shift = 0, mask = 0, -- NYI preload.
}
local map_media = {
shift = 20, mask = 31,
[0] = false,
{ --01
shift = 5, mask = 7,
[0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM",
"sadd8DNM", false, false, "ssub8DNM",
},
{ --02
shift = 5, mask = 7,
[0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM",
"qadd8DNM", false, false, "qsub8DNM",
},
{ --03
shift = 5, mask = 7,
[0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM",
"shadd8DNM", false, false, "shsub8DNM",
},
false,
{ --05
shift = 5, mask = 7,
[0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM",
"uadd8DNM", false, false, "usub8DNM",
},
{ --06
shift = 5, mask = 7,
[0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM",
"uqadd8DNM", false, false, "uqsub8DNM",
},
{ --07
shift = 5, mask = 7,
[0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM",
"uhadd8DNM", false, false, "uhsub8DNM",
},
{ --08
shift = 5, mask = 7,
[0] = "pkhbtDNMU", false, "pkhtbDNMU",
{ shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", },
"pkhbtDNMU", "selDNM", "pkhtbDNMU",
},
false,
{ --0a
shift = 5, mask = 7,
[0] = "ssatDxMu", "ssat16DxM", "ssatDxMu",
{ shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", },
"ssatDxMu", false, "ssatDxMu",
},
{ --0b
shift = 5, mask = 7,
[0] = "ssatDxMu", "revDM", "ssatDxMu",
{ shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", },
"ssatDxMu", "rev16DM", "ssatDxMu",
},
{ --0c
shift = 5, mask = 7,
[3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", },
},
false,
{ --0e
shift = 5, mask = 7,
[0] = "usatDwMu", "usat16DwM", "usatDwMu",
{ shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", },
"usatDwMu", false, "usatDwMu",
},
{ --0f
shift = 5, mask = 7,
[0] = "usatDwMu", "rbitDM", "usatDwMu",
{ shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", },
"usatDwMu", "revshDM", "usatDwMu",
},
{ --10
shift = 12, mask = 15,
[15] = {
shift = 5, mask = 7,
"smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS",
},
_ = {
shift = 5, mask = 7,
[0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD",
},
},
false, false, false,
{ --14
shift = 5, mask = 7,
[0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS",
},
{ --15
shift = 5, mask = 7,
[0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", },
{ shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", },
false, false, false, false,
"smmlsNMSD", "smmlsrNMSD",
},
false, false,
{ --18
shift = 5, mask = 7,
[0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", },
},
false,
{ --1a
shift = 5, mask = 3, [2] = "sbfxDMvw",
},
{ --1b
shift = 5, mask = 3, [2] = "sbfxDMvw",
},
{ --1c
shift = 5, mask = 3,
[0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
},
{ --1d
shift = 5, mask = 3,
[0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
},
{ --1e
shift = 5, mask = 3, [2] = "ubfxDMvw",
},
{ --1f
shift = 5, mask = 3, [2] = "ubfxDMvw",
},
}
local map_load = {
shift = 21, mask = 9,
{
shift = 20, mask = 5,
[0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL",
},
_ = {
shift = 20, mask = 5,
[0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL",
}
}
local map_load1 = {
shift = 4, mask = 1,
[0] = map_load, map_media,
}
local map_loadm = {
shift = 20, mask = 1,
[0] = {
shift = 23, mask = 3,
[0] = "stmdaNR", "stmNR",
{ shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR",
},
{
shift = 23, mask = 3,
[0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", },
"ldmdbNR", "ldmibNR",
},
}
local map_data = {
shift = 21, mask = 15,
[0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs",
"addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs",
"tstNP", "teqNP", "cmpNP", "cmnNP",
"orrDNPs", "movDPs", "bicDNPs", "mvnDPs",
}
local map_mul = {
shift = 21, mask = 7,
[0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS",
"umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs",
}
local map_sync = {
shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd.
[0] = "swpDMN", false, false, false,
"swpbDMN", false, false, false,
"strexDMN", "ldrexDN", "strexdDN", "ldrexdDN",
"strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN",
}
local map_mulh = {
shift = 21, mask = 3,
[0] = { shift = 5, mask = 3,
[0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", },
{ shift = 5, mask = 3,
[0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", },
{ shift = 5, mask = 3,
[0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", },
{ shift = 5, mask = 3,
[0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", },
}
local map_misc = {
shift = 4, mask = 7,
-- NYI: decode PSR bits of msr.
[0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", },
{ shift = 21, mask = 3, "bxM", false, "clzDM", },
{ shift = 21, mask = 3, "bxjM", },
{ shift = 21, mask = 3, "blxM", },
false,
{ shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", },
false,
{ shift = 21, mask = 3, "bkptK", },
}
local map_datar = {
shift = 4, mask = 9,
[9] = {
shift = 5, mask = 3,
[0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, },
{ shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", },
{ shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", },
{ shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", },
},
_ = {
shift = 20, mask = 25,
[16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, },
_ = {
shift = 0, mask = 0xffffffff,
[bor(0xe1a00000)] = "nop",
_ = map_data,
}
},
}
local map_datai = {
shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12.
[16] = "movwDW", [20] = "movtDW",
[18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", },
[22] = "msrNW",
_ = map_data,
}
local map_branch = {
shift = 24, mask = 1,
[0] = "bB", "blB"
}
local map_condins = {
[0] = map_datar, map_datai, map_load, map_load1,
map_loadm, map_branch, map_loadc, map_datac
}
-- NYI: setend.
local map_uncondins = {
[0] = false, map_simddata, map_simdload, map_preload,
false, "blxB", map_loadcu, map_datacu,
}
------------------------------------------------------------------------------
local map_gpr = {
[0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
}
local map_cond = {
[0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt", "gt", "le", "al",
}
local map_shift = { [0] = "lsl", "lsr", "asr", "ror", }
------------------------------------------------------------------------------
-- Output a nicely formatted line with an opcode and operands.
local function putop(ctx, text, operands)
local pos = ctx.pos
local extra = ""
if ctx.rel then
local sym = ctx.symtab[ctx.rel]
if sym then
extra = "\t->"..sym
elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then
extra = "\t; 0x"..tohex(ctx.rel)
end
end
if ctx.hexdump > 0 then
ctx.out(format("%08x %s %-5s %s%s\n",
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
else
ctx.out(format("%08x %-5s %s%s\n",
ctx.addr+pos, text, concat(operands, ", "), extra))
end
ctx.pos = pos + 4
end
-- Fallback for unknown opcodes.
local function unknown(ctx)
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
end
-- Format operand 2 of load/store opcodes.
local function fmtload(ctx, op, pos)
local base = map_gpr[band(rshift(op, 16), 15)]
local x, ofs
local ext = (band(op, 0x04000000) == 0)
if not ext and band(op, 0x02000000) == 0 then
ofs = band(op, 4095)
if band(op, 0x00800000) == 0 then ofs = -ofs end
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
ofs = "#"..ofs
elseif ext and band(op, 0x00400000) ~= 0 then
ofs = band(op, 15) + band(rshift(op, 4), 0xf0)
if band(op, 0x00800000) == 0 then ofs = -ofs end
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
ofs = "#"..ofs
else
ofs = map_gpr[band(op, 15)]
if ext or band(op, 0xfe0) == 0 then
elseif band(op, 0xfe0) == 0x60 then
ofs = format("%s, rrx", ofs)
else
local sh = band(rshift(op, 7), 31)
if sh == 0 then sh = 32 end
ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh)
end
if band(op, 0x00800000) == 0 then ofs = "-"..ofs end
end
if ofs == "#0" then
x = format("[%s]", base)
elseif band(op, 0x01000000) == 0 then
x = format("[%s], %s", base, ofs)
else
x = format("[%s, %s]", base, ofs)
end
if band(op, 0x01200000) == 0x01200000 then x = x.."!" end
return x
end
-- Format operand 2 of vector load/store opcodes.
local function fmtvload(ctx, op, pos)
local base = map_gpr[band(rshift(op, 16), 15)]
local ofs = band(op, 255)*4
if band(op, 0x00800000) == 0 then ofs = -ofs end
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
if ofs == 0 then
return format("[%s]", base)
else
return format("[%s, #%d]", base, ofs)
end
end
local function fmtvr(op, vr, sh0, sh1)
if vr == "s" then
return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1))
else
return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16))
end
end
-- Disassemble a single instruction.
local function disass_ins(ctx)
local pos = ctx.pos
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
local operands = {}
local suffix = ""
local last, name, pat
local vr
ctx.op = op
ctx.rel = nil
local cond = rshift(op, 28)
local opat
if cond == 15 then
opat = map_uncondins[band(rshift(op, 25), 7)]
else
if cond ~= 14 then suffix = map_cond[cond] end
opat = map_condins[band(rshift(op, 25), 7)]
end
while type(opat) ~= "string" do
if not opat then return unknown(ctx) end
opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
end
name, pat = match(opat, "^([a-z0-9]*)(.*)")
if sub(pat, 1, 1) == "." then
local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)")
suffix = suffix..s2
pat = p2
end
for p in gmatch(pat, ".") do
local x = nil
if p == "D" then
x = map_gpr[band(rshift(op, 12), 15)]
elseif p == "N" then
x = map_gpr[band(rshift(op, 16), 15)]
elseif p == "S" then
x = map_gpr[band(rshift(op, 8), 15)]
elseif p == "M" then
x = map_gpr[band(op, 15)]
elseif p == "d" then
x = fmtvr(op, vr, 12, 22)
elseif p == "n" then
x = fmtvr(op, vr, 16, 7)
elseif p == "m" then
x = fmtvr(op, vr, 0, 5)
elseif p == "P" then
if band(op, 0x02000000) ~= 0 then
x = ror(band(op, 255), 2*band(rshift(op, 8), 15))
else
x = map_gpr[band(op, 15)]
if band(op, 0xff0) ~= 0 then
operands[#operands+1] = x
local s = map_shift[band(rshift(op, 5), 3)]
local r = nil
if band(op, 0xf90) == 0 then
if s == "ror" then s = "rrx" else r = "#32" end
elseif band(op, 0x10) == 0 then
r = "#"..band(rshift(op, 7), 31)
else
r = map_gpr[band(rshift(op, 8), 15)]
end
if name == "mov" then name = s; x = r
elseif r then x = format("%s %s", s, r)
else x = s end
end
end
elseif p == "L" then
x = fmtload(ctx, op, pos)
elseif p == "l" then
x = fmtvload(ctx, op, pos)
elseif p == "B" then
local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6)
if cond == 15 then addr = addr + band(rshift(op, 23), 2) end
ctx.rel = addr
x = "0x"..tohex(addr)
elseif p == "F" then
vr = "s"
elseif p == "G" then
vr = "d"
elseif p == "." then
suffix = suffix..(vr == "s" and ".f32" or ".f64")
elseif p == "R" then
if band(op, 0x00200000) ~= 0 and #operands == 1 then
operands[1] = operands[1].."!"
end
local t = {}
for i=0,15 do
if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end
end
x = "{"..concat(t, ", ").."}"
elseif p == "r" then
if band(op, 0x00200000) ~= 0 and #operands == 2 then
operands[1] = operands[1].."!"
end
local s = tonumber(sub(last, 2))
local n = band(op, 255)
if vr == "d" then n = rshift(n, 1) end
operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1)
elseif p == "W" then
x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000)
elseif p == "T" then
x = "#0x"..tohex(band(op, 0x00ffffff), 6)
elseif p == "U" then
x = band(rshift(op, 7), 31)
if x == 0 then x = nil end
elseif p == "u" then
x = band(rshift(op, 7), 31)
if band(op, 0x40) == 0 then
if x == 0 then x = nil else x = "lsl #"..x end
else
if x == 0 then x = "asr #32" else x = "asr #"..x end
end
elseif p == "v" then
x = band(rshift(op, 7), 31)
elseif p == "w" then
x = band(rshift(op, 16), 31)
elseif p == "x" then
x = band(rshift(op, 16), 31) + 1
elseif p == "X" then
x = band(rshift(op, 16), 31) - last + 1
elseif p == "Y" then
x = band(rshift(op, 12), 0xf0) + band(op, 0x0f)
elseif p == "K" then
x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4)
elseif p == "s" then
if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end
else
assert(false)
end
if x then
last = x
if type(x) == "number" then x = "#"..x end
operands[#operands+1] = x
end
end
return putop(ctx, name..suffix, operands)
end
------------------------------------------------------------------------------
-- Disassemble a block of code.
local function disass_block(ctx, ofs, len)
if not ofs then ofs = 0 end
local stop = len and ofs+len or #ctx.code
ctx.pos = ofs
ctx.rel = nil
while ctx.pos < stop do disass_ins(ctx) end
end
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
local function create_(code, addr, out)
local ctx = {}
ctx.code = code
ctx.addr = addr or 0
ctx.out = out or io.write
ctx.symtab = {}
ctx.disass = disass_block
ctx.hexdump = 8
return ctx
end
-- Simple API: disassemble code (a string) at address and output via out.
local function disass_(code, addr, out)
create_(code, addr, out):disass()
end
-- Return register name for RID.
local function regname_(r)
if r < 16 then return map_gpr[r] end
return "d"..(r-16)
end
-- Public module functions.
module(...)
create = create_
disass = disass_
regname = regname_

View File

@ -1,428 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT MIPS disassembler module.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT/X license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This is a helper module used by the LuaJIT machine code dumper module.
--
-- It disassembles all standard MIPS32R1/R2 instructions.
-- Default mode is big-endian, but see: dis_mipsel.lua
------------------------------------------------------------------------------
local type = type
local byte, format = string.byte, string.format
local match, gmatch = string.match, string.gmatch
local concat = table.concat
local bit = require("bit")
local band, bor, tohex = bit.band, bit.bor, bit.tohex
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
------------------------------------------------------------------------------
-- Primary and extended opcode maps
------------------------------------------------------------------------------
local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
local map_special = {
shift = 0, mask = 63,
[0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
map_movci, map_srl, "sraDTA",
"sllvDTS", false, map_srlv, "sravDTS",
"jrS", "jalrD1S", "movzDST", "movnDST",
"syscallY", "breakY", false, "sync",
"mfhiD", "mthiS", "mfloD", "mtloS",
false, false, false, false,
"multST", "multuST", "divST", "divuST",
false, false, false, false,
"addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
"andDST", "orDST", "xorDST", "nor|notDST0",
false, false, "sltDST", "sltuDST",
false, false, false, false,
"tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
"teqSTZ", false, "tneSTZ",
}
local map_special2 = {
shift = 0, mask = 63,
[0] = "maddST", "madduST", "mulDST", false,
"msubST", "msubuST",
[32] = "clzDS", [33] = "cloDS",
[63] = "sdbbpY",
}
local map_bshfl = {
shift = 6, mask = 31,
[2] = "wsbhDT",
[16] = "sebDT",
[24] = "sehDT",
}
local map_special3 = {
shift = 0, mask = 63,
[0] = "extTSAK", [4] = "insTSAL",
[32] = map_bshfl,
[59] = "rdhwrTD",
}
local map_regimm = {
shift = 16, mask = 31,
[0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB",
false, false, false, false,
"tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI",
"teqiSI", false, "tneiSI", false,
"bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB",
false, false, false, false,
false, false, false, false,
false, false, false, "synciSO",
}
local map_cop0 = {
shift = 25, mask = 1,
[0] = {
shift = 21, mask = 15,
[0] = "mfc0TDW", [4] = "mtc0TDW",
[10] = "rdpgprDT",
[11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", },
[14] = "wrpgprDT",
}, {
shift = 0, mask = 63,
[1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
[24] = "eret", [31] = "deret",
[32] = "wait",
},
}
local map_cop1s = {
shift = 0, mask = 63,
[0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
"sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
"round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
"round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
false,
{ shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" },
"movz.sFGT", "movn.sFGT",
false, "recip.sFG", "rsqrt.sFG", false,
false, false, false, false,
false, false, false, false,
false, "cvt.d.sFG", false, false,
"cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false,
false, false, false, false,
false, false, false, false,
"c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH",
"c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH",
"c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH",
"c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH",
}
local map_cop1d = {
shift = 0, mask = 63,
[0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
"sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
"round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
"round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
false,
{ shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" },
"movz.dFGT", "movn.dFGT",
false, "recip.dFG", "rsqrt.dFG", false,
false, false, false, false,
false, false, false, false,
"cvt.s.dFG", false, false, false,
"cvt.w.dFG", "cvt.l.dFG", false, false,
false, false, false, false,
false, false, false, false,
"c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH",
"c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH",
"c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH",
"c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH",
}
local map_cop1ps = {
shift = 0, mask = 63,
[0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false,
false, "abs.psFG", "mov.psFG", "neg.psFG",
false, false, false, false,
false, false, false, false,
false,
{ shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" },
"movz.psFGT", "movn.psFGT",
false, false, false, false,
false, false, false, false,
false, false, false, false,
"cvt.s.puFG", false, false, false,
false, false, false, false,
"cvt.s.plFG", false, false, false,
"pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH",
"c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH",
"c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH",
"c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH",
"c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH",
}
local map_cop1w = {
shift = 0, mask = 63,
[32] = "cvt.s.wFG", [33] = "cvt.d.wFG",
}
local map_cop1l = {
shift = 0, mask = 63,
[32] = "cvt.s.lFG", [33] = "cvt.d.lFG",
}
local map_cop1bc = {
shift = 16, mask = 3,
[0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB",
}
local map_cop1 = {
shift = 21, mask = 31,
[0] = "mfc1TG", false, "cfc1TG", "mfhc1TG",
"mtc1TG", false, "ctc1TG", "mthc1TG",
map_cop1bc, false, false, false,
false, false, false, false,
map_cop1s, map_cop1d, false, false,
map_cop1w, map_cop1l, map_cop1ps,
}
local map_cop1x = {
shift = 0, mask = 63,
[0] = "lwxc1FSX", "ldxc1FSX", false, false,
false, "luxc1FSX", false, false,
"swxc1FSX", "sdxc1FSX", false, false,
false, "suxc1FSX", false, "prefxMSX",
false, false, false, false,
false, false, false, false,
false, false, false, false,
false, false, "alnv.psFGHS", false,
"madd.sFRGH", "madd.dFRGH", false, false,
false, false, "madd.psFRGH", false,
"msub.sFRGH", "msub.dFRGH", false, false,
false, false, "msub.psFRGH", false,
"nmadd.sFRGH", "nmadd.dFRGH", false, false,
false, false, "nmadd.psFRGH", false,
"nmsub.sFRGH", "nmsub.dFRGH", false, false,
false, false, "nmsub.psFRGH", false,
}
local map_pri = {
[0] = map_special, map_regimm, "jJ", "jalJ",
"beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB",
"addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI",
"andiTSU", "ori|liTS0U", "xoriTSU", "luiTU",
map_cop0, map_cop1, false, map_cop1x,
"beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB",
false, false, false, false,
map_special2, false, false, map_special3,
"lbTSO", "lhTSO", "lwlTSO", "lwTSO",
"lbuTSO", "lhuTSO", "lwrTSO", false,
"sbTSO", "shTSO", "swlTSO", "swTSO",
false, false, "swrTSO", "cacheNSO",
"llTSO", "lwc1HSO", "lwc2TSO", "prefNSO",
false, "ldc1HSO", "ldc2TSO", false,
"scTSO", "swc1HSO", "swc2TSO", false,
false, "sdc1HSO", "sdc2TSO", false,
}
------------------------------------------------------------------------------
local map_gpr = {
[0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra",
}
------------------------------------------------------------------------------
-- Output a nicely formatted line with an opcode and operands.
local function putop(ctx, text, operands)
local pos = ctx.pos
local extra = ""
if ctx.rel then
local sym = ctx.symtab[ctx.rel]
if sym then extra = "\t->"..sym end
end
if ctx.hexdump > 0 then
ctx.out(format("%08x %s %-7s %s%s\n",
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
else
ctx.out(format("%08x %-7s %s%s\n",
ctx.addr+pos, text, concat(operands, ", "), extra))
end
ctx.pos = pos + 4
end
-- Fallback for unknown opcodes.
local function unknown(ctx)
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
end
local function get_be(ctx)
local pos = ctx.pos
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
end
local function get_le(ctx)
local pos = ctx.pos
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
end
-- Disassemble a single instruction.
local function disass_ins(ctx)
local op = ctx:get()
local operands = {}
local last = nil
ctx.op = op
ctx.rel = nil
local opat = map_pri[rshift(op, 26)]
while type(opat) ~= "string" do
if not opat then return unknown(ctx) end
opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
end
local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
if altname then pat = pat2 end
for p in gmatch(pat, ".") do
local x = nil
if p == "S" then
x = map_gpr[band(rshift(op, 21), 31)]
elseif p == "T" then
x = map_gpr[band(rshift(op, 16), 31)]
elseif p == "D" then
x = map_gpr[band(rshift(op, 11), 31)]
elseif p == "F" then
x = "f"..band(rshift(op, 6), 31)
elseif p == "G" then
x = "f"..band(rshift(op, 11), 31)
elseif p == "H" then
x = "f"..band(rshift(op, 16), 31)
elseif p == "R" then
x = "f"..band(rshift(op, 21), 31)
elseif p == "A" then
x = band(rshift(op, 6), 31)
elseif p == "M" then
x = band(rshift(op, 11), 31)
elseif p == "N" then
x = band(rshift(op, 16), 31)
elseif p == "C" then
x = band(rshift(op, 18), 7)
if x == 0 then x = nil end
elseif p == "K" then
x = band(rshift(op, 11), 31) + 1
elseif p == "L" then
x = band(rshift(op, 11), 31) - last + 1
elseif p == "I" then
x = arshift(lshift(op, 16), 16)
elseif p == "U" then
x = band(op, 0xffff)
elseif p == "O" then
local disp = arshift(lshift(op, 16), 16)
operands[#operands] = format("%d(%s)", disp, last)
elseif p == "X" then
local index = map_gpr[band(rshift(op, 16), 31)]
operands[#operands] = format("%s(%s)", index, last)
elseif p == "B" then
x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 16)*4 + 4
ctx.rel = x
x = "0x"..tohex(x)
elseif p == "J" then
x = band(ctx.addr + ctx.pos, 0xf0000000) + band(op, 0x03ffffff)*4
ctx.rel = x
x = "0x"..tohex(x)
elseif p == "V" then
x = band(rshift(op, 8), 7)
if x == 0 then x = nil end
elseif p == "W" then
x = band(op, 7)
if x == 0 then x = nil end
elseif p == "Y" then
x = band(rshift(op, 6), 0x000fffff)
if x == 0 then x = nil end
elseif p == "Z" then
x = band(rshift(op, 6), 1023)
if x == 0 then x = nil end
elseif p == "0" then
if last == "r0" or last == 0 then
local n = #operands
operands[n] = nil
last = operands[n-1]
if altname then
local a1, a2 = match(altname, "([^|]*)|(.*)")
if a1 then name, altname = a1, a2
else name = altname end
end
end
elseif p == "1" then
if last == "ra" then
operands[#operands] = nil
end
else
assert(false)
end
if x then operands[#operands+1] = x; last = x end
end
return putop(ctx, name, operands)
end
------------------------------------------------------------------------------
-- Disassemble a block of code.
local function disass_block(ctx, ofs, len)
if not ofs then ofs = 0 end
local stop = len and ofs+len or #ctx.code
stop = stop - stop % 4
ctx.pos = ofs - ofs % 4
ctx.rel = nil
while ctx.pos < stop do disass_ins(ctx) end
end
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
local function create_(code, addr, out)
local ctx = {}
ctx.code = code
ctx.addr = addr or 0
ctx.out = out or io.write
ctx.symtab = {}
ctx.disass = disass_block
ctx.hexdump = 8
ctx.get = get_be
return ctx
end
local function create_el_(code, addr, out)
local ctx = create_(code, addr, out)
ctx.get = get_le
return ctx
end
-- Simple API: disassemble code (a string) at address and output via out.
local function disass_(code, addr, out)
create_(code, addr, out):disass()
end
local function disass_el_(code, addr, out)
create_el_(code, addr, out):disass()
end
-- Return register name for RID.
local function regname_(r)
if r < 32 then return map_gpr[r] end
return "f"..(r-32)
end
-- Public module functions.
module(...)
create = create_
create_el = create_el_
disass = disass_
disass_el = disass_el_
regname = regname_

View File

@ -1,20 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT MIPSEL disassembler wrapper module.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This module just exports the little-endian functions from the
-- MIPS disassembler module. All the interesting stuff is there.
------------------------------------------------------------------------------
local require = require
module(...)
local dis_mips = require(_PACKAGE.."dis_mips")
create = dis_mips.create_el
disass = dis_mips.disass_el
regname = dis_mips.regname

View File

@ -1,591 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT PPC disassembler module.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT/X license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This is a helper module used by the LuaJIT machine code dumper module.
--
-- It disassembles all common, non-privileged 32/64 bit PowerPC instructions
-- plus the e500 SPE instructions and some Cell/Xenon extensions.
--
-- NYI: VMX, VMX128
------------------------------------------------------------------------------
local type = type
local byte, format = string.byte, string.format
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
local concat = table.concat
local bit = require("bit")
local band, bor, tohex = bit.band, bit.bor, bit.tohex
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
------------------------------------------------------------------------------
-- Primary and extended opcode maps
------------------------------------------------------------------------------
local map_crops = {
shift = 1, mask = 1023,
[0] = "mcrfXX",
[33] = "crnor|crnotCCC=", [129] = "crandcCCC",
[193] = "crxor|crclrCCC%", [225] = "crnandCCC",
[257] = "crandCCC", [289] = "creqv|crsetCCC%",
[417] = "crorcCCC", [449] = "cror|crmoveCCC=",
[16] = "b_lrKB", [528] = "b_ctrKB",
[150] = "isync",
}
local map_rlwinm = setmetatable({
shift = 0, mask = -1,
},
{ __index = function(t, x)
local rot = band(rshift(x, 11), 31)
local mb = band(rshift(x, 6), 31)
local me = band(rshift(x, 1), 31)
if mb == 0 and me == 31-rot then
return "slwiRR~A."
elseif me == 31 and mb == 32-rot then
return "srwiRR~-A."
else
return "rlwinmRR~AAA."
end
end
})
local map_rld = {
shift = 2, mask = 7,
[0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.",
{
shift = 1, mask = 1,
[0] = "rldclRR~RM.", "rldcrRR~RM.",
},
}
local map_ext = setmetatable({
shift = 1, mask = 1023,
[0] = "cmp_YLRR", [32] = "cmpl_YLRR",
[4] = "twARR", [68] = "tdARR",
[8] = "subfcRRR.", [40] = "subfRRR.",
[104] = "negRR.", [136] = "subfeRRR.",
[200] = "subfzeRR.", [232] = "subfmeRR.",
[520] = "subfcoRRR.", [552] = "subfoRRR.",
[616] = "negoRR.", [648] = "subfeoRRR.",
[712] = "subfzeoRR.", [744] = "subfmeoRR.",
[9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.",
[457] = "divduRRR.", [489] = "divdRRR.",
[745] = "mulldoRRR.",
[969] = "divduoRRR.", [1001] = "divdoRRR.",
[10] = "addcRRR.", [138] = "addeRRR.",
[202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.",
[522] = "addcoRRR.", [650] = "addeoRRR.",
[714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.",
[11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.",
[459] = "divwuRRR.", [491] = "divwRRR.",
[747] = "mullwoRRR.",
[971] = "divwouRRR.", [1003] = "divwoRRR.",
[15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR",
[144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", },
[19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", },
[371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", },
[339] = {
shift = 11, mask = 1023,
[32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR",
},
[467] = {
shift = 11, mask = 1023,
[32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR",
},
[20] = "lwarxRR0R", [84] = "ldarxRR0R",
[21] = "ldxRR0R", [53] = "lduxRRR",
[149] = "stdxRR0R", [181] = "stduxRRR",
[341] = "lwaxRR0R", [373] = "lwauxRRR",
[23] = "lwzxRR0R", [55] = "lwzuxRRR",
[87] = "lbzxRR0R", [119] = "lbzuxRRR",
[151] = "stwxRR0R", [183] = "stwuxRRR",
[215] = "stbxRR0R", [247] = "stbuxRRR",
[279] = "lhzxRR0R", [311] = "lhzuxRRR",
[343] = "lhaxRR0R", [375] = "lhauxRRR",
[407] = "sthxRR0R", [439] = "sthuxRRR",
[54] = "dcbst-R0R", [86] = "dcbf-R0R",
[150] = "stwcxRR0R.", [214] = "stdcxRR0R.",
[246] = "dcbtst-R0R", [278] = "dcbt-R0R",
[310] = "eciwxRR0R", [438] = "ecowxRR0R",
[470] = "dcbi-RR",
[598] = {
shift = 21, mask = 3,
[0] = "sync", "lwsync", "ptesync",
},
[758] = "dcba-RR",
[854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R",
[26] = "cntlzwRR~", [58] = "cntlzdRR~",
[122] = "popcntbRR~",
[154] = "prtywRR~", [186] = "prtydRR~",
[28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.",
[284] = "eqvRR~R.", [316] = "xorRR~R.",
[412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.",
[508] = "cmpbRR~R",
[512] = "mcrxrX",
[532] = "ldbrxRR0R", [660] = "stdbrxRR0R",
[533] = "lswxRR0R", [597] = "lswiRR0A",
[661] = "stswxRR0R", [725] = "stswiRR0A",
[534] = "lwbrxRR0R", [662] = "stwbrxRR0R",
[790] = "lhbrxRR0R", [918] = "sthbrxRR0R",
[535] = "lfsxFR0R", [567] = "lfsuxFRR",
[599] = "lfdxFR0R", [631] = "lfduxFRR",
[663] = "stfsxFR0R", [695] = "stfsuxFRR",
[727] = "stfdxFR0R", [759] = "stfduxFR0R",
[855] = "lfiwaxFR0R",
[983] = "stfiwxFR0R",
[24] = "slwRR~R.",
[27] = "sldRR~R.", [536] = "srwRR~R.",
[792] = "srawRR~R.", [824] = "srawiRR~A.",
[794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.",
[922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.",
[539] = "srdRR~R.",
},
{ __index = function(t, x)
if band(x, 31) == 15 then return "iselRRRC" end
end
})
local map_ld = {
shift = 0, mask = 3,
[0] = "ldRRE", "lduRRE", "lwaRRE",
}
local map_std = {
shift = 0, mask = 3,
[0] = "stdRRE", "stduRRE",
}
local map_fps = {
shift = 5, mask = 1,
{
shift = 1, mask = 15,
[0] = false, false, "fdivsFFF.", false,
"fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false,
"fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false,
"fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.",
}
}
local map_fpd = {
shift = 5, mask = 1,
[0] = {
shift = 1, mask = 1023,
[0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX",
[38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>",
[8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.",
[136] = "fnabsF-F.", [264] = "fabsF-F.",
[12] = "frspF-F.",
[14] = "fctiwF-F.", [15] = "fctiwzF-F.",
[583] = "mffsF.", [711] = "mtfsfZF.",
[392] = "frinF-F.", [424] = "frizF-F.",
[456] = "fripF-F.", [488] = "frimF-F.",
[814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.",
},
{
shift = 1, mask = 15,
[0] = false, false, "fdivFFF.", false,
"fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.",
"freF-F.", "fmulFF-F.", "frsqrteF-F.", false,
"fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.",
}
}
local map_spe = {
shift = 0, mask = 2047,
[512] = "evaddwRRR", [514] = "evaddiwRAR~",
[516] = "evsubwRRR~", [518] = "evsubiwRAR~",
[520] = "evabsRR", [521] = "evnegRR",
[522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR",
[525] = "evcntlzwRR", [526] = "evcntlswRR",
[527] = "brincRRR",
[529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR",
[535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=",
[537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR",
[544] = "evsrwuRRR", [545] = "evsrwsRRR",
[546] = "evsrwiuRRA", [547] = "evsrwisRRA",
[548] = "evslwRRR", [550] = "evslwiRRA",
[552] = "evrlwRRR", [553] = "evsplatiRS",
[554] = "evrlwiRRA", [555] = "evsplatfiRS",
[556] = "evmergehiRRR", [557] = "evmergeloRRR",
[558] = "evmergehiloRRR", [559] = "evmergelohiRRR",
[560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR",
[562] = "evcmpltuYRR", [563] = "evcmpltsYRR",
[564] = "evcmpeqYRR",
[632] = "evselRRR", [633] = "evselRRRW",
[634] = "evselRRRW", [635] = "evselRRRW",
[636] = "evselRRRW", [637] = "evselRRRW",
[638] = "evselRRRW", [639] = "evselRRRW",
[640] = "evfsaddRRR", [641] = "evfssubRRR",
[644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR",
[648] = "evfsmulRRR", [649] = "evfsdivRRR",
[652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR",
[656] = "evfscfuiR-R", [657] = "evfscfsiR-R",
[658] = "evfscfufR-R", [659] = "evfscfsfR-R",
[660] = "evfsctuiR-R", [661] = "evfsctsiR-R",
[662] = "evfsctufR-R", [663] = "evfsctsfR-R",
[664] = "evfsctuizR-R", [666] = "evfsctsizR-R",
[668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR",
[704] = "efsaddRRR", [705] = "efssubRRR",
[708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR",
[712] = "efsmulRRR", [713] = "efsdivRRR",
[716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR",
[719] = "efscfdR-R",
[720] = "efscfuiR-R", [721] = "efscfsiR-R",
[722] = "efscfufR-R", [723] = "efscfsfR-R",
[724] = "efsctuiR-R", [725] = "efsctsiR-R",
[726] = "efsctufR-R", [727] = "efsctsfR-R",
[728] = "efsctuizR-R", [730] = "efsctsizR-R",
[732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR",
[736] = "efdaddRRR", [737] = "efdsubRRR",
[738] = "efdcfuidR-R", [739] = "efdcfsidR-R",
[740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR",
[744] = "efdmulRRR", [745] = "efddivRRR",
[746] = "efdctuidzR-R", [747] = "efdctsidzR-R",
[748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR",
[751] = "efdcfsR-R",
[752] = "efdcfuiR-R", [753] = "efdcfsiR-R",
[754] = "efdcfufR-R", [755] = "efdcfsfR-R",
[756] = "efdctuiR-R", [757] = "efdctsiR-R",
[758] = "efdctufR-R", [759] = "efdctsfR-R",
[760] = "efdctuizR-R", [762] = "efdctsizR-R",
[764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR",
[768] = "evlddxRR0R", [769] = "evlddRR8",
[770] = "evldwxRR0R", [771] = "evldwRR8",
[772] = "evldhxRR0R", [773] = "evldhRR8",
[776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2",
[780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2",
[782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2",
[784] = "evlwhexRR0R", [785] = "evlwheRR4",
[788] = "evlwhouxRR0R", [789] = "evlwhouRR4",
[790] = "evlwhosxRR0R", [791] = "evlwhosRR4",
[792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4",
[796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4",
[800] = "evstddxRR0R", [801] = "evstddRR8",
[802] = "evstdwxRR0R", [803] = "evstdwRR8",
[804] = "evstdhxRR0R", [805] = "evstdhRR8",
[816] = "evstwhexRR0R", [817] = "evstwheRR4",
[820] = "evstwhoxRR0R", [821] = "evstwhoRR4",
[824] = "evstwwexRR0R", [825] = "evstwweRR4",
[828] = "evstwwoxRR0R", [829] = "evstwwoRR4",
[1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR",
[1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR",
[1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR",
[1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR",
[1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR",
[1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR",
[1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR",
[1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR",
[1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR",
[1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR",
[1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR",
[1147] = "evmwsmfaRRR",
[1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR",
[1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR",
[1220] = "evmraRR",
[1222] = "evdivwsRRR", [1223] = "evdivwuRRR",
[1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR",
[1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR",
[1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR",
[1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR",
[1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR",
[1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR",
[1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR",
[1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR",
[1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR",
[1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR",
[1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR",
[1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR",
[1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR",
[1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR",
[1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR",
[1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR",
[1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR",
[1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR",
[1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR",
[1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR",
[1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR",
[1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR",
[1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR",
[1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR",
[1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR",
[1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR",
[1491] = "evmwssfanRRR", [1496] = "evmwumianRRR",
[1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR",
}
local map_pri = {
[0] = false, false, "tdiARI", "twiARI",
map_spe, false, false, "mulliRRI",
"subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI",
"addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I",
"b_KBJ", "sc", "bKJ", map_crops,
"rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.",
"oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U",
"andi.RR~U", "andis.RR~U", map_rld, map_ext,
"lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD",
"stwRRD", "stwuRRD", "stbRRD", "stbuRRD",
"lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD",
"sthRRD", "sthuRRD", "lmwRRD", "stmwRRD",
"lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD",
"stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD",
false, false, map_ld, map_fps,
false, false, map_std, map_fpd,
}
------------------------------------------------------------------------------
local map_gpr = {
[0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
}
local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", }
-- Format a condition bit.
local function condfmt(cond)
if cond <= 3 then
return map_cond[band(cond, 3)]
else
return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)])
end
end
------------------------------------------------------------------------------
-- Output a nicely formatted line with an opcode and operands.
local function putop(ctx, text, operands)
local pos = ctx.pos
local extra = ""
if ctx.rel then
local sym = ctx.symtab[ctx.rel]
if sym then extra = "\t->"..sym end
end
if ctx.hexdump > 0 then
ctx.out(format("%08x %s %-7s %s%s\n",
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
else
ctx.out(format("%08x %-7s %s%s\n",
ctx.addr+pos, text, concat(operands, ", "), extra))
end
ctx.pos = pos + 4
end
-- Fallback for unknown opcodes.
local function unknown(ctx)
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
end
-- Disassemble a single instruction.
local function disass_ins(ctx)
local pos = ctx.pos
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
local operands = {}
local last = nil
local rs = 21
ctx.op = op
ctx.rel = nil
local opat = map_pri[rshift(b0, 2)]
while type(opat) ~= "string" do
if not opat then return unknown(ctx) end
opat = opat[band(rshift(op, opat.shift), opat.mask)]
end
local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)")
if altname then pat = pat2 end
for p in gmatch(pat, ".") do
local x = nil
if p == "R" then
x = map_gpr[band(rshift(op, rs), 31)]
rs = rs - 5
elseif p == "F" then
x = "f"..band(rshift(op, rs), 31)
rs = rs - 5
elseif p == "A" then
x = band(rshift(op, rs), 31)
rs = rs - 5
elseif p == "S" then
x = arshift(lshift(op, 27-rs), 27)
rs = rs - 5
elseif p == "I" then
x = arshift(lshift(op, 16), 16)
elseif p == "U" then
x = band(op, 0xffff)
elseif p == "D" or p == "E" then
local disp = arshift(lshift(op, 16), 16)
if p == "E" then disp = band(disp, -4) end
if last == "r0" then last = "0" end
operands[#operands] = format("%d(%s)", disp, last)
elseif p >= "2" and p <= "8" then
local disp = band(rshift(op, rs), 31) * p
if last == "r0" then last = "0" end
operands[#operands] = format("%d(%s)", disp, last)
elseif p == "H" then
x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4)
rs = rs - 5
elseif p == "M" then
x = band(rshift(op, rs), 31) + band(op, 0x20)
elseif p == "C" then
x = condfmt(band(rshift(op, rs), 31))
rs = rs - 5
elseif p == "B" then
local bo = rshift(op, 21)
local cond = band(rshift(op, 16), 31)
local cn = ""
rs = rs - 10
if band(bo, 4) == 0 then
cn = band(bo, 2) == 0 and "dnz" or "dz"
if band(bo, 0x10) == 0 then
cn = cn..(band(bo, 8) == 0 and "f" or "t")
end
if band(bo, 0x10) == 0 then x = condfmt(cond) end
name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+")
elseif band(bo, 0x10) == 0 then
cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)]
if cond > 3 then x = "cr"..rshift(cond, 2) end
name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+")
end
name = gsub(name, "_", cn)
elseif p == "J" then
x = arshift(lshift(op, 27-rs), 29-rs)*4
if band(op, 2) == 0 then x = ctx.addr + pos + x end
ctx.rel = x
x = "0x"..tohex(x)
elseif p == "K" then
if band(op, 1) ~= 0 then name = name.."l" end
if band(op, 2) ~= 0 then name = name.."a" end
elseif p == "X" or p == "Y" then
x = band(rshift(op, rs+2), 7)
if x == 0 and p == "Y" then x = nil else x = "cr"..x end
rs = rs - 5
elseif p == "W" then
x = "cr"..band(op, 7)
elseif p == "Z" then
x = band(rshift(op, rs-4), 255)
rs = rs - 10
elseif p == ">" then
operands[#operands] = rshift(operands[#operands], 1)
elseif p == "0" then
if last == "r0" then
operands[#operands] = nil
if altname then name = altname end
end
elseif p == "L" then
name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w")
elseif p == "." then
if band(op, 1) == 1 then name = name.."." end
elseif p == "N" then
if op == 0x60000000 then name = "nop"; break end
elseif p == "~" then
local n = #operands
operands[n-1], operands[n] = operands[n], operands[n-1]
elseif p == "=" then
local n = #operands
if last == operands[n-1] then
operands[n] = nil
name = altname
end
elseif p == "%" then
local n = #operands
if last == operands[n-1] and last == operands[n-2] then
operands[n] = nil
operands[n-1] = nil
name = altname
end
elseif p == "-" then
rs = rs - 5
else
assert(false)
end
if x then operands[#operands+1] = x; last = x end
end
return putop(ctx, name, operands)
end
------------------------------------------------------------------------------
-- Disassemble a block of code.
local function disass_block(ctx, ofs, len)
if not ofs then ofs = 0 end
local stop = len and ofs+len or #ctx.code
stop = stop - stop % 4
ctx.pos = ofs - ofs % 4
ctx.rel = nil
while ctx.pos < stop do disass_ins(ctx) end
end
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
local function create_(code, addr, out)
local ctx = {}
ctx.code = code
ctx.addr = addr or 0
ctx.out = out or io.write
ctx.symtab = {}
ctx.disass = disass_block
ctx.hexdump = 8
return ctx
end
-- Simple API: disassemble code (a string) at address and output via out.
local function disass_(code, addr, out)
create_(code, addr, out):disass()
end
-- Return register name for RID.
local function regname_(r)
if r < 32 then return map_gpr[r] end
return "f"..(r-32)
end
-- Public module functions.
module(...)
create = create_
disass = disass_
regname = regname_

View File

@ -1,20 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT x64 disassembler wrapper module.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This module just exports the 64 bit functions from the combined
-- x86/x64 disassembler module. All the interesting stuff is there.
------------------------------------------------------------------------------
local require = require
module(...)
local dis_x86 = require(_PACKAGE.."dis_x86")
create = dis_x86.create64
disass = dis_x86.disass64
regname = dis_x86.regname64

View File

@ -1,836 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT x86/x64 disassembler module.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This is a helper module used by the LuaJIT machine code dumper module.
--
-- Sending small code snippets to an external disassembler and mixing the
-- output with our own stuff was too fragile. So I had to bite the bullet
-- and write yet another x86 disassembler. Oh well ...
--
-- The output format is very similar to what ndisasm generates. But it has
-- been developed independently by looking at the opcode tables from the
-- Intel and AMD manuals. The supported instruction set is quite extensive
-- and reflects what a current generation Intel or AMD CPU implements in
-- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3,
-- SSE4.1, SSE4.2, SSE4a and even privileged and hypervisor (VMX/SVM)
-- instructions.
--
-- Notes:
-- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported.
-- * No attempt at optimization has been made -- it's fast enough for my needs.
-- * The public API may change when more architectures are added.
------------------------------------------------------------------------------
local type = type
local sub, byte, format = string.sub, string.byte, string.format
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
local lower, rep = string.lower, string.rep
-- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on.
local map_opc1_32 = {
--0x
[0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es",
"orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*",
--1x
"adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss",
"sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds",
--2x
"andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa",
"subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das",
--3x
"xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa",
"cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas",
--4x
"incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR",
"decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR",
--5x
"pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR",
"popUR","popUR","popUR","popUR","popUR","popUR","popUR","popUR",
--6x
"sz*pushaw,pusha","sz*popaw,popa","boundVrm","arplWmr",
"fs:seg","gs:seg","o16:","a16",
"pushUi","imulVrmi","pushBs","imulVrms",
"insb","insVS","outsb","outsVS",
--7x
"joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj",
"jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj",
--8x
"arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms",
"testBmr","testVmr","xchgBrm","xchgVrm",
"movBmr","movVmr","movBrm","movVrm",
"movVmg","leaVrm","movWgm","popUm",
--9x
"nop*xchgVaR|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR",
"xchgVaR","xchgVaR","xchgVaR","xchgVaR",
"sz*cbw,cwde,cdqe","sz*cwd,cdq,cqo","call farViw","wait",
"sz*pushfw,pushf","sz*popfw,popf","sahf","lahf",
--Ax
"movBao","movVao","movBoa","movVoa",
"movsb","movsVS","cmpsb","cmpsVS",
"testBai","testVai","stosb","stosVS",
"lodsb","lodsVS","scasb","scasVS",
--Bx
"movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi",
"movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI",
--Cx
"shift!Bmu","shift!Vmu","retBw","ret","$lesVrm","$ldsVrm","movBmi","movVmi",
"enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS",
--Dx
"shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb",
"fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7",
--Ex
"loopneBj","loopeBj","loopBj","sz*jcxzBj,jecxzBj,jrcxzBj",
"inBau","inVau","outBua","outVua",
"callVj","jmpVj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda",
--Fx
"lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm",
"clc","stc","cli","sti","cld","std","incb!Bm","incd!Vm",
}
assert(#map_opc1_32 == 255)
-- Map for 1st opcode byte in 64 bit mode (overrides only).
local map_opc1_64 = setmetatable({
[0x06]=false, [0x07]=false, [0x0e]=false,
[0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false,
[0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false,
[0x60]=false, [0x61]=false, [0x62]=false, [0x63]="movsxdVrDmt", [0x67]="a32:",
[0x40]="rex*", [0x41]="rex*b", [0x42]="rex*x", [0x43]="rex*xb",
[0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb",
[0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb",
[0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb",
[0x82]=false, [0x9a]=false, [0xc4]=false, [0xc5]=false, [0xce]=false,
[0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false,
}, { __index = map_opc1_32 })
-- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you.
-- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2
local map_opc2 = {
--0x
[0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret",
"invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu",
--1x
"movupsXrm|movssXrm|movupdXrm|movsdXrm",
"movupsXmr|movssXmr|movupdXmr|movsdXmr",
"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm",
"movlpsXmr||movlpdXmr",
"unpcklpsXrm||unpcklpdXrm",
"unpckhpsXrm||unpckhpdXrm",
"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm",
"movhpsXmr||movhpdXmr",
"$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm",
"hintnopVm","hintnopVm","hintnopVm","hintnopVm",
--2x
"movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil,
"movapsXrm||movapdXrm",
"movapsXmr||movapdXmr",
"cvtpi2psXrMm|cvtsi2ssXrVmt|cvtpi2pdXrMm|cvtsi2sdXrVmt",
"movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr",
"cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm",
"cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm",
"ucomissXrm||ucomisdXrm",
"comissXrm||comisdXrm",
--3x
"wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,"getsec",
"opc3*38",nil,"opc3*3a",nil,nil,nil,nil,nil,
--4x
"cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm",
"cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm",
"cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm",
"cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm",
--5x
"movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm",
"rsqrtpsXrm|rsqrtssXrm","rcppsXrm|rcpssXrm",
"andpsXrm||andpdXrm","andnpsXrm||andnpdXrm",
"orpsXrm||orpdXrm","xorpsXrm||xorpdXrm",
"addpsXrm|addssXrm|addpdXrm|addsdXrm","mulpsXrm|mulssXrm|mulpdXrm|mulsdXrm",
"cvtps2pdXrm|cvtss2sdXrm|cvtpd2psXrm|cvtsd2ssXrm",
"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm",
"subpsXrm|subssXrm|subpdXrm|subsdXrm","minpsXrm|minssXrm|minpdXrm|minsdXrm",
"divpsXrm|divssXrm|divpdXrm|divsdXrm","maxpsXrm|maxssXrm|maxpdXrm|maxsdXrm",
--6x
"punpcklbwPrm","punpcklwdPrm","punpckldqPrm","packsswbPrm",
"pcmpgtbPrm","pcmpgtwPrm","pcmpgtdPrm","packuswbPrm",
"punpckhbwPrm","punpckhwdPrm","punpckhdqPrm","packssdwPrm",
"||punpcklqdqXrm","||punpckhqdqXrm",
"movPrVSm","movqMrm|movdquXrm|movdqaXrm",
--7x
"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pmu",
"pshiftd!Pmu","pshiftq!Mmu||pshiftdq!Xmu",
"pcmpeqbPrm","pcmpeqwPrm","pcmpeqdPrm","emms|",
"vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$",
nil,nil,
"||haddpdXrm|haddpsXrm","||hsubpdXrm|hsubpsXrm",
"movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr",
--8x
"joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj",
"jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj",
--9x
"setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm",
"setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm",
--Ax
"push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil,
"push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm",
--Bx
"cmpxchgBmr","cmpxchgVmr","$lssVrm","btrVmr",
"$lfsVrm","$lgsVrm","movzxVrBmt","movzxVrWmt",
"|popcntVrm","ud2Dp","bt!Vmu","btcVmr",
"bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt",
--Cx
"xaddBmr","xaddVmr",
"cmppsXrmu|cmpssXrmu|cmppdXrmu|cmpsdXrmu","$movntiVmr|",
"pinsrwPrWmu","pextrwDrPmu",
"shufpsXrmu||shufpdXrmu","$cmpxchg!Qmp",
"bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR",
--Dx
"||addsubpdXrm|addsubpsXrm","psrlwPrm","psrldPrm","psrlqPrm",
"paddqPrm","pmullwPrm",
"|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm",
"psubusbPrm","psubuswPrm","pminubPrm","pandPrm",
"paddusbPrm","padduswPrm","pmaxubPrm","pandnPrm",
--Ex
"pavgbPrm","psrawPrm","psradPrm","pavgwPrm",
"pmulhuwPrm","pmulhwPrm",
"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr",
"psubsbPrm","psubswPrm","pminswPrm","porPrm",
"paddsbPrm","paddswPrm","pmaxswPrm","pxorPrm",
--Fx
"|||lddquXrm","psllwPrm","pslldPrm","psllqPrm",
"pmuludqPrm","pmaddwdPrm","psadbwPrm","maskmovqMrm||maskmovdquXrm$",
"psubbPrm","psubwPrm","psubdPrm","psubqPrm",
"paddbPrm","paddwPrm","padddPrm","ud",
}
assert(map_opc2[255] == "ud")
-- Map for three-byte opcodes. Can't wait for their next invention.
local map_opc3 = {
["38"] = { -- [66] 0f 38 xx
--0x
[0]="pshufbPrm","phaddwPrm","phadddPrm","phaddswPrm",
"pmaddubswPrm","phsubwPrm","phsubdPrm","phsubswPrm",
"psignbPrm","psignwPrm","psigndPrm","pmulhrswPrm",
nil,nil,nil,nil,
--1x
"||pblendvbXrma",nil,nil,nil,
"||blendvpsXrma","||blendvpdXrma",nil,"||ptestXrm",
nil,nil,nil,nil,
"pabsbPrm","pabswPrm","pabsdPrm",nil,
--2x
"||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm",
"||pmovsxwqXrm","||pmovsxdqXrm",nil,nil,
"||pmuldqXrm","||pcmpeqqXrm","||$movntdqaXrm","||packusdwXrm",
nil,nil,nil,nil,
--3x
"||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm",
"||pmovzxwqXrm","||pmovzxdqXrm",nil,"||pcmpgtqXrm",
"||pminsbXrm","||pminsdXrm","||pminuwXrm","||pminudXrm",
"||pmaxsbXrm","||pmaxsdXrm","||pmaxuwXrm","||pmaxudXrm",
--4x
"||pmulddXrm","||phminposuwXrm",
--Fx
[0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt",
},
["3a"] = { -- [66] 0f 3a xx
--0x
[0x00]=nil,nil,nil,nil,nil,nil,nil,nil,
"||roundpsXrmu","||roundpdXrmu","||roundssXrmu","||roundsdXrmu",
"||blendpsXrmu","||blendpdXrmu","||pblendwXrmu","palignrPrmu",
--1x
nil,nil,nil,nil,
"||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru",
nil,nil,nil,nil,nil,nil,nil,nil,
--2x
"||pinsrbXrVmu","||insertpsXrmu","||pinsrXrVmuS",nil,
--4x
[0x40] = "||dppsXrmu",
[0x41] = "||dppdXrmu",
[0x42] = "||mpsadbwXrmu",
--6x
[0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu",
[0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu",
},
}
-- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands).
local map_opcvm = {
[0xc1]="vmcall",[0xc2]="vmlaunch",[0xc3]="vmresume",[0xc4]="vmxoff",
[0xc8]="monitor",[0xc9]="mwait",
[0xd8]="vmrun",[0xd9]="vmmcall",[0xda]="vmload",[0xdb]="vmsave",
[0xdc]="stgi",[0xdd]="clgi",[0xde]="skinit",[0xdf]="invlpga",
[0xf8]="swapgs",[0xf9]="rdtscp",
}
-- Map for FP opcodes. And you thought stack machines are simple?
local map_opcfp = {
-- D8-DF 00-BF: opcodes with a memory operand.
-- D8
[0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm",
"fldFm",nil,"fstFm","fstpFm","fldenvVm","fldcwWm","fnstenvVm","fnstcwWm",
-- DA
"fiaddDm","fimulDm","ficomDm","ficompDm",
"fisubDm","fisubrDm","fidivDm","fidivrDm",
-- DB
"fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp",
-- DC
"faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm",
-- DD
"fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm",
-- DE
"fiaddWm","fimulWm","ficomWm","ficompWm",
"fisubWm","fisubrWm","fidivWm","fidivrWm",
-- DF
"fildWm","fisttpWm","fistWm","fistpWm",
"fbld twordFmp","fildQm","fbstp twordFmp","fistpQm",
-- xx C0-FF: opcodes with a pseudo-register operand.
-- D8
"faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf",
-- D9
"fldFf","fxchFf",{"fnop"},nil,
{"fchs","fabs",nil,nil,"ftst","fxam"},
{"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"},
{"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"},
{"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"},
-- DA
"fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil,
-- DB
"fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf",
{nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil,
-- DC
"fadd toFf","fmul toFf",nil,nil,
"fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf",
-- DD
"ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil,
-- DE
"faddpFf","fmulpFf",nil,{nil,"fcompp"},
"fsubrpFf","fsubpFf","fdivrpFf","fdivpFf",
-- DF
nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil,
}
assert(map_opcfp[126] == "fcomipFf")
-- Map for opcode groups. The subkey is sp from the ModRM byte.
local map_opcgroup = {
arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" },
shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" },
testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" },
testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" },
incb = { "inc", "dec" },
incd = { "inc", "dec", "callUmp", "$call farDmp",
"jmpUmp", "$jmp farDmp", "pushUm" },
sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" },
sgdt = { "vm*$sgdt", "vm*$sidt", "$lgdt", "vm*$lidt",
"smsw", nil, "lmsw", "vm*$invlpg" },
bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" },
cmpxchg = { nil, "sz*,cmpxchg8bQmp,cmpxchg16bXmp", nil, nil,
nil, nil, "vmptrld|vmxon|vmclear", "vmptrst" },
pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" },
pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" },
pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" },
pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" },
fxsave = { "$fxsave", "$fxrstor", "$ldmxcsr", "$stmxcsr",
nil, "lfenceDp$", "mfenceDp$", "sfenceDp$clflush" },
prefetch = { "prefetch", "prefetchw" },
prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" },
}
------------------------------------------------------------------------------
-- Maps for register names.
local map_regs = {
B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
B64 = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" },
D = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" },
Q = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" },
M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext!
X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" },
}
local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" }
-- Maps for size names.
local map_sz2n = {
B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16,
}
local map_sz2prefix = {
B = "byte", W = "word", D = "dword",
Q = "qword",
M = "qword", X = "xword",
F = "dword", G = "qword", -- No need for sizes/register names for these two.
}
------------------------------------------------------------------------------
-- Output a nicely formatted line with an opcode and operands.
local function putop(ctx, text, operands)
local code, pos, hex = ctx.code, ctx.pos, ""
local hmax = ctx.hexdump
if hmax > 0 then
for i=ctx.start,pos-1 do
hex = hex..format("%02X", byte(code, i, i))
end
if #hex > hmax then hex = sub(hex, 1, hmax)..". "
else hex = hex..rep(" ", hmax-#hex+2) end
end
if operands then text = text.." "..operands end
if ctx.o16 then text = "o16 "..text; ctx.o16 = false end
if ctx.a32 then text = "a32 "..text; ctx.a32 = false end
if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end
if ctx.rex then
local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "")..
(ctx.rexx and "x" or "")..(ctx.rexb and "b" or "")
if t ~= "" then text = "rex."..t.." "..text end
ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
ctx.rex = false
end
if ctx.seg then
local text2, n = gsub(text, "%[", "["..ctx.seg..":")
if n == 0 then text = ctx.seg.." "..text else text = text2 end
ctx.seg = false
end
if ctx.lock then text = "lock "..text; ctx.lock = false end
local imm = ctx.imm
if imm then
local sym = ctx.symtab[imm]
if sym then text = text.."\t->"..sym end
end
ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text))
ctx.mrm = false
ctx.start = pos
ctx.imm = nil
end
-- Clear all prefix flags.
local function clearprefixes(ctx)
ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false
ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
ctx.rex = false; ctx.a32 = false
end
-- Fallback for incomplete opcodes at the end.
local function incomplete(ctx)
ctx.pos = ctx.stop+1
clearprefixes(ctx)
return putop(ctx, "(incomplete)")
end
-- Fallback for unknown opcodes.
local function unknown(ctx)
clearprefixes(ctx)
return putop(ctx, "(unknown)")
end
-- Return an immediate of the specified size.
local function getimm(ctx, pos, n)
if pos+n-1 > ctx.stop then return incomplete(ctx) end
local code = ctx.code
if n == 1 then
local b1 = byte(code, pos, pos)
return b1
elseif n == 2 then
local b1, b2 = byte(code, pos, pos+1)
return b1+b2*256
else
local b1, b2, b3, b4 = byte(code, pos, pos+3)
local imm = b1+b2*256+b3*65536+b4*16777216
ctx.imm = imm
return imm
end
end
-- Process pattern string and generate the operands.
local function putpat(ctx, name, pat)
local operands, regs, sz, mode, sp, rm, sc, rx, sdisp
local code, pos, stop = ctx.code, ctx.pos, ctx.stop
-- Chars used: 1DFGIMPQRSTUVWXacdfgijmoprstuwxyz
for p in gmatch(pat, ".") do
local x = nil
if p == "V" or p == "U" then
if ctx.rexw then sz = "Q"; ctx.rexw = false
elseif ctx.o16 then sz = "W"; ctx.o16 = false
elseif p == "U" and ctx.x64 then sz = "Q"
else sz = "D" end
regs = map_regs[sz]
elseif p == "T" then
if ctx.rexw then sz = "Q"; ctx.rexw = false else sz = "D" end
regs = map_regs[sz]
elseif p == "B" then
sz = "B"
regs = ctx.rex and map_regs.B64 or map_regs.B
elseif match(p, "[WDQMXFG]") then
sz = p
regs = map_regs[sz]
elseif p == "P" then
sz = ctx.o16 and "X" or "M"; ctx.o16 = false
regs = map_regs[sz]
elseif p == "S" then
name = name..lower(sz)
elseif p == "s" then
local imm = getimm(ctx, pos, 1); if not imm then return end
x = imm <= 127 and format("+0x%02x", imm)
or format("-0x%02x", 256-imm)
pos = pos+1
elseif p == "u" then
local imm = getimm(ctx, pos, 1); if not imm then return end
x = format("0x%02x", imm)
pos = pos+1
elseif p == "w" then
local imm = getimm(ctx, pos, 2); if not imm then return end
x = format("0x%x", imm)
pos = pos+2
elseif p == "o" then -- [offset]
if ctx.x64 then
local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
x = format("[0x%08x%08x]", imm2, imm1)
pos = pos+8
else
local imm = getimm(ctx, pos, 4); if not imm then return end
x = format("[0x%08x]", imm)
pos = pos+4
end
elseif p == "i" or p == "I" then
local n = map_sz2n[sz]
if n == 8 and ctx.x64 and p == "I" then
local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
x = format("0x%08x%08x", imm2, imm1)
else
if n == 8 then n = 4 end
local imm = getimm(ctx, pos, n); if not imm then return end
if sz == "Q" and (imm < 0 or imm > 0x7fffffff) then
imm = (0xffffffff+1)-imm
x = format(imm > 65535 and "-0x%08x" or "-0x%x", imm)
else
x = format(imm > 65535 and "0x%08x" or "0x%x", imm)
end
end
pos = pos+n
elseif p == "j" then
local n = map_sz2n[sz]
if n == 8 then n = 4 end
local imm = getimm(ctx, pos, n); if not imm then return end
if sz == "B" and imm > 127 then imm = imm-256
elseif imm > 2147483647 then imm = imm-4294967296 end
pos = pos+n
imm = imm + pos + ctx.addr
if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end
ctx.imm = imm
if sz == "W" then
x = format("word 0x%04x", imm%65536)
elseif ctx.x64 then
local lo = imm % 0x1000000
x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo)
else
x = format("0x%08x", imm)
end
elseif p == "R" then
local r = byte(code, pos-1, pos-1)%8
if ctx.rexb then r = r + 8; ctx.rexb = false end
x = regs[r+1]
elseif p == "a" then x = regs[1]
elseif p == "c" then x = "cl"
elseif p == "d" then x = "dx"
elseif p == "1" then x = "1"
else
if not mode then
mode = ctx.mrm
if not mode then
if pos > stop then return incomplete(ctx) end
mode = byte(code, pos, pos)
pos = pos+1
end
rm = mode%8; mode = (mode-rm)/8
sp = mode%8; mode = (mode-sp)/8
sdisp = ""
if mode < 3 then
if rm == 4 then
if pos > stop then return incomplete(ctx) end
sc = byte(code, pos, pos)
pos = pos+1
rm = sc%8; sc = (sc-rm)/8
rx = sc%8; sc = (sc-rx)/8
if ctx.rexx then rx = rx + 8; ctx.rexx = false end
if rx == 4 then rx = nil end
end
if mode > 0 or rm == 5 then
local dsz = mode
if dsz ~= 1 then dsz = 4 end
local disp = getimm(ctx, pos, dsz); if not disp then return end
if mode == 0 then rm = nil end
if rm or rx or (not sc and ctx.x64 and not ctx.a32) then
if dsz == 1 and disp > 127 then
sdisp = format("-0x%x", 256-disp)
elseif disp >= 0 and disp <= 0x7fffffff then
sdisp = format("+0x%x", disp)
else
sdisp = format("-0x%x", (0xffffffff+1)-disp)
end
else
sdisp = format(ctx.x64 and not ctx.a32 and
not (disp >= 0 and disp <= 0x7fffffff)
and "0xffffffff%08x" or "0x%08x", disp)
end
pos = pos+dsz
end
end
if rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end
if ctx.rexr then sp = sp + 8; ctx.rexr = false end
end
if p == "m" then
if mode == 3 then x = regs[rm+1]
else
local aregs = ctx.a32 and map_regs.D or ctx.aregs
local srm, srx = "", ""
if rm then srm = aregs[rm+1]
elseif not sc and ctx.x64 and not ctx.a32 then srm = "rip" end
ctx.a32 = false
if rx then
if rm then srm = srm.."+" end
srx = aregs[rx+1]
if sc > 0 then srx = srx.."*"..(2^sc) end
end
x = format("[%s%s%s]", srm, srx, sdisp)
end
if mode < 3 and
(not match(pat, "[aRrgp]") or match(pat, "t")) then -- Yuck.
x = map_sz2prefix[sz].." "..x
end
elseif p == "r" then x = regs[sp+1]
elseif p == "g" then x = map_segregs[sp+1]
elseif p == "p" then -- Suppress prefix.
elseif p == "f" then x = "st"..rm
elseif p == "x" then
if sp == 0 and ctx.lock and not ctx.x64 then
x = "CR8"; ctx.lock = false
else
x = "CR"..sp
end
elseif p == "y" then x = "DR"..sp
elseif p == "z" then x = "TR"..sp
elseif p == "t" then
else
error("bad pattern `"..pat.."'")
end
end
if x then operands = operands and operands..", "..x or x end
end
ctx.pos = pos
return putop(ctx, name, operands)
end
-- Forward declaration.
local map_act
-- Fetch and cache MRM byte.
local function getmrm(ctx)
local mrm = ctx.mrm
if not mrm then
local pos = ctx.pos
if pos > ctx.stop then return nil end
mrm = byte(ctx.code, pos, pos)
ctx.pos = pos+1
ctx.mrm = mrm
end
return mrm
end
-- Dispatch to handler depending on pattern.
local function dispatch(ctx, opat, patgrp)
if not opat then return unknown(ctx) end
if match(opat, "%|") then -- MMX/SSE variants depending on prefix.
local p
if ctx.rep then
p = ctx.rep=="rep" and "%|([^%|]*)" or "%|[^%|]*%|[^%|]*%|([^%|]*)"
ctx.rep = false
elseif ctx.o16 then p = "%|[^%|]*%|([^%|]*)"; ctx.o16 = false
else p = "^[^%|]*" end
opat = match(opat, p)
if not opat then return unknown(ctx) end
-- ctx.rep = false; ctx.o16 = false
--XXX fails for 66 f2 0f 38 f1 06 crc32 eax,WORD PTR [esi]
--XXX remove in branches?
end
if match(opat, "%$") then -- reg$mem variants.
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
opat = match(opat, mrm >= 192 and "^[^%$]*" or "%$(.*)")
if opat == "" then return unknown(ctx) end
end
if opat == "" then return unknown(ctx) end
local name, pat = match(opat, "^([a-z0-9 ]*)(.*)")
if pat == "" and patgrp then pat = patgrp end
return map_act[sub(pat, 1, 1)](ctx, name, pat)
end
-- Get a pattern from an opcode map and dispatch to handler.
local function dispatchmap(ctx, opcmap)
local pos = ctx.pos
local opat = opcmap[byte(ctx.code, pos, pos)]
pos = pos + 1
ctx.pos = pos
return dispatch(ctx, opat)
end
-- Map for action codes. The key is the first char after the name.
map_act = {
-- Simple opcodes without operands.
[""] = function(ctx, name, pat)
return putop(ctx, name)
end,
-- Operand size chars fall right through.
B = putpat, W = putpat, D = putpat, Q = putpat,
V = putpat, U = putpat, T = putpat,
M = putpat, X = putpat, P = putpat,
F = putpat, G = putpat,
-- Collect prefixes.
[":"] = function(ctx, name, pat)
ctx[pat == ":" and name or sub(pat, 2)] = name
if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes.
end,
-- Chain to special handler specified by name.
["*"] = function(ctx, name, pat)
return map_act[name](ctx, name, sub(pat, 2))
end,
-- Use named subtable for opcode group.
["!"] = function(ctx, name, pat)
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2))
end,
-- o16,o32[,o64] variants.
sz = function(ctx, name, pat)
if ctx.o16 then ctx.o16 = false
else
pat = match(pat, ",(.*)")
if ctx.rexw then
local p = match(pat, ",(.*)")
if p then pat = p; ctx.rexw = false end
end
end
pat = match(pat, "^[^,]*")
return dispatch(ctx, pat)
end,
-- Two-byte opcode dispatch.
opc2 = function(ctx, name, pat)
return dispatchmap(ctx, map_opc2)
end,
-- Three-byte opcode dispatch.
opc3 = function(ctx, name, pat)
return dispatchmap(ctx, map_opc3[pat])
end,
-- VMX/SVM dispatch.
vm = function(ctx, name, pat)
return dispatch(ctx, map_opcvm[ctx.mrm])
end,
-- Floating point opcode dispatch.
fp = function(ctx, name, pat)
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
local rm = mrm%8
local idx = pat*8 + ((mrm-rm)/8)%8
if mrm >= 192 then idx = idx + 64 end
local opat = map_opcfp[idx]
if type(opat) == "table" then opat = opat[rm+1] end
return dispatch(ctx, opat)
end,
-- REX prefix.
rex = function(ctx, name, pat)
if ctx.rex then return unknown(ctx) end -- Only 1 REX prefix allowed.
for p in gmatch(pat, ".") do ctx["rex"..p] = true end
ctx.rex = true
end,
-- Special case for nop with REX prefix.
nop = function(ctx, name, pat)
return dispatch(ctx, ctx.rex and pat or "nop")
end,
}
------------------------------------------------------------------------------
-- Disassemble a block of code.
local function disass_block(ctx, ofs, len)
if not ofs then ofs = 0 end
local stop = len and ofs+len or #ctx.code
ofs = ofs + 1
ctx.start = ofs
ctx.pos = ofs
ctx.stop = stop
ctx.imm = nil
ctx.mrm = false
clearprefixes(ctx)
while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end
if ctx.pos ~= ctx.start then incomplete(ctx) end
end
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
local function create_(code, addr, out)
local ctx = {}
ctx.code = code
ctx.addr = (addr or 0) - 1
ctx.out = out or io.write
ctx.symtab = {}
ctx.disass = disass_block
ctx.hexdump = 16
ctx.x64 = false
ctx.map1 = map_opc1_32
ctx.aregs = map_regs.D
return ctx
end
local function create64_(code, addr, out)
local ctx = create_(code, addr, out)
ctx.x64 = true
ctx.map1 = map_opc1_64
ctx.aregs = map_regs.Q
return ctx
end
-- Simple API: disassemble code (a string) at address and output via out.
local function disass_(code, addr, out)
create_(code, addr, out):disass()
end
local function disass64_(code, addr, out)
create64_(code, addr, out):disass()
end
-- Return register name for RID.
local function regname_(r)
if r < 8 then return map_regs.D[r+1] end
return map_regs.X[r-7]
end
local function regname64_(r)
if r < 16 then return map_regs.Q[r+1] end
return map_regs.X[r-15]
end
-- Public module functions.
module(...)
create = create_
create64 = create64_
disass = disass_
disass64 = disass64_
regname = regname_
regname64 = regname64_

View File

@ -1,701 +0,0 @@
----------------------------------------------------------------------------
-- LuaJIT compiler dump module.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module can be used to debug the JIT compiler itself. It dumps the
-- code representations and structures used in various compiler stages.
--
-- Example usage:
--
-- luajit -jdump -e "local x=0; for i=1,1e6 do x=x+i end; print(x)"
-- luajit -jdump=im -e "for i=1,1000 do for j=1,1000 do end end" | less -R
-- luajit -jdump=is myapp.lua | less -R
-- luajit -jdump=-b myapp.lua
-- luajit -jdump=+aH,myapp.html myapp.lua
-- luajit -jdump=ixT,myapp.dump myapp.lua
--
-- The first argument specifies the dump mode. The second argument gives
-- the output file name. Default output is to stdout, unless the environment
-- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the
-- module is started.
--
-- Different features can be turned on or off with the dump mode. If the
-- mode starts with a '+', the following features are added to the default
-- set of features; a '-' removes them. Otherwise the features are replaced.
--
-- The following dump features are available (* marks the default):
--
-- * t Print a line for each started, ended or aborted trace (see also -jv).
-- * b Dump the traced bytecode.
-- * i Dump the IR (intermediate representation).
-- r Augment the IR with register/stack slots.
-- s Dump the snapshot map.
-- * m Dump the generated machine code.
-- x Print each taken trace exit.
-- X Print each taken trace exit and the contents of all registers.
-- a Print the IR of aborted traces, too.
--
-- The output format can be set with the following characters:
--
-- T Plain text output.
-- A ANSI-colored text output
-- H Colorized HTML + CSS output.
--
-- The default output format is plain text. It's set to ANSI-colored text
-- if the COLORTERM variable is set. Note: this is independent of any output
-- redirection, which is actually considered a feature.
--
-- You probably want to use less -R to enjoy viewing ANSI-colored text from
-- a pipe or a file. Add this to your ~/.bashrc: export LESS="-R"
--
------------------------------------------------------------------------------
-- Cache some library functions and objects.
local jit = require("jit")
assert(jit.version_num == 20005, "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local vmdef = require("jit.vmdef")
local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc
local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek
local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap
local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr
local bit = require("bit")
local band, shr = bit.band, bit.rshift
local sub, gsub, format = string.sub, string.gsub, string.format
local byte, rep = string.byte, string.rep
local type, tostring = type, tostring
local stdout, stderr = io.stdout, io.stderr
-- Load other modules on-demand.
local bcline, disass
-- Active flag, output file handle and dump mode.
local active, out, dumpmode
------------------------------------------------------------------------------
local symtabmt = { __index = false }
local symtab = {}
local nexitsym = 0
-- Fill nested symbol table with per-trace exit stub addresses.
local function fillsymtab_tr(tr, nexit)
local t = {}
symtabmt.__index = t
if jit.arch == "mips" or jit.arch == "mipsel" then
t[traceexitstub(tr, 0)] = "exit"
return
end
for i=0,nexit-1 do
local addr = traceexitstub(tr, i)
t[addr] = tostring(i)
end
local addr = traceexitstub(tr, nexit)
if addr then t[addr] = "stack_check" end
end
-- Fill symbol table with trace exit stub addresses.
local function fillsymtab(tr, nexit)
local t = symtab
if nexitsym == 0 then
local ircall = vmdef.ircall
for i=0,#ircall do
local addr = ircalladdr(i)
if addr ~= 0 then t[addr] = ircall[i] end
end
end
if nexitsym == 1000000 then -- Per-trace exit stubs.
fillsymtab_tr(tr, nexit)
elseif nexit > nexitsym then -- Shared exit stubs.
for i=nexitsym,nexit-1 do
local addr = traceexitstub(i)
if addr == nil then -- Fall back to per-trace exit stubs.
fillsymtab_tr(tr, nexit)
setmetatable(symtab, symtabmt)
nexit = 1000000
break
end
t[addr] = tostring(i)
end
nexitsym = nexit
end
return t
end
local function dumpwrite(s)
out:write(s)
end
-- Disassemble machine code.
local function dump_mcode(tr)
local info = traceinfo(tr)
if not info then return end
local mcode, addr, loop = tracemc(tr)
if not mcode then return end
if not disass then disass = require("jit.dis_"..jit.arch) end
out:write("---- TRACE ", tr, " mcode ", #mcode, "\n")
local ctx = disass.create(mcode, addr, dumpwrite)
ctx.hexdump = 0
ctx.symtab = fillsymtab(tr, info.nexit)
if loop ~= 0 then
symtab[addr+loop] = "LOOP"
ctx:disass(0, loop)
out:write("->LOOP:\n")
ctx:disass(loop, #mcode-loop)
symtab[addr+loop] = nil
else
ctx:disass(0, #mcode)
end
end
------------------------------------------------------------------------------
local irtype_text = {
[0] = "nil",
"fal",
"tru",
"lud",
"str",
"p32",
"thr",
"pro",
"fun",
"p64",
"cdt",
"tab",
"udt",
"flt",
"num",
"i8 ",
"u8 ",
"i16",
"u16",
"int",
"u32",
"i64",
"u64",
"sfp",
}
local colortype_ansi = {
[0] = "%s",
"%s",
"%s",
"\027[36m%s\027[m",
"\027[32m%s\027[m",
"%s",
"\027[1m%s\027[m",
"%s",
"\027[1m%s\027[m",
"%s",
"\027[33m%s\027[m",
"\027[31m%s\027[m",
"\027[36m%s\027[m",
"\027[34m%s\027[m",
"\027[34m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
}
local function colorize_text(s)
return s
end
local function colorize_ansi(s, t)
return format(colortype_ansi[t], s)
end
local irtype_ansi = setmetatable({},
{ __index = function(tab, t)
local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end })
local html_escape = { ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;", }
local function colorize_html(s, t)
s = gsub(s, "[<>&]", html_escape)
return format('<span class="irt_%s">%s</span>', irtype_text[t], s)
end
local irtype_html = setmetatable({},
{ __index = function(tab, t)
local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end })
local header_html = [[
<style type="text/css">
background { background: #ffffff; color: #000000; }
pre.ljdump {
font-size: 10pt;
background: #f0f4ff;
color: #000000;
border: 1px solid #bfcfff;
padding: 0.5em;
margin-left: 2em;
margin-right: 2em;
}
span.irt_str { color: #00a000; }
span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; }
span.irt_tab { color: #c00000; }
span.irt_udt, span.irt_lud { color: #00c0c0; }
span.irt_num { color: #4040c0; }
span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; }
</style>
]]
local colorize, irtype
-- Lookup tables to convert some literals into names.
local litname = {
["SLOAD "] = setmetatable({}, { __index = function(t, mode)
local s = ""
if band(mode, 1) ~= 0 then s = s.."P" end
if band(mode, 2) ~= 0 then s = s.."F" end
if band(mode, 4) ~= 0 then s = s.."T" end
if band(mode, 8) ~= 0 then s = s.."C" end
if band(mode, 16) ~= 0 then s = s.."R" end
if band(mode, 32) ~= 0 then s = s.."I" end
t[mode] = s
return s
end}),
["XLOAD "] = { [0] = "", "R", "V", "RV", "U", "RU", "VU", "RVU", },
["CONV "] = setmetatable({}, { __index = function(t, mode)
local s = irtype[band(mode, 31)]
s = irtype[band(shr(mode, 5), 31)].."."..s
if band(mode, 0x400) ~= 0 then s = s.." trunc"
elseif band(mode, 0x800) ~= 0 then s = s.." sext" end
local c = shr(mode, 14)
if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end
t[mode] = s
return s
end}),
["FLOAD "] = vmdef.irfield,
["FREF "] = vmdef.irfield,
["FPMATH"] = vmdef.irfpm,
}
local function ctlsub(c)
if c == "\n" then return "\\n"
elseif c == "\r" then return "\\r"
elseif c == "\t" then return "\\t"
else return format("\\%03d", byte(c))
end
end
local function fmtfunc(func, pc)
local fi = funcinfo(func, pc)
if fi.loc then
return fi.loc
elseif fi.ffid then
return vmdef.ffnames[fi.ffid]
elseif fi.addr then
return format("C:%x", fi.addr)
else
return "(?)"
end
end
local function formatk(tr, idx)
local k, t, slot = tracek(tr, idx)
local tn = type(k)
local s
if tn == "number" then
if k == 2^52+2^51 then
s = "bias"
else
s = format("%+.14g", k)
end
elseif tn == "string" then
s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub))
elseif tn == "function" then
s = fmtfunc(k)
elseif tn == "table" then
s = format("{%p}", k)
elseif tn == "userdata" then
if t == 12 then
s = format("userdata:%p", k)
else
s = format("[%p]", k)
if s == "[NULL]" then s = "NULL" end
end
elseif t == 21 then -- int64_t
s = sub(tostring(k), 1, -3)
if sub(s, 1, 1) ~= "-" then s = "+"..s end
else
s = tostring(k) -- For primitives.
end
s = colorize(format("%-4s", s), t)
if slot then
s = format("%s @%d", s, slot)
end
return s
end
local function printsnap(tr, snap)
local n = 2
for s=0,snap[1]-1 do
local sn = snap[n]
if shr(sn, 24) == s then
n = n + 1
local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS
if ref < 0 then
out:write(formatk(tr, ref))
elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM
out:write(colorize(format("%04d/%04d", ref, ref+1), 14))
else
local m, ot, op1, op2 = traceir(tr, ref)
out:write(colorize(format("%04d", ref), band(ot, 31)))
end
out:write(band(sn, 0x10000) == 0 and " " or "|") -- SNAP_FRAME
else
out:write("---- ")
end
end
out:write("]\n")
end
-- Dump snapshots (not interleaved with IR).
local function dump_snap(tr)
out:write("---- TRACE ", tr, " snapshots\n")
for i=0,1000000000 do
local snap = tracesnap(tr, i)
if not snap then break end
out:write(format("#%-3d %04d [ ", i, snap[0]))
printsnap(tr, snap)
end
end
-- Return a register name or stack slot for a rid/sp location.
local function ridsp_name(ridsp, ins)
if not disass then disass = require("jit.dis_"..jit.arch) end
local rid, slot = band(ridsp, 0xff), shr(ridsp, 8)
if rid == 253 or rid == 254 then
return (slot == 0 or slot == 255) and " {sink" or format(" {%04d", ins-slot)
end
if ridsp > 255 then return format("[%x]", slot*4) end
if rid < 128 then return disass.regname(rid) end
return ""
end
-- Dump CALL* function ref and return optional ctype.
local function dumpcallfunc(tr, ins)
local ctype
if ins > 0 then
local m, ot, op1, op2 = traceir(tr, ins)
if band(ot, 31) == 0 then -- nil type means CARG(func, ctype).
ins = op1
ctype = formatk(tr, op2)
end
end
if ins < 0 then
out:write(format("[0x%x](", tonumber((tracek(tr, ins)))))
else
out:write(format("%04d (", ins))
end
return ctype
end
-- Recursively gather CALL* args and dump them.
local function dumpcallargs(tr, ins)
if ins < 0 then
out:write(formatk(tr, ins))
else
local m, ot, op1, op2 = traceir(tr, ins)
local oidx = 6*shr(ot, 8)
local op = sub(vmdef.irnames, oidx+1, oidx+6)
if op == "CARG " then
dumpcallargs(tr, op1)
if op2 < 0 then
out:write(" ", formatk(tr, op2))
else
out:write(" ", format("%04d", op2))
end
else
out:write(format("%04d", ins))
end
end
end
-- Dump IR and interleaved snapshots.
local function dump_ir(tr, dumpsnap, dumpreg)
local info = traceinfo(tr)
if not info then return end
local nins = info.nins
out:write("---- TRACE ", tr, " IR\n")
local irnames = vmdef.irnames
local snapref = 65536
local snap, snapno
if dumpsnap then
snap = tracesnap(tr, 0)
snapref = snap[0]
snapno = 0
end
for ins=1,nins do
if ins >= snapref then
if dumpreg then
out:write(format(".... SNAP #%-3d [ ", snapno))
else
out:write(format(".... SNAP #%-3d [ ", snapno))
end
printsnap(tr, snap)
snapno = snapno + 1
snap = tracesnap(tr, snapno)
snapref = snap and snap[0] or 65536
end
local m, ot, op1, op2, ridsp = traceir(tr, ins)
local oidx, t = 6*shr(ot, 8), band(ot, 31)
local op = sub(irnames, oidx+1, oidx+6)
if op == "LOOP " then
if dumpreg then
out:write(format("%04d ------------ LOOP ------------\n", ins))
else
out:write(format("%04d ------ LOOP ------------\n", ins))
end
elseif op ~= "NOP " and op ~= "CARG " and
(dumpreg or op ~= "RENAME") then
local rid = band(ridsp, 255)
if dumpreg then
out:write(format("%04d %-6s", ins, ridsp_name(ridsp, ins)))
else
out:write(format("%04d ", ins))
end
out:write(format("%s%s %s %s ",
(rid == 254 or rid == 253) and "}" or
(band(ot, 128) == 0 and " " or ">"),
band(ot, 64) == 0 and " " or "+",
irtype[t], op))
local m1, m2 = band(m, 3), band(m, 3*4)
if sub(op, 1, 4) == "CALL" then
local ctype
if m2 == 1*4 then -- op2 == IRMlit
out:write(format("%-10s (", vmdef.ircall[op2]))
else
ctype = dumpcallfunc(tr, op2)
end
if op1 ~= -1 then dumpcallargs(tr, op1) end
out:write(")")
if ctype then out:write(" ctype ", ctype) end
elseif op == "CNEW " and op2 == -1 then
out:write(formatk(tr, op1))
elseif m1 ~= 3 then -- op1 != IRMnone
if op1 < 0 then
out:write(formatk(tr, op1))
else
out:write(format(m1 == 0 and "%04d" or "#%-3d", op1))
end
if m2 ~= 3*4 then -- op2 != IRMnone
if m2 == 1*4 then -- op2 == IRMlit
local litn = litname[op]
if litn and litn[op2] then
out:write(" ", litn[op2])
elseif op == "UREFO " or op == "UREFC " then
out:write(format(" #%-3d", shr(op2, 8)))
else
out:write(format(" #%-3d", op2))
end
elseif op2 < 0 then
out:write(" ", formatk(tr, op2))
else
out:write(format(" %04d", op2))
end
end
end
out:write("\n")
end
end
if snap then
if dumpreg then
out:write(format(".... SNAP #%-3d [ ", snapno))
else
out:write(format(".... SNAP #%-3d [ ", snapno))
end
printsnap(tr, snap)
end
end
------------------------------------------------------------------------------
local recprefix = ""
local recdepth = 0
-- Format trace error message.
local function fmterr(err, info)
if type(err) == "number" then
if type(info) == "function" then info = fmtfunc(info) end
err = format(vmdef.traceerr[err], info)
end
return err
end
-- Dump trace states.
local function dump_trace(what, tr, func, pc, otr, oex)
if what == "stop" or (what == "abort" and dumpmode.a) then
if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == "stop")
elseif dumpmode.s then dump_snap(tr) end
if dumpmode.m then dump_mcode(tr) end
end
if what == "start" then
if dumpmode.H then out:write('<pre class="ljdump">\n') end
out:write("---- TRACE ", tr, " ", what)
if otr then out:write(" ", otr, "/", oex) end
out:write(" ", fmtfunc(func, pc), "\n")
elseif what == "stop" or what == "abort" then
out:write("---- TRACE ", tr, " ", what)
if what == "abort" then
out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n")
else
local info = traceinfo(tr)
local link, ltype = info.link, info.linktype
if link == tr or link == 0 then
out:write(" -> ", ltype, "\n")
elseif ltype == "root" then
out:write(" -> ", link, "\n")
else
out:write(" -> ", link, " ", ltype, "\n")
end
end
if dumpmode.H then out:write("</pre>\n\n") else out:write("\n") end
else
if what == "flush" then symtab, nexitsym = {}, 0 end
out:write("---- TRACE ", what, "\n\n")
end
out:flush()
end
-- Dump recorded bytecode.
local function dump_record(tr, func, pc, depth, callee)
if depth ~= recdepth then
recdepth = depth
recprefix = rep(" .", depth)
end
local line
if pc >= 0 then
line = bcline(func, pc, recprefix)
if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end
else
line = "0000 "..recprefix.." FUNCC \n"
callee = func
end
if pc <= 0 then
out:write(sub(line, 1, -2), " ; ", fmtfunc(func), "\n")
else
out:write(line)
end
if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC
out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond.
end
end
------------------------------------------------------------------------------
-- Dump taken trace exits.
local function dump_texit(tr, ex, ngpr, nfpr, ...)
out:write("---- TRACE ", tr, " exit ", ex, "\n")
if dumpmode.X then
local regs = {...}
if jit.arch == "x64" then
for i=1,ngpr do
out:write(format(" %016x", regs[i]))
if i % 4 == 0 then out:write("\n") end
end
else
for i=1,ngpr do
out:write(format(" %08x", regs[i]))
if i % 8 == 0 then out:write("\n") end
end
end
if jit.arch == "mips" or jit.arch == "mipsel" then
for i=1,nfpr,2 do
out:write(format(" %+17.14g", regs[ngpr+i]))
if i % 8 == 7 then out:write("\n") end
end
else
for i=1,nfpr do
out:write(format(" %+17.14g", regs[ngpr+i]))
if i % 4 == 0 then out:write("\n") end
end
end
end
end
------------------------------------------------------------------------------
-- Detach dump handlers.
local function dumpoff()
if active then
active = false
jit.attach(dump_texit)
jit.attach(dump_record)
jit.attach(dump_trace)
if out and out ~= stdout and out ~= stderr then out:close() end
out = nil
end
end
-- Open the output file and attach dump handlers.
local function dumpon(opt, outfile)
if active then dumpoff() end
local term = os.getenv("TERM")
local colormode = (term and term:match("color") or os.getenv("COLORTERM")) and "A" or "T"
if opt then
opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end)
end
local m = { t=true, b=true, i=true, m=true, }
if opt and opt ~= "" then
local o = sub(opt, 1, 1)
if o ~= "+" and o ~= "-" then m = {} end
for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end
end
dumpmode = m
if m.t or m.b or m.i or m.s or m.m then
jit.attach(dump_trace, "trace")
end
if m.b then
jit.attach(dump_record, "record")
if not bcline then bcline = require("jit.bc").line end
end
if m.x or m.X then
jit.attach(dump_texit, "texit")
end
if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end
if outfile then
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
else
out = stdout
end
m[colormode] = true
if colormode == "A" then
colorize = colorize_ansi
irtype = irtype_ansi
elseif colormode == "H" then
colorize = colorize_html
irtype = irtype_html
out:write(header_html)
else
colorize = colorize_text
irtype = irtype_text
end
active = true
end
-- Public module functions.
module(...)
on = dumpon
off = dumpoff
start = dumpon -- For -j command line option.

View File

@ -1,167 +0,0 @@
----------------------------------------------------------------------------
-- Verbose mode of the LuaJIT compiler.
--
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module shows verbose information about the progress of the
-- JIT compiler. It prints one line for each generated trace. This module
-- is useful to see which code has been compiled or where the compiler
-- punts and falls back to the interpreter.
--
-- Example usage:
--
-- luajit -jv -e "for i=1,1000 do for j=1,1000 do end end"
-- luajit -jv=myapp.out myapp.lua
--
-- Default output is to stderr. To redirect the output to a file, pass a
-- filename as an argument (use '-' for stdout) or set the environment
-- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the
-- module is started.
--
-- The output from the first example should look like this:
--
-- [TRACE 1 (command line):1 loop]
-- [TRACE 2 (1/3) (command line):1 -> 1]
--
-- The first number in each line is the internal trace number. Next are
-- the file name ('(command line)') and the line number (':1') where the
-- trace has started. Side traces also show the parent trace number and
-- the exit number where they are attached to in parentheses ('(1/3)').
-- An arrow at the end shows where the trace links to ('-> 1'), unless
-- it loops to itself.
--
-- In this case the inner loop gets hot and is traced first, generating
-- a root trace. Then the last exit from the 1st trace gets hot, too,
-- and triggers generation of the 2nd trace. The side trace follows the
-- path along the outer loop and *around* the inner loop, back to its
-- start, and then links to the 1st trace. Yes, this may seem unusual,
-- if you know how traditional compilers work. Trace compilers are full
-- of surprises like this -- have fun! :-)
--
-- Aborted traces are shown like this:
--
-- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50]
--
-- Don't worry -- trace aborts are quite common, even in programs which
-- can be fully compiled. The compiler may retry several times until it
-- finds a suitable trace.
--
-- Of course this doesn't work with features that are not-yet-implemented
-- (NYI error messages). The VM simply falls back to the interpreter. This
-- may not matter at all if the particular trace is not very high up in
-- the CPU usage profile. Oh, and the interpreter is quite fast, too.
--
-- Also check out the -jdump module, which prints all the gory details.
--
------------------------------------------------------------------------------
-- Cache some library functions and objects.
local jit = require("jit")
assert(jit.version_num == 20005, "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local vmdef = require("jit.vmdef")
local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo
local type, format = type, string.format
local stdout, stderr = io.stdout, io.stderr
-- Active flag and output file handle.
local active, out
------------------------------------------------------------------------------
local startloc, startex
local function fmtfunc(func, pc)
local fi = funcinfo(func, pc)
if fi.loc then
return fi.loc
elseif fi.ffid then
return vmdef.ffnames[fi.ffid]
elseif fi.addr then
return format("C:%x", fi.addr)
else
return "(?)"
end
end
-- Format trace error message.
local function fmterr(err, info)
if type(err) == "number" then
if type(info) == "function" then info = fmtfunc(info) end
err = format(vmdef.traceerr[err], info)
end
return err
end
-- Dump trace states.
local function dump_trace(what, tr, func, pc, otr, oex)
if what == "start" then
startloc = fmtfunc(func, pc)
startex = otr and "("..otr.."/"..oex..") " or ""
else
if what == "abort" then
local loc = fmtfunc(func, pc)
if loc ~= startloc then
out:write(format("[TRACE --- %s%s -- %s at %s]\n",
startex, startloc, fmterr(otr, oex), loc))
else
out:write(format("[TRACE --- %s%s -- %s]\n",
startex, startloc, fmterr(otr, oex)))
end
elseif what == "stop" then
local info = traceinfo(tr)
local link, ltype = info.link, info.linktype
if ltype == "interpreter" then
out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
tr, startex, startloc))
elseif link == tr or link == 0 then
out:write(format("[TRACE %3s %s%s %s]\n",
tr, startex, startloc, ltype))
elseif ltype == "root" then
out:write(format("[TRACE %3s %s%s -> %d]\n",
tr, startex, startloc, link))
else
out:write(format("[TRACE %3s %s%s -> %d %s]\n",
tr, startex, startloc, link, ltype))
end
else
out:write(format("[TRACE %s]\n", what))
end
out:flush()
end
end
------------------------------------------------------------------------------
-- Detach dump handlers.
local function dumpoff()
if active then
active = false
jit.attach(dump_trace)
if out and out ~= stdout and out ~= stderr then out:close() end
out = nil
end
end
-- Open the output file and attach dump handlers.
local function dumpon(outfile)
if active then dumpoff() end
if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end
if outfile then
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
else
out = stderr
end
jit.attach(dump_trace, "trace")
active = true
end
-- Public module functions.
module(...)
on = dumpon
off = dumpoff
start = dumpon -- For -j command line option.

View File

@ -1,167 +0,0 @@
/*
** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#ifndef lauxlib_h
#define lauxlib_h
#include <stddef.h>
#include <stdio.h>
#include "lua.h"
#define luaL_getn(L,i) ((int)lua_objlen(L, i))
#define luaL_setn(L,i,j) ((void)0) /* no op! */
/* extra error code for `luaL_load' */
#define LUA_ERRFILE (LUA_ERRERR+1)
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
const luaL_Reg *l);
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
const char *def, size_t *l);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
lua_Integer def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
const char *const lst[]);
LUALIB_API int (luaL_ref) (lua_State *L, int t);
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
const char *name);
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);
LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
const char *fname, int szhint);
/* From Lua 5.2. */
LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname);
LUALIB_API int luaL_execresult(lua_State *L, int stat);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
const char *name, const char *mode);
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
int level);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define luaL_argcheck(L, cond,numarg,extramsg) \
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
typedef struct luaL_Buffer {
char *p; /* current position in buffer */
int lvl; /* number of strings in the stack (level) */
lua_State *L;
char buffer[LUAL_BUFFERSIZE];
} luaL_Buffer;
#define luaL_addchar(B,c) \
((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
(*(B)->p++ = (char)(c)))
/* compatibility only */
#define luaL_putchar(B,c) luaL_addchar(B,c)
#define luaL_addsize(B,n) ((B)->p += (n))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
/* }====================================================== */
/* compatibility with ref system */
/* pre-defined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
(lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))
#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref))
#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref))
#define luaL_reg luaL_Reg
#endif

View File

@ -1,356 +0,0 @@
/*
** Auxiliary library for the Lua/C API.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** Major parts taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#define lib_aux_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_state.h"
#include "lj_trace.h"
#include "lj_lib.h"
#if LJ_TARGET_POSIX
#include <sys/wait.h>
#endif
/* -- I/O error handling -------------------------------------------------- */
LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname)
{
if (stat) {
setboolV(L->top++, 1);
return 1;
} else {
int en = errno; /* Lua API calls may change this value. */
setnilV(L->top++);
if (fname)
lua_pushfstring(L, "%s: %s", fname, strerror(en));
else
lua_pushfstring(L, "%s", strerror(en));
setintV(L->top++, en);
lj_trace_abort(G(L));
return 3;
}
}
LUALIB_API int luaL_execresult(lua_State *L, int stat)
{
if (stat != -1) {
#if LJ_TARGET_POSIX
if (WIFSIGNALED(stat)) {
stat = WTERMSIG(stat);
setnilV(L->top++);
lua_pushliteral(L, "signal");
} else {
if (WIFEXITED(stat))
stat = WEXITSTATUS(stat);
if (stat == 0)
setboolV(L->top++, 1);
else
setnilV(L->top++);
lua_pushliteral(L, "exit");
}
#else
if (stat == 0)
setboolV(L->top++, 1);
else
setnilV(L->top++);
lua_pushliteral(L, "exit");
#endif
setintV(L->top++, stat);
return 3;
}
return luaL_fileresult(L, 0, NULL);
}
/* -- Module registration ------------------------------------------------- */
LUALIB_API const char *luaL_findtable(lua_State *L, int idx,
const char *fname, int szhint)
{
const char *e;
lua_pushvalue(L, idx);
do {
e = strchr(fname, '.');
if (e == NULL) e = fname + strlen(fname);
lua_pushlstring(L, fname, (size_t)(e - fname));
lua_rawget(L, -2);
if (lua_isnil(L, -1)) { /* no such field? */
lua_pop(L, 1); /* remove this nil */
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
lua_pushlstring(L, fname, (size_t)(e - fname));
lua_pushvalue(L, -2);
lua_settable(L, -4); /* set new table into field */
} else if (!lua_istable(L, -1)) { /* field has a non-table value? */
lua_pop(L, 2); /* remove table and value */
return fname; /* return problematic part of the name */
}
lua_remove(L, -2); /* remove previous table */
fname = e + 1;
} while (*e == '.');
return NULL;
}
static int libsize(const luaL_Reg *l)
{
int size = 0;
for (; l->name; l++) size++;
return size;
}
LUALIB_API void luaL_openlib(lua_State *L, const char *libname,
const luaL_Reg *l, int nup)
{
lj_lib_checkfpu(L);
if (libname) {
int size = libsize(l);
/* check whether lib already exists */
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
lua_getfield(L, -1, libname); /* get _LOADED[libname] */
if (!lua_istable(L, -1)) { /* not found? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
lj_err_callerv(L, LJ_ERR_BADMODN, libname);
lua_pushvalue(L, -1);
lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */
}
lua_remove(L, -2); /* remove _LOADED table */
lua_insert(L, -(nup+1)); /* move library table to below upvalues */
}
for (; l->name; l++) {
int i;
for (i = 0; i < nup; i++) /* copy upvalues to the top */
lua_pushvalue(L, -nup);
lua_pushcclosure(L, l->func, nup);
lua_setfield(L, -(nup+2), l->name);
}
lua_pop(L, nup); /* remove upvalues */
}
LUALIB_API void luaL_register(lua_State *L, const char *libname,
const luaL_Reg *l)
{
luaL_openlib(L, libname, l, 0);
}
LUALIB_API const char *luaL_gsub(lua_State *L, const char *s,
const char *p, const char *r)
{
const char *wild;
size_t l = strlen(p);
luaL_Buffer b;
luaL_buffinit(L, &b);
while ((wild = strstr(s, p)) != NULL) {
luaL_addlstring(&b, s, (size_t)(wild - s)); /* push prefix */
luaL_addstring(&b, r); /* push replacement in place of pattern */
s = wild + l; /* continue after `p' */
}
luaL_addstring(&b, s); /* push last suffix */
luaL_pushresult(&b);
return lua_tostring(L, -1);
}
/* -- Buffer handling ----------------------------------------------------- */
#define bufflen(B) ((size_t)((B)->p - (B)->buffer))
#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
static int emptybuffer(luaL_Buffer *B)
{
size_t l = bufflen(B);
if (l == 0)
return 0; /* put nothing on stack */
lua_pushlstring(B->L, B->buffer, l);
B->p = B->buffer;
B->lvl++;
return 1;
}
static void adjuststack(luaL_Buffer *B)
{
if (B->lvl > 1) {
lua_State *L = B->L;
int toget = 1; /* number of levels to concat */
size_t toplen = lua_strlen(L, -1);
do {
size_t l = lua_strlen(L, -(toget+1));
if (!(B->lvl - toget + 1 >= LUA_MINSTACK/2 || toplen > l))
break;
toplen += l;
toget++;
} while (toget < B->lvl);
lua_concat(L, toget);
B->lvl = B->lvl - toget + 1;
}
}
LUALIB_API char *luaL_prepbuffer(luaL_Buffer *B)
{
if (emptybuffer(B))
adjuststack(B);
return B->buffer;
}
LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l)
{
while (l--)
luaL_addchar(B, *s++);
}
LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s)
{
luaL_addlstring(B, s, strlen(s));
}
LUALIB_API void luaL_pushresult(luaL_Buffer *B)
{
emptybuffer(B);
lua_concat(B->L, B->lvl);
B->lvl = 1;
}
LUALIB_API void luaL_addvalue(luaL_Buffer *B)
{
lua_State *L = B->L;
size_t vl;
const char *s = lua_tolstring(L, -1, &vl);
if (vl <= bufffree(B)) { /* fit into buffer? */
memcpy(B->p, s, vl); /* put it there */
B->p += vl;
lua_pop(L, 1); /* remove from stack */
} else {
if (emptybuffer(B))
lua_insert(L, -2); /* put buffer before new value */
B->lvl++; /* add new value into B stack */
adjuststack(B);
}
}
LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
{
B->L = L;
B->p = B->buffer;
B->lvl = 0;
}
/* -- Reference management ------------------------------------------------ */
#define FREELIST_REF 0
/* Convert a stack index to an absolute index. */
#define abs_index(L, i) \
((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
LUALIB_API int luaL_ref(lua_State *L, int t)
{
int ref;
t = abs_index(L, t);
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* remove from stack */
return LUA_REFNIL; /* `nil' has a unique fixed reference */
}
lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */
lua_pop(L, 1); /* remove it from stack */
if (ref != 0) { /* any free element? */
lua_rawgeti(L, t, ref); /* remove it from list */
lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
} else { /* no free elements */
ref = (int)lua_objlen(L, t);
ref++; /* create new reference */
}
lua_rawseti(L, t, ref);
return ref;
}
LUALIB_API void luaL_unref(lua_State *L, int t, int ref)
{
if (ref >= 0) {
t = abs_index(L, t);
lua_rawgeti(L, t, FREELIST_REF);
lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
lua_pushinteger(L, ref);
lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
}
}
/* -- Default allocator and panic function -------------------------------- */
static int panic(lua_State *L)
{
const char *s = lua_tostring(L, -1);
fputs("PANIC: unprotected error in call to Lua API (", stderr);
fputs(s ? s : "?", stderr);
fputc(')', stderr); fputc('\n', stderr);
fflush(stderr);
return 0;
}
#ifdef LUAJIT_USE_SYSMALLOC
#if LJ_64 && !defined(LUAJIT_USE_VALGRIND)
#error "Must use builtin allocator for 64 bit target"
#endif
static void *mem_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
(void)ud;
(void)osize;
if (nsize == 0) {
free(ptr);
return NULL;
} else {
return realloc(ptr, nsize);
}
}
LUALIB_API lua_State *luaL_newstate(void)
{
lua_State *L = lua_newstate(mem_alloc, NULL);
if (L) G(L)->panic = panic;
return L;
}
#else
#include "lj_alloc.h"
LUALIB_API lua_State *luaL_newstate(void)
{
lua_State *L;
void *ud = lj_alloc_create();
if (ud == NULL) return NULL;
#if LJ_64
L = lj_state_newstate(lj_alloc_f, ud);
#else
L = lua_newstate(lj_alloc_f, ud);
#endif
if (L) G(L)->panic = panic;
return L;
}
#if LJ_64
LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
{
UNUSED(f); UNUSED(ud);
fputs("Must use luaL_newstate() for 64 bit target\n", stderr);
return NULL;
}
#endif
#endif

View File

@ -1,683 +0,0 @@
/*
** Base and coroutine library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2011 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#include <stdio.h>
#define lib_base_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_debug.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_meta.h"
#include "lj_state.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_cconv.h"
#endif
#include "lj_bc.h"
#include "lj_ff.h"
#include "lj_dispatch.h"
#include "lj_char.h"
#include "lj_strscan.h"
#include "lj_lib.h"
/* -- Base library: checks ------------------------------------------------ */
#define LJLIB_MODULE_base
LJLIB_ASM(assert) LJLIB_REC(.)
{
GCstr *s;
lj_lib_checkany(L, 1);
s = lj_lib_optstr(L, 2);
if (s)
lj_err_callermsg(L, strdata(s));
else
lj_err_caller(L, LJ_ERR_ASSERT);
return FFH_UNREACHABLE;
}
/* ORDER LJ_T */
LJLIB_PUSH("nil")
LJLIB_PUSH("boolean")
LJLIB_PUSH(top-1) /* boolean */
LJLIB_PUSH("userdata")
LJLIB_PUSH("string")
LJLIB_PUSH("upval")
LJLIB_PUSH("thread")
LJLIB_PUSH("proto")
LJLIB_PUSH("function")
LJLIB_PUSH("trace")
LJLIB_PUSH("cdata")
LJLIB_PUSH("table")
LJLIB_PUSH(top-9) /* userdata */
LJLIB_PUSH("number")
LJLIB_ASM_(type) LJLIB_REC(.)
/* Recycle the lj_lib_checkany(L, 1) from assert. */
/* -- Base library: iterators --------------------------------------------- */
/* This solves a circular dependency problem -- change FF_next_N as needed. */
LJ_STATIC_ASSERT((int)FF_next == FF_next_N);
LJLIB_ASM(next)
{
lj_lib_checktab(L, 1);
return FFH_UNREACHABLE;
}
#if LJ_52 || LJ_HASFFI
static int ffh_pairs(lua_State *L, MMS mm)
{
TValue *o = lj_lib_checkany(L, 1);
cTValue *mo = lj_meta_lookup(L, o, mm);
if ((LJ_52 || tviscdata(o)) && !tvisnil(mo)) {
L->top = o+1; /* Only keep one argument. */
copyTV(L, L->base-1, mo); /* Replace callable. */
return FFH_TAILCALL;
} else {
if (!tvistab(o)) lj_err_argt(L, 1, LUA_TTABLE);
setfuncV(L, o-1, funcV(lj_lib_upvalue(L, 1)));
if (mm == MM_pairs) setnilV(o+1); else setintV(o+1, 0);
return FFH_RES(3);
}
}
#else
#define ffh_pairs(L, mm) (lj_lib_checktab(L, 1), FFH_UNREACHABLE)
#endif
LJLIB_PUSH(lastcl)
LJLIB_ASM(pairs)
{
return ffh_pairs(L, MM_pairs);
}
LJLIB_NOREGUV LJLIB_ASM(ipairs_aux) LJLIB_REC(.)
{
lj_lib_checktab(L, 1);
lj_lib_checkint(L, 2);
return FFH_UNREACHABLE;
}
LJLIB_PUSH(lastcl)
LJLIB_ASM(ipairs) LJLIB_REC(.)
{
return ffh_pairs(L, MM_ipairs);
}
/* -- Base library: getters and setters ----------------------------------- */
LJLIB_ASM_(getmetatable) LJLIB_REC(.)
/* Recycle the lj_lib_checkany(L, 1) from assert. */
LJLIB_ASM(setmetatable) LJLIB_REC(.)
{
GCtab *t = lj_lib_checktab(L, 1);
GCtab *mt = lj_lib_checktabornil(L, 2);
if (!tvisnil(lj_meta_lookup(L, L->base, MM_metatable)))
lj_err_caller(L, LJ_ERR_PROTMT);
setgcref(t->metatable, obj2gco(mt));
if (mt) { lj_gc_objbarriert(L, t, mt); }
settabV(L, L->base-1, t);
return FFH_RES(1);
}
LJLIB_CF(getfenv)
{
GCfunc *fn;
cTValue *o = L->base;
if (!(o < L->top && tvisfunc(o))) {
int level = lj_lib_optint(L, 1, 1);
o = lj_debug_frame(L, level, &level);
if (o == NULL)
lj_err_arg(L, 1, LJ_ERR_INVLVL);
}
fn = &gcval(o)->fn;
settabV(L, L->top++, isluafunc(fn) ? tabref(fn->l.env) : tabref(L->env));
return 1;
}
LJLIB_CF(setfenv)
{
GCfunc *fn;
GCtab *t = lj_lib_checktab(L, 2);
cTValue *o = L->base;
if (!(o < L->top && tvisfunc(o))) {
int level = lj_lib_checkint(L, 1);
if (level == 0) {
/* NOBARRIER: A thread (i.e. L) is never black. */
setgcref(L->env, obj2gco(t));
return 0;
}
o = lj_debug_frame(L, level, &level);
if (o == NULL)
lj_err_arg(L, 1, LJ_ERR_INVLVL);
}
fn = &gcval(o)->fn;
if (!isluafunc(fn))
lj_err_caller(L, LJ_ERR_SETFENV);
setgcref(fn->l.env, obj2gco(t));
lj_gc_objbarrier(L, obj2gco(fn), t);
setfuncV(L, L->top++, fn);
return 1;
}
LJLIB_ASM(rawget) LJLIB_REC(.)
{
lj_lib_checktab(L, 1);
lj_lib_checkany(L, 2);
return FFH_UNREACHABLE;
}
LJLIB_CF(rawset) LJLIB_REC(.)
{
lj_lib_checktab(L, 1);
lj_lib_checkany(L, 2);
L->top = 1+lj_lib_checkany(L, 3);
lua_rawset(L, 1);
return 1;
}
LJLIB_CF(rawequal) LJLIB_REC(.)
{
cTValue *o1 = lj_lib_checkany(L, 1);
cTValue *o2 = lj_lib_checkany(L, 2);
setboolV(L->top-1, lj_obj_equal(o1, o2));
return 1;
}
#if LJ_52
LJLIB_CF(rawlen) LJLIB_REC(.)
{
cTValue *o = L->base;
int32_t len;
if (L->top > o && tvisstr(o))
len = (int32_t)strV(o)->len;
else
len = (int32_t)lj_tab_len(lj_lib_checktab(L, 1));
setintV(L->top-1, len);
return 1;
}
#endif
LJLIB_CF(unpack)
{
GCtab *t = lj_lib_checktab(L, 1);
int32_t n, i = lj_lib_optint(L, 2, 1);
int32_t e = (L->base+3-1 < L->top && !tvisnil(L->base+3-1)) ?
lj_lib_checkint(L, 3) : (int32_t)lj_tab_len(t);
if (i > e) return 0;
n = e - i + 1;
if (n <= 0 || !lua_checkstack(L, n))
lj_err_caller(L, LJ_ERR_UNPACK);
do {
cTValue *tv = lj_tab_getint(t, i);
if (tv) {
copyTV(L, L->top++, tv);
} else {
setnilV(L->top++);
}
} while (i++ < e);
return n;
}
LJLIB_CF(select) LJLIB_REC(.)
{
int32_t n = (int32_t)(L->top - L->base);
if (n >= 1 && tvisstr(L->base) && *strVdata(L->base) == '#') {
setintV(L->top-1, n-1);
return 1;
} else {
int32_t i = lj_lib_checkint(L, 1);
if (i < 0) i = n + i; else if (i > n) i = n;
if (i < 1)
lj_err_arg(L, 1, LJ_ERR_IDXRNG);
return n - i;
}
}
/* -- Base library: conversions ------------------------------------------- */
LJLIB_ASM(tonumber) LJLIB_REC(.)
{
int32_t base = lj_lib_optint(L, 2, 10);
if (base == 10) {
TValue *o = lj_lib_checkany(L, 1);
if (lj_strscan_numberobj(o)) {
copyTV(L, L->base-1, o);
return FFH_RES(1);
}
#if LJ_HASFFI
if (tviscdata(o)) {
CTState *cts = ctype_cts(L);
CType *ct = lj_ctype_rawref(cts, cdataV(o)->ctypeid);
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
if (ctype_isnum(ct->info) || ctype_iscomplex(ct->info)) {
if (LJ_DUALNUM && ctype_isinteger_or_bool(ct->info) &&
ct->size <= 4 && !(ct->size == 4 && (ct->info & CTF_UNSIGNED))) {
int32_t i;
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o, 0);
setintV(L->base-1, i);
return FFH_RES(1);
}
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_DOUBLE),
(uint8_t *)&(L->base-1)->n, o, 0);
return FFH_RES(1);
}
}
#endif
} else {
const char *p = strdata(lj_lib_checkstr(L, 1));
char *ep;
unsigned long ul;
if (base < 2 || base > 36)
lj_err_arg(L, 2, LJ_ERR_BASERNG);
ul = strtoul(p, &ep, base);
if (p != ep) {
while (lj_char_isspace((unsigned char)(*ep))) ep++;
if (*ep == '\0') {
if (LJ_DUALNUM && LJ_LIKELY(ul < 0x80000000u))
setintV(L->base-1, (int32_t)ul);
else
setnumV(L->base-1, (lua_Number)ul);
return FFH_RES(1);
}
}
}
setnilV(L->base-1);
return FFH_RES(1);
}
LJLIB_PUSH("nil")
LJLIB_PUSH("false")
LJLIB_PUSH("true")
LJLIB_ASM(tostring) LJLIB_REC(.)
{
TValue *o = lj_lib_checkany(L, 1);
cTValue *mo;
L->top = o+1; /* Only keep one argument. */
if (!tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
copyTV(L, L->base-1, mo); /* Replace callable. */
return FFH_TAILCALL;
} else {
GCstr *s;
if (tvisnumber(o)) {
s = lj_str_fromnumber(L, o);
} else if (tvispri(o)) {
s = strV(lj_lib_upvalue(L, -(int32_t)itype(o)));
} else {
if (tvisfunc(o) && isffunc(funcV(o)))
lua_pushfstring(L, "function: builtin#%d", funcV(o)->c.ffid);
else
lua_pushfstring(L, "%s: %p", lj_typename(o), lua_topointer(L, 1));
/* Note: lua_pushfstring calls the GC which may invalidate o. */
s = strV(L->top-1);
}
setstrV(L, L->base-1, s);
return FFH_RES(1);
}
}
/* -- Base library: throw and catch errors -------------------------------- */
LJLIB_CF(error)
{
int32_t level = lj_lib_optint(L, 2, 1);
lua_settop(L, 1);
if (lua_isstring(L, 1) && level > 0) {
luaL_where(L, level);
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
return lua_error(L);
}
LJLIB_ASM(pcall) LJLIB_REC(.)
{
lj_lib_checkany(L, 1);
lj_lib_checkfunc(L, 2); /* For xpcall only. */
return FFH_UNREACHABLE;
}
LJLIB_ASM_(xpcall) LJLIB_REC(.)
/* -- Base library: load Lua code ----------------------------------------- */
static int load_aux(lua_State *L, int status, int envarg)
{
if (status == 0) {
if (tvistab(L->base+envarg-1)) {
GCfunc *fn = funcV(L->top-1);
GCtab *t = tabV(L->base+envarg-1);
setgcref(fn->c.env, obj2gco(t));
lj_gc_objbarrier(L, fn, t);
}
return 1;
} else {
setnilV(L->top-2);
return 2;
}
}
LJLIB_CF(loadfile)
{
GCstr *fname = lj_lib_optstr(L, 1);
GCstr *mode = lj_lib_optstr(L, 2);
int status;
lua_settop(L, 3); /* Ensure env arg exists. */
status = luaL_loadfilex(L, fname ? strdata(fname) : NULL,
mode ? strdata(mode) : NULL);
return load_aux(L, status, 3);
}
static const char *reader_func(lua_State *L, void *ud, size_t *size)
{
UNUSED(ud);
luaL_checkstack(L, 2, "too many nested functions");
copyTV(L, L->top++, L->base);
lua_call(L, 0, 1); /* Call user-supplied function. */
L->top--;
if (tvisnil(L->top)) {
*size = 0;
return NULL;
} else if (tvisstr(L->top) || tvisnumber(L->top)) {
copyTV(L, L->base+4, L->top); /* Anchor string in reserved stack slot. */
return lua_tolstring(L, 5, size);
} else {
lj_err_caller(L, LJ_ERR_RDRSTR);
return NULL;
}
}
LJLIB_CF(load)
{
GCstr *name = lj_lib_optstr(L, 2);
GCstr *mode = lj_lib_optstr(L, 3);
int status;
if (L->base < L->top && (tvisstr(L->base) || tvisnumber(L->base))) {
GCstr *s = lj_lib_checkstr(L, 1);
lua_settop(L, 4); /* Ensure env arg exists. */
status = luaL_loadbufferx(L, strdata(s), s->len, strdata(name ? name : s),
mode ? strdata(mode) : NULL);
} else {
lj_lib_checkfunc(L, 1);
lua_settop(L, 5); /* Reserve a slot for the string from the reader. */
status = lua_loadx(L, reader_func, NULL, name ? strdata(name) : "=(load)",
mode ? strdata(mode) : NULL);
}
return load_aux(L, status, 4);
}
LJLIB_CF(loadstring)
{
return lj_cf_load(L);
}
LJLIB_CF(dofile)
{
GCstr *fname = lj_lib_optstr(L, 1);
setnilV(L->top);
L->top = L->base+1;
if (luaL_loadfile(L, fname ? strdata(fname) : NULL) != 0)
lua_error(L);
lua_call(L, 0, LUA_MULTRET);
return (int)(L->top - L->base) - 1;
}
/* -- Base library: GC control -------------------------------------------- */
LJLIB_CF(gcinfo)
{
setintV(L->top++, (G(L)->gc.total >> 10));
return 1;
}
LJLIB_CF(collectgarbage)
{
int opt = lj_lib_checkopt(L, 1, LUA_GCCOLLECT, /* ORDER LUA_GC* */
"\4stop\7restart\7collect\5count\1\377\4step\10setpause\12setstepmul");
int32_t data = lj_lib_optint(L, 2, 0);
if (opt == LUA_GCCOUNT) {
setnumV(L->top, (lua_Number)G(L)->gc.total/1024.0);
} else {
int res = lua_gc(L, opt, data);
if (opt == LUA_GCSTEP)
setboolV(L->top, res);
else
setintV(L->top, res);
}
L->top++;
return 1;
}
/* -- Base library: miscellaneous functions ------------------------------- */
LJLIB_PUSH(top-2) /* Upvalue holds weak table. */
LJLIB_CF(newproxy)
{
lua_settop(L, 1);
lua_newuserdata(L, 0);
if (lua_toboolean(L, 1) == 0) { /* newproxy(): without metatable. */
return 1;
} else if (lua_isboolean(L, 1)) { /* newproxy(true): with metatable. */
lua_newtable(L);
lua_pushvalue(L, -1);
lua_pushboolean(L, 1);
lua_rawset(L, lua_upvalueindex(1)); /* Remember mt in weak table. */
} else { /* newproxy(proxy): inherit metatable. */
int validproxy = 0;
if (lua_getmetatable(L, 1)) {
lua_rawget(L, lua_upvalueindex(1));
validproxy = lua_toboolean(L, -1);
lua_pop(L, 1);
}
if (!validproxy)
lj_err_arg(L, 1, LJ_ERR_NOPROXY);
lua_getmetatable(L, 1);
}
lua_setmetatable(L, 2);
return 1;
}
LJLIB_PUSH("tostring")
LJLIB_CF(print)
{
ptrdiff_t i, nargs = L->top - L->base;
cTValue *tv = lj_tab_getstr(tabref(L->env), strV(lj_lib_upvalue(L, 1)));
int shortcut;
if (tv && !tvisnil(tv)) {
copyTV(L, L->top++, tv);
} else {
setstrV(L, L->top++, strV(lj_lib_upvalue(L, 1)));
lua_gettable(L, LUA_GLOBALSINDEX);
tv = L->top-1;
}
shortcut = (tvisfunc(tv) && funcV(tv)->c.ffid == FF_tostring);
for (i = 0; i < nargs; i++) {
const char *str;
size_t size;
cTValue *o = &L->base[i];
if (shortcut && tvisstr(o)) {
str = strVdata(o);
size = strV(o)->len;
} else if (shortcut && tvisint(o)) {
char buf[LJ_STR_INTBUF];
char *p = lj_str_bufint(buf, intV(o));
size = (size_t)(buf+LJ_STR_INTBUF-p);
str = p;
} else if (shortcut && tvisnum(o)) {
char buf[LJ_STR_NUMBUF];
size = lj_str_bufnum(buf, o);
str = buf;
} else {
copyTV(L, L->top+1, o);
copyTV(L, L->top, L->top-1);
L->top += 2;
lua_call(L, 1, 1);
str = lua_tolstring(L, -1, &size);
if (!str)
lj_err_caller(L, LJ_ERR_PRTOSTR);
L->top--;
}
if (i)
putchar('\t');
fwrite(str, 1, size, stdout);
}
putchar('\n');
return 0;
}
LJLIB_PUSH(top-3)
LJLIB_SET(_VERSION)
#include "lj_libdef.h"
/* -- Coroutine library --------------------------------------------------- */
#define LJLIB_MODULE_coroutine
LJLIB_CF(coroutine_status)
{
const char *s;
lua_State *co;
if (!(L->top > L->base && tvisthread(L->base)))
lj_err_arg(L, 1, LJ_ERR_NOCORO);
co = threadV(L->base);
if (co == L) s = "running";
else if (co->status == LUA_YIELD) s = "suspended";
else if (co->status != 0) s = "dead";
else if (co->base > tvref(co->stack)+1) s = "normal";
else if (co->top == co->base) s = "dead";
else s = "suspended";
lua_pushstring(L, s);
return 1;
}
LJLIB_CF(coroutine_running)
{
#if LJ_52
int ismain = lua_pushthread(L);
setboolV(L->top++, ismain);
return 2;
#else
if (lua_pushthread(L))
setnilV(L->top++);
return 1;
#endif
}
LJLIB_CF(coroutine_create)
{
lua_State *L1;
if (!(L->base < L->top && tvisfunc(L->base)))
lj_err_argt(L, 1, LUA_TFUNCTION);
L1 = lua_newthread(L);
setfuncV(L, L1->top++, funcV(L->base));
return 1;
}
LJLIB_ASM(coroutine_yield)
{
lj_err_caller(L, LJ_ERR_CYIELD);
return FFH_UNREACHABLE;
}
static int ffh_resume(lua_State *L, lua_State *co, int wrap)
{
if (co->cframe != NULL || co->status > LUA_YIELD ||
(co->status == 0 && co->top == co->base)) {
ErrMsg em = co->cframe ? LJ_ERR_CORUN : LJ_ERR_CODEAD;
if (wrap) lj_err_caller(L, em);
setboolV(L->base-1, 0);
setstrV(L, L->base, lj_err_str(L, em));
return FFH_RES(2);
}
lj_state_growstack(co, (MSize)(L->top - L->base));
return FFH_RETRY;
}
LJLIB_ASM(coroutine_resume)
{
if (!(L->top > L->base && tvisthread(L->base)))
lj_err_arg(L, 1, LJ_ERR_NOCORO);
return ffh_resume(L, threadV(L->base), 0);
}
LJLIB_NOREG LJLIB_ASM(coroutine_wrap_aux)
{
return ffh_resume(L, threadV(lj_lib_upvalue(L, 1)), 1);
}
/* Inline declarations. */
LJ_ASMF void lj_ff_coroutine_wrap_aux(void);
#if !(LJ_TARGET_MIPS && defined(ljamalg_c))
LJ_FUNCA_NORET void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L,
lua_State *co);
#endif
/* Error handler, called from assembler VM. */
void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L, lua_State *co)
{
co->top--; copyTV(L, L->top, co->top); L->top++;
if (tvisstr(L->top-1))
lj_err_callermsg(L, strVdata(L->top-1));
else
lj_err_run(L);
}
/* Forward declaration. */
static void setpc_wrap_aux(lua_State *L, GCfunc *fn);
LJLIB_CF(coroutine_wrap)
{
lj_cf_coroutine_create(L);
lj_lib_pushcc(L, lj_ffh_coroutine_wrap_aux, FF_coroutine_wrap_aux, 1);
setpc_wrap_aux(L, funcV(L->top-1));
return 1;
}
#include "lj_libdef.h"
/* Fix the PC of wrap_aux. Really ugly workaround. */
static void setpc_wrap_aux(lua_State *L, GCfunc *fn)
{
setmref(fn->c.pc, &L2GG(L)->bcff[lj_lib_init_coroutine[1]+2]);
}
/* ------------------------------------------------------------------------ */
static void newproxy_weaktable(lua_State *L)
{
/* NOBARRIER: The table is new (marked white). */
GCtab *t = lj_tab_new(L, 0, 1);
settabV(L, L->top++, t);
setgcref(t->metatable, obj2gco(t));
setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
lj_str_newlit(L, "kv"));
t->nomm = (uint8_t)(~(1u<<MM_mode));
}
LUALIB_API int luaopen_base(lua_State *L)
{
/* NOBARRIER: Table and value are the same. */
GCtab *env = tabref(L->env);
settabV(L, lj_tab_setstr(L, env, lj_str_newlit(L, "_G")), env);
lua_pushliteral(L, LUA_VERSION); /* top-3. */
newproxy_weaktable(L); /* top-2. */
LJ_LIB_REG(L, "_G", base);
LJ_LIB_REG(L, LUA_COLIBNAME, coroutine);
return 2;
}

View File

@ -1,74 +0,0 @@
/*
** Bit manipulation library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#define lib_bit_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_bit
LJLIB_ASM(bit_tobit) LJLIB_REC(bit_unary IR_TOBIT)
{
lj_lib_checknumber(L, 1);
return FFH_RETRY;
}
LJLIB_ASM_(bit_bnot) LJLIB_REC(bit_unary IR_BNOT)
LJLIB_ASM_(bit_bswap) LJLIB_REC(bit_unary IR_BSWAP)
LJLIB_ASM(bit_lshift) LJLIB_REC(bit_shift IR_BSHL)
{
lj_lib_checknumber(L, 1);
lj_lib_checkbit(L, 2);
return FFH_RETRY;
}
LJLIB_ASM_(bit_rshift) LJLIB_REC(bit_shift IR_BSHR)
LJLIB_ASM_(bit_arshift) LJLIB_REC(bit_shift IR_BSAR)
LJLIB_ASM_(bit_rol) LJLIB_REC(bit_shift IR_BROL)
LJLIB_ASM_(bit_ror) LJLIB_REC(bit_shift IR_BROR)
LJLIB_ASM(bit_band) LJLIB_REC(bit_nary IR_BAND)
{
int i = 0;
do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top);
return FFH_RETRY;
}
LJLIB_ASM_(bit_bor) LJLIB_REC(bit_nary IR_BOR)
LJLIB_ASM_(bit_bxor) LJLIB_REC(bit_nary IR_BXOR)
/* ------------------------------------------------------------------------ */
LJLIB_CF(bit_tohex)
{
uint32_t b = (uint32_t)lj_lib_checkbit(L, 1);
int32_t i, n = L->base+1 >= L->top ? 8 : lj_lib_checkbit(L, 2);
const char *hexdigits = "0123456789abcdef";
char buf[8];
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 8) n = 8;
for (i = n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
lua_pushlstring(L, buf, (size_t)n);
return 1;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_bit(lua_State *L)
{
LJ_LIB_REG(L, LUA_BITLIBNAME, bit);
return 1;
}

View File

@ -1,405 +0,0 @@
/*
** Debug library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lib_debug_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_debug.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_debug
LJLIB_CF(debug_getregistry)
{
copyTV(L, L->top++, registry(L));
return 1;
}
LJLIB_CF(debug_getmetatable)
{
lj_lib_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
setnilV(L->top-1);
}
return 1;
}
LJLIB_CF(debug_setmetatable)
{
lj_lib_checktabornil(L, 2);
L->top = L->base+2;
lua_setmetatable(L, 1);
#if !LJ_52
setboolV(L->top-1, 1);
#endif
return 1;
}
LJLIB_CF(debug_getfenv)
{
lj_lib_checkany(L, 1);
lua_getfenv(L, 1);
return 1;
}
LJLIB_CF(debug_setfenv)
{
lj_lib_checktab(L, 2);
L->top = L->base+2;
if (!lua_setfenv(L, 1))
lj_err_caller(L, LJ_ERR_SETFENV);
return 1;
}
/* ------------------------------------------------------------------------ */
static void settabss(lua_State *L, const char *i, const char *v)
{
lua_pushstring(L, v);
lua_setfield(L, -2, i);
}
static void settabsi(lua_State *L, const char *i, int v)
{
lua_pushinteger(L, v);
lua_setfield(L, -2, i);
}
static void settabsb(lua_State *L, const char *i, int v)
{
lua_pushboolean(L, v);
lua_setfield(L, -2, i);
}
static lua_State *getthread(lua_State *L, int *arg)
{
if (L->base < L->top && tvisthread(L->base)) {
*arg = 1;
return threadV(L->base);
} else {
*arg = 0;
return L;
}
}
static void treatstackoption(lua_State *L, lua_State *L1, const char *fname)
{
if (L == L1) {
lua_pushvalue(L, -2);
lua_remove(L, -3);
}
else
lua_xmove(L1, L, 1);
lua_setfield(L, -2, fname);
}
LJLIB_CF(debug_getinfo)
{
lj_Debug ar;
int arg, opt_f = 0, opt_L = 0;
lua_State *L1 = getthread(L, &arg);
const char *options = luaL_optstring(L, arg+2, "flnSu");
if (lua_isnumber(L, arg+1)) {
if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), (lua_Debug *)&ar)) {
setnilV(L->top-1);
return 1;
}
} else if (L->base+arg < L->top && tvisfunc(L->base+arg)) {
options = lua_pushfstring(L, ">%s", options);
setfuncV(L1, L1->top++, funcV(L->base+arg));
} else {
lj_err_arg(L, arg+1, LJ_ERR_NOFUNCL);
}
if (!lj_debug_getinfo(L1, options, &ar, 1))
lj_err_arg(L, arg+2, LJ_ERR_INVOPT);
lua_createtable(L, 0, 16); /* Create result table. */
for (; *options; options++) {
switch (*options) {
case 'S':
settabss(L, "source", ar.source);
settabss(L, "short_src", ar.short_src);
settabsi(L, "linedefined", ar.linedefined);
settabsi(L, "lastlinedefined", ar.lastlinedefined);
settabss(L, "what", ar.what);
break;
case 'l':
settabsi(L, "currentline", ar.currentline);
break;
case 'u':
settabsi(L, "nups", ar.nups);
settabsi(L, "nparams", ar.nparams);
settabsb(L, "isvararg", ar.isvararg);
break;
case 'n':
settabss(L, "name", ar.name);
settabss(L, "namewhat", ar.namewhat);
break;
case 'f': opt_f = 1; break;
case 'L': opt_L = 1; break;
default: break;
}
}
if (opt_L) treatstackoption(L, L1, "activelines");
if (opt_f) treatstackoption(L, L1, "func");
return 1; /* Return result table. */
}
LJLIB_CF(debug_getlocal)
{
int arg;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
const char *name;
int slot = lj_lib_checkint(L, arg+2);
if (tvisfunc(L->base+arg)) {
L->top = L->base+arg+1;
lua_pushstring(L, lua_getlocal(L, NULL, slot));
return 1;
}
if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar))
lj_err_arg(L, arg+1, LJ_ERR_LVLRNG);
name = lua_getlocal(L1, &ar, slot);
if (name) {
lua_xmove(L1, L, 1);
lua_pushstring(L, name);
lua_pushvalue(L, -2);
return 2;
} else {
setnilV(L->top-1);
return 1;
}
}
LJLIB_CF(debug_setlocal)
{
int arg;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
TValue *tv;
if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar))
lj_err_arg(L, arg+1, LJ_ERR_LVLRNG);
tv = lj_lib_checkany(L, arg+3);
copyTV(L1, L1->top++, tv);
lua_pushstring(L, lua_setlocal(L1, &ar, lj_lib_checkint(L, arg+2)));
return 1;
}
static int debug_getupvalue(lua_State *L, int get)
{
int32_t n = lj_lib_checkint(L, 2);
const char *name;
lj_lib_checkfunc(L, 1);
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
if (name) {
lua_pushstring(L, name);
if (!get) return 1;
copyTV(L, L->top, L->top-2);
L->top++;
return 2;
}
return 0;
}
LJLIB_CF(debug_getupvalue)
{
return debug_getupvalue(L, 1);
}
LJLIB_CF(debug_setupvalue)
{
lj_lib_checkany(L, 3);
return debug_getupvalue(L, 0);
}
LJLIB_CF(debug_upvalueid)
{
GCfunc *fn = lj_lib_checkfunc(L, 1);
int32_t n = lj_lib_checkint(L, 2) - 1;
if ((uint32_t)n >= fn->l.nupvalues)
lj_err_arg(L, 2, LJ_ERR_IDXRNG);
setlightudV(L->top-1, isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) :
(void *)&fn->c.upvalue[n]);
return 1;
}
LJLIB_CF(debug_upvaluejoin)
{
GCfunc *fn[2];
GCRef *p[2];
int i;
for (i = 0; i < 2; i++) {
int32_t n;
fn[i] = lj_lib_checkfunc(L, 2*i+1);
if (!isluafunc(fn[i]))
lj_err_arg(L, 2*i+1, LJ_ERR_NOLFUNC);
n = lj_lib_checkint(L, 2*i+2) - 1;
if ((uint32_t)n >= fn[i]->l.nupvalues)
lj_err_arg(L, 2*i+2, LJ_ERR_IDXRNG);
p[i] = &fn[i]->l.uvptr[n];
}
setgcrefr(*p[0], *p[1]);
lj_gc_objbarrier(L, fn[0], gcref(*p[1]));
return 0;
}
#if LJ_52
LJLIB_CF(debug_getuservalue)
{
TValue *o = L->base;
if (o < L->top && tvisudata(o))
settabV(L, o, tabref(udataV(o)->env));
else
setnilV(o);
L->top = o+1;
return 1;
}
LJLIB_CF(debug_setuservalue)
{
TValue *o = L->base;
if (!(o < L->top && tvisudata(o)))
lj_err_argt(L, 1, LUA_TUSERDATA);
if (!(o+1 < L->top && tvistab(o+1)))
lj_err_argt(L, 2, LUA_TTABLE);
L->top = o+2;
lua_setfenv(L, 1);
return 1;
}
#endif
/* ------------------------------------------------------------------------ */
static const char KEY_HOOK = 'h';
static void hookf(lua_State *L, lua_Debug *ar)
{
static const char *const hooknames[] =
{"call", "return", "line", "count", "tail return"};
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
lua_rawget(L, LUA_REGISTRYINDEX);
if (lua_isfunction(L, -1)) {
lua_pushstring(L, hooknames[(int)ar->event]);
if (ar->currentline >= 0)
lua_pushinteger(L, ar->currentline);
else lua_pushnil(L);
lua_call(L, 2, 0);
}
}
static int makemask(const char *smask, int count)
{
int mask = 0;
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
if (count > 0) mask |= LUA_MASKCOUNT;
return mask;
}
static char *unmakemask(int mask, char *smask)
{
int i = 0;
if (mask & LUA_MASKCALL) smask[i++] = 'c';
if (mask & LUA_MASKRET) smask[i++] = 'r';
if (mask & LUA_MASKLINE) smask[i++] = 'l';
smask[i] = '\0';
return smask;
}
LJLIB_CF(debug_sethook)
{
int arg, mask, count;
lua_Hook func;
(void)getthread(L, &arg);
if (lua_isnoneornil(L, arg+1)) {
lua_settop(L, arg+1);
func = NULL; mask = 0; count = 0; /* turn off hooks */
} else {
const char *smask = luaL_checkstring(L, arg+2);
luaL_checktype(L, arg+1, LUA_TFUNCTION);
count = luaL_optint(L, arg+3, 0);
func = hookf; mask = makemask(smask, count);
}
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
lua_pushvalue(L, arg+1);
lua_rawset(L, LUA_REGISTRYINDEX);
lua_sethook(L, func, mask, count);
return 0;
}
LJLIB_CF(debug_gethook)
{
char buff[5];
int mask = lua_gethookmask(L);
lua_Hook hook = lua_gethook(L);
if (hook != NULL && hook != hookf) { /* external hook? */
lua_pushliteral(L, "external hook");
} else {
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
}
lua_pushstring(L, unmakemask(mask, buff));
lua_pushinteger(L, lua_gethookcount(L));
return 3;
}
/* ------------------------------------------------------------------------ */
LJLIB_CF(debug_debug)
{
for (;;) {
char buffer[250];
fputs("lua_debug> ", stderr);
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
strcmp(buffer, "cont\n") == 0)
return 0;
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
lua_pcall(L, 0, 0, 0)) {
fputs(lua_tostring(L, -1), stderr);
fputs("\n", stderr);
}
lua_settop(L, 0); /* remove eventual returns */
}
}
/* ------------------------------------------------------------------------ */
#define LEVELS1 12 /* size of the first part of the stack */
#define LEVELS2 10 /* size of the second part of the stack */
LJLIB_CF(debug_traceback)
{
int arg;
lua_State *L1 = getthread(L, &arg);
const char *msg = lua_tostring(L, arg+1);
if (msg == NULL && L->top > L->base+arg)
L->top = L->base+arg+1;
else
luaL_traceback(L, L1, msg, lj_lib_optint(L, arg+2, (L == L1)));
return 1;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_debug(lua_State *L)
{
LJ_LIB_REG(L, LUA_DBLIBNAME, debug);
return 1;
}

View File

@ -1,851 +0,0 @@
/*
** FFI library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#define lib_ffi_c
#define LUA_LIB
#include <errno.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_meta.h"
#include "lj_ctype.h"
#include "lj_cparse.h"
#include "lj_cdata.h"
#include "lj_cconv.h"
#include "lj_carith.h"
#include "lj_ccall.h"
#include "lj_ccallback.h"
#include "lj_clib.h"
#include "lj_ff.h"
#include "lj_lib.h"
/* -- C type checks ------------------------------------------------------- */
/* Check first argument for a C type and returns its ID. */
static CTypeID ffi_checkctype(lua_State *L, CTState *cts, TValue *param)
{
TValue *o = L->base;
if (!(o < L->top)) {
err_argtype:
lj_err_argtype(L, 1, "C type");
}
if (tvisstr(o)) { /* Parse an abstract C type declaration. */
GCstr *s = strV(o);
CPState cp;
int errcode;
cp.L = L;
cp.cts = cts;
cp.srcname = strdata(s);
cp.p = strdata(s);
cp.param = param;
cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT;
errcode = lj_cparse(&cp);
if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */
return cp.val.id;
} else {
GCcdata *cd;
if (!tviscdata(o)) goto err_argtype;
if (param && param < L->top) lj_err_arg(L, 1, LJ_ERR_FFI_NUMPARAM);
cd = cdataV(o);
return cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->ctypeid;
}
}
/* Check argument for C data and return it. */
static GCcdata *ffi_checkcdata(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
if (!(o < L->top && tviscdata(o)))
lj_err_argt(L, narg, LUA_TCDATA);
return cdataV(o);
}
/* Convert argument to C pointer. */
static void *ffi_checkptr(lua_State *L, int narg, CTypeID id)
{
CTState *cts = ctype_cts(L);
TValue *o = L->base + narg-1;
void *p;
if (o >= L->top)
lj_err_arg(L, narg, LJ_ERR_NOVAL);
lj_cconv_ct_tv(cts, ctype_get(cts, id), (uint8_t *)&p, o, CCF_ARG(narg));
return p;
}
/* Convert argument to int32_t. */
static int32_t ffi_checkint(lua_State *L, int narg)
{
CTState *cts = ctype_cts(L);
TValue *o = L->base + narg-1;
int32_t i;
if (o >= L->top)
lj_err_arg(L, narg, LJ_ERR_NOVAL);
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o,
CCF_ARG(narg));
return i;
}
/* -- C type metamethods -------------------------------------------------- */
#define LJLIB_MODULE_ffi_meta
/* Handle ctype __index/__newindex metamethods. */
static int ffi_index_meta(lua_State *L, CTState *cts, CType *ct, MMS mm)
{
CTypeID id = ctype_typeid(cts, ct);
cTValue *tv = lj_ctype_meta(cts, id, mm);
TValue *base = L->base;
if (!tv) {
const char *s;
err_index:
s = strdata(lj_ctype_repr(L, id, NULL));
if (tvisstr(L->base+1)) {
lj_err_callerv(L, LJ_ERR_FFI_BADMEMBER, s, strVdata(L->base+1));
} else {
const char *key = tviscdata(L->base+1) ?
strdata(lj_ctype_repr(L, cdataV(L->base+1)->ctypeid, NULL)) :
lj_typename(L->base+1);
lj_err_callerv(L, LJ_ERR_FFI_BADIDXW, s, key);
}
}
if (!tvisfunc(tv)) {
if (mm == MM_index) {
cTValue *o = lj_meta_tget(L, tv, base+1);
if (o) {
if (tvisnil(o)) goto err_index;
copyTV(L, L->top-1, o);
return 1;
}
} else {
TValue *o = lj_meta_tset(L, tv, base+1);
if (o) {
copyTV(L, o, base+2);
return 0;
}
}
copyTV(L, base, L->top);
tv = L->top-1;
}
return lj_meta_tailcall(L, tv);
}
LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0)
{
CTState *cts = ctype_cts(L);
CTInfo qual = 0;
CType *ct;
uint8_t *p;
TValue *o = L->base;
if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */
lj_err_argt(L, 1, LUA_TCDATA);
ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
if ((qual & 1))
return ffi_index_meta(L, cts, ct, MM_index);
if (lj_cdata_get(cts, ct, L->top-1, p))
lj_gc_check(L);
return 1;
}
LJLIB_CF(ffi_meta___newindex) LJLIB_REC(cdata_index 1)
{
CTState *cts = ctype_cts(L);
CTInfo qual = 0;
CType *ct;
uint8_t *p;
TValue *o = L->base;
if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */
lj_err_argt(L, 1, LUA_TCDATA);
ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
if ((qual & 1)) {
if ((qual & CTF_CONST))
lj_err_caller(L, LJ_ERR_FFI_WRCONST);
return ffi_index_meta(L, cts, ct, MM_newindex);
}
lj_cdata_set(cts, ct, p, o+2, qual);
return 0;
}
/* Common handler for cdata arithmetic. */
static int ffi_arith(lua_State *L)
{
MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___eq + (int)MM_eq);
return lj_carith_op(L, mm);
}
/* The following functions must be in contiguous ORDER MM. */
LJLIB_CF(ffi_meta___eq) LJLIB_REC(cdata_arith MM_eq)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___len) LJLIB_REC(cdata_arith MM_len)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___lt) LJLIB_REC(cdata_arith MM_lt)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___le) LJLIB_REC(cdata_arith MM_le)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___concat) LJLIB_REC(cdata_arith MM_concat)
{
return ffi_arith(L);
}
/* Forward declaration. */
static int lj_cf_ffi_new(lua_State *L);
LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call)
{
CTState *cts = ctype_cts(L);
GCcdata *cd = ffi_checkcdata(L, 1);
CTypeID id = cd->ctypeid;
CType *ct;
cTValue *tv;
MMS mm = MM_call;
if (cd->ctypeid == CTID_CTYPEID) {
id = *(CTypeID *)cdataptr(cd);
mm = MM_new;
} else {
int ret = lj_ccall_func(L, cd);
if (ret >= 0)
return ret;
}
/* Handle ctype __call/__new metamethod. */
ct = ctype_raw(cts, id);
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
tv = lj_ctype_meta(cts, id, mm);
if (tv)
return lj_meta_tailcall(L, tv);
else if (mm == MM_call)
lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL)));
return lj_cf_ffi_new(L);
}
LJLIB_CF(ffi_meta___add) LJLIB_REC(cdata_arith MM_add)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___sub) LJLIB_REC(cdata_arith MM_sub)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___mul) LJLIB_REC(cdata_arith MM_mul)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___div) LJLIB_REC(cdata_arith MM_div)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___mod) LJLIB_REC(cdata_arith MM_mod)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___pow) LJLIB_REC(cdata_arith MM_pow)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___unm) LJLIB_REC(cdata_arith MM_unm)
{
return ffi_arith(L);
}
/* End of contiguous ORDER MM. */
LJLIB_CF(ffi_meta___tostring)
{
GCcdata *cd = ffi_checkcdata(L, 1);
const char *msg = "cdata<%s>: %p";
CTypeID id = cd->ctypeid;
void *p = cdataptr(cd);
if (id == CTID_CTYPEID) {
msg = "ctype<%s>";
id = *(CTypeID *)p;
} else {
CTState *cts = ctype_cts(L);
CType *ct = ctype_raw(cts, id);
if (ctype_isref(ct->info)) {
p = *(void **)p;
ct = ctype_rawchild(cts, ct);
}
if (ctype_iscomplex(ct->info)) {
setstrV(L, L->top-1, lj_ctype_repr_complex(L, cdataptr(cd), ct->size));
goto checkgc;
} else if (ct->size == 8 && ctype_isinteger(ct->info)) {
setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd),
(ct->info & CTF_UNSIGNED)));
goto checkgc;
} else if (ctype_isfunc(ct->info)) {
p = *(void **)p;
} else if (ctype_isenum(ct->info)) {
msg = "cdata<%s>: %d";
p = (void *)(uintptr_t)*(uint32_t **)p;
} else {
if (ctype_isptr(ct->info)) {
p = cdata_getptr(p, ct->size);
ct = ctype_rawchild(cts, ct);
}
if (ctype_isstruct(ct->info) || ctype_isvector(ct->info)) {
/* Handle ctype __tostring metamethod. */
cTValue *tv = lj_ctype_meta(cts, ctype_typeid(cts, ct), MM_tostring);
if (tv)
return lj_meta_tailcall(L, tv);
}
}
}
lj_str_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), p);
checkgc:
lj_gc_check(L);
return 1;
}
static int ffi_pairs(lua_State *L, MMS mm)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkcdata(L, 1)->ctypeid;
CType *ct = ctype_raw(cts, id);
cTValue *tv;
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
tv = lj_ctype_meta(cts, id, mm);
if (!tv)
lj_err_callerv(L, LJ_ERR_FFI_BADMM, strdata(lj_ctype_repr(L, id, NULL)),
strdata(mmname_str(G(L), mm)));
return lj_meta_tailcall(L, tv);
}
LJLIB_CF(ffi_meta___pairs)
{
return ffi_pairs(L, MM_pairs);
}
LJLIB_CF(ffi_meta___ipairs)
{
return ffi_pairs(L, MM_ipairs);
}
LJLIB_PUSH("ffi") LJLIB_SET(__metatable)
#include "lj_libdef.h"
/* -- C library metamethods ----------------------------------------------- */
#define LJLIB_MODULE_ffi_clib
/* Index C library by a name. */
static TValue *ffi_clib_index(lua_State *L)
{
TValue *o = L->base;
CLibrary *cl;
if (!(o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB))
lj_err_argt(L, 1, LUA_TUSERDATA);
cl = (CLibrary *)uddata(udataV(o));
if (!(o+1 < L->top && tvisstr(o+1)))
lj_err_argt(L, 2, LUA_TSTRING);
return lj_clib_index(L, cl, strV(o+1));
}
LJLIB_CF(ffi_clib___index) LJLIB_REC(clib_index 1)
{
TValue *tv = ffi_clib_index(L);
if (tviscdata(tv)) {
CTState *cts = ctype_cts(L);
GCcdata *cd = cdataV(tv);
CType *s = ctype_get(cts, cd->ctypeid);
if (ctype_isextern(s->info)) {
CTypeID sid = ctype_cid(s->info);
void *sp = *(void **)cdataptr(cd);
CType *ct = ctype_raw(cts, sid);
if (lj_cconv_tv_ct(cts, ct, sid, L->top-1, sp))
lj_gc_check(L);
return 1;
}
}
copyTV(L, L->top-1, tv);
return 1;
}
LJLIB_CF(ffi_clib___newindex) LJLIB_REC(clib_index 0)
{
TValue *tv = ffi_clib_index(L);
TValue *o = L->base+2;
if (o < L->top && tviscdata(tv)) {
CTState *cts = ctype_cts(L);
GCcdata *cd = cdataV(tv);
CType *d = ctype_get(cts, cd->ctypeid);
if (ctype_isextern(d->info)) {
CTInfo qual = 0;
for (;;) { /* Skip attributes and collect qualifiers. */
d = ctype_child(cts, d);
if (!ctype_isattrib(d->info)) break;
if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
}
if (!((d->info|qual) & CTF_CONST)) {
lj_cconv_ct_tv(cts, d, *(void **)cdataptr(cd), o, 0);
return 0;
}
}
}
lj_err_caller(L, LJ_ERR_FFI_WRCONST);
return 0; /* unreachable */
}
LJLIB_CF(ffi_clib___gc)
{
TValue *o = L->base;
if (o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB)
lj_clib_unload((CLibrary *)uddata(udataV(o)));
return 0;
}
#include "lj_libdef.h"
/* -- Callback function metamethods --------------------------------------- */
#define LJLIB_MODULE_ffi_callback
static int ffi_callback_set(lua_State *L, GCfunc *fn)
{
GCcdata *cd = ffi_checkcdata(L, 1);
CTState *cts = ctype_cts(L);
CType *ct = ctype_raw(cts, cd->ctypeid);
if (ctype_isptr(ct->info) && (LJ_32 || ct->size == 8)) {
MSize slot = lj_ccallback_ptr2slot(cts, *(void **)cdataptr(cd));
if (slot < cts->cb.sizeid && cts->cb.cbid[slot] != 0) {
GCtab *t = cts->miscmap;
TValue *tv = lj_tab_setint(L, t, (int32_t)slot);
if (fn) {
setfuncV(L, tv, fn);
lj_gc_anybarriert(L, t);
} else {
setnilV(tv);
cts->cb.cbid[slot] = 0;
cts->cb.topid = slot < cts->cb.topid ? slot : cts->cb.topid;
}
return 0;
}
}
lj_err_caller(L, LJ_ERR_FFI_BADCBACK);
return 0;
}
LJLIB_CF(ffi_callback_free)
{
return ffi_callback_set(L, NULL);
}
LJLIB_CF(ffi_callback_set)
{
GCfunc *fn = lj_lib_checkfunc(L, 2);
return ffi_callback_set(L, fn);
}
LJLIB_PUSH(top-1) LJLIB_SET(__index)
#include "lj_libdef.h"
/* -- FFI library functions ----------------------------------------------- */
#define LJLIB_MODULE_ffi
LJLIB_CF(ffi_cdef)
{
GCstr *s = lj_lib_checkstr(L, 1);
CPState cp;
int errcode;
cp.L = L;
cp.cts = ctype_cts(L);
cp.srcname = strdata(s);
cp.p = strdata(s);
cp.param = L->base+1;
cp.mode = CPARSE_MODE_MULTI|CPARSE_MODE_DIRECT;
errcode = lj_cparse(&cp);
if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */
lj_gc_check(L);
return 0;
}
LJLIB_CF(ffi_new) LJLIB_REC(.)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
CType *ct = ctype_raw(cts, id);
CTSize sz;
CTInfo info = lj_ctype_info(cts, id, &sz);
TValue *o = L->base+1;
GCcdata *cd;
if ((info & CTF_VLA)) {
o++;
sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
}
if (sz == CTSIZE_INVALID)
lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE);
if (!(info & CTF_VLA) && ctype_align(info) <= CT_MEMALIGN)
cd = lj_cdata_new(cts, id, sz);
else
cd = lj_cdata_newv(cts, id, sz, ctype_align(info));
setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */
lj_cconv_ct_init(cts, ct, sz, cdataptr(cd),
o, (MSize)(L->top - o)); /* Initialize cdata. */
if (ctype_isstruct(ct->info)) {
/* Handle ctype __gc metamethod. Use the fast lookup here. */
cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)id);
if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) {
GCtab *t = cts->finalizer;
if (gcref(t->metatable)) {
/* Add to finalizer table, if still enabled. */
copyTV(L, lj_tab_set(L, t, o-1), tv);
lj_gc_anybarriert(L, t);
cd->marked |= LJ_GC_CDATA_FIN;
}
}
}
L->top = o; /* Only return the cdata itself. */
lj_gc_check(L);
return 1;
}
LJLIB_CF(ffi_cast) LJLIB_REC(ffi_new)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
CType *d = ctype_raw(cts, id);
TValue *o = lj_lib_checkany(L, 2);
L->top = o+1; /* Make sure this is the last item on the stack. */
if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || ctype_isenum(d->info)))
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
if (!(tviscdata(o) && cdataV(o)->ctypeid == id)) {
GCcdata *cd = lj_cdata_new(cts, id, d->size);
lj_cconv_ct_tv(cts, d, cdataptr(cd), o, CCF_CAST);
setcdataV(L, o, cd);
lj_gc_check(L);
}
return 1;
}
LJLIB_CF(ffi_typeof) LJLIB_REC(.)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, L->base+1);
GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
*(CTypeID *)cdataptr(cd) = id;
setcdataV(L, L->top-1, cd);
lj_gc_check(L);
return 1;
}
LJLIB_CF(ffi_istype) LJLIB_REC(.)
{
CTState *cts = ctype_cts(L);
CTypeID id1 = ffi_checkctype(L, cts, NULL);
TValue *o = lj_lib_checkany(L, 2);
int b = 0;
if (tviscdata(o)) {
GCcdata *cd = cdataV(o);
CTypeID id2 = cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) :
cd->ctypeid;
CType *ct1 = lj_ctype_rawref(cts, id1);
CType *ct2 = lj_ctype_rawref(cts, id2);
if (ct1 == ct2) {
b = 1;
} else if (ctype_type(ct1->info) == ctype_type(ct2->info) &&
ct1->size == ct2->size) {
if (ctype_ispointer(ct1->info))
b = lj_cconv_compatptr(cts, ct1, ct2, CCF_IGNQUAL);
else if (ctype_isnum(ct1->info) || ctype_isvoid(ct1->info))
b = (((ct1->info ^ ct2->info) & ~(CTF_QUAL|CTF_LONG)) == 0);
} else if (ctype_isstruct(ct1->info) && ctype_isptr(ct2->info) &&
ct1 == ctype_rawchild(cts, ct2)) {
b = 1;
}
}
setboolV(L->top-1, b);
setboolV(&G(L)->tmptv2, b); /* Remember for trace recorder. */
return 1;
}
LJLIB_CF(ffi_sizeof) LJLIB_REC(ffi_xof FF_ffi_sizeof)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
CTSize sz;
if (LJ_UNLIKELY(tviscdata(L->base) && cdataisv(cdataV(L->base)))) {
sz = cdatavlen(cdataV(L->base));
} else {
CType *ct = lj_ctype_rawref(cts, id);
if (ctype_isvltype(ct->info))
sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
else
sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_INVALID;
if (LJ_UNLIKELY(sz == CTSIZE_INVALID)) {
setnilV(L->top-1);
return 1;
}
}
setintV(L->top-1, (int32_t)sz);
return 1;
}
LJLIB_CF(ffi_alignof) LJLIB_REC(ffi_xof FF_ffi_alignof)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
CTSize sz = 0;
CTInfo info = lj_ctype_info(cts, id, &sz);
setintV(L->top-1, 1 << ctype_align(info));
return 1;
}
LJLIB_CF(ffi_offsetof) LJLIB_REC(ffi_xof FF_ffi_offsetof)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
GCstr *name = lj_lib_checkstr(L, 2);
CType *ct = lj_ctype_rawref(cts, id);
CTSize ofs;
if (ctype_isstruct(ct->info) && ct->size != CTSIZE_INVALID) {
CType *fct = lj_ctype_getfield(cts, ct, name, &ofs);
if (fct) {
setintV(L->top-1, ofs);
if (ctype_isfield(fct->info)) {
return 1;
} else if (ctype_isbitfield(fct->info)) {
setintV(L->top++, ctype_bitpos(fct->info));
setintV(L->top++, ctype_bitbsz(fct->info));
return 3;
}
}
}
return 0;
}
LJLIB_CF(ffi_errno) LJLIB_REC(.)
{
int err = errno;
if (L->top > L->base)
errno = ffi_checkint(L, 1);
setintV(L->top++, err);
return 1;
}
LJLIB_CF(ffi_string) LJLIB_REC(.)
{
CTState *cts = ctype_cts(L);
TValue *o = lj_lib_checkany(L, 1);
const char *p;
size_t len;
if (o+1 < L->top && !tvisnil(o+1)) {
len = (size_t)ffi_checkint(L, 2);
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p, o,
CCF_ARG(1));
} else {
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CCHAR), (uint8_t *)&p, o,
CCF_ARG(1));
len = strlen(p);
}
L->top = o+1; /* Make sure this is the last item on the stack. */
setstrV(L, o, lj_str_new(L, p, len));
lj_gc_check(L);
return 1;
}
LJLIB_CF(ffi_copy) LJLIB_REC(.)
{
void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
void *sp = ffi_checkptr(L, 2, CTID_P_CVOID);
TValue *o = L->base+1;
CTSize len;
if (tvisstr(o) && o+1 >= L->top)
len = strV(o)->len+1; /* Copy Lua string including trailing '\0'. */
else
len = (CTSize)ffi_checkint(L, 3);
memcpy(dp, sp, len);
return 0;
}
LJLIB_CF(ffi_fill) LJLIB_REC(.)
{
void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
CTSize len = (CTSize)ffi_checkint(L, 2);
int32_t fill = 0;
if (L->base+2 < L->top && !tvisnil(L->base+2)) fill = ffi_checkint(L, 3);
memset(dp, fill, len);
return 0;
}
#define H_(le, be) LJ_ENDIAN_SELECT(0x##le, 0x##be)
/* Test ABI string. */
LJLIB_CF(ffi_abi) LJLIB_REC(.)
{
GCstr *s = lj_lib_checkstr(L, 1);
int b = 0;
switch (s->hash) {
#if LJ_64
case H_(849858eb,ad35fd06): b = 1; break; /* 64bit */
#else
case H_(662d3c79,d0e22477): b = 1; break; /* 32bit */
#endif
#if LJ_ARCH_HASFPU
case H_(e33ee463,e33ee463): b = 1; break; /* fpu */
#endif
#if LJ_ABI_SOFTFP
case H_(61211a23,c2e8c81c): b = 1; break; /* softfp */
#else
case H_(539417a8,8ce0812f): b = 1; break; /* hardfp */
#endif
#if LJ_ABI_EABI
case H_(2182df8f,f2ed1152): b = 1; break; /* eabi */
#endif
#if LJ_ABI_WIN
case H_(4ab624a8,4ab624a8): b = 1; break; /* win */
#endif
case H_(3af93066,1f001464): b = 1; break; /* le/be */
default:
break;
}
setboolV(L->top-1, b);
setboolV(&G(L)->tmptv2, b); /* Remember for trace recorder. */
return 1;
}
#undef H_
LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to miscmap table. */
LJLIB_CF(ffi_metatype)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
GCtab *mt = lj_lib_checktab(L, 2);
GCtab *t = cts->miscmap;
CType *ct = ctype_get(cts, id); /* Only allow raw types. */
TValue *tv;
GCcdata *cd;
if (!(ctype_isstruct(ct->info) || ctype_iscomplex(ct->info) ||
ctype_isvector(ct->info)))
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
tv = lj_tab_setinth(L, t, -(int32_t)id);
if (!tvisnil(tv))
lj_err_caller(L, LJ_ERR_PROTMT);
settabV(L, tv, mt);
lj_gc_anybarriert(L, t);
cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
*(CTypeID *)cdataptr(cd) = id;
setcdataV(L, L->top-1, cd);
lj_gc_check(L);
return 1;
}
LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to finalizer table. */
LJLIB_CF(ffi_gc) LJLIB_REC(.)
{
GCcdata *cd = ffi_checkcdata(L, 1);
TValue *fin = lj_lib_checkany(L, 2);
CTState *cts = ctype_cts(L);
GCtab *t = cts->finalizer;
CType *ct = ctype_raw(cts, cd->ctypeid);
if (!(ctype_isptr(ct->info) || ctype_isstruct(ct->info) ||
ctype_isrefarray(ct->info)))
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
if (gcref(t->metatable)) { /* Update finalizer table, if still enabled. */
copyTV(L, lj_tab_set(L, t, L->base), fin);
lj_gc_anybarriert(L, t);
if (!tvisnil(fin))
cd->marked |= LJ_GC_CDATA_FIN;
else
cd->marked &= ~LJ_GC_CDATA_FIN;
}
L->top = L->base+1; /* Pass through the cdata object. */
return 1;
}
LJLIB_PUSH(top-5) LJLIB_SET(!) /* Store clib metatable in func environment. */
LJLIB_CF(ffi_load)
{
GCstr *name = lj_lib_checkstr(L, 1);
int global = (L->base+1 < L->top && tvistruecond(L->base+1));
lj_clib_load(L, tabref(curr_func(L)->c.env), name, global);
return 1;
}
LJLIB_PUSH(top-4) LJLIB_SET(C)
LJLIB_PUSH(top-3) LJLIB_SET(os)
LJLIB_PUSH(top-2) LJLIB_SET(arch)
#include "lj_libdef.h"
/* ------------------------------------------------------------------------ */
/* Create special weak-keyed finalizer table. */
static GCtab *ffi_finalizer(lua_State *L)
{
/* NOBARRIER: The table is new (marked white). */
GCtab *t = lj_tab_new(L, 0, 1);
settabV(L, L->top++, t);
setgcref(t->metatable, obj2gco(t));
setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
lj_str_newlit(L, "k"));
t->nomm = (uint8_t)(~(1u<<MM_mode));
return t;
}
/* Register FFI module as loaded. */
static void ffi_register_module(lua_State *L)
{
cTValue *tmp = lj_tab_getstr(tabV(registry(L)), lj_str_newlit(L, "_LOADED"));
if (tmp && tvistab(tmp)) {
GCtab *t = tabV(tmp);
copyTV(L, lj_tab_setstr(L, t, lj_str_newlit(L, LUA_FFILIBNAME)), L->top-1);
lj_gc_anybarriert(L, t);
}
}
LUALIB_API int luaopen_ffi(lua_State *L)
{
CTState *cts = lj_ctype_init(L);
settabV(L, L->top++, (cts->miscmap = lj_tab_new(L, 0, 1)));
cts->finalizer = ffi_finalizer(L);
LJ_LIB_REG(L, NULL, ffi_meta);
/* NOBARRIER: basemt is a GC root. */
setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
LJ_LIB_REG(L, NULL, ffi_clib);
LJ_LIB_REG(L, NULL, ffi_callback);
/* NOBARRIER: the key is new and lj_tab_newkey() handles the barrier. */
settabV(L, lj_tab_setstr(L, cts->miscmap, &cts->g->strempty), tabV(L->top-1));
L->top--;
lj_clib_default(L, tabV(L->top-1)); /* Create ffi.C default namespace. */
lua_pushliteral(L, LJ_OS_NAME);
lua_pushliteral(L, LJ_ARCH_NAME);
LJ_LIB_REG(L, NULL, ffi); /* Note: no global "ffi" created! */
ffi_register_module(L);
return 1;
}
#endif

View File

@ -1,55 +0,0 @@
/*
** Library initialization.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** Major parts taken verbatim from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lib_init_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_arch.h"
static const luaL_Reg lj_lib_load[] = {
{ "", luaopen_base },
{ LUA_LOADLIBNAME, luaopen_package },
{ LUA_TABLIBNAME, luaopen_table },
{ LUA_IOLIBNAME, luaopen_io },
{ LUA_OSLIBNAME, luaopen_os },
{ LUA_STRLIBNAME, luaopen_string },
{ LUA_MATHLIBNAME, luaopen_math },
{ LUA_DBLIBNAME, luaopen_debug },
{ LUA_BITLIBNAME, luaopen_bit },
{ LUA_JITLIBNAME, luaopen_jit },
{ NULL, NULL }
};
static const luaL_Reg lj_lib_preload[] = {
#if LJ_HASFFI
{ LUA_FFILIBNAME, luaopen_ffi },
#endif
{ NULL, NULL }
};
LUALIB_API void luaL_openlibs(lua_State *L)
{
const luaL_Reg *lib;
for (lib = lj_lib_load; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_pushstring(L, lib->name);
lua_call(L, 1, 0);
}
luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD",
sizeof(lj_lib_preload)/sizeof(lj_lib_preload[0])-1);
for (lib = lj_lib_preload; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_setfield(L, -2, lib->name);
}
lua_pop(L, 1);
}

View File

@ -1,574 +0,0 @@
/*
** I/O library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2011 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#include <errno.h>
#include <stdio.h>
#define lib_io_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_state.h"
#include "lj_ff.h"
#include "lj_lib.h"
#if LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
static int widen(const char *in, wchar_t *out)
{
return MultiByteToWideChar(CP_UTF8, 0, in, -1, out, MAX_PATH);
}
#endif
/* Userdata payload for I/O file. */
typedef struct IOFileUD {
FILE *fp; /* File handle. */
uint32_t type; /* File type. */
} IOFileUD;
#define IOFILE_TYPE_FILE 0 /* Regular file. */
#define IOFILE_TYPE_PIPE 1 /* Pipe. */
#define IOFILE_TYPE_STDF 2 /* Standard file handle. */
#define IOFILE_TYPE_MASK 3
#define IOFILE_FLAG_CLOSE 4 /* Close after io.lines() iterator. */
#define IOSTDF_UD(L, id) (&gcref(G(L)->gcroot[(id)])->ud)
#define IOSTDF_IOF(L, id) ((IOFileUD *)uddata(IOSTDF_UD(L, (id))))
/* -- Open/close helpers -------------------------------------------------- */
static IOFileUD *io_tofilep(lua_State *L)
{
if (!(L->base < L->top && tvisudata(L->base) &&
udataV(L->base)->udtype == UDTYPE_IO_FILE))
lj_err_argtype(L, 1, "FILE*");
return (IOFileUD *)uddata(udataV(L->base));
}
static IOFileUD *io_tofile(lua_State *L)
{
IOFileUD *iof = io_tofilep(L);
if (iof->fp == NULL)
lj_err_caller(L, LJ_ERR_IOCLFL);
return iof;
}
static FILE *io_stdfile(lua_State *L, ptrdiff_t id)
{
IOFileUD *iof = IOSTDF_IOF(L, id);
if (iof->fp == NULL)
lj_err_caller(L, LJ_ERR_IOSTDCL);
return iof->fp;
}
static IOFileUD *io_file_new(lua_State *L)
{
IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD));
GCudata *ud = udataV(L->top-1);
ud->udtype = UDTYPE_IO_FILE;
/* NOBARRIER: The GCudata is new (marked white). */
setgcrefr(ud->metatable, curr_func(L)->c.env);
iof->fp = NULL;
iof->type = IOFILE_TYPE_FILE;
return iof;
}
static IOFileUD *io_file_open(lua_State *L, const char *mode)
{
const char *fname = strdata(lj_lib_checkstr(L, 1));
IOFileUD *iof = io_file_new(L);
#if LJ_TARGET_WINDOWS
wchar_t wfname[MAX_PATH];
wchar_t wmode[MAX_PATH];
if (!widen(fname, wfname) || !widen(mode, wmode))
luaL_argerror(L, 1, lj_str_pushf(L, "%s: failed to convert path to utf-16", fname));
iof->fp = _wfopen(wfname, wmode);
#else
iof->fp = fopen(fname, mode);
#endif
if (iof->fp == NULL)
luaL_argerror(L, 1, lj_str_pushf(L, "%s: %s", fname, strerror(errno)));
return iof;
}
static int io_file_close(lua_State *L, IOFileUD *iof)
{
int ok;
if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_FILE) {
ok = (fclose(iof->fp) == 0);
} else if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_PIPE) {
int stat = -1;
#if LJ_TARGET_POSIX
stat = pclose(iof->fp);
#elif LJ_TARGET_WINDOWS
stat = _pclose(iof->fp);
#else
lua_assert(0);
return 0;
#endif
#if LJ_52
iof->fp = NULL;
return luaL_execresult(L, stat);
#else
ok = (stat != -1);
#endif
} else {
lua_assert((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_STDF);
setnilV(L->top++);
lua_pushliteral(L, "cannot close standard file");
return 2;
}
iof->fp = NULL;
return luaL_fileresult(L, ok, NULL);
}
/* -- Read/write helpers -------------------------------------------------- */
static int io_file_readnum(lua_State *L, FILE *fp)
{
lua_Number d;
if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) {
if (LJ_DUALNUM) {
int32_t i = lj_num2int(d);
if (d == (lua_Number)i && !tvismzero((cTValue *)&d)) {
setintV(L->top++, i);
return 1;
}
}
setnumV(L->top++, d);
return 1;
} else {
setnilV(L->top++);
return 0;
}
}
static int io_file_readline(lua_State *L, FILE *fp, MSize chop)
{
MSize m = LUAL_BUFFERSIZE, n = 0, ok = 0;
char *buf;
for (;;) {
buf = lj_str_needbuf(L, &G(L)->tmpbuf, m);
if (fgets(buf+n, m-n, fp) == NULL) break;
n += (MSize)strlen(buf+n);
ok |= n;
if (n && buf[n-1] == '\n') { n -= chop; break; }
if (n >= m - 64) m += m;
}
setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n));
lj_gc_check(L);
return (int)ok;
}
static void io_file_readall(lua_State *L, FILE *fp)
{
MSize m, n;
for (m = LUAL_BUFFERSIZE, n = 0; ; m += m) {
char *buf = lj_str_needbuf(L, &G(L)->tmpbuf, m);
n += (MSize)fread(buf+n, 1, m-n, fp);
if (n != m) {
setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n));
lj_gc_check(L);
return;
}
}
}
static int io_file_readlen(lua_State *L, FILE *fp, MSize m)
{
if (m) {
char *buf = lj_str_needbuf(L, &G(L)->tmpbuf, m);
MSize n = (MSize)fread(buf, 1, m, fp);
setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n));
lj_gc_check(L);
return (n > 0 || m == 0);
} else {
int c = getc(fp);
ungetc(c, fp);
setstrV(L, L->top++, &G(L)->strempty);
return (c != EOF);
}
}
static int io_file_read(lua_State *L, FILE *fp, int start)
{
int ok, n, nargs = (int)(L->top - L->base) - start;
clearerr(fp);
if (nargs == 0) {
ok = io_file_readline(L, fp, 1);
n = start+1; /* Return 1 result. */
} else {
/* The results plus the buffers go on top of the args. */
luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
ok = 1;
for (n = start; nargs-- && ok; n++) {
if (tvisstr(L->base+n)) {
const char *p = strVdata(L->base+n);
if (p[0] != '*')
lj_err_arg(L, n+1, LJ_ERR_INVOPT);
if (p[1] == 'n')
ok = io_file_readnum(L, fp);
else if ((p[1] & ~0x20) == 'L')
ok = io_file_readline(L, fp, (p[1] == 'l'));
else if (p[1] == 'a')
io_file_readall(L, fp);
else
lj_err_arg(L, n+1, LJ_ERR_INVFMT);
} else if (tvisnumber(L->base+n)) {
ok = io_file_readlen(L, fp, (MSize)lj_lib_checkint(L, n+1));
} else {
lj_err_arg(L, n+1, LJ_ERR_INVOPT);
}
}
}
if (ferror(fp))
return luaL_fileresult(L, 0, NULL);
if (!ok)
setnilV(L->top-1); /* Replace last result with nil. */
return n - start;
}
static int io_file_write(lua_State *L, FILE *fp, int start)
{
cTValue *tv;
int status = 1;
for (tv = L->base+start; tv < L->top; tv++) {
if (tvisstr(tv)) {
MSize len = strV(tv)->len;
status = status && (fwrite(strVdata(tv), 1, len, fp) == len);
} else if (tvisint(tv)) {
char buf[LJ_STR_INTBUF];
char *p = lj_str_bufint(buf, intV(tv));
size_t len = (size_t)(buf+LJ_STR_INTBUF-p);
status = status && (fwrite(p, 1, len, fp) == len);
} else if (tvisnum(tv)) {
status = status && (fprintf(fp, LUA_NUMBER_FMT, numV(tv)) > 0);
} else {
lj_err_argt(L, (int)(tv - L->base) + 1, LUA_TSTRING);
}
}
if (LJ_52 && status) {
L->top = L->base+1;
if (start == 0)
setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_OUTPUT));
return 1;
}
return luaL_fileresult(L, status, NULL);
}
static int io_file_iter(lua_State *L)
{
GCfunc *fn = curr_func(L);
IOFileUD *iof = uddata(udataV(&fn->c.upvalue[0]));
int n = fn->c.nupvalues - 1;
if (iof->fp == NULL)
lj_err_caller(L, LJ_ERR_IOCLFL);
L->top = L->base;
if (n) { /* Copy upvalues with options to stack. */
if (n > LUAI_MAXCSTACK)
lj_err_caller(L, LJ_ERR_STKOV);
lj_state_checkstack(L, (MSize)n);
memcpy(L->top, &fn->c.upvalue[1], n*sizeof(TValue));
L->top += n;
}
n = io_file_read(L, iof->fp, 0);
if (ferror(iof->fp))
lj_err_callermsg(L, strVdata(L->top-2));
if (tvisnil(L->base) && (iof->type & IOFILE_FLAG_CLOSE)) {
io_file_close(L, iof); /* Return values are ignored. */
return 0;
}
return n;
}
static int io_file_lines(lua_State *L)
{
int n = (int)(L->top - L->base);
if (n > LJ_MAX_UPVAL)
lj_err_caller(L, LJ_ERR_UNPACK);
lua_pushcclosure(L, io_file_iter, n);
return 1;
}
/* -- I/O file methods ---------------------------------------------------- */
#define LJLIB_MODULE_io_method
LJLIB_CF(io_method_close)
{
IOFileUD *iof = L->base < L->top ? io_tofile(L) :
IOSTDF_IOF(L, GCROOT_IO_OUTPUT);
return io_file_close(L, iof);
}
LJLIB_CF(io_method_read)
{
return io_file_read(L, io_tofile(L)->fp, 1);
}
LJLIB_CF(io_method_write) LJLIB_REC(io_write 0)
{
return io_file_write(L, io_tofile(L)->fp, 1);
}
LJLIB_CF(io_method_flush) LJLIB_REC(io_flush 0)
{
return luaL_fileresult(L, fflush(io_tofile(L)->fp) == 0, NULL);
}
LJLIB_CF(io_method_seek)
{
FILE *fp = io_tofile(L)->fp;
int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end");
int64_t ofs = 0;
cTValue *o;
int res;
if (opt == 0) opt = SEEK_SET;
else if (opt == 1) opt = SEEK_CUR;
else if (opt == 2) opt = SEEK_END;
o = L->base+2;
if (o < L->top) {
if (tvisint(o))
ofs = (int64_t)intV(o);
else if (tvisnum(o))
ofs = (int64_t)numV(o);
else if (!tvisnil(o))
lj_err_argt(L, 3, LUA_TNUMBER);
}
#if LJ_TARGET_POSIX
res = fseeko(fp, ofs, opt);
#elif _MSC_VER >= 1400
res = _fseeki64(fp, ofs, opt);
#elif defined(__MINGW32__)
res = fseeko64(fp, ofs, opt);
#else
res = fseek(fp, (long)ofs, opt);
#endif
if (res)
return luaL_fileresult(L, 0, NULL);
#if LJ_TARGET_POSIX
ofs = ftello(fp);
#elif _MSC_VER >= 1400
ofs = _ftelli64(fp);
#elif defined(__MINGW32__)
ofs = ftello64(fp);
#else
ofs = (int64_t)ftell(fp);
#endif
setint64V(L->top-1, ofs);
return 1;
}
LJLIB_CF(io_method_setvbuf)
{
FILE *fp = io_tofile(L)->fp;
int opt = lj_lib_checkopt(L, 2, -1, "\4full\4line\2no");
size_t sz = (size_t)lj_lib_optint(L, 3, LUAL_BUFFERSIZE);
if (opt == 0) opt = _IOFBF;
else if (opt == 1) opt = _IOLBF;
else if (opt == 2) opt = _IONBF;
return luaL_fileresult(L, setvbuf(fp, NULL, opt, sz) == 0, NULL);
}
LJLIB_CF(io_method_lines)
{
io_tofile(L);
return io_file_lines(L);
}
LJLIB_CF(io_method___gc)
{
IOFileUD *iof = io_tofilep(L);
if (iof->fp != NULL && (iof->type & IOFILE_TYPE_MASK) != IOFILE_TYPE_STDF)
io_file_close(L, iof);
return 0;
}
LJLIB_CF(io_method___tostring)
{
IOFileUD *iof = io_tofilep(L);
if (iof->fp != NULL)
lua_pushfstring(L, "file (%p)", iof->fp);
else
lua_pushliteral(L, "file (closed)");
return 1;
}
LJLIB_PUSH(top-1) LJLIB_SET(__index)
#include "lj_libdef.h"
/* -- I/O library functions ----------------------------------------------- */
#define LJLIB_MODULE_io
LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
LJLIB_CF(io_open)
{
const char *fname = strdata(lj_lib_checkstr(L, 1));
GCstr *s = lj_lib_optstr(L, 2);
const char *mode = s ? strdata(s) : "r";
IOFileUD *iof = io_file_new(L);
#if LJ_TARGET_WINDOWS
wchar_t wfname[MAX_PATH];
wchar_t wmode[MAX_PATH];
if (widen(fname, wfname) && widen(mode, wmode))
iof->fp = _wfopen(wfname, wmode);
#else
iof->fp = fopen(fname, mode);
#endif
return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname);
}
LJLIB_CF(io_popen)
{
#if LJ_TARGET_POSIX || LJ_TARGET_WINDOWS
const char *fname = strdata(lj_lib_checkstr(L, 1));
GCstr *s = lj_lib_optstr(L, 2);
const char *mode = s ? strdata(s) : "r";
IOFileUD *iof = io_file_new(L);
iof->type = IOFILE_TYPE_PIPE;
#if LJ_TARGET_POSIX
fflush(NULL);
iof->fp = popen(fname, mode);
#else
wchar_t wfname[MAX_PATH];
wchar_t wmode[MAX_PATH];
if (widen(fname, wfname) && widen(mode, wmode))
iof->fp = _wpopen(wfname, wmode);
#endif
return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname);
#else
return luaL_error(L, LUA_QL("popen") " not supported");
#endif
}
LJLIB_CF(io_tmpfile)
{
IOFileUD *iof = io_file_new(L);
#if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PSVITA
iof->fp = NULL; errno = ENOSYS;
#else
iof->fp = tmpfile();
#endif
return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, NULL);
}
LJLIB_CF(io_close)
{
return lj_cf_io_method_close(L);
}
LJLIB_CF(io_read)
{
return io_file_read(L, io_stdfile(L, GCROOT_IO_INPUT), 0);
}
LJLIB_CF(io_write) LJLIB_REC(io_write GCROOT_IO_OUTPUT)
{
return io_file_write(L, io_stdfile(L, GCROOT_IO_OUTPUT), 0);
}
LJLIB_CF(io_flush) LJLIB_REC(io_flush GCROOT_IO_OUTPUT)
{
return luaL_fileresult(L, fflush(io_stdfile(L, GCROOT_IO_OUTPUT)) == 0, NULL);
}
static int io_std_getset(lua_State *L, ptrdiff_t id, const char *mode)
{
if (L->base < L->top && !tvisnil(L->base)) {
if (tvisudata(L->base)) {
io_tofile(L);
L->top = L->base+1;
} else {
io_file_open(L, mode);
}
/* NOBARRIER: The standard I/O handles are GC roots. */
setgcref(G(L)->gcroot[id], gcV(L->top-1));
} else {
setudataV(L, L->top++, IOSTDF_UD(L, id));
}
return 1;
}
LJLIB_CF(io_input)
{
return io_std_getset(L, GCROOT_IO_INPUT, "r");
}
LJLIB_CF(io_output)
{
return io_std_getset(L, GCROOT_IO_OUTPUT, "w");
}
LJLIB_CF(io_lines)
{
if (L->base == L->top) setnilV(L->top++);
if (!tvisnil(L->base)) { /* io.lines(fname) */
IOFileUD *iof = io_file_open(L, "r");
iof->type = IOFILE_TYPE_FILE|IOFILE_FLAG_CLOSE;
L->top--;
setudataV(L, L->base, udataV(L->top));
} else { /* io.lines() iterates over stdin. */
setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_INPUT));
}
return io_file_lines(L);
}
LJLIB_CF(io_type)
{
cTValue *o = lj_lib_checkany(L, 1);
if (!(tvisudata(o) && udataV(o)->udtype == UDTYPE_IO_FILE))
setnilV(L->top++);
else if (((IOFileUD *)uddata(udataV(o)))->fp != NULL)
lua_pushliteral(L, "file");
else
lua_pushliteral(L, "closed file");
return 1;
}
#include "lj_libdef.h"
/* ------------------------------------------------------------------------ */
static GCobj *io_std_new(lua_State *L, FILE *fp, const char *name)
{
IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD));
GCudata *ud = udataV(L->top-1);
ud->udtype = UDTYPE_IO_FILE;
/* NOBARRIER: The GCudata is new (marked white). */
setgcref(ud->metatable, gcV(L->top-3));
iof->fp = fp;
iof->type = IOFILE_TYPE_STDF;
lua_setfield(L, -2, name);
return obj2gco(ud);
}
LUALIB_API int luaopen_io(lua_State *L)
{
LJ_LIB_REG(L, NULL, io_method);
copyTV(L, L->top, L->top-1); L->top++;
lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
LJ_LIB_REG(L, LUA_IOLIBNAME, io);
setgcref(G(L)->gcroot[GCROOT_IO_INPUT], io_std_new(L, stdin, "stdin"));
setgcref(G(L)->gcroot[GCROOT_IO_OUTPUT], io_std_new(L, stdout, "stdout"));
io_std_new(L, stderr, "stderr");
return 1;
}

View File

@ -1,664 +0,0 @@
/*
** JIT library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#define lib_jit_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_arch.h"
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_debug.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_bc.h"
#if LJ_HASJIT
#include "lj_ir.h"
#include "lj_jit.h"
#include "lj_ircall.h"
#include "lj_iropt.h"
#include "lj_target.h"
#endif
#include "lj_dispatch.h"
#include "lj_vm.h"
#include "lj_vmevent.h"
#include "lj_lib.h"
#include "luajit.h"
/* -- jit.* functions ----------------------------------------------------- */
#define LJLIB_MODULE_jit
static int setjitmode(lua_State *L, int mode)
{
int idx = 0;
if (L->base == L->top || tvisnil(L->base)) { /* jit.on/off/flush([nil]) */
mode |= LUAJIT_MODE_ENGINE;
} else {
/* jit.on/off/flush(func|proto, nil|true|false) */
if (tvisfunc(L->base) || tvisproto(L->base))
idx = 1;
else if (!tvistrue(L->base)) /* jit.on/off/flush(true, nil|true|false) */
goto err;
if (L->base+1 < L->top && tvisbool(L->base+1))
mode |= boolV(L->base+1) ? LUAJIT_MODE_ALLFUNC : LUAJIT_MODE_ALLSUBFUNC;
else
mode |= LUAJIT_MODE_FUNC;
}
if (luaJIT_setmode(L, idx, mode) != 1) {
if ((mode & LUAJIT_MODE_MASK) == LUAJIT_MODE_ENGINE)
lj_err_caller(L, LJ_ERR_NOJIT);
err:
lj_err_argt(L, 1, LUA_TFUNCTION);
}
return 0;
}
LJLIB_CF(jit_on)
{
return setjitmode(L, LUAJIT_MODE_ON);
}
LJLIB_CF(jit_off)
{
return setjitmode(L, LUAJIT_MODE_OFF);
}
LJLIB_CF(jit_flush)
{
#if LJ_HASJIT
if (L->base < L->top && tvisnumber(L->base)) {
int traceno = lj_lib_checkint(L, 1);
luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE);
return 0;
}
#endif
return setjitmode(L, LUAJIT_MODE_FLUSH);
}
#if LJ_HASJIT
/* Push a string for every flag bit that is set. */
static void flagbits_to_strings(lua_State *L, uint32_t flags, uint32_t base,
const char *str)
{
for (; *str; base <<= 1, str += 1+*str)
if (flags & base)
setstrV(L, L->top++, lj_str_new(L, str+1, *(uint8_t *)str));
}
#endif
LJLIB_CF(jit_status)
{
#if LJ_HASJIT
jit_State *J = L2J(L);
L->top = L->base;
setboolV(L->top++, (J->flags & JIT_F_ON) ? 1 : 0);
flagbits_to_strings(L, J->flags, JIT_F_CPU_FIRST, JIT_F_CPUSTRING);
flagbits_to_strings(L, J->flags, JIT_F_OPT_FIRST, JIT_F_OPTSTRING);
return (int)(L->top - L->base);
#else
setboolV(L->top++, 0);
return 1;
#endif
}
LJLIB_CF(jit_attach)
{
#ifdef LUAJIT_DISABLE_VMEVENT
luaL_error(L, "vmevent API disabled");
#else
GCfunc *fn = lj_lib_checkfunc(L, 1);
GCstr *s = lj_lib_optstr(L, 2);
luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
if (s) { /* Attach to given event. */
const uint8_t *p = (const uint8_t *)strdata(s);
uint32_t h = s->len;
while (*p) h = h ^ (lj_rol(h, 6) + *p++);
lua_pushvalue(L, 1);
lua_rawseti(L, -2, VMEVENT_HASHIDX(h));
G(L)->vmevmask = VMEVENT_NOCACHE; /* Invalidate cache. */
} else { /* Detach if no event given. */
setnilV(L->top++);
while (lua_next(L, -2)) {
L->top--;
if (tvisfunc(L->top) && funcV(L->top) == fn) {
setnilV(lj_tab_set(L, tabV(L->top-2), L->top-1));
}
}
}
#endif
return 0;
}
LJLIB_PUSH(top-5) LJLIB_SET(os)
LJLIB_PUSH(top-4) LJLIB_SET(arch)
LJLIB_PUSH(top-3) LJLIB_SET(version_num)
LJLIB_PUSH(top-2) LJLIB_SET(version)
#include "lj_libdef.h"
/* -- jit.util.* functions ------------------------------------------------ */
#define LJLIB_MODULE_jit_util
/* -- Reflection API for Lua functions ------------------------------------ */
/* Return prototype of first argument (Lua function or prototype object) */
static GCproto *check_Lproto(lua_State *L, int nolua)
{
TValue *o = L->base;
if (L->top > o) {
if (tvisproto(o)) {
return protoV(o);
} else if (tvisfunc(o)) {
if (isluafunc(funcV(o)))
return funcproto(funcV(o));
else if (nolua)
return NULL;
}
}
lj_err_argt(L, 1, LUA_TFUNCTION);
return NULL; /* unreachable */
}
static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val)
{
setintV(lj_tab_setstr(L, t, lj_str_newz(L, name)), val);
}
/* local info = jit.util.funcinfo(func [,pc]) */
LJLIB_CF(jit_util_funcinfo)
{
GCproto *pt = check_Lproto(L, 1);
if (pt) {
BCPos pc = (BCPos)lj_lib_optint(L, 2, 0);
GCtab *t;
lua_createtable(L, 0, 16); /* Increment hash size if fields are added. */
t = tabV(L->top-1);
setintfield(L, t, "linedefined", pt->firstline);
setintfield(L, t, "lastlinedefined", pt->firstline + pt->numline);
setintfield(L, t, "stackslots", pt->framesize);
setintfield(L, t, "params", pt->numparams);
setintfield(L, t, "bytecodes", (int32_t)pt->sizebc);
setintfield(L, t, "gcconsts", (int32_t)pt->sizekgc);
setintfield(L, t, "nconsts", (int32_t)pt->sizekn);
setintfield(L, t, "upvalues", (int32_t)pt->sizeuv);
if (pc < pt->sizebc)
setintfield(L, t, "currentline", lj_debug_line(pt, pc));
lua_pushboolean(L, (pt->flags & PROTO_VARARG));
lua_setfield(L, -2, "isvararg");
lua_pushboolean(L, (pt->flags & PROTO_CHILD));
lua_setfield(L, -2, "children");
setstrV(L, L->top++, proto_chunkname(pt));
lua_setfield(L, -2, "source");
lj_debug_pushloc(L, pt, pc);
lua_setfield(L, -2, "loc");
setprotoV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "proto")), pt);
} else {
GCfunc *fn = funcV(L->base);
GCtab *t;
lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */
t = tabV(L->top-1);
if (!iscfunc(fn))
setintfield(L, t, "ffid", fn->c.ffid);
setintptrV(lj_tab_setstr(L, t, lj_str_newlit(L, "addr")),
(intptr_t)(void *)fn->c.f);
setintfield(L, t, "upvalues", fn->c.nupvalues);
}
return 1;
}
/* local ins, m = jit.util.funcbc(func, pc) */
LJLIB_CF(jit_util_funcbc)
{
GCproto *pt = check_Lproto(L, 0);
BCPos pc = (BCPos)lj_lib_checkint(L, 2);
if (pc < pt->sizebc) {
BCIns ins = proto_bc(pt)[pc];
BCOp op = bc_op(ins);
lua_assert(op < BC__MAX);
setintV(L->top, ins);
setintV(L->top+1, lj_bc_mode[op]);
L->top += 2;
return 2;
}
return 0;
}
/* local k = jit.util.funck(func, idx) */
LJLIB_CF(jit_util_funck)
{
GCproto *pt = check_Lproto(L, 0);
ptrdiff_t idx = (ptrdiff_t)lj_lib_checkint(L, 2);
if (idx >= 0) {
if (idx < (ptrdiff_t)pt->sizekn) {
copyTV(L, L->top-1, proto_knumtv(pt, idx));
return 1;
}
} else {
if (~idx < (ptrdiff_t)pt->sizekgc) {
GCobj *gc = proto_kgc(pt, idx);
setgcV(L, L->top-1, gc, ~gc->gch.gct);
return 1;
}
}
return 0;
}
/* local name = jit.util.funcuvname(func, idx) */
LJLIB_CF(jit_util_funcuvname)
{
GCproto *pt = check_Lproto(L, 0);
uint32_t idx = (uint32_t)lj_lib_checkint(L, 2);
if (idx < pt->sizeuv) {
setstrV(L, L->top-1, lj_str_newz(L, lj_debug_uvname(pt, idx)));
return 1;
}
return 0;
}
/* -- Reflection API for traces ------------------------------------------- */
#if LJ_HASJIT
/* Check trace argument. Must not throw for non-existent trace numbers. */
static GCtrace *jit_checktrace(lua_State *L)
{
TraceNo tr = (TraceNo)lj_lib_checkint(L, 1);
jit_State *J = L2J(L);
if (tr > 0 && tr < J->sizetrace)
return traceref(J, tr);
return NULL;
}
/* Names of link types. ORDER LJ_TRLINK */
static const char *const jit_trlinkname[] = {
"none", "root", "loop", "tail-recursion", "up-recursion", "down-recursion",
"interpreter", "return"
};
/* local info = jit.util.traceinfo(tr) */
LJLIB_CF(jit_util_traceinfo)
{
GCtrace *T = jit_checktrace(L);
if (T) {
GCtab *t;
lua_createtable(L, 0, 8); /* Increment hash size if fields are added. */
t = tabV(L->top-1);
setintfield(L, t, "nins", (int32_t)T->nins - REF_BIAS - 1);
setintfield(L, t, "nk", REF_BIAS - (int32_t)T->nk);
setintfield(L, t, "link", T->link);
setintfield(L, t, "nexit", T->nsnap);
setstrV(L, L->top++, lj_str_newz(L, jit_trlinkname[T->linktype]));
lua_setfield(L, -2, "linktype");
/* There are many more fields. Add them only when needed. */
return 1;
}
return 0;
}
/* local m, ot, op1, op2, prev = jit.util.traceir(tr, idx) */
LJLIB_CF(jit_util_traceir)
{
GCtrace *T = jit_checktrace(L);
IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
if (T && ref >= REF_BIAS && ref < T->nins) {
IRIns *ir = &T->ir[ref];
int32_t m = lj_ir_mode[ir->o];
setintV(L->top-2, m);
setintV(L->top-1, ir->ot);
setintV(L->top++, (int32_t)ir->op1 - (irm_op1(m)==IRMref ? REF_BIAS : 0));
setintV(L->top++, (int32_t)ir->op2 - (irm_op2(m)==IRMref ? REF_BIAS : 0));
setintV(L->top++, ir->prev);
return 5;
}
return 0;
}
/* local k, t [, slot] = jit.util.tracek(tr, idx) */
LJLIB_CF(jit_util_tracek)
{
GCtrace *T = jit_checktrace(L);
IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
if (T && ref >= T->nk && ref < REF_BIAS) {
IRIns *ir = &T->ir[ref];
int32_t slot = -1;
if (ir->o == IR_KSLOT) {
slot = ir->op2;
ir = &T->ir[ir->op1];
}
lj_ir_kvalue(L, L->top-2, ir);
setintV(L->top-1, (int32_t)irt_type(ir->t));
if (slot == -1)
return 2;
setintV(L->top++, slot);
return 3;
}
return 0;
}
/* local snap = jit.util.tracesnap(tr, sn) */
LJLIB_CF(jit_util_tracesnap)
{
GCtrace *T = jit_checktrace(L);
SnapNo sn = (SnapNo)lj_lib_checkint(L, 2);
if (T && sn < T->nsnap) {
SnapShot *snap = &T->snap[sn];
SnapEntry *map = &T->snapmap[snap->mapofs];
MSize n, nent = snap->nent;
GCtab *t;
lua_createtable(L, nent+2, 0);
t = tabV(L->top-1);
setintV(lj_tab_setint(L, t, 0), (int32_t)snap->ref - REF_BIAS);
setintV(lj_tab_setint(L, t, 1), (int32_t)snap->nslots);
for (n = 0; n < nent; n++)
setintV(lj_tab_setint(L, t, (int32_t)(n+2)), (int32_t)map[n]);
setintV(lj_tab_setint(L, t, (int32_t)(nent+2)), (int32_t)SNAP(255, 0, 0));
return 1;
}
return 0;
}
/* local mcode, addr, loop = jit.util.tracemc(tr) */
LJLIB_CF(jit_util_tracemc)
{
GCtrace *T = jit_checktrace(L);
if (T && T->mcode != NULL) {
setstrV(L, L->top-1, lj_str_new(L, (const char *)T->mcode, T->szmcode));
setintptrV(L->top++, (intptr_t)(void *)T->mcode);
setintV(L->top++, T->mcloop);
return 3;
}
return 0;
}
/* local addr = jit.util.traceexitstub([tr,] exitno) */
LJLIB_CF(jit_util_traceexitstub)
{
#ifdef EXITSTUBS_PER_GROUP
ExitNo exitno = (ExitNo)lj_lib_checkint(L, 1);
jit_State *J = L2J(L);
if (exitno < EXITSTUBS_PER_GROUP*LJ_MAX_EXITSTUBGR) {
setintptrV(L->top-1, (intptr_t)(void *)exitstub_addr(J, exitno));
return 1;
}
#else
if (L->top > L->base+1) { /* Don't throw for one-argument variant. */
GCtrace *T = jit_checktrace(L);
ExitNo exitno = (ExitNo)lj_lib_checkint(L, 2);
ExitNo maxexit = T->root ? T->nsnap+1 : T->nsnap;
if (T && T->mcode != NULL && exitno < maxexit) {
setintptrV(L->top-1, (intptr_t)(void *)exitstub_trace_addr(T, exitno));
return 1;
}
}
#endif
return 0;
}
/* local addr = jit.util.ircalladdr(idx) */
LJLIB_CF(jit_util_ircalladdr)
{
uint32_t idx = (uint32_t)lj_lib_checkint(L, 1);
if (idx < IRCALL__MAX) {
setintptrV(L->top-1, (intptr_t)(void *)lj_ir_callinfo[idx].func);
return 1;
}
return 0;
}
#endif
#include "lj_libdef.h"
/* -- jit.opt module ------------------------------------------------------ */
#if LJ_HASJIT
#define LJLIB_MODULE_jit_opt
/* Parse optimization level. */
static int jitopt_level(jit_State *J, const char *str)
{
if (str[0] >= '0' && str[0] <= '9' && str[1] == '\0') {
uint32_t flags;
if (str[0] == '0') flags = JIT_F_OPT_0;
else if (str[0] == '1') flags = JIT_F_OPT_1;
else if (str[0] == '2') flags = JIT_F_OPT_2;
else flags = JIT_F_OPT_3;
J->flags = (J->flags & ~JIT_F_OPT_MASK) | flags;
return 1; /* Ok. */
}
return 0; /* No match. */
}
/* Parse optimization flag. */
static int jitopt_flag(jit_State *J, const char *str)
{
const char *lst = JIT_F_OPTSTRING;
uint32_t opt;
int set = 1;
if (str[0] == '+') {
str++;
} else if (str[0] == '-') {
str++;
set = 0;
} else if (str[0] == 'n' && str[1] == 'o') {
str += str[2] == '-' ? 3 : 2;
set = 0;
}
for (opt = JIT_F_OPT_FIRST; ; opt <<= 1) {
size_t len = *(const uint8_t *)lst;
if (len == 0)
break;
if (strncmp(str, lst+1, len) == 0 && str[len] == '\0') {
if (set) J->flags |= opt; else J->flags &= ~opt;
return 1; /* Ok. */
}
lst += 1+len;
}
return 0; /* No match. */
}
/* Parse optimization parameter. */
static int jitopt_param(jit_State *J, const char *str)
{
const char *lst = JIT_P_STRING;
int i;
for (i = 0; i < JIT_P__MAX; i++) {
size_t len = *(const uint8_t *)lst;
lua_assert(len != 0);
if (strncmp(str, lst+1, len) == 0 && str[len] == '=') {
int32_t n = 0;
const char *p = &str[len+1];
while (*p >= '0' && *p <= '9')
n = n*10 + (*p++ - '0');
if (*p) return 0; /* Malformed number. */
J->param[i] = n;
if (i == JIT_P_hotloop)
lj_dispatch_init_hotcount(J2G(J));
return 1; /* Ok. */
}
lst += 1+len;
}
return 0; /* No match. */
}
/* jit.opt.start(flags...) */
LJLIB_CF(jit_opt_start)
{
jit_State *J = L2J(L);
int nargs = (int)(L->top - L->base);
if (nargs == 0) {
J->flags = (J->flags & ~JIT_F_OPT_MASK) | JIT_F_OPT_DEFAULT;
} else {
int i;
for (i = 1; i <= nargs; i++) {
const char *str = strdata(lj_lib_checkstr(L, i));
if (!jitopt_level(J, str) &&
!jitopt_flag(J, str) &&
!jitopt_param(J, str))
lj_err_callerv(L, LJ_ERR_JITOPT, str);
}
}
return 0;
}
#include "lj_libdef.h"
#endif
/* -- JIT compiler initialization ----------------------------------------- */
#if LJ_HASJIT
/* Default values for JIT parameters. */
static const int32_t jit_param_default[JIT_P__MAX+1] = {
#define JIT_PARAMINIT(len, name, value) (value),
JIT_PARAMDEF(JIT_PARAMINIT)
#undef JIT_PARAMINIT
0
};
#endif
#if LJ_TARGET_ARM && LJ_TARGET_LINUX
#include <sys/utsname.h>
#endif
/* Arch-dependent CPU detection. */
static uint32_t jit_cpudetect(lua_State *L)
{
uint32_t flags = 0;
#if LJ_TARGET_X86ORX64
uint32_t vendor[4];
uint32_t features[4];
if (lj_vm_cpuid(0, vendor) && lj_vm_cpuid(1, features)) {
#if !LJ_HASJIT
#define JIT_F_CMOV 1
#define JIT_F_SSE2 2
#endif
flags |= ((features[3] >> 15)&1) * JIT_F_CMOV;
flags |= ((features[3] >> 26)&1) * JIT_F_SSE2;
#if LJ_HASJIT
flags |= ((features[2] >> 0)&1) * JIT_F_SSE3;
flags |= ((features[2] >> 19)&1) * JIT_F_SSE4_1;
if (vendor[2] == 0x6c65746e) { /* Intel. */
if ((features[0] & 0x0ff00f00) == 0x00000f00) /* P4. */
flags |= JIT_F_P4; /* Currently unused. */
else if ((features[0] & 0x0fff0ff0) == 0x000106c0) /* Atom. */
flags |= JIT_F_LEA_AGU;
} else if (vendor[2] == 0x444d4163) { /* AMD. */
uint32_t fam = (features[0] & 0x0ff00f00);
if (fam == 0x00000f00) /* K8. */
flags |= JIT_F_SPLIT_XMM;
if (fam >= 0x00000f00) /* K8, K10. */
flags |= JIT_F_PREFER_IMUL;
}
#endif
}
/* Check for required instruction set support on x86 (unnecessary on x64). */
#if LJ_TARGET_X86
#if !defined(LUAJIT_CPU_NOCMOV)
if (!(flags & JIT_F_CMOV))
luaL_error(L, "CPU not supported");
#endif
#if defined(LUAJIT_CPU_SSE2)
if (!(flags & JIT_F_SSE2))
luaL_error(L, "CPU does not support SSE2 (recompile without -DLUAJIT_CPU_SSE2)");
#endif
#endif
#elif LJ_TARGET_ARM
#if LJ_HASJIT
int ver = LJ_ARCH_VERSION; /* Compile-time ARM CPU detection. */
#if LJ_TARGET_LINUX
if (ver < 70) { /* Runtime ARM CPU detection. */
struct utsname ut;
uname(&ut);
if (strncmp(ut.machine, "armv", 4) == 0) {
if (ut.machine[4] >= '7')
ver = 70;
else if (ut.machine[4] == '6')
ver = 60;
}
}
#endif
flags |= ver >= 70 ? JIT_F_ARMV7 :
ver >= 61 ? JIT_F_ARMV6T2_ :
ver >= 60 ? JIT_F_ARMV6_ : 0;
flags |= LJ_ARCH_HASFPU == 0 ? 0 : ver >= 70 ? JIT_F_VFPV3 : JIT_F_VFPV2;
#endif
#elif LJ_TARGET_PPC
#if LJ_HASJIT
#if LJ_ARCH_SQRT
flags |= JIT_F_SQRT;
#endif
#if LJ_ARCH_ROUND
flags |= JIT_F_ROUND;
#endif
#endif
#elif LJ_TARGET_PPCSPE
/* Nothing to do. */
#elif LJ_TARGET_MIPS
#if LJ_HASJIT
/* Compile-time MIPS CPU detection. */
#if LJ_ARCH_VERSION >= 20
flags |= JIT_F_MIPS32R2;
#endif
/* Runtime MIPS CPU detection. */
#if defined(__GNUC__)
if (!(flags & JIT_F_MIPS32R2)) {
int x;
/* On MIPS32R1 rotr is treated as srl. rotr r2,r2,1 -> srl r2,r2,1. */
__asm__("li $2, 1\n\t.long 0x00221042\n\tmove %0, $2" : "=r"(x) : : "$2");
if (x) flags |= JIT_F_MIPS32R2; /* Either 0x80000000 (R2) or 0 (R1). */
}
#endif
#endif
#else
#error "Missing CPU detection for this architecture"
#endif
UNUSED(L);
return flags;
}
/* Initialize JIT compiler. */
static void jit_init(lua_State *L)
{
uint32_t flags = jit_cpudetect(L);
#if LJ_HASJIT
jit_State *J = L2J(L);
#if LJ_TARGET_X86
/* Silently turn off the JIT compiler on CPUs without SSE2. */
if ((flags & JIT_F_SSE2))
#endif
J->flags = flags | JIT_F_ON | JIT_F_OPT_DEFAULT;
memcpy(J->param, jit_param_default, sizeof(J->param));
lj_dispatch_update(G(L));
#else
UNUSED(flags);
#endif
}
LUALIB_API int luaopen_jit(lua_State *L)
{
lua_pushliteral(L, LJ_OS_NAME);
lua_pushliteral(L, LJ_ARCH_NAME);
lua_pushinteger(L, LUAJIT_VERSION_NUM);
lua_pushliteral(L, LUAJIT_VERSION);
LJ_LIB_REG(L, LUA_JITLIBNAME, jit);
#ifndef LUAJIT_DISABLE_JITUTIL
LJ_LIB_REG(L, "jit.util", jit_util);
#endif
#if LJ_HASJIT
LJ_LIB_REG(L, "jit.opt", jit_opt);
#endif
L->top -= 2;
jit_init(L);
return 1;
}

View File

@ -1,233 +0,0 @@
/*
** Math library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include <math.h>
#define lib_math_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_lib.h"
#include "lj_vm.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_math
LJLIB_ASM(math_abs) LJLIB_REC(.)
{
lj_lib_checknumber(L, 1);
return FFH_RETRY;
}
LJLIB_ASM_(math_floor) LJLIB_REC(math_round IRFPM_FLOOR)
LJLIB_ASM_(math_ceil) LJLIB_REC(math_round IRFPM_CEIL)
LJLIB_ASM(math_sqrt) LJLIB_REC(math_unary IRFPM_SQRT)
{
lj_lib_checknum(L, 1);
return FFH_RETRY;
}
LJLIB_ASM_(math_log10) LJLIB_REC(math_unary IRFPM_LOG10)
LJLIB_ASM_(math_exp) LJLIB_REC(math_unary IRFPM_EXP)
LJLIB_ASM_(math_sin) LJLIB_REC(math_unary IRFPM_SIN)
LJLIB_ASM_(math_cos) LJLIB_REC(math_unary IRFPM_COS)
LJLIB_ASM_(math_tan) LJLIB_REC(math_unary IRFPM_TAN)
LJLIB_ASM_(math_asin) LJLIB_REC(math_atrig FF_math_asin)
LJLIB_ASM_(math_acos) LJLIB_REC(math_atrig FF_math_acos)
LJLIB_ASM_(math_atan) LJLIB_REC(math_atrig FF_math_atan)
LJLIB_ASM_(math_sinh) LJLIB_REC(math_htrig IRCALL_sinh)
LJLIB_ASM_(math_cosh) LJLIB_REC(math_htrig IRCALL_cosh)
LJLIB_ASM_(math_tanh) LJLIB_REC(math_htrig IRCALL_tanh)
LJLIB_ASM_(math_frexp)
LJLIB_ASM_(math_modf) LJLIB_REC(.)
LJLIB_PUSH(57.29577951308232)
LJLIB_ASM_(math_deg) LJLIB_REC(math_degrad)
LJLIB_PUSH(0.017453292519943295)
LJLIB_ASM_(math_rad) LJLIB_REC(math_degrad)
LJLIB_ASM(math_log) LJLIB_REC(math_log)
{
double x = lj_lib_checknum(L, 1);
if (L->base+1 < L->top) {
double y = lj_lib_checknum(L, 2);
#ifdef LUAJIT_NO_LOG2
x = log(x); y = 1.0 / log(y);
#else
x = lj_vm_log2(x); y = 1.0 / lj_vm_log2(y);
#endif
setnumV(L->base-1, x*y); /* Do NOT join the expression to x / y. */
return FFH_RES(1);
}
return FFH_RETRY;
}
LJLIB_ASM(math_atan2) LJLIB_REC(.)
{
lj_lib_checknum(L, 1);
lj_lib_checknum(L, 2);
return FFH_RETRY;
}
LJLIB_ASM_(math_pow) LJLIB_REC(.)
LJLIB_ASM_(math_fmod)
LJLIB_ASM(math_ldexp) LJLIB_REC(.)
{
lj_lib_checknum(L, 1);
#if LJ_DUALNUM && !LJ_TARGET_X86ORX64
lj_lib_checkint(L, 2);
#else
lj_lib_checknum(L, 2);
#endif
return FFH_RETRY;
}
LJLIB_ASM(math_min) LJLIB_REC(math_minmax IR_MIN)
{
int i = 0;
do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top);
return FFH_RETRY;
}
LJLIB_ASM_(math_max) LJLIB_REC(math_minmax IR_MAX)
LJLIB_PUSH(3.14159265358979323846) LJLIB_SET(pi)
LJLIB_PUSH(1e310) LJLIB_SET(huge)
/* ------------------------------------------------------------------------ */
/* This implements a Tausworthe PRNG with period 2^223. Based on:
** Tables of maximally-equidistributed combined LFSR generators,
** Pierre L'Ecuyer, 1991, table 3, 1st entry.
** Full-period ME-CF generator with L=64, J=4, k=223, N1=49.
*/
/* PRNG state. */
struct RandomState {
uint64_t gen[4]; /* State of the 4 LFSR generators. */
int valid; /* State is valid. */
};
/* Union needed for bit-pattern conversion between uint64_t and double. */
typedef union { uint64_t u64; double d; } U64double;
/* Update generator i and compute a running xor of all states. */
#define TW223_GEN(i, k, q, s) \
z = rs->gen[i]; \
z = (((z<<q)^z) >> (k-s)) ^ ((z&((uint64_t)(int64_t)-1 << (64-k)))<<s); \
r ^= z; rs->gen[i] = z;
/* PRNG step function. Returns a double in the range 1.0 <= d < 2.0. */
LJ_NOINLINE uint64_t LJ_FASTCALL lj_math_random_step(RandomState *rs)
{
uint64_t z, r = 0;
TW223_GEN(0, 63, 31, 18)
TW223_GEN(1, 58, 19, 28)
TW223_GEN(2, 55, 24, 7)
TW223_GEN(3, 47, 21, 8)
return (r & U64x(000fffff,ffffffff)) | U64x(3ff00000,00000000);
}
/* PRNG initialization function. */
static void random_init(RandomState *rs, double d)
{
uint32_t r = 0x11090601; /* 64-k[i] as four 8 bit constants. */
int i;
for (i = 0; i < 4; i++) {
U64double u;
uint32_t m = 1u << (r&255);
r >>= 8;
u.d = d = d * 3.14159265358979323846 + 2.7182818284590452354;
if (u.u64 < m) u.u64 += m; /* Ensure k[i] MSB of gen[i] are non-zero. */
rs->gen[i] = u.u64;
}
rs->valid = 1;
for (i = 0; i < 10; i++)
lj_math_random_step(rs);
}
/* PRNG extract function. */
LJLIB_PUSH(top-2) /* Upvalue holds userdata with RandomState. */
LJLIB_CF(math_random) LJLIB_REC(.)
{
int n = (int)(L->top - L->base);
RandomState *rs = (RandomState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
U64double u;
double d;
if (LJ_UNLIKELY(!rs->valid)) random_init(rs, 0.0);
u.u64 = lj_math_random_step(rs);
d = u.d - 1.0;
if (n > 0) {
#if LJ_DUALNUM
int isint = 1;
double r1;
lj_lib_checknumber(L, 1);
if (tvisint(L->base)) {
r1 = (lua_Number)intV(L->base);
} else {
isint = 0;
r1 = numV(L->base);
}
#else
double r1 = lj_lib_checknum(L, 1);
#endif
if (n == 1) {
d = lj_vm_floor(d*r1) + 1.0; /* d is an int in range [1, r1] */
} else {
#if LJ_DUALNUM
double r2;
lj_lib_checknumber(L, 2);
if (tvisint(L->base+1)) {
r2 = (lua_Number)intV(L->base+1);
} else {
isint = 0;
r2 = numV(L->base+1);
}
#else
double r2 = lj_lib_checknum(L, 2);
#endif
d = lj_vm_floor(d*(r2-r1+1.0)) + r1; /* d is an int in range [r1, r2] */
}
#if LJ_DUALNUM
if (isint) {
setintV(L->top-1, lj_num2int(d));
return 1;
}
#endif
} /* else: d is a double in range [0, 1] */
setnumV(L->top++, d);
return 1;
}
/* PRNG seed function. */
LJLIB_PUSH(top-2) /* Upvalue holds userdata with RandomState. */
LJLIB_CF(math_randomseed)
{
RandomState *rs = (RandomState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
random_init(rs, lj_lib_checknum(L, 1));
return 0;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_math(lua_State *L)
{
RandomState *rs;
rs = (RandomState *)lua_newuserdata(L, sizeof(RandomState));
rs->valid = 0; /* Use lazy initialization to save some time on startup. */
LJ_LIB_REG(L, LUA_MATHLIBNAME, math);
#if defined(LUA_COMPAT_MOD) && !LJ_52
lua_getfield(L, -1, "fmod");
lua_setfield(L, -2, "mod");
#endif
return 1;
}

View File

@ -1,304 +0,0 @@
/*
** OS library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#include <errno.h>
#include <time.h>
#define lib_os_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_lib.h"
#if LJ_TARGET_POSIX
#include <unistd.h>
#else
#include <stdio.h>
#endif
#if !LJ_TARGET_PSVITA
#include <locale.h>
#endif
/* ------------------------------------------------------------------------ */
#if LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
static wchar_t *widen_static(const char *narrow, int idx)
{
__declspec(thread) static wchar_t buffer[2][MAX_PATH];
return MultiByteToWideChar(CP_UTF8, 0, narrow, -1, buffer[idx], MAX_PATH) ? buffer[idx] : L"";
}
#define remove(x) _wremove(widen_static(x, 0))
#define system(x) _wsystem(widen_static(x, 0))
#define rename(x, y) _wrename(widen_static(x, 0), widen_static(y, 1))
#endif
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_os
LJLIB_CF(os_execute)
{
#if LJ_NO_SYSTEM
#if LJ_52
errno = ENOSYS;
return luaL_fileresult(L, 0, NULL);
#else
lua_pushinteger(L, -1);
return 1;
#endif
#else
const char *cmd = luaL_optstring(L, 1, NULL);
int stat = system(cmd);
#if LJ_52
if (cmd)
return luaL_execresult(L, stat);
setboolV(L->top++, 1);
#else
setintV(L->top++, stat);
#endif
return 1;
#endif
}
LJLIB_CF(os_remove)
{
const char *filename = luaL_checkstring(L, 1);
return luaL_fileresult(L, remove(filename) == 0, filename);
}
LJLIB_CF(os_rename)
{
const char *fromname = luaL_checkstring(L, 1);
const char *toname = luaL_checkstring(L, 2);
return luaL_fileresult(L, rename(fromname, toname) == 0, fromname);
}
LJLIB_CF(os_tmpname)
{
#if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PSVITA
lj_err_caller(L, LJ_ERR_OSUNIQF);
return 0;
#else
#if LJ_TARGET_POSIX
char buf[15+1];
int fp;
strcpy(buf, "/tmp/lua_XXXXXX");
fp = mkstemp(buf);
if (fp != -1)
close(fp);
else
lj_err_caller(L, LJ_ERR_OSUNIQF);
#else
char buf[L_tmpnam];
if (tmpnam(buf) == NULL)
lj_err_caller(L, LJ_ERR_OSUNIQF);
#endif
lua_pushstring(L, buf);
return 1;
#endif
}
LJLIB_CF(os_getenv)
{
#if LJ_TARGET_CONSOLE
lua_pushnil(L);
#else
lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */
#endif
return 1;
}
LJLIB_CF(os_exit)
{
int status;
if (L->base < L->top && tvisbool(L->base))
status = boolV(L->base) ? EXIT_SUCCESS : EXIT_FAILURE;
else
status = lj_lib_optint(L, 1, EXIT_SUCCESS);
if (L->base+1 < L->top && tvistruecond(L->base+1))
lua_close(L);
exit(status);
return 0; /* Unreachable. */
}
LJLIB_CF(os_clock)
{
setnumV(L->top++, ((lua_Number)clock())*(1.0/(lua_Number)CLOCKS_PER_SEC));
return 1;
}
/* ------------------------------------------------------------------------ */
static void setfield(lua_State *L, const char *key, int value)
{
lua_pushinteger(L, value);
lua_setfield(L, -2, key);
}
static void setboolfield(lua_State *L, const char *key, int value)
{
if (value < 0) /* undefined? */
return; /* does not set field */
lua_pushboolean(L, value);
lua_setfield(L, -2, key);
}
static int getboolfield(lua_State *L, const char *key)
{
int res;
lua_getfield(L, -1, key);
res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
lua_pop(L, 1);
return res;
}
static int getfield(lua_State *L, const char *key, int d)
{
int res;
lua_getfield(L, -1, key);
if (lua_isnumber(L, -1)) {
res = (int)lua_tointeger(L, -1);
} else {
if (d < 0)
lj_err_callerv(L, LJ_ERR_OSDATEF, key);
res = d;
}
lua_pop(L, 1);
return res;
}
LJLIB_CF(os_date)
{
const char *s = luaL_optstring(L, 1, "%c");
time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL));
struct tm *stm;
#if LJ_TARGET_POSIX
struct tm rtm;
#endif
if (*s == '!') { /* UTC? */
s++; /* Skip '!' */
#if LJ_TARGET_POSIX
stm = gmtime_r(&t, &rtm);
#else
stm = gmtime(&t);
#endif
} else {
#if LJ_TARGET_POSIX
stm = localtime_r(&t, &rtm);
#else
stm = localtime(&t);
#endif
}
if (stm == NULL) { /* Invalid date? */
setnilV(L->top-1);
} else if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */
setfield(L, "sec", stm->tm_sec);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon+1);
setfield(L, "year", stm->tm_year+1900);
setfield(L, "wday", stm->tm_wday+1);
setfield(L, "yday", stm->tm_yday+1);
setboolfield(L, "isdst", stm->tm_isdst);
} else {
char cc[3];
luaL_Buffer b;
cc[0] = '%'; cc[2] = '\0';
luaL_buffinit(L, &b);
for (; *s; s++) {
if (*s != '%' || *(s + 1) == '\0') { /* No conversion specifier? */
luaL_addchar(&b, *s);
} else {
size_t reslen;
char buff[200]; /* Should be big enough for any conversion result. */
cc[1] = *(++s);
reslen = strftime(buff, sizeof(buff), cc, stm);
luaL_addlstring(&b, buff, reslen);
}
}
luaL_pushresult(&b);
}
return 1;
}
LJLIB_CF(os_time)
{
time_t t;
if (lua_isnoneornil(L, 1)) { /* called without args? */
t = time(NULL); /* get current time */
} else {
struct tm ts;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); /* make sure table is at the top */
ts.tm_sec = getfield(L, "sec", 0);
ts.tm_min = getfield(L, "min", 0);
ts.tm_hour = getfield(L, "hour", 12);
ts.tm_mday = getfield(L, "day", -1);
ts.tm_mon = getfield(L, "month", -1) - 1;
ts.tm_year = getfield(L, "year", -1) - 1900;
ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts);
}
if (t == (time_t)(-1))
lua_pushnil(L);
else
lua_pushnumber(L, (lua_Number)t);
return 1;
}
LJLIB_CF(os_difftime)
{
lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
(time_t)(luaL_optnumber(L, 2, (lua_Number)0))));
return 1;
}
/* ------------------------------------------------------------------------ */
LJLIB_CF(os_setlocale)
{
#if LJ_TARGET_PSVITA
lua_pushliteral(L, "C");
#else
GCstr *s = lj_lib_optstr(L, 1);
const char *str = s ? strdata(s) : NULL;
int opt = lj_lib_checkopt(L, 2, 6,
"\5ctype\7numeric\4time\7collate\10monetary\1\377\3all");
if (opt == 0) opt = LC_CTYPE;
else if (opt == 1) opt = LC_NUMERIC;
else if (opt == 2) opt = LC_TIME;
else if (opt == 3) opt = LC_COLLATE;
else if (opt == 4) opt = LC_MONETARY;
else if (opt == 6) opt = LC_ALL;
lua_pushstring(L, setlocale(opt, str));
#endif
return 1;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_os(lua_State *L)
{
LJ_LIB_REG(L, LUA_OSLIBNAME, os);
return 1;
}

View File

@ -1,602 +0,0 @@
/*
** Package library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2012 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lib_package_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
/* Error codes for ll_loadfunc. */
#define PACKAGE_ERR_LIB 1
#define PACKAGE_ERR_FUNC 2
#define PACKAGE_ERR_LOAD 3
/* Redefined in platform specific part. */
#define PACKAGE_LIB_FAIL "open"
#define setprogdir(L) ((void)0)
/* Symbol name prefixes. */
#define SYMPREFIX_CF "luaopen_%s"
#define SYMPREFIX_BC "luaJIT_BC_%s"
#if LJ_TARGET_DLOPEN
#include <dlfcn.h>
static void ll_unloadlib(void *lib)
{
dlclose(lib);
}
static void *ll_load(lua_State *L, const char *path, int gl)
{
void *lib = dlopen(path, RTLD_NOW | (gl ? RTLD_GLOBAL : RTLD_LOCAL));
if (lib == NULL) lua_pushstring(L, dlerror());
return lib;
}
static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym)
{
lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
if (f == NULL) lua_pushstring(L, dlerror());
return f;
}
static const char *ll_bcsym(void *lib, const char *sym)
{
#if defined(RTLD_DEFAULT)
if (lib == NULL) lib = RTLD_DEFAULT;
#elif LJ_TARGET_OSX || LJ_TARGET_BSD
if (lib == NULL) lib = (void *)(intptr_t)-2;
#endif
return (const char *)dlsym(lib, sym);
}
#elif LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
#endif
#undef setprogdir
static void setprogdir(lua_State *L)
{
char buff[MAX_PATH + 1];
char *lb;
DWORD nsize = sizeof(buff);
DWORD n = GetModuleFileNameA(NULL, buff, nsize);
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) {
luaL_error(L, "unable to get ModuleFileName");
} else {
*lb = '\0';
luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff);
lua_remove(L, -2); /* remove original string */
}
}
static void pusherror(lua_State *L)
{
DWORD error = GetLastError();
char buffer[128];
if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, 0, buffer, sizeof(buffer), NULL))
lua_pushstring(L, buffer);
else
lua_pushfstring(L, "system error %d\n", error);
}
static void ll_unloadlib(void *lib)
{
FreeLibrary((HINSTANCE)lib);
}
static void *ll_load(lua_State *L, const char *path, int gl)
{
HINSTANCE lib = LoadLibraryA(path);
if (lib == NULL) pusherror(L);
UNUSED(gl);
return lib;
}
static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym)
{
lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym);
if (f == NULL) pusherror(L);
return f;
}
static const char *ll_bcsym(void *lib, const char *sym)
{
if (lib) {
return (const char *)GetProcAddress((HINSTANCE)lib, sym);
} else {
HINSTANCE h = GetModuleHandleA(NULL);
const char *p = (const char *)GetProcAddress(h, sym);
if (p == NULL && GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(const char *)ll_bcsym, &h))
p = (const char *)GetProcAddress(h, sym);
return p;
}
}
#else
#undef PACKAGE_LIB_FAIL
#define PACKAGE_LIB_FAIL "absent"
#define DLMSG "dynamic libraries not enabled; no support for target OS"
static void ll_unloadlib(void *lib)
{
UNUSED(lib);
}
static void *ll_load(lua_State *L, const char *path, int gl)
{
UNUSED(path); UNUSED(gl);
lua_pushliteral(L, DLMSG);
return NULL;
}
static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym)
{
UNUSED(lib); UNUSED(sym);
lua_pushliteral(L, DLMSG);
return NULL;
}
static const char *ll_bcsym(void *lib, const char *sym)
{
UNUSED(lib); UNUSED(sym);
return NULL;
}
#endif
/* ------------------------------------------------------------------------ */
static void **ll_register(lua_State *L, const char *path)
{
void **plib;
lua_pushfstring(L, "LOADLIB: %s", path);
lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */
if (!lua_isnil(L, -1)) { /* is there an entry? */
plib = (void **)lua_touserdata(L, -1);
} else { /* no entry yet; create one */
lua_pop(L, 1);
plib = (void **)lua_newuserdata(L, sizeof(void *));
*plib = NULL;
luaL_getmetatable(L, "_LOADLIB");
lua_setmetatable(L, -2);
lua_pushfstring(L, "LOADLIB: %s", path);
lua_pushvalue(L, -2);
lua_settable(L, LUA_REGISTRYINDEX);
}
return plib;
}
static const char *mksymname(lua_State *L, const char *modname,
const char *prefix)
{
const char *funcname;
const char *mark = strchr(modname, *LUA_IGMARK);
if (mark) modname = mark + 1;
funcname = luaL_gsub(L, modname, ".", "_");
funcname = lua_pushfstring(L, prefix, funcname);
lua_remove(L, -2); /* remove 'gsub' result */
return funcname;
}
static int ll_loadfunc(lua_State *L, const char *path, const char *name, int r)
{
void **reg = ll_register(L, path);
if (*reg == NULL) *reg = ll_load(L, path, (*name == '*'));
if (*reg == NULL) {
return PACKAGE_ERR_LIB; /* Unable to load library. */
} else if (*name == '*') { /* Only load library into global namespace. */
lua_pushboolean(L, 1);
return 0;
} else {
const char *sym = r ? name : mksymname(L, name, SYMPREFIX_CF);
lua_CFunction f = ll_sym(L, *reg, sym);
if (f) {
lua_pushcfunction(L, f);
return 0;
}
if (!r) {
const char *bcdata = ll_bcsym(*reg, mksymname(L, name, SYMPREFIX_BC));
lua_pop(L, 1);
if (bcdata) {
if (luaL_loadbuffer(L, bcdata, ~(size_t)0, name) != 0)
return PACKAGE_ERR_LOAD;
return 0;
}
}
return PACKAGE_ERR_FUNC; /* Unable to find function. */
}
}
static int lj_cf_package_loadlib(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
const char *init = luaL_checkstring(L, 2);
int st = ll_loadfunc(L, path, init, 1);
if (st == 0) { /* no errors? */
return 1; /* return the loaded function */
} else { /* error; error message is on stack top */
lua_pushnil(L);
lua_insert(L, -2);
lua_pushstring(L, (st == PACKAGE_ERR_LIB) ? PACKAGE_LIB_FAIL : "init");
return 3; /* return nil, error message, and where */
}
}
static int lj_cf_package_unloadlib(lua_State *L)
{
void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
if (*lib) ll_unloadlib(*lib);
*lib = NULL; /* mark library as closed */
return 0;
}
/* ------------------------------------------------------------------------ */
static int readable(const char *filename)
{
FILE *f = fopen(filename, "r"); /* try to open file */
if (f == NULL) return 0; /* open failed */
fclose(f);
return 1;
}
static const char *pushnexttemplate(lua_State *L, const char *path)
{
const char *l;
while (*path == *LUA_PATHSEP) path++; /* skip separators */
if (*path == '\0') return NULL; /* no more templates */
l = strchr(path, *LUA_PATHSEP); /* find next separator */
if (l == NULL) l = path + strlen(path);
lua_pushlstring(L, path, (size_t)(l - path)); /* template */
return l;
}
static const char *searchpath (lua_State *L, const char *name,
const char *path, const char *sep,
const char *dirsep)
{
luaL_Buffer msg; /* to build error message */
luaL_buffinit(L, &msg);
if (*sep != '\0') /* non-empty separator? */
name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */
while ((path = pushnexttemplate(L, path)) != NULL) {
const char *filename = luaL_gsub(L, lua_tostring(L, -1),
LUA_PATH_MARK, name);
lua_remove(L, -2); /* remove path template */
if (readable(filename)) /* does file exist and is readable? */
return filename; /* return that file name */
lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
lua_remove(L, -2); /* remove file name */
luaL_addvalue(&msg); /* concatenate error msg. entry */
}
luaL_pushresult(&msg); /* create error message */
return NULL; /* not found */
}
static int lj_cf_package_searchpath(lua_State *L)
{
const char *f = searchpath(L, luaL_checkstring(L, 1),
luaL_checkstring(L, 2),
luaL_optstring(L, 3, "."),
luaL_optstring(L, 4, LUA_DIRSEP));
if (f != NULL) {
return 1;
} else { /* error message is on top of the stack */
lua_pushnil(L);
lua_insert(L, -2);
return 2; /* return nil + error message */
}
}
static const char *findfile(lua_State *L, const char *name,
const char *pname)
{
const char *path;
lua_getfield(L, LUA_ENVIRONINDEX, pname);
path = lua_tostring(L, -1);
if (path == NULL)
luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
return searchpath(L, name, path, ".", LUA_DIRSEP);
}
static void loaderror(lua_State *L, const char *filename)
{
luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s",
lua_tostring(L, 1), filename, lua_tostring(L, -1));
}
static int lj_cf_package_loader_lua(lua_State *L)
{
const char *filename;
const char *name = luaL_checkstring(L, 1);
filename = findfile(L, name, "path");
if (filename == NULL) return 1; /* library not found in this path */
if (luaL_loadfile(L, filename) != 0)
loaderror(L, filename);
return 1; /* library loaded successfully */
}
static int lj_cf_package_loader_c(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
const char *filename = findfile(L, name, "cpath");
if (filename == NULL) return 1; /* library not found in this path */
if (ll_loadfunc(L, filename, name, 0) != 0)
loaderror(L, filename);
return 1; /* library loaded successfully */
}
static int lj_cf_package_loader_croot(lua_State *L)
{
const char *filename;
const char *name = luaL_checkstring(L, 1);
const char *p = strchr(name, '.');
int st;
if (p == NULL) return 0; /* is root */
lua_pushlstring(L, name, (size_t)(p - name));
filename = findfile(L, lua_tostring(L, -1), "cpath");
if (filename == NULL) return 1; /* root not found */
if ((st = ll_loadfunc(L, filename, name, 0)) != 0) {
if (st != PACKAGE_ERR_FUNC) loaderror(L, filename); /* real error */
lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
name, filename);
return 1; /* function not found */
}
return 1;
}
static int lj_cf_package_loader_preload(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
lua_getfield(L, LUA_ENVIRONINDEX, "preload");
if (!lua_istable(L, -1))
luaL_error(L, LUA_QL("package.preload") " must be a table");
lua_getfield(L, -1, name);
if (lua_isnil(L, -1)) { /* Not found? */
const char *bcname = mksymname(L, name, SYMPREFIX_BC);
const char *bcdata = ll_bcsym(NULL, bcname);
if (bcdata == NULL || luaL_loadbuffer(L, bcdata, ~(size_t)0, name) != 0)
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
}
return 1;
}
/* ------------------------------------------------------------------------ */
static const int sentinel_ = 0;
#define sentinel ((void *)&sentinel_)
static int lj_cf_package_require(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
int i;
lua_settop(L, 1); /* _LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, 2, name);
if (lua_toboolean(L, -1)) { /* is it there? */
if (lua_touserdata(L, -1) == sentinel) /* check loops */
luaL_error(L, "loop or previous error loading module " LUA_QS, name);
return 1; /* package is already loaded */
}
/* else must load it; iterate over available loaders */
lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
if (!lua_istable(L, -1))
luaL_error(L, LUA_QL("package.loaders") " must be a table");
lua_pushliteral(L, ""); /* error message accumulator */
for (i = 1; ; i++) {
lua_rawgeti(L, -2, i); /* get a loader */
if (lua_isnil(L, -1))
luaL_error(L, "module " LUA_QS " not found:%s",
name, lua_tostring(L, -2));
lua_pushstring(L, name);
lua_call(L, 1, 1); /* call it */
if (lua_isfunction(L, -1)) /* did it find module? */
break; /* module loaded successfully */
else if (lua_isstring(L, -1)) /* loader returned error message? */
lua_concat(L, 2); /* accumulate it */
else
lua_pop(L, 1);
}
lua_pushlightuserdata(L, sentinel);
lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */
lua_pushstring(L, name); /* pass name as argument to module */
lua_call(L, 1, 1); /* run loaded module */
if (!lua_isnil(L, -1)) /* non-nil return? */
lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
lua_getfield(L, 2, name);
if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */
lua_pushboolean(L, 1); /* use true as result */
lua_pushvalue(L, -1); /* extra copy to be returned */
lua_setfield(L, 2, name); /* _LOADED[name] = true */
}
lj_lib_checkfpu(L);
return 1;
}
/* ------------------------------------------------------------------------ */
static void setfenv(lua_State *L)
{
lua_Debug ar;
if (lua_getstack(L, 1, &ar) == 0 ||
lua_getinfo(L, "f", &ar) == 0 || /* get calling function */
lua_iscfunction(L, -1))
luaL_error(L, LUA_QL("module") " not called from a Lua function");
lua_pushvalue(L, -2);
lua_setfenv(L, -2);
lua_pop(L, 1);
}
static void dooptions(lua_State *L, int n)
{
int i;
for (i = 2; i <= n; i++) {
lua_pushvalue(L, i); /* get option (a function) */
lua_pushvalue(L, -2); /* module */
lua_call(L, 1, 0);
}
}
static void modinit(lua_State *L, const char *modname)
{
const char *dot;
lua_pushvalue(L, -1);
lua_setfield(L, -2, "_M"); /* module._M = module */
lua_pushstring(L, modname);
lua_setfield(L, -2, "_NAME");
dot = strrchr(modname, '.'); /* look for last dot in module name */
if (dot == NULL) dot = modname; else dot++;
/* set _PACKAGE as package name (full module name minus last part) */
lua_pushlstring(L, modname, (size_t)(dot - modname));
lua_setfield(L, -2, "_PACKAGE");
}
static int lj_cf_package_module(lua_State *L)
{
const char *modname = luaL_checkstring(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] */
if (!lua_istable(L, -1)) { /* not found? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL)
lj_err_callerv(L, LJ_ERR_BADMODN, modname);
lua_pushvalue(L, -1);
lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */
}
/* check whether table already has a _NAME field */
lua_getfield(L, -1, "_NAME");
if (!lua_isnil(L, -1)) { /* is table an initialized module? */
lua_pop(L, 1);
} else { /* no; initialize it */
lua_pop(L, 1);
modinit(L, modname);
}
lua_pushvalue(L, -1);
setfenv(L);
dooptions(L, loaded - 1);
return 0;
}
static int lj_cf_package_seeall(lua_State *L)
{
luaL_checktype(L, 1, LUA_TTABLE);
if (!lua_getmetatable(L, 1)) {
lua_createtable(L, 0, 1); /* create new metatable */
lua_pushvalue(L, -1);
lua_setmetatable(L, 1);
}
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setfield(L, -2, "__index"); /* mt.__index = _G */
return 0;
}
/* ------------------------------------------------------------------------ */
#define AUXMARK "\1"
static void setpath(lua_State *L, const char *fieldname, const char *envname,
const char *def, int noenv)
{
#if LJ_TARGET_CONSOLE
const char *path = NULL;
UNUSED(envname);
#else
const char *path = getenv(envname);
#endif
if (path == NULL || noenv) {
lua_pushstring(L, def);
} else {
path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP,
LUA_PATHSEP AUXMARK LUA_PATHSEP);
luaL_gsub(L, path, AUXMARK, def);
lua_remove(L, -2);
}
setprogdir(L);
lua_setfield(L, -2, fieldname);
}
static const luaL_Reg package_lib[] = {
{ "loadlib", lj_cf_package_loadlib },
{ "searchpath", lj_cf_package_searchpath },
{ "seeall", lj_cf_package_seeall },
{ NULL, NULL }
};
static const luaL_Reg package_global[] = {
{ "module", lj_cf_package_module },
{ "require", lj_cf_package_require },
{ NULL, NULL }
};
static const lua_CFunction package_loaders[] =
{
lj_cf_package_loader_preload,
lj_cf_package_loader_lua,
lj_cf_package_loader_c,
lj_cf_package_loader_croot,
NULL
};
LUALIB_API int luaopen_package(lua_State *L)
{
int i;
int noenv;
luaL_newmetatable(L, "_LOADLIB");
lj_lib_pushcf(L, lj_cf_package_unloadlib, 1);
lua_setfield(L, -2, "__gc");
luaL_register(L, LUA_LOADLIBNAME, package_lib);
lua_pushvalue(L, -1);
lua_replace(L, LUA_ENVIRONINDEX);
lua_createtable(L, sizeof(package_loaders)/sizeof(package_loaders[0])-1, 0);
for (i = 0; package_loaders[i] != NULL; i++) {
lj_lib_pushcf(L, package_loaders[i], 1);
lua_rawseti(L, -2, i+1);
}
lua_setfield(L, -2, "loaders");
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
noenv = lua_toboolean(L, -1);
lua_pop(L, 1);
setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT, noenv);
setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT, noenv);
lua_pushliteral(L, LUA_PATH_CONFIG);
lua_setfield(L, -2, "config");
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
lua_setfield(L, -2, "loaded");
luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD", 4);
lua_setfield(L, -2, "preload");
lua_pushvalue(L, LUA_GLOBALSINDEX);
luaL_register(L, NULL, package_global);
lua_pop(L, 1);
return 1;
}

View File

@ -1,940 +0,0 @@
/*
** String library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#include <stdio.h>
#define lib_string_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_meta.h"
#include "lj_state.h"
#include "lj_ff.h"
#include "lj_bcdump.h"
#include "lj_char.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_string
LJLIB_ASM(string_len) LJLIB_REC(.)
{
lj_lib_checkstr(L, 1);
return FFH_RETRY;
}
LJLIB_ASM(string_byte) LJLIB_REC(string_range 0)
{
GCstr *s = lj_lib_checkstr(L, 1);
int32_t len = (int32_t)s->len;
int32_t start = lj_lib_optint(L, 2, 1);
int32_t stop = lj_lib_optint(L, 3, start);
int32_t n, i;
const unsigned char *p;
if (stop < 0) stop += len+1;
if (start < 0) start += len+1;
if (start <= 0) start = 1;
if (stop > len) stop = len;
if (start > stop) return FFH_RES(0); /* Empty interval: return no results. */
start--;
n = stop - start;
if ((uint32_t)n > LUAI_MAXCSTACK)
lj_err_caller(L, LJ_ERR_STRSLC);
lj_state_checkstack(L, (MSize)n);
p = (const unsigned char *)strdata(s) + start;
for (i = 0; i < n; i++)
setintV(L->base + i-1, p[i]);
return FFH_RES(n);
}
LJLIB_ASM(string_char)
{
int i, nargs = (int)(L->top - L->base);
char *buf = lj_str_needbuf(L, &G(L)->tmpbuf, (MSize)nargs);
for (i = 1; i <= nargs; i++) {
int32_t k = lj_lib_checkint(L, i);
if (!checku8(k))
lj_err_arg(L, i, LJ_ERR_BADVAL);
buf[i-1] = (char)k;
}
setstrV(L, L->base-1, lj_str_new(L, buf, (size_t)nargs));
return FFH_RES(1);
}
LJLIB_ASM(string_sub) LJLIB_REC(string_range 1)
{
lj_lib_checkstr(L, 1);
lj_lib_checkint(L, 2);
setintV(L->base+2, lj_lib_optint(L, 3, -1));
return FFH_RETRY;
}
LJLIB_ASM(string_rep)
{
GCstr *s = lj_lib_checkstr(L, 1);
int32_t k = lj_lib_checkint(L, 2);
GCstr *sep = lj_lib_optstr(L, 3);
int32_t len = (int32_t)s->len;
global_State *g = G(L);
int64_t tlen;
const char *src;
char *buf;
if (k <= 0) {
empty:
setstrV(L, L->base-1, &g->strempty);
return FFH_RES(1);
}
if (sep) {
tlen = (int64_t)len + sep->len;
if (tlen > LJ_MAX_STR)
lj_err_caller(L, LJ_ERR_STROV);
tlen *= k;
if (tlen > LJ_MAX_STR)
lj_err_caller(L, LJ_ERR_STROV);
} else {
tlen = (int64_t)k * len;
if (tlen > LJ_MAX_STR)
lj_err_caller(L, LJ_ERR_STROV);
}
if (tlen == 0) goto empty;
buf = lj_str_needbuf(L, &g->tmpbuf, (MSize)tlen);
src = strdata(s);
if (sep) {
tlen -= sep->len; /* Ignore trailing separator. */
if (k > 1) { /* Paste one string and one separator. */
int32_t i;
i = 0; while (i < len) *buf++ = src[i++];
src = strdata(sep); len = sep->len;
i = 0; while (i < len) *buf++ = src[i++];
src = g->tmpbuf.buf; len += s->len; k--; /* Now copy that k-1 times. */
}
}
do {
int32_t i = 0;
do { *buf++ = src[i++]; } while (i < len);
} while (--k > 0);
setstrV(L, L->base-1, lj_str_new(L, g->tmpbuf.buf, (size_t)tlen));
return FFH_RES(1);
}
LJLIB_ASM(string_reverse)
{
GCstr *s = lj_lib_checkstr(L, 1);
lj_str_needbuf(L, &G(L)->tmpbuf, s->len);
return FFH_RETRY;
}
LJLIB_ASM_(string_lower)
LJLIB_ASM_(string_upper)
/* ------------------------------------------------------------------------ */
static int writer_buf(lua_State *L, const void *p, size_t size, void *b)
{
luaL_addlstring((luaL_Buffer *)b, (const char *)p, size);
UNUSED(L);
return 0;
}
LJLIB_CF(string_dump)
{
GCfunc *fn = lj_lib_checkfunc(L, 1);
int strip = L->base+1 < L->top && tvistruecond(L->base+1);
luaL_Buffer b;
L->top = L->base+1;
luaL_buffinit(L, &b);
if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, &b, strip))
lj_err_caller(L, LJ_ERR_STRDUMP);
luaL_pushresult(&b);
return 1;
}
/* ------------------------------------------------------------------------ */
/* macro to `unsign' a character */
#define uchar(c) ((unsigned char)(c))
#define CAP_UNFINISHED (-1)
#define CAP_POSITION (-2)
typedef struct MatchState {
const char *src_init; /* init of source string */
const char *src_end; /* end (`\0') of source string */
lua_State *L;
int level; /* total number of captures (finished or unfinished) */
int depth;
struct {
const char *init;
ptrdiff_t len;
} capture[LUA_MAXCAPTURES];
} MatchState;
#define L_ESC '%'
#define SPECIALS "^$*+?.([%-"
static int check_capture(MatchState *ms, int l)
{
l -= '1';
if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
lj_err_caller(ms->L, LJ_ERR_STRCAPI);
return l;
}
static int capture_to_close(MatchState *ms)
{
int level = ms->level;
for (level--; level>=0; level--)
if (ms->capture[level].len == CAP_UNFINISHED) return level;
lj_err_caller(ms->L, LJ_ERR_STRPATC);
return 0; /* unreachable */
}
static const char *classend(MatchState *ms, const char *p)
{
switch (*p++) {
case L_ESC:
if (*p == '\0')
lj_err_caller(ms->L, LJ_ERR_STRPATE);
return p+1;
case '[':
if (*p == '^') p++;
do { /* look for a `]' */
if (*p == '\0')
lj_err_caller(ms->L, LJ_ERR_STRPATM);
if (*(p++) == L_ESC && *p != '\0')
p++; /* skip escapes (e.g. `%]') */
} while (*p != ']');
return p+1;
default:
return p;
}
}
static const unsigned char match_class_map[32] = {
0,LJ_CHAR_ALPHA,0,LJ_CHAR_CNTRL,LJ_CHAR_DIGIT,0,0,LJ_CHAR_GRAPH,0,0,0,0,
LJ_CHAR_LOWER,0,0,0,LJ_CHAR_PUNCT,0,0,LJ_CHAR_SPACE,0,
LJ_CHAR_UPPER,0,LJ_CHAR_ALNUM,LJ_CHAR_XDIGIT,0,0,0,0,0,0,0
};
static int match_class(int c, int cl)
{
if ((cl & 0xc0) == 0x40) {
int t = match_class_map[(cl&0x1f)];
if (t) {
t = lj_char_isa(c, t);
return (cl & 0x20) ? t : !t;
}
if (cl == 'z') return c == 0;
if (cl == 'Z') return c != 0;
}
return (cl == c);
}
static int matchbracketclass(int c, const char *p, const char *ec)
{
int sig = 1;
if (*(p+1) == '^') {
sig = 0;
p++; /* skip the `^' */
}
while (++p < ec) {
if (*p == L_ESC) {
p++;
if (match_class(c, uchar(*p)))
return sig;
}
else if ((*(p+1) == '-') && (p+2 < ec)) {
p+=2;
if (uchar(*(p-2)) <= c && c <= uchar(*p))
return sig;
}
else if (uchar(*p) == c) return sig;
}
return !sig;
}
static int singlematch(int c, const char *p, const char *ep)
{
switch (*p) {
case '.': return 1; /* matches any char */
case L_ESC: return match_class(c, uchar(*(p+1)));
case '[': return matchbracketclass(c, p, ep-1);
default: return (uchar(*p) == c);
}
}
static const char *match(MatchState *ms, const char *s, const char *p);
static const char *matchbalance(MatchState *ms, const char *s, const char *p)
{
if (*p == 0 || *(p+1) == 0)
lj_err_caller(ms->L, LJ_ERR_STRPATU);
if (*s != *p) {
return NULL;
} else {
int b = *p;
int e = *(p+1);
int cont = 1;
while (++s < ms->src_end) {
if (*s == e) {
if (--cont == 0) return s+1;
} else if (*s == b) {
cont++;
}
}
}
return NULL; /* string ends out of balance */
}
static const char *max_expand(MatchState *ms, const char *s,
const char *p, const char *ep)
{
ptrdiff_t i = 0; /* counts maximum expand for item */
while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
i++;
/* keeps trying to match with the maximum repetitions */
while (i>=0) {
const char *res = match(ms, (s+i), ep+1);
if (res) return res;
i--; /* else didn't match; reduce 1 repetition to try again */
}
return NULL;
}
static const char *min_expand(MatchState *ms, const char *s,
const char *p, const char *ep)
{
for (;;) {
const char *res = match(ms, s, ep+1);
if (res != NULL)
return res;
else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
s++; /* try with one more repetition */
else
return NULL;
}
}
static const char *start_capture(MatchState *ms, const char *s,
const char *p, int what)
{
const char *res;
int level = ms->level;
if (level >= LUA_MAXCAPTURES) lj_err_caller(ms->L, LJ_ERR_STRCAPN);
ms->capture[level].init = s;
ms->capture[level].len = what;
ms->level = level+1;
if ((res=match(ms, s, p)) == NULL) /* match failed? */
ms->level--; /* undo capture */
return res;
}
static const char *end_capture(MatchState *ms, const char *s,
const char *p)
{
int l = capture_to_close(ms);
const char *res;
ms->capture[l].len = s - ms->capture[l].init; /* close capture */
if ((res = match(ms, s, p)) == NULL) /* match failed? */
ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
return res;
}
static const char *match_capture(MatchState *ms, const char *s, int l)
{
size_t len;
l = check_capture(ms, l);
len = (size_t)ms->capture[l].len;
if ((size_t)(ms->src_end-s) >= len &&
memcmp(ms->capture[l].init, s, len) == 0)
return s+len;
else
return NULL;
}
static const char *match(MatchState *ms, const char *s, const char *p)
{
if (++ms->depth > LJ_MAX_XLEVEL)
lj_err_caller(ms->L, LJ_ERR_STRPATX);
init: /* using goto's to optimize tail recursion */
switch (*p) {
case '(': /* start capture */
if (*(p+1) == ')') /* position capture? */
s = start_capture(ms, s, p+2, CAP_POSITION);
else
s = start_capture(ms, s, p+1, CAP_UNFINISHED);
break;
case ')': /* end capture */
s = end_capture(ms, s, p+1);
break;
case L_ESC:
switch (*(p+1)) {
case 'b': /* balanced string? */
s = matchbalance(ms, s, p+2);
if (s == NULL) break;
p+=4;
goto init; /* else s = match(ms, s, p+4); */
case 'f': { /* frontier? */
const char *ep; char previous;
p += 2;
if (*p != '[')
lj_err_caller(ms->L, LJ_ERR_STRPATB);
ep = classend(ms, p); /* points to what is next */
previous = (s == ms->src_init) ? '\0' : *(s-1);
if (matchbracketclass(uchar(previous), p, ep-1) ||
!matchbracketclass(uchar(*s), p, ep-1)) { s = NULL; break; }
p=ep;
goto init; /* else s = match(ms, s, ep); */
}
default:
if (lj_char_isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */
s = match_capture(ms, s, uchar(*(p+1)));
if (s == NULL) break;
p+=2;
goto init; /* else s = match(ms, s, p+2) */
}
goto dflt; /* case default */
}
break;
case '\0': /* end of pattern */
break; /* match succeeded */
case '$':
/* is the `$' the last char in pattern? */
if (*(p+1) != '\0') goto dflt;
if (s != ms->src_end) s = NULL; /* check end of string */
break;
default: dflt: { /* it is a pattern item */
const char *ep = classend(ms, p); /* points to what is next */
int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
switch (*ep) {
case '?': { /* optional */
const char *res;
if (m && ((res=match(ms, s+1, ep+1)) != NULL)) {
s = res;
break;
}
p=ep+1;
goto init; /* else s = match(ms, s, ep+1); */
}
case '*': /* 0 or more repetitions */
s = max_expand(ms, s, p, ep);
break;
case '+': /* 1 or more repetitions */
s = (m ? max_expand(ms, s+1, p, ep) : NULL);
break;
case '-': /* 0 or more repetitions (minimum) */
s = min_expand(ms, s, p, ep);
break;
default:
if (m) { s++; p=ep; goto init; } /* else s = match(ms, s+1, ep); */
s = NULL;
break;
}
break;
}
}
ms->depth--;
return s;
}
static const char *lmemfind(const char *s1, size_t l1,
const char *s2, size_t l2)
{
if (l2 == 0) {
return s1; /* empty strings are everywhere */
} else if (l2 > l1) {
return NULL; /* avoids a negative `l1' */
} else {
const char *init; /* to search for a `*s2' inside `s1' */
l2--; /* 1st char will be checked by `memchr' */
l1 = l1-l2; /* `s2' cannot be found after that */
while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
init++; /* 1st char is already checked */
if (memcmp(init, s2+1, l2) == 0) {
return init-1;
} else { /* correct `l1' and `s1' to try again */
l1 -= (size_t)(init-s1);
s1 = init;
}
}
return NULL; /* not found */
}
}
static void push_onecapture(MatchState *ms, int i, const char *s, const char *e)
{
if (i >= ms->level) {
if (i == 0) /* ms->level == 0, too */
lua_pushlstring(ms->L, s, (size_t)(e - s)); /* add whole match */
else
lj_err_caller(ms->L, LJ_ERR_STRCAPI);
} else {
ptrdiff_t l = ms->capture[i].len;
if (l == CAP_UNFINISHED) lj_err_caller(ms->L, LJ_ERR_STRCAPU);
if (l == CAP_POSITION)
lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
else
lua_pushlstring(ms->L, ms->capture[i].init, (size_t)l);
}
}
static int push_captures(MatchState *ms, const char *s, const char *e)
{
int i;
int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
luaL_checkstack(ms->L, nlevels, "too many captures");
for (i = 0; i < nlevels; i++)
push_onecapture(ms, i, s, e);
return nlevels; /* number of strings pushed */
}
static ptrdiff_t posrelat(ptrdiff_t pos, size_t len)
{
/* relative string position: negative means back from end */
if (pos < 0) pos += (ptrdiff_t)len + 1;
return (pos >= 0) ? pos : 0;
}
static int str_find_aux(lua_State *L, int find)
{
size_t l1, l2;
const char *s = luaL_checklstring(L, 1, &l1);
const char *p = luaL_checklstring(L, 2, &l2);
ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
if (init < 0) {
init = 0;
} else if ((size_t)(init) > l1) {
#if LJ_52
setnilV(L->top-1);
return 1;
#else
init = (ptrdiff_t)l1;
#endif
}
if (find && (lua_toboolean(L, 4) || /* explicit request? */
strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */
/* do a plain search */
const char *s2 = lmemfind(s+init, l1-(size_t)init, p, l2);
if (s2) {
lua_pushinteger(L, s2-s+1);
lua_pushinteger(L, s2-s+(ptrdiff_t)l2);
return 2;
}
} else {
MatchState ms;
int anchor = (*p == '^') ? (p++, 1) : 0;
const char *s1=s+init;
ms.L = L;
ms.src_init = s;
ms.src_end = s+l1;
do {
const char *res;
ms.level = ms.depth = 0;
if ((res=match(&ms, s1, p)) != NULL) {
if (find) {
lua_pushinteger(L, s1-s+1); /* start */
lua_pushinteger(L, res-s); /* end */
return push_captures(&ms, NULL, 0) + 2;
} else {
return push_captures(&ms, s1, res);
}
}
} while (s1++ < ms.src_end && !anchor);
}
lua_pushnil(L); /* not found */
return 1;
}
LJLIB_CF(string_find)
{
return str_find_aux(L, 1);
}
LJLIB_CF(string_match)
{
return str_find_aux(L, 0);
}
LJLIB_NOREG LJLIB_CF(string_gmatch_aux)
{
const char *p = strVdata(lj_lib_upvalue(L, 2));
GCstr *str = strV(lj_lib_upvalue(L, 1));
const char *s = strdata(str);
TValue *tvpos = lj_lib_upvalue(L, 3);
const char *src = s + tvpos->u32.lo;
MatchState ms;
ms.L = L;
ms.src_init = s;
ms.src_end = s + str->len;
for (; src <= ms.src_end; src++) {
const char *e;
ms.level = ms.depth = 0;
if ((e = match(&ms, src, p)) != NULL) {
int32_t pos = (int32_t)(e - s);
if (e == src) pos++; /* Ensure progress for empty match. */
tvpos->u32.lo = (uint32_t)pos;
return push_captures(&ms, src, e);
}
}
return 0; /* not found */
}
LJLIB_CF(string_gmatch)
{
lj_lib_checkstr(L, 1);
lj_lib_checkstr(L, 2);
L->top = L->base+3;
(L->top-1)->u64 = 0;
lj_lib_pushcc(L, lj_cf_string_gmatch_aux, FF_string_gmatch_aux, 3);
return 1;
}
static void add_s(MatchState *ms, luaL_Buffer *b, const char *s, const char *e)
{
size_t l, i;
const char *news = lua_tolstring(ms->L, 3, &l);
for (i = 0; i < l; i++) {
if (news[i] != L_ESC) {
luaL_addchar(b, news[i]);
} else {
i++; /* skip ESC */
if (!lj_char_isdigit(uchar(news[i]))) {
luaL_addchar(b, news[i]);
} else if (news[i] == '0') {
luaL_addlstring(b, s, (size_t)(e - s));
} else {
push_onecapture(ms, news[i] - '1', s, e);
luaL_addvalue(b); /* add capture to accumulated result */
}
}
}
}
static void add_value(MatchState *ms, luaL_Buffer *b,
const char *s, const char *e)
{
lua_State *L = ms->L;
switch (lua_type(L, 3)) {
case LUA_TNUMBER:
case LUA_TSTRING: {
add_s(ms, b, s, e);
return;
}
case LUA_TFUNCTION: {
int n;
lua_pushvalue(L, 3);
n = push_captures(ms, s, e);
lua_call(L, n, 1);
break;
}
case LUA_TTABLE: {
push_onecapture(ms, 0, s, e);
lua_gettable(L, 3);
break;
}
}
if (!lua_toboolean(L, -1)) { /* nil or false? */
lua_pop(L, 1);
lua_pushlstring(L, s, (size_t)(e - s)); /* keep original text */
} else if (!lua_isstring(L, -1)) {
lj_err_callerv(L, LJ_ERR_STRGSRV, luaL_typename(L, -1));
}
luaL_addvalue(b); /* add result to accumulator */
}
LJLIB_CF(string_gsub)
{
size_t srcl;
const char *src = luaL_checklstring(L, 1, &srcl);
const char *p = luaL_checkstring(L, 2);
int tr = lua_type(L, 3);
int max_s = luaL_optint(L, 4, (int)(srcl+1));
int anchor = (*p == '^') ? (p++, 1) : 0;
int n = 0;
MatchState ms;
luaL_Buffer b;
if (!(tr == LUA_TNUMBER || tr == LUA_TSTRING ||
tr == LUA_TFUNCTION || tr == LUA_TTABLE))
lj_err_arg(L, 3, LJ_ERR_NOSFT);
luaL_buffinit(L, &b);
ms.L = L;
ms.src_init = src;
ms.src_end = src+srcl;
while (n < max_s) {
const char *e;
ms.level = ms.depth = 0;
e = match(&ms, src, p);
if (e) {
n++;
add_value(&ms, &b, src, e);
}
if (e && e>src) /* non empty match? */
src = e; /* skip it */
else if (src < ms.src_end)
luaL_addchar(&b, *src++);
else
break;
if (anchor)
break;
}
luaL_addlstring(&b, src, (size_t)(ms.src_end-src));
luaL_pushresult(&b);
lua_pushinteger(L, n); /* number of substitutions */
return 2;
}
/* ------------------------------------------------------------------------ */
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
#define MAX_FMTITEM 512
/* valid flags in a format specification */
#define FMT_FLAGS "-+ #0"
/*
** maximum size of each format specification (such as '%-099.99d')
** (+10 accounts for %99.99x plus margin of error)
*/
#define MAX_FMTSPEC (sizeof(FMT_FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
static void addquoted(lua_State *L, luaL_Buffer *b, int arg)
{
GCstr *str = lj_lib_checkstr(L, arg);
int32_t len = (int32_t)str->len;
const char *s = strdata(str);
luaL_addchar(b, '"');
while (len--) {
uint32_t c = uchar(*s);
if (c == '"' || c == '\\' || c == '\n') {
luaL_addchar(b, '\\');
} else if (lj_char_iscntrl(c)) { /* This can only be 0-31 or 127. */
uint32_t d;
luaL_addchar(b, '\\');
if (c >= 100 || lj_char_isdigit(uchar(s[1]))) {
luaL_addchar(b, '0'+(c >= 100)); if (c >= 100) c -= 100;
goto tens;
} else if (c >= 10) {
tens:
d = (c * 205) >> 11; c -= d * 10; luaL_addchar(b, '0'+d);
}
c += '0';
}
luaL_addchar(b, c);
s++;
}
luaL_addchar(b, '"');
}
static const char *scanformat(lua_State *L, const char *strfrmt, char *form)
{
const char *p = strfrmt;
while (*p != '\0' && strchr(FMT_FLAGS, *p) != NULL) p++; /* skip flags */
if ((size_t)(p - strfrmt) >= sizeof(FMT_FLAGS))
lj_err_caller(L, LJ_ERR_STRFMTR);
if (lj_char_isdigit(uchar(*p))) p++; /* skip width */
if (lj_char_isdigit(uchar(*p))) p++; /* (2 digits at most) */
if (*p == '.') {
p++;
if (lj_char_isdigit(uchar(*p))) p++; /* skip precision */
if (lj_char_isdigit(uchar(*p))) p++; /* (2 digits at most) */
}
if (lj_char_isdigit(uchar(*p)))
lj_err_caller(L, LJ_ERR_STRFMTW);
*(form++) = '%';
strncpy(form, strfrmt, (size_t)(p - strfrmt + 1));
form += p - strfrmt + 1;
*form = '\0';
return p;
}
static void addintlen(char *form)
{
size_t l = strlen(form);
char spec = form[l - 1];
strcpy(form + l - 1, LUA_INTFRMLEN);
form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
}
static unsigned LUA_INTFRM_T num2intfrm(lua_State *L, int arg)
{
if (sizeof(LUA_INTFRM_T) == 4) {
return (LUA_INTFRM_T)lj_lib_checkbit(L, arg);
} else {
cTValue *o;
lj_lib_checknumber(L, arg);
o = L->base+arg-1;
if (tvisint(o))
return (LUA_INTFRM_T)intV(o);
else
return (LUA_INTFRM_T)numV(o);
}
}
static unsigned LUA_INTFRM_T num2uintfrm(lua_State *L, int arg)
{
if (sizeof(LUA_INTFRM_T) == 4) {
return (unsigned LUA_INTFRM_T)lj_lib_checkbit(L, arg);
} else {
cTValue *o;
lj_lib_checknumber(L, arg);
o = L->base+arg-1;
if (tvisint(o))
return (unsigned LUA_INTFRM_T)intV(o);
else if ((int32_t)o->u32.hi < 0)
return (unsigned LUA_INTFRM_T)(LUA_INTFRM_T)numV(o);
else
return (unsigned LUA_INTFRM_T)numV(o);
}
}
static GCstr *meta_tostring(lua_State *L, int arg)
{
TValue *o = L->base+arg-1;
cTValue *mo;
lua_assert(o < L->top); /* Caller already checks for existence. */
if (LJ_LIKELY(tvisstr(o)))
return strV(o);
if (!tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
copyTV(L, L->top++, mo);
copyTV(L, L->top++, o);
lua_call(L, 1, 1);
L->top--;
if (tvisstr(L->top))
return strV(L->top);
o = L->base+arg-1;
copyTV(L, o, L->top);
}
if (tvisnumber(o)) {
return lj_str_fromnumber(L, o);
} else if (tvisnil(o)) {
return lj_str_newlit(L, "nil");
} else if (tvisfalse(o)) {
return lj_str_newlit(L, "false");
} else if (tvistrue(o)) {
return lj_str_newlit(L, "true");
} else {
if (tvisfunc(o) && isffunc(funcV(o)))
lj_str_pushf(L, "function: builtin#%d", funcV(o)->c.ffid);
else
lj_str_pushf(L, "%s: %p", lj_typename(o), lua_topointer(L, arg));
L->top--;
return strV(L->top);
}
}
LJLIB_CF(string_format)
{
int arg = 1, top = (int)(L->top - L->base);
GCstr *fmt = lj_lib_checkstr(L, arg);
const char *strfrmt = strdata(fmt);
const char *strfrmt_end = strfrmt + fmt->len;
luaL_Buffer b;
luaL_buffinit(L, &b);
while (strfrmt < strfrmt_end) {
if (*strfrmt != L_ESC) {
luaL_addchar(&b, *strfrmt++);
} else if (*++strfrmt == L_ESC) {
luaL_addchar(&b, *strfrmt++); /* %% */
} else { /* format item */
char form[MAX_FMTSPEC]; /* to store the format (`%...') */
char buff[MAX_FMTITEM]; /* to store the formatted item */
if (++arg > top)
luaL_argerror(L, arg, lj_obj_typename[0]);
strfrmt = scanformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c':
sprintf(buff, form, lj_lib_checkint(L, arg));
break;
case 'd': case 'i':
addintlen(form);
sprintf(buff, form, num2intfrm(L, arg));
break;
case 'o': case 'u': case 'x': case 'X':
addintlen(form);
sprintf(buff, form, num2uintfrm(L, arg));
break;
case 'e': case 'E': case 'f': case 'g': case 'G': case 'a': case 'A': {
TValue tv;
tv.n = lj_lib_checknum(L, arg);
if (LJ_UNLIKELY((tv.u32.hi << 1) >= 0xffe00000)) {
/* Canonicalize output of non-finite values. */
char *p, nbuf[LJ_STR_NUMBUF];
size_t len = lj_str_bufnum(nbuf, &tv);
if (strfrmt[-1] < 'a') {
nbuf[len-3] = nbuf[len-3] - 0x20;
nbuf[len-2] = nbuf[len-2] - 0x20;
nbuf[len-1] = nbuf[len-1] - 0x20;
}
nbuf[len] = '\0';
for (p = form; *p < 'A' && *p != '.'; p++) ;
*p++ = 's'; *p = '\0';
sprintf(buff, form, nbuf);
break;
}
sprintf(buff, form, (double)tv.n);
break;
}
case 'q':
addquoted(L, &b, arg);
continue;
case 'p':
lj_str_pushf(L, "%p", lua_topointer(L, arg));
luaL_addvalue(&b);
continue;
case 's': {
GCstr *str = meta_tostring(L, arg);
if (!strchr(form, '.') && str->len >= 100) {
/* no precision and string is too long to be formatted;
keep original string */
setstrV(L, L->top++, str);
luaL_addvalue(&b);
continue;
}
sprintf(buff, form, strdata(str));
break;
}
default:
lj_err_callerv(L, LJ_ERR_STRFMTO, *(strfrmt -1));
break;
}
luaL_addlstring(&b, buff, strlen(buff));
}
}
luaL_pushresult(&b);
return 1;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_string(lua_State *L)
{
GCtab *mt;
global_State *g;
LJ_LIB_REG(L, LUA_STRLIBNAME, string);
#if defined(LUA_COMPAT_GFIND) && !LJ_52
lua_getfield(L, -1, "gmatch");
lua_setfield(L, -2, "gfind");
#endif
mt = lj_tab_new(L, 0, 1);
/* NOBARRIER: basemt is a GC root. */
g = G(L);
setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt));
settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1));
mt->nomm = (uint8_t)(~(1u<<MM_index));
return 1;
}

View File

@ -1,300 +0,0 @@
/*
** Table library.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lib_table_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_tab.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_table
LJLIB_CF(table_foreachi)
{
GCtab *t = lj_lib_checktab(L, 1);
GCfunc *func = lj_lib_checkfunc(L, 2);
MSize i, n = lj_tab_len(t);
for (i = 1; i <= n; i++) {
cTValue *val;
setfuncV(L, L->top, func);
setintV(L->top+1, i);
val = lj_tab_getint(t, (int32_t)i);
if (val) { copyTV(L, L->top+2, val); } else { setnilV(L->top+2); }
L->top += 3;
lua_call(L, 2, 1);
if (!tvisnil(L->top-1))
return 1;
L->top--;
}
return 0;
}
LJLIB_CF(table_foreach)
{
GCtab *t = lj_lib_checktab(L, 1);
GCfunc *func = lj_lib_checkfunc(L, 2);
L->top = L->base+3;
setnilV(L->top-1);
while (lj_tab_next(L, t, L->top-1)) {
copyTV(L, L->top+2, L->top);
copyTV(L, L->top+1, L->top-1);
setfuncV(L, L->top, func);
L->top += 3;
lua_call(L, 2, 1);
if (!tvisnil(L->top-1))
return 1;
L->top--;
}
return 0;
}
LJLIB_ASM(table_getn) LJLIB_REC(.)
{
lj_lib_checktab(L, 1);
return FFH_UNREACHABLE;
}
LJLIB_CF(table_maxn)
{
GCtab *t = lj_lib_checktab(L, 1);
TValue *array = tvref(t->array);
Node *node;
lua_Number m = 0;
ptrdiff_t i;
for (i = (ptrdiff_t)t->asize - 1; i >= 0; i--)
if (!tvisnil(&array[i])) {
m = (lua_Number)(int32_t)i;
break;
}
node = noderef(t->node);
for (i = (ptrdiff_t)t->hmask; i >= 0; i--)
if (!tvisnil(&node[i].val) && tvisnumber(&node[i].key)) {
lua_Number n = numberVnum(&node[i].key);
if (n > m) m = n;
}
setnumV(L->top-1, m);
return 1;
}
LJLIB_CF(table_insert) LJLIB_REC(.)
{
GCtab *t = lj_lib_checktab(L, 1);
int32_t n, i = (int32_t)lj_tab_len(t) + 1;
int nargs = (int)((char *)L->top - (char *)L->base);
if (nargs != 2*sizeof(TValue)) {
if (nargs != 3*sizeof(TValue))
lj_err_caller(L, LJ_ERR_TABINS);
/* NOBARRIER: This just moves existing elements around. */
for (n = lj_lib_checkint(L, 2); i > n; i--) {
/* The set may invalidate the get pointer, so need to do it first! */
TValue *dst = lj_tab_setint(L, t, i);
cTValue *src = lj_tab_getint(t, i-1);
if (src) {
copyTV(L, dst, src);
} else {
setnilV(dst);
}
}
i = n;
}
{
TValue *dst = lj_tab_setint(L, t, i);
copyTV(L, dst, L->top-1); /* Set new value. */
lj_gc_barriert(L, t, dst);
}
return 0;
}
LJLIB_CF(table_remove) LJLIB_REC(.)
{
GCtab *t = lj_lib_checktab(L, 1);
int32_t e = (int32_t)lj_tab_len(t);
int32_t pos = lj_lib_optint(L, 2, e);
if (!(1 <= pos && pos <= e)) /* Nothing to remove? */
return 0;
lua_rawgeti(L, 1, pos); /* Get previous value. */
/* NOBARRIER: This just moves existing elements around. */
for (; pos < e; pos++) {
cTValue *src = lj_tab_getint(t, pos+1);
TValue *dst = lj_tab_setint(L, t, pos);
if (src) {
copyTV(L, dst, src);
} else {
setnilV(dst);
}
}
setnilV(lj_tab_setint(L, t, e)); /* Remove (last) value. */
return 1; /* Return previous value. */
}
LJLIB_CF(table_concat)
{
luaL_Buffer b;
GCtab *t = lj_lib_checktab(L, 1);
GCstr *sep = lj_lib_optstr(L, 2);
MSize seplen = sep ? sep->len : 0;
int32_t i = lj_lib_optint(L, 3, 1);
int32_t e = (L->base+3 < L->top && !tvisnil(L->base+3)) ?
lj_lib_checkint(L, 4) : (int32_t)lj_tab_len(t);
luaL_buffinit(L, &b);
if (i <= e) {
for (;;) {
cTValue *o;
lua_rawgeti(L, 1, i);
o = L->top-1;
if (!(tvisstr(o) || tvisnumber(o)))
lj_err_callerv(L, LJ_ERR_TABCAT, lj_typename(o), i);
luaL_addvalue(&b);
if (i++ == e) break;
if (seplen)
luaL_addlstring(&b, strdata(sep), seplen);
}
}
luaL_pushresult(&b);
return 1;
}
/* ------------------------------------------------------------------------ */
static void set2(lua_State *L, int i, int j)
{
lua_rawseti(L, 1, i);
lua_rawseti(L, 1, j);
}
static int sort_comp(lua_State *L, int a, int b)
{
if (!lua_isnil(L, 2)) { /* function? */
int res;
lua_pushvalue(L, 2);
lua_pushvalue(L, a-1); /* -1 to compensate function */
lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */
lua_call(L, 2, 1);
res = lua_toboolean(L, -1);
lua_pop(L, 1);
return res;
} else { /* a < b? */
return lua_lessthan(L, a, b);
}
}
static void auxsort(lua_State *L, int l, int u)
{
while (l < u) { /* for tail recursion */
int i, j;
/* sort elements a[l], a[(l+u)/2] and a[u] */
lua_rawgeti(L, 1, l);
lua_rawgeti(L, 1, u);
if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
set2(L, l, u); /* swap a[l] - a[u] */
else
lua_pop(L, 2);
if (u-l == 1) break; /* only 2 elements */
i = (l+u)/2;
lua_rawgeti(L, 1, i);
lua_rawgeti(L, 1, l);
if (sort_comp(L, -2, -1)) { /* a[i]<a[l]? */
set2(L, i, l);
} else {
lua_pop(L, 1); /* remove a[l] */
lua_rawgeti(L, 1, u);
if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
set2(L, i, u);
else
lua_pop(L, 2);
}
if (u-l == 2) break; /* only 3 elements */
lua_rawgeti(L, 1, i); /* Pivot */
lua_pushvalue(L, -1);
lua_rawgeti(L, 1, u-1);
set2(L, i, u-1);
/* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
i = l; j = u-1;
for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
/* repeat ++i until a[i] >= P */
while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
if (i>=u) lj_err_caller(L, LJ_ERR_TABSORT);
lua_pop(L, 1); /* remove a[i] */
}
/* repeat --j until a[j] <= P */
while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
if (j<=l) lj_err_caller(L, LJ_ERR_TABSORT);
lua_pop(L, 1); /* remove a[j] */
}
if (j<i) {
lua_pop(L, 3); /* pop pivot, a[i], a[j] */
break;
}
set2(L, i, j);
}
lua_rawgeti(L, 1, u-1);
lua_rawgeti(L, 1, i);
set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */
/* a[l..i-1] <= a[i] == P <= a[i+1..u] */
/* adjust so that smaller half is in [j..i] and larger one in [l..u] */
if (i-l < u-i) {
j=l; i=i-1; l=i+2;
} else {
j=i+1; i=u; u=j-2;
}
auxsort(L, j, i); /* call recursively the smaller one */
} /* repeat the routine for the larger one */
}
LJLIB_CF(table_sort)
{
GCtab *t = lj_lib_checktab(L, 1);
int32_t n = (int32_t)lj_tab_len(t);
lua_settop(L, 2);
if (!tvisnil(L->base+1))
lj_lib_checkfunc(L, 2);
auxsort(L, 1, n);
return 0;
}
#if LJ_52
LJLIB_PUSH("n")
LJLIB_CF(table_pack)
{
TValue *array, *base = L->base;
MSize i, n = (uint32_t)(L->top - base);
GCtab *t = lj_tab_new(L, n ? n+1 : 0, 1);
/* NOBARRIER: The table is new (marked white). */
setintV(lj_tab_setstr(L, t, strV(lj_lib_upvalue(L, 1))), (int32_t)n);
for (array = tvref(t->array) + 1, i = 0; i < n; i++)
copyTV(L, &array[i], &base[i]);
settabV(L, base, t);
L->top = base+1;
lj_gc_check(L);
return 1;
}
#endif
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_table(lua_State *L)
{
LJ_LIB_REG(L, LUA_TABLIBNAME, table);
#if LJ_52
lua_getglobal(L, "unpack");
lua_setfield(L, -2, "unpack");
#endif
return 1;
}

View File

@ -1,41 +0,0 @@
# Valgrind suppression file for LuaJIT 2.0.
{
Optimized string compare
Memcheck:Addr4
fun:lj_str_cmp
}
{
Optimized string compare
Memcheck:Addr1
fun:lj_str_cmp
}
{
Optimized string compare
Memcheck:Addr4
fun:lj_str_new
}
{
Optimized string compare
Memcheck:Addr1
fun:lj_str_new
}
{
Optimized string compare
Memcheck:Cond
fun:lj_str_new
}
{
Optimized string compare
Memcheck:Addr4
fun:str_fastcmp
}
{
Optimized string compare
Memcheck:Addr1
fun:str_fastcmp
}
{
Optimized string compare
Memcheck:Cond
fun:str_fastcmp
}

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
/*
** Bundled memory allocator.
** Donated to the public domain.
*/
#ifndef _LJ_ALLOC_H
#define _LJ_ALLOC_H
#include "lj_def.h"
#ifndef LUAJIT_USE_SYSMALLOC
LJ_FUNC void *lj_alloc_create(void);
LJ_FUNC void lj_alloc_destroy(void *msp);
LJ_FUNC void *lj_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize);
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,452 +0,0 @@
/*
** Target architecture selection.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_ARCH_H
#define _LJ_ARCH_H
#include "lua.h"
/* Target endianess. */
#define LUAJIT_LE 0
#define LUAJIT_BE 1
/* Target architectures. */
#define LUAJIT_ARCH_X86 1
#define LUAJIT_ARCH_x86 1
#define LUAJIT_ARCH_X64 2
#define LUAJIT_ARCH_x64 2
#define LUAJIT_ARCH_ARM 3
#define LUAJIT_ARCH_arm 3
#define LUAJIT_ARCH_PPC 4
#define LUAJIT_ARCH_ppc 4
#define LUAJIT_ARCH_PPCSPE 5
#define LUAJIT_ARCH_ppcspe 5
#define LUAJIT_ARCH_MIPS 6
#define LUAJIT_ARCH_mips 6
/* Target OS. */
#define LUAJIT_OS_OTHER 0
#define LUAJIT_OS_WINDOWS 1
#define LUAJIT_OS_LINUX 2
#define LUAJIT_OS_OSX 3
#define LUAJIT_OS_BSD 4
#define LUAJIT_OS_POSIX 5
/* Select native target if no target defined. */
#ifndef LUAJIT_TARGET
#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
#define LUAJIT_TARGET LUAJIT_ARCH_X86
#elif defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
#define LUAJIT_TARGET LUAJIT_ARCH_X64
#elif defined(__arm__) || defined(__arm) || defined(__ARM__) || defined(__ARM)
#define LUAJIT_TARGET LUAJIT_ARCH_ARM
#elif defined(__ppc__) || defined(__ppc) || defined(__PPC__) || defined(__PPC) || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) || defined(__POWERPC) || defined(_M_PPC)
#ifdef __NO_FPRS__
#define LUAJIT_TARGET LUAJIT_ARCH_PPCSPE
#else
#define LUAJIT_TARGET LUAJIT_ARCH_PPC
#endif
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(__MIPS)
#define LUAJIT_TARGET LUAJIT_ARCH_MIPS
#else
#error "No support for this architecture (yet)"
#endif
#endif
/* Select native OS if no target OS defined. */
#ifndef LUAJIT_OS
#if defined(_WIN32) && !defined(_XBOX_VER)
#define LUAJIT_OS LUAJIT_OS_WINDOWS
#elif defined(__linux__)
#define LUAJIT_OS LUAJIT_OS_LINUX
#elif defined(__MACH__) && defined(__APPLE__)
#define LUAJIT_OS LUAJIT_OS_OSX
#elif (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__DragonFly__)) && !defined(__ORBIS__)
#define LUAJIT_OS LUAJIT_OS_BSD
#elif (defined(__sun__) && defined(__svr4__))
#define LUAJIT_OS LUAJIT_OS_POSIX
#elif defined(__CYGWIN__)
#define LJ_TARGET_CYGWIN 1
#define LUAJIT_OS LUAJIT_OS_POSIX
#else
#define LUAJIT_OS LUAJIT_OS_OTHER
#endif
#endif
/* Set target OS properties. */
#if LUAJIT_OS == LUAJIT_OS_WINDOWS
#define LJ_OS_NAME "Windows"
#elif LUAJIT_OS == LUAJIT_OS_LINUX
#define LJ_OS_NAME "Linux"
#elif LUAJIT_OS == LUAJIT_OS_OSX
#define LJ_OS_NAME "OSX"
#elif LUAJIT_OS == LUAJIT_OS_BSD
#define LJ_OS_NAME "BSD"
#elif LUAJIT_OS == LUAJIT_OS_POSIX
#define LJ_OS_NAME "POSIX"
#else
#define LJ_OS_NAME "Other"
#endif
#define LJ_TARGET_WINDOWS (LUAJIT_OS == LUAJIT_OS_WINDOWS)
#define LJ_TARGET_LINUX (LUAJIT_OS == LUAJIT_OS_LINUX)
#define LJ_TARGET_OSX (LUAJIT_OS == LUAJIT_OS_OSX)
#define LJ_TARGET_IOS (LJ_TARGET_OSX && LUAJIT_TARGET == LUAJIT_ARCH_ARM)
#define LJ_TARGET_POSIX (LUAJIT_OS > LUAJIT_OS_WINDOWS)
#define LJ_TARGET_DLOPEN LJ_TARGET_POSIX
#ifdef __CELLOS_LV2__
#define LJ_TARGET_PS3 1
#define LJ_TARGET_CONSOLE 1
#endif
#ifdef __ORBIS__
#define LJ_TARGET_PS4 1
#define LJ_TARGET_CONSOLE 1
#undef NULL
#define NULL ((void*)0)
#endif
#ifdef __psp2__
#define LJ_TARGET_PSVITA 1
#define LJ_TARGET_CONSOLE 1
#endif
#if _XBOX_VER >= 200
#define LJ_TARGET_XBOX360 1
#define LJ_TARGET_CONSOLE 1
#endif
#define LJ_NUMMODE_SINGLE 0 /* Single-number mode only. */
#define LJ_NUMMODE_SINGLE_DUAL 1 /* Default to single-number mode. */
#define LJ_NUMMODE_DUAL 2 /* Dual-number mode only. */
#define LJ_NUMMODE_DUAL_SINGLE 3 /* Default to dual-number mode. */
/* Set target architecture properties. */
#if LUAJIT_TARGET == LUAJIT_ARCH_X86
#define LJ_ARCH_NAME "x86"
#define LJ_ARCH_BITS 32
#define LJ_ARCH_ENDIAN LUAJIT_LE
#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
#define LJ_ABI_WIN 1
#else
#define LJ_ABI_WIN 0
#endif
#define LJ_TARGET_X86 1
#define LJ_TARGET_X86ORX64 1
#define LJ_TARGET_EHRETREG 0
#define LJ_TARGET_MASKSHIFT 1
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNALIGNED 1
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL
#elif LUAJIT_TARGET == LUAJIT_ARCH_X64
#define LJ_ARCH_NAME "x64"
#define LJ_ARCH_BITS 64
#define LJ_ARCH_ENDIAN LUAJIT_LE
#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
#define LJ_ABI_WIN 1
#else
#define LJ_ABI_WIN 0
#endif
#define LJ_TARGET_X64 1
#define LJ_TARGET_X86ORX64 1
#define LJ_TARGET_EHRETREG 0
#define LJ_TARGET_JUMPRANGE 31 /* +-2^31 = +-2GB */
#define LJ_TARGET_MASKSHIFT 1
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNALIGNED 1
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL
#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM
#define LJ_ARCH_NAME "arm"
#define LJ_ARCH_BITS 32
#define LJ_ARCH_ENDIAN LUAJIT_LE
#if !defined(LJ_ARCH_HASFPU) && __SOFTFP__
#define LJ_ARCH_HASFPU 0
#endif
#if !defined(LJ_ABI_SOFTFP) && !__ARM_PCS_VFP
#define LJ_ABI_SOFTFP 1
#endif
#define LJ_ABI_EABI 1
#define LJ_TARGET_ARM 1
#define LJ_TARGET_EHRETREG 0
#define LJ_TARGET_JUMPRANGE 25 /* +-2^25 = +-32MB */
#define LJ_TARGET_MASKSHIFT 0
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
#if __ARM_ARCH____ARM_ARCH_8__ || __ARM_ARCH_8A__
#define LJ_ARCH_VERSION 80
#elif __ARM_ARCH_7__ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH_7S__ || __ARM_ARCH_7VE__
#define LJ_ARCH_VERSION 70
#elif __ARM_ARCH_6T2__
#define LJ_ARCH_VERSION 61
#elif __ARM_ARCH_6__ || __ARM_ARCH_6J__ || __ARM_ARCH_6K__ || __ARM_ARCH_6Z__ || __ARM_ARCH_6ZK__
#define LJ_ARCH_VERSION 60
#else
#define LJ_ARCH_VERSION 50
#endif
#elif LUAJIT_TARGET == LUAJIT_ARCH_PPC
#define LJ_ARCH_NAME "ppc"
#if _LP64
#define LJ_ARCH_BITS 64
#else
#define LJ_ARCH_BITS 32
#endif
#define LJ_ARCH_ENDIAN LUAJIT_BE
#define LJ_TARGET_PPC 1
#define LJ_TARGET_EHRETREG 3
#define LJ_TARGET_JUMPRANGE 25 /* +-2^25 = +-32MB */
#define LJ_TARGET_MASKSHIFT 0
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNIFYROT 1 /* Want only IR_BROL. */
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL_SINGLE
#if _ARCH_PWR7
#define LJ_ARCH_VERSION 70
#elif _ARCH_PWR6
#define LJ_ARCH_VERSION 60
#elif _ARCH_PWR5X
#define LJ_ARCH_VERSION 51
#elif _ARCH_PWR5
#define LJ_ARCH_VERSION 50
#elif _ARCH_PWR4
#define LJ_ARCH_VERSION 40
#else
#define LJ_ARCH_VERSION 0
#endif
#if __PPC64__ || __powerpc64__ || LJ_TARGET_CONSOLE
#define LJ_ARCH_PPC64 1
#define LJ_ARCH_NOFFI 1
#endif
#if _ARCH_PPCSQ
#define LJ_ARCH_SQRT 1
#endif
#if _ARCH_PWR5X
#define LJ_ARCH_ROUND 1
#endif
#if __PPU__
#define LJ_ARCH_CELL 1
#endif
#if LJ_TARGET_XBOX360
#define LJ_ARCH_XENON 1
#endif
#elif LUAJIT_TARGET == LUAJIT_ARCH_PPCSPE
#define LJ_ARCH_NAME "ppcspe"
#define LJ_ARCH_BITS 32
#define LJ_ARCH_ENDIAN LUAJIT_BE
#ifndef LJ_ABI_SOFTFP
#define LJ_ABI_SOFTFP 1
#endif
#define LJ_ABI_EABI 1
#define LJ_TARGET_PPCSPE 1
#define LJ_TARGET_EHRETREG 3
#define LJ_TARGET_JUMPRANGE 25 /* +-2^25 = +-32MB */
#define LJ_TARGET_MASKSHIFT 0
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNIFYROT 1 /* Want only IR_BROL. */
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE
#define LJ_ARCH_NOFFI 1 /* NYI: comparisons, calls. */
#define LJ_ARCH_NOJIT 1
#elif LUAJIT_TARGET == LUAJIT_ARCH_MIPS
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
#define LJ_ARCH_NAME "mipsel"
#define LJ_ARCH_ENDIAN LUAJIT_LE
#else
#define LJ_ARCH_NAME "mips"
#define LJ_ARCH_ENDIAN LUAJIT_BE
#endif
#define LJ_ARCH_BITS 32
#define LJ_TARGET_MIPS 1
#define LJ_TARGET_EHRETREG 4
#define LJ_TARGET_JUMPRANGE 27 /* 2*2^27 = 256MB-aligned region */
#define LJ_TARGET_MASKSHIFT 1
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE
#if _MIPS_ARCH_MIPS32R2
#define LJ_ARCH_VERSION 20
#else
#define LJ_ARCH_VERSION 10
#endif
#else
#error "No target architecture defined"
#endif
#ifndef LJ_PAGESIZE
#define LJ_PAGESIZE 4096
#endif
/* Check for minimum required compiler versions. */
#if defined(__GNUC__)
#if LJ_TARGET_X86
#if (__GNUC__ < 3) || ((__GNUC__ == 3) && __GNUC_MINOR__ < 4)
#error "Need at least GCC 3.4 or newer"
#endif
#elif LJ_TARGET_X64
#if __GNUC__ < 4
#error "Need at least GCC 4.0 or newer"
#endif
#elif LJ_TARGET_ARM
#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 2)
#error "Need at least GCC 4.2 or newer"
#endif
#elif !LJ_TARGET_PS3
#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 3)
#error "Need at least GCC 4.3 or newer"
#endif
#endif
#endif
/* Check target-specific constraints. */
#ifndef _BUILDVM_H
#if LJ_TARGET_X64
#if __USING_SJLJ_EXCEPTIONS__
#error "Need a C compiler with native exception handling on x64"
#endif
#elif LJ_TARGET_ARM
#if defined(__ARMEB__)
#error "No support for big-endian ARM"
#endif
#if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__
#error "No support for Cortex-M CPUs"
#endif
#if !(__ARM_EABI__ || LJ_TARGET_IOS)
#error "Only ARM EABI or iOS 3.0+ ABI is supported"
#endif
#elif LJ_TARGET_PPC || LJ_TARGET_PPCSPE
#if defined(_SOFT_FLOAT) || defined(_SOFT_DOUBLE)
#error "No support for PowerPC CPUs without double-precision FPU"
#endif
#if defined(_LITTLE_ENDIAN)
#error "No support for little-endian PowerPC"
#endif
#if defined(_LP64)
#error "No support for PowerPC 64 bit mode"
#endif
#elif LJ_TARGET_MIPS
#if defined(__mips_soft_float)
#error "No support for MIPS CPUs without FPU"
#endif
#if defined(_LP64)
#error "No support for MIPS64"
#endif
#endif
#endif
/* Enable or disable the dual-number mode for the VM. */
#if (LJ_ARCH_NUMMODE == LJ_NUMMODE_SINGLE && LUAJIT_NUMMODE == 2) || \
(LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL && LUAJIT_NUMMODE == 1)
#error "No support for this number mode on this architecture"
#endif
#if LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL || \
(LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL_SINGLE && LUAJIT_NUMMODE != 1) || \
(LJ_ARCH_NUMMODE == LJ_NUMMODE_SINGLE_DUAL && LUAJIT_NUMMODE == 2)
#define LJ_DUALNUM 1
#else
#define LJ_DUALNUM 0
#endif
#if LJ_TARGET_IOS || LJ_TARGET_CONSOLE
/* Runtime code generation is restricted on iOS. Complain to Apple, not me. */
/* Ditto for the consoles. Complain to Sony or MS, not me. */
#ifndef LUAJIT_ENABLE_JIT
#define LJ_OS_NOJIT 1
#endif
#endif
/* Disable or enable the JIT compiler. */
#if defined(LUAJIT_DISABLE_JIT) || defined(LJ_ARCH_NOJIT) || defined(LJ_OS_NOJIT)
#define LJ_HASJIT 0
#else
#define LJ_HASJIT 1
#endif
/* Disable or enable the FFI extension. */
#if defined(LUAJIT_DISABLE_FFI) || defined(LJ_ARCH_NOFFI)
#define LJ_HASFFI 0
#else
#define LJ_HASFFI 1
#endif
#ifndef LJ_ARCH_HASFPU
#define LJ_ARCH_HASFPU 1
#endif
#ifndef LJ_ABI_SOFTFP
#define LJ_ABI_SOFTFP 0
#endif
#define LJ_SOFTFP (!LJ_ARCH_HASFPU)
#if LJ_ARCH_ENDIAN == LUAJIT_BE
#define LJ_LE 0
#define LJ_BE 1
#define LJ_ENDIAN_SELECT(le, be) be
#define LJ_ENDIAN_LOHI(lo, hi) hi lo
#else
#define LJ_LE 1
#define LJ_BE 0
#define LJ_ENDIAN_SELECT(le, be) le
#define LJ_ENDIAN_LOHI(lo, hi) lo hi
#endif
#if LJ_ARCH_BITS == 32
#define LJ_32 1
#define LJ_64 0
#else
#define LJ_32 0
#define LJ_64 1
#endif
#ifndef LJ_TARGET_UNALIGNED
#define LJ_TARGET_UNALIGNED 0
#endif
/* Various workarounds for embedded operating systems. */
#if (defined(__ANDROID__) && !defined(LJ_TARGET_X86ORX64)) || defined(__symbian__) || LJ_TARGET_XBOX360
#define LUAJIT_NO_LOG2
#endif
#if defined(__symbian__)
#define LUAJIT_NO_EXP2
#endif
#if LJ_TARGET_CONSOLE || (LJ_TARGET_IOS && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0)
#define LJ_NO_SYSTEM 1
#endif
#if !defined(LUAJIT_NO_UNWIND) && __GNU_COMPACT_EH__
/* NYI: no support for compact unwind specification, yet. */
#define LUAJIT_NO_UNWIND 1
#endif
#if defined(LUAJIT_NO_UNWIND) || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4
#define LJ_NO_UNWIND 1
#endif
/* Compatibility with Lua 5.1 vs. 5.2. */
#ifdef LUAJIT_ENABLE_LUA52COMPAT
#define LJ_52 1
#else
#define LJ_52 0
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
/*
** IR assembler (SSA IR -> machine code).
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_ASM_H
#define _LJ_ASM_H
#include "lj_jit.h"
#if LJ_HASJIT
LJ_FUNC void lj_asm_trace(jit_State *J, GCtrace *T);
LJ_FUNC void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno,
MCode *target);
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +0,0 @@
/*
** Bytecode instruction modes.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_bc_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_bc.h"
/* Bytecode offsets and bytecode instruction modes. */
#include "lj_bcdef.h"

View File

@ -1,261 +0,0 @@
/*
** Bytecode instruction format.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_BC_H
#define _LJ_BC_H
#include "lj_def.h"
#include "lj_arch.h"
/* Bytecode instruction format, 32 bit wide, fields of 8 or 16 bit:
**
** +----+----+----+----+
** | B | C | A | OP | Format ABC
** +----+----+----+----+
** | D | A | OP | Format AD
** +--------------------
** MSB LSB
**
** In-memory instructions are always stored in host byte order.
*/
/* Operand ranges and related constants. */
#define BCMAX_A 0xff
#define BCMAX_B 0xff
#define BCMAX_C 0xff
#define BCMAX_D 0xffff
#define BCBIAS_J 0x8000
#define NO_REG BCMAX_A
#define NO_JMP (~(BCPos)0)
/* Macros to get instruction fields. */
#define bc_op(i) ((BCOp)((i)&0xff))
#define bc_a(i) ((BCReg)(((i)>>8)&0xff))
#define bc_b(i) ((BCReg)((i)>>24))
#define bc_c(i) ((BCReg)(((i)>>16)&0xff))
#define bc_d(i) ((BCReg)((i)>>16))
#define bc_j(i) ((ptrdiff_t)bc_d(i)-BCBIAS_J)
/* Macros to set instruction fields. */
#define setbc_byte(p, x, ofs) \
((uint8_t *)(p))[LJ_ENDIAN_SELECT(ofs, 3-ofs)] = (uint8_t)(x)
#define setbc_op(p, x) setbc_byte(p, (x), 0)
#define setbc_a(p, x) setbc_byte(p, (x), 1)
#define setbc_b(p, x) setbc_byte(p, (x), 3)
#define setbc_c(p, x) setbc_byte(p, (x), 2)
#define setbc_d(p, x) \
((uint16_t *)(p))[LJ_ENDIAN_SELECT(1, 0)] = (uint16_t)(x)
#define setbc_j(p, x) setbc_d(p, (BCPos)((int32_t)(x)+BCBIAS_J))
/* Macros to compose instructions. */
#define BCINS_ABC(o, a, b, c) \
(((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(b)<<24)|((BCIns)(c)<<16))
#define BCINS_AD(o, a, d) \
(((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(d)<<16))
#define BCINS_AJ(o, a, j) BCINS_AD(o, a, (BCPos)((int32_t)(j)+BCBIAS_J))
/* Bytecode instruction definition. Order matters, see below.
**
** (name, filler, Amode, Bmode, Cmode or Dmode, metamethod)
**
** The opcode name suffixes specify the type for RB/RC or RD:
** V = variable slot
** S = string const
** N = number const
** P = primitive type (~itype)
** B = unsigned byte literal
** M = multiple args/results
*/
#define BCDEF(_) \
/* Comparison ops. ORDER OPR. */ \
_(ISLT, var, ___, var, lt) \
_(ISGE, var, ___, var, lt) \
_(ISLE, var, ___, var, le) \
_(ISGT, var, ___, var, le) \
\
_(ISEQV, var, ___, var, eq) \
_(ISNEV, var, ___, var, eq) \
_(ISEQS, var, ___, str, eq) \
_(ISNES, var, ___, str, eq) \
_(ISEQN, var, ___, num, eq) \
_(ISNEN, var, ___, num, eq) \
_(ISEQP, var, ___, pri, eq) \
_(ISNEP, var, ___, pri, eq) \
\
/* Unary test and copy ops. */ \
_(ISTC, dst, ___, var, ___) \
_(ISFC, dst, ___, var, ___) \
_(IST, ___, ___, var, ___) \
_(ISF, ___, ___, var, ___) \
\
/* Unary ops. */ \
_(MOV, dst, ___, var, ___) \
_(NOT, dst, ___, var, ___) \
_(UNM, dst, ___, var, unm) \
_(LEN, dst, ___, var, len) \
\
/* Binary ops. ORDER OPR. VV last, POW must be next. */ \
_(ADDVN, dst, var, num, add) \
_(SUBVN, dst, var, num, sub) \
_(MULVN, dst, var, num, mul) \
_(DIVVN, dst, var, num, div) \
_(MODVN, dst, var, num, mod) \
\
_(ADDNV, dst, var, num, add) \
_(SUBNV, dst, var, num, sub) \
_(MULNV, dst, var, num, mul) \
_(DIVNV, dst, var, num, div) \
_(MODNV, dst, var, num, mod) \
\
_(ADDVV, dst, var, var, add) \
_(SUBVV, dst, var, var, sub) \
_(MULVV, dst, var, var, mul) \
_(DIVVV, dst, var, var, div) \
_(MODVV, dst, var, var, mod) \
\
_(POW, dst, var, var, pow) \
_(CAT, dst, rbase, rbase, concat) \
\
/* Constant ops. */ \
_(KSTR, dst, ___, str, ___) \
_(KCDATA, dst, ___, cdata, ___) \
_(KSHORT, dst, ___, lits, ___) \
_(KNUM, dst, ___, num, ___) \
_(KPRI, dst, ___, pri, ___) \
_(KNIL, base, ___, base, ___) \
\
/* Upvalue and function ops. */ \
_(UGET, dst, ___, uv, ___) \
_(USETV, uv, ___, var, ___) \
_(USETS, uv, ___, str, ___) \
_(USETN, uv, ___, num, ___) \
_(USETP, uv, ___, pri, ___) \
_(UCLO, rbase, ___, jump, ___) \
_(FNEW, dst, ___, func, gc) \
\
/* Table ops. */ \
_(TNEW, dst, ___, lit, gc) \
_(TDUP, dst, ___, tab, gc) \
_(GGET, dst, ___, str, index) \
_(GSET, var, ___, str, newindex) \
_(TGETV, dst, var, var, index) \
_(TGETS, dst, var, str, index) \
_(TGETB, dst, var, lit, index) \
_(TSETV, var, var, var, newindex) \
_(TSETS, var, var, str, newindex) \
_(TSETB, var, var, lit, newindex) \
_(TSETM, base, ___, num, newindex) \
\
/* Calls and vararg handling. T = tail call. */ \
_(CALLM, base, lit, lit, call) \
_(CALL, base, lit, lit, call) \
_(CALLMT, base, ___, lit, call) \
_(CALLT, base, ___, lit, call) \
_(ITERC, base, lit, lit, call) \
_(ITERN, base, lit, lit, call) \
_(VARG, base, lit, lit, ___) \
_(ISNEXT, base, ___, jump, ___) \
\
/* Returns. */ \
_(RETM, base, ___, lit, ___) \
_(RET, rbase, ___, lit, ___) \
_(RET0, rbase, ___, lit, ___) \
_(RET1, rbase, ___, lit, ___) \
\
/* Loops and branches. I/J = interp/JIT, I/C/L = init/call/loop. */ \
_(FORI, base, ___, jump, ___) \
_(JFORI, base, ___, jump, ___) \
\
_(FORL, base, ___, jump, ___) \
_(IFORL, base, ___, jump, ___) \
_(JFORL, base, ___, lit, ___) \
\
_(ITERL, base, ___, jump, ___) \
_(IITERL, base, ___, jump, ___) \
_(JITERL, base, ___, lit, ___) \
\
_(LOOP, rbase, ___, jump, ___) \
_(ILOOP, rbase, ___, jump, ___) \
_(JLOOP, rbase, ___, lit, ___) \
\
_(JMP, rbase, ___, jump, ___) \
\
/* Function headers. I/J = interp/JIT, F/V/C = fixarg/vararg/C func. */ \
_(FUNCF, rbase, ___, ___, ___) \
_(IFUNCF, rbase, ___, ___, ___) \
_(JFUNCF, rbase, ___, lit, ___) \
_(FUNCV, rbase, ___, ___, ___) \
_(IFUNCV, rbase, ___, ___, ___) \
_(JFUNCV, rbase, ___, lit, ___) \
_(FUNCC, rbase, ___, ___, ___) \
_(FUNCCW, rbase, ___, ___, ___)
/* Bytecode opcode numbers. */
typedef enum {
#define BCENUM(name, ma, mb, mc, mt) BC_##name,
BCDEF(BCENUM)
#undef BCENUM
BC__MAX
} BCOp;
LJ_STATIC_ASSERT((int)BC_ISEQV+1 == (int)BC_ISNEV);
LJ_STATIC_ASSERT(((int)BC_ISEQV^1) == (int)BC_ISNEV);
LJ_STATIC_ASSERT(((int)BC_ISEQS^1) == (int)BC_ISNES);
LJ_STATIC_ASSERT(((int)BC_ISEQN^1) == (int)BC_ISNEN);
LJ_STATIC_ASSERT(((int)BC_ISEQP^1) == (int)BC_ISNEP);
LJ_STATIC_ASSERT(((int)BC_ISLT^1) == (int)BC_ISGE);
LJ_STATIC_ASSERT(((int)BC_ISLE^1) == (int)BC_ISGT);
LJ_STATIC_ASSERT(((int)BC_ISLT^3) == (int)BC_ISGT);
LJ_STATIC_ASSERT((int)BC_IST-(int)BC_ISTC == (int)BC_ISF-(int)BC_ISFC);
LJ_STATIC_ASSERT((int)BC_CALLT-(int)BC_CALL == (int)BC_CALLMT-(int)BC_CALLM);
LJ_STATIC_ASSERT((int)BC_CALLMT + 1 == (int)BC_CALLT);
LJ_STATIC_ASSERT((int)BC_RETM + 1 == (int)BC_RET);
LJ_STATIC_ASSERT((int)BC_FORL + 1 == (int)BC_IFORL);
LJ_STATIC_ASSERT((int)BC_FORL + 2 == (int)BC_JFORL);
LJ_STATIC_ASSERT((int)BC_ITERL + 1 == (int)BC_IITERL);
LJ_STATIC_ASSERT((int)BC_ITERL + 2 == (int)BC_JITERL);
LJ_STATIC_ASSERT((int)BC_LOOP + 1 == (int)BC_ILOOP);
LJ_STATIC_ASSERT((int)BC_LOOP + 2 == (int)BC_JLOOP);
LJ_STATIC_ASSERT((int)BC_FUNCF + 1 == (int)BC_IFUNCF);
LJ_STATIC_ASSERT((int)BC_FUNCF + 2 == (int)BC_JFUNCF);
LJ_STATIC_ASSERT((int)BC_FUNCV + 1 == (int)BC_IFUNCV);
LJ_STATIC_ASSERT((int)BC_FUNCV + 2 == (int)BC_JFUNCV);
/* This solves a circular dependency problem, change as needed. */
#define FF_next_N 4
/* Stack slots used by FORI/FORL, relative to operand A. */
enum {
FORL_IDX, FORL_STOP, FORL_STEP, FORL_EXT
};
/* Bytecode operand modes. ORDER BCMode */
typedef enum {
BCMnone, BCMdst, BCMbase, BCMvar, BCMrbase, BCMuv, /* Mode A must be <= 7 */
BCMlit, BCMlits, BCMpri, BCMnum, BCMstr, BCMtab, BCMfunc, BCMjump, BCMcdata,
BCM_max
} BCMode;
#define BCM___ BCMnone
#define bcmode_a(op) ((BCMode)(lj_bc_mode[op] & 7))
#define bcmode_b(op) ((BCMode)((lj_bc_mode[op]>>3) & 15))
#define bcmode_c(op) ((BCMode)((lj_bc_mode[op]>>7) & 15))
#define bcmode_d(op) bcmode_c(op)
#define bcmode_hasd(op) ((lj_bc_mode[op] & (15<<3)) == (BCMnone<<3))
#define bcmode_mm(op) ((MMS)(lj_bc_mode[op]>>11))
#define BCMODE(name, ma, mb, mc, mm) \
(BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)),
#define BCMODE_FF 0
static LJ_AINLINE int bc_isret(BCOp op)
{
return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1);
}
LJ_DATA const uint16_t lj_bc_mode[];
LJ_DATA const uint16_t lj_bc_ofs[];
#endif

View File

@ -1,66 +0,0 @@
/*
** Bytecode dump definitions.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_BCDUMP_H
#define _LJ_BCDUMP_H
#include "lj_obj.h"
#include "lj_lex.h"
/* -- Bytecode dump format ------------------------------------------------ */
/*
** dump = header proto+ 0U
** header = ESC 'L' 'J' versionB flagsU [namelenU nameB*]
** proto = lengthU pdata
** pdata = phead bcinsW* uvdataH* kgc* knum* [debugB*]
** phead = flagsB numparamsB framesizeB numuvB numkgcU numknU numbcU
** [debuglenU [firstlineU numlineU]]
** kgc = kgctypeU { ktab | (loU hiU) | (rloU rhiU iloU ihiU) | strB* }
** knum = intU0 | (loU1 hiU)
** ktab = narrayU nhashU karray* khash*
** karray = ktabk
** khash = ktabk ktabk
** ktabk = ktabtypeU { intU | (loU hiU) | strB* }
**
** B = 8 bit, H = 16 bit, W = 32 bit, U = ULEB128 of W, U0/U1 = ULEB128 of W+1
*/
/* Bytecode dump header. */
#define BCDUMP_HEAD1 0x1b
#define BCDUMP_HEAD2 0x4c
#define BCDUMP_HEAD3 0x4a
/* If you perform *any* kind of private modifications to the bytecode itself
** or to the dump format, you *must* set BCDUMP_VERSION to 0x80 or higher.
*/
#define BCDUMP_VERSION 1
/* Compatibility flags. */
#define BCDUMP_F_BE 0x01
#define BCDUMP_F_STRIP 0x02
#define BCDUMP_F_FFI 0x04
#define BCDUMP_F_KNOWN (BCDUMP_F_FFI*2-1)
/* Type codes for the GC constants of a prototype. Plus length for strings. */
enum {
BCDUMP_KGC_CHILD, BCDUMP_KGC_TAB, BCDUMP_KGC_I64, BCDUMP_KGC_U64,
BCDUMP_KGC_COMPLEX, BCDUMP_KGC_STR
};
/* Type codes for the keys/values of a constant table. */
enum {
BCDUMP_KTAB_NIL, BCDUMP_KTAB_FALSE, BCDUMP_KTAB_TRUE,
BCDUMP_KTAB_INT, BCDUMP_KTAB_NUM, BCDUMP_KTAB_STR
};
/* -- Bytecode reader/writer ---------------------------------------------- */
LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer,
void *data, int strip);
LJ_FUNC GCproto *lj_bcread(LexState *ls);
#endif

View File

@ -1,476 +0,0 @@
/*
** Bytecode reader.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_bcread_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_bc.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lualib.h"
#endif
#include "lj_lex.h"
#include "lj_bcdump.h"
#include "lj_state.h"
/* Reuse some lexer fields for our own purposes. */
#define bcread_flags(ls) ls->level
#define bcread_swap(ls) \
((bcread_flags(ls) & BCDUMP_F_BE) != LJ_BE*BCDUMP_F_BE)
#define bcread_oldtop(L, ls) restorestack(L, ls->lastline)
#define bcread_savetop(L, ls, top) \
ls->lastline = (BCLine)savestack(L, (top))
/* -- Input buffer handling ----------------------------------------------- */
/* Throw reader error. */
static LJ_NOINLINE void bcread_error(LexState *ls, ErrMsg em)
{
lua_State *L = ls->L;
const char *name = ls->chunkarg;
if (*name == BCDUMP_HEAD1) name = "(binary)";
else if (*name == '@' || *name == '=') name++;
lj_str_pushf(L, "%s: %s", name, err2msg(em));
lj_err_throw(L, LUA_ERRSYNTAX);
}
/* Resize input buffer. */
static void bcread_resize(LexState *ls, MSize len)
{
if (ls->sb.sz < len) {
MSize sz = ls->sb.sz * 2;
while (len > sz) sz = sz * 2;
lj_str_resizebuf(ls->L, &ls->sb, sz);
/* Caveat: this may change ls->sb.buf which may affect ls->p. */
}
}
/* Refill buffer if needed. */
static LJ_NOINLINE void bcread_fill(LexState *ls, MSize len, int need)
{
lua_assert(len != 0);
if (len > LJ_MAX_MEM || ls->current < 0)
bcread_error(ls, LJ_ERR_BCBAD);
do {
const char *buf;
size_t size;
if (ls->n) { /* Copy remainder to buffer. */
if (ls->sb.n) { /* Move down in buffer. */
lua_assert(ls->p + ls->n == ls->sb.buf + ls->sb.n);
if (ls->n != ls->sb.n)
memmove(ls->sb.buf, ls->p, ls->n);
} else { /* Copy from buffer provided by reader. */
bcread_resize(ls, len);
memcpy(ls->sb.buf, ls->p, ls->n);
}
ls->p = ls->sb.buf;
}
ls->sb.n = ls->n;
buf = ls->rfunc(ls->L, ls->rdata, &size); /* Get more data from reader. */
if (buf == NULL || size == 0) { /* EOF? */
if (need) bcread_error(ls, LJ_ERR_BCBAD);
ls->current = -1; /* Only bad if we get called again. */
break;
}
if (ls->sb.n) { /* Append to buffer. */
MSize n = ls->sb.n + (MSize)size;
bcread_resize(ls, n < len ? len : n);
memcpy(ls->sb.buf + ls->sb.n, buf, size);
ls->n = ls->sb.n = n;
ls->p = ls->sb.buf;
} else { /* Return buffer provided by reader. */
ls->n = (MSize)size;
ls->p = buf;
}
} while (ls->n < len);
}
/* Need a certain number of bytes. */
static LJ_AINLINE void bcread_need(LexState *ls, MSize len)
{
if (LJ_UNLIKELY(ls->n < len))
bcread_fill(ls, len, 1);
}
/* Want to read up to a certain number of bytes, but may need less. */
static LJ_AINLINE void bcread_want(LexState *ls, MSize len)
{
if (LJ_UNLIKELY(ls->n < len))
bcread_fill(ls, len, 0);
}
#define bcread_dec(ls) check_exp(ls->n > 0, ls->n--)
#define bcread_consume(ls, len) check_exp(ls->n >= (len), ls->n -= (len))
/* Return memory block from buffer. */
static uint8_t *bcread_mem(LexState *ls, MSize len)
{
uint8_t *p = (uint8_t *)ls->p;
bcread_consume(ls, len);
ls->p = (char *)p + len;
return p;
}
/* Copy memory block from buffer. */
static void bcread_block(LexState *ls, void *q, MSize len)
{
memcpy(q, bcread_mem(ls, len), len);
}
/* Read byte from buffer. */
static LJ_AINLINE uint32_t bcread_byte(LexState *ls)
{
bcread_dec(ls);
return (uint32_t)(uint8_t)*ls->p++;
}
/* Read ULEB128 value from buffer. */
static uint32_t bcread_uleb128(LexState *ls)
{
const uint8_t *p = (const uint8_t *)ls->p;
uint32_t v = *p++;
if (LJ_UNLIKELY(v >= 0x80)) {
int sh = 0;
v &= 0x7f;
do {
v |= ((*p & 0x7f) << (sh += 7));
bcread_dec(ls);
} while (*p++ >= 0x80);
}
bcread_dec(ls);
ls->p = (char *)p;
return v;
}
/* Read top 32 bits of 33 bit ULEB128 value from buffer. */
static uint32_t bcread_uleb128_33(LexState *ls)
{
const uint8_t *p = (const uint8_t *)ls->p;
uint32_t v = (*p++ >> 1);
if (LJ_UNLIKELY(v >= 0x40)) {
int sh = -1;
v &= 0x3f;
do {
v |= ((*p & 0x7f) << (sh += 7));
bcread_dec(ls);
} while (*p++ >= 0x80);
}
bcread_dec(ls);
ls->p = (char *)p;
return v;
}
/* -- Bytecode reader ----------------------------------------------------- */
/* Read debug info of a prototype. */
static void bcread_dbg(LexState *ls, GCproto *pt, MSize sizedbg)
{
void *lineinfo = (void *)proto_lineinfo(pt);
bcread_block(ls, lineinfo, sizedbg);
/* Swap lineinfo if the endianess differs. */
if (bcread_swap(ls) && pt->numline >= 256) {
MSize i, n = pt->sizebc-1;
if (pt->numline < 65536) {
uint16_t *p = (uint16_t *)lineinfo;
for (i = 0; i < n; i++) p[i] = (uint16_t)((p[i] >> 8)|(p[i] << 8));
} else {
uint32_t *p = (uint32_t *)lineinfo;
for (i = 0; i < n; i++) p[i] = lj_bswap(p[i]);
}
}
}
/* Find pointer to varinfo. */
static const void *bcread_varinfo(GCproto *pt)
{
const uint8_t *p = proto_uvinfo(pt);
MSize n = pt->sizeuv;
if (n) while (*p++ || --n) ;
return p;
}
/* Read a single constant key/value of a template table. */
static void bcread_ktabk(LexState *ls, TValue *o)
{
MSize tp = bcread_uleb128(ls);
if (tp >= BCDUMP_KTAB_STR) {
MSize len = tp - BCDUMP_KTAB_STR;
const char *p = (const char *)bcread_mem(ls, len);
setstrV(ls->L, o, lj_str_new(ls->L, p, len));
} else if (tp == BCDUMP_KTAB_INT) {
setintV(o, (int32_t)bcread_uleb128(ls));
} else if (tp == BCDUMP_KTAB_NUM) {
o->u32.lo = bcread_uleb128(ls);
o->u32.hi = bcread_uleb128(ls);
} else {
lua_assert(tp <= BCDUMP_KTAB_TRUE);
setitype(o, ~tp);
}
}
/* Read a template table. */
static GCtab *bcread_ktab(LexState *ls)
{
MSize narray = bcread_uleb128(ls);
MSize nhash = bcread_uleb128(ls);
GCtab *t = lj_tab_new(ls->L, narray, hsize2hbits(nhash));
if (narray) { /* Read array entries. */
MSize i;
TValue *o = tvref(t->array);
for (i = 0; i < narray; i++, o++)
bcread_ktabk(ls, o);
}
if (nhash) { /* Read hash entries. */
MSize i;
for (i = 0; i < nhash; i++) {
TValue key;
bcread_ktabk(ls, &key);
lua_assert(!tvisnil(&key));
bcread_ktabk(ls, lj_tab_set(ls->L, t, &key));
}
}
return t;
}
/* Read GC constants of a prototype. */
static void bcread_kgc(LexState *ls, GCproto *pt, MSize sizekgc)
{
MSize i;
GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc;
for (i = 0; i < sizekgc; i++, kr++) {
MSize tp = bcread_uleb128(ls);
if (tp >= BCDUMP_KGC_STR) {
MSize len = tp - BCDUMP_KGC_STR;
const char *p = (const char *)bcread_mem(ls, len);
setgcref(*kr, obj2gco(lj_str_new(ls->L, p, len)));
} else if (tp == BCDUMP_KGC_TAB) {
setgcref(*kr, obj2gco(bcread_ktab(ls)));
#if LJ_HASFFI
} else if (tp != BCDUMP_KGC_CHILD) {
CTypeID id = tp == BCDUMP_KGC_COMPLEX ? CTID_COMPLEX_DOUBLE :
tp == BCDUMP_KGC_I64 ? CTID_INT64 : CTID_UINT64;
CTSize sz = tp == BCDUMP_KGC_COMPLEX ? 16 : 8;
GCcdata *cd = lj_cdata_new_(ls->L, id, sz);
TValue *p = (TValue *)cdataptr(cd);
setgcref(*kr, obj2gco(cd));
p[0].u32.lo = bcread_uleb128(ls);
p[0].u32.hi = bcread_uleb128(ls);
if (tp == BCDUMP_KGC_COMPLEX) {
p[1].u32.lo = bcread_uleb128(ls);
p[1].u32.hi = bcread_uleb128(ls);
}
#endif
} else {
lua_State *L = ls->L;
lua_assert(tp == BCDUMP_KGC_CHILD);
if (L->top <= bcread_oldtop(L, ls)) /* Stack underflow? */
bcread_error(ls, LJ_ERR_BCBAD);
L->top--;
setgcref(*kr, obj2gco(protoV(L->top)));
}
}
}
/* Read number constants of a prototype. */
static void bcread_knum(LexState *ls, GCproto *pt, MSize sizekn)
{
MSize i;
TValue *o = mref(pt->k, TValue);
for (i = 0; i < sizekn; i++, o++) {
int isnum = (ls->p[0] & 1);
uint32_t lo = bcread_uleb128_33(ls);
if (isnum) {
o->u32.lo = lo;
o->u32.hi = bcread_uleb128(ls);
} else {
setintV(o, lo);
}
}
}
/* Read bytecode instructions. */
static void bcread_bytecode(LexState *ls, GCproto *pt, MSize sizebc)
{
BCIns *bc = proto_bc(pt);
bc[0] = BCINS_AD((pt->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF,
pt->framesize, 0);
bcread_block(ls, bc+1, (sizebc-1)*(MSize)sizeof(BCIns));
/* Swap bytecode instructions if the endianess differs. */
if (bcread_swap(ls)) {
MSize i;
for (i = 1; i < sizebc; i++) bc[i] = lj_bswap(bc[i]);
}
}
/* Read upvalue refs. */
static void bcread_uv(LexState *ls, GCproto *pt, MSize sizeuv)
{
if (sizeuv) {
uint16_t *uv = proto_uv(pt);
bcread_block(ls, uv, sizeuv*2);
/* Swap upvalue refs if the endianess differs. */
if (bcread_swap(ls)) {
MSize i;
for (i = 0; i < sizeuv; i++)
uv[i] = (uint16_t)((uv[i] >> 8)|(uv[i] << 8));
}
}
}
/* Read a prototype. */
static GCproto *bcread_proto(LexState *ls)
{
GCproto *pt;
MSize framesize, numparams, flags, sizeuv, sizekgc, sizekn, sizebc, sizept;
MSize ofsk, ofsuv, ofsdbg;
MSize sizedbg = 0;
BCLine firstline = 0, numline = 0;
MSize len, startn;
/* Read length. */
if (ls->n > 0 && ls->p[0] == 0) { /* Shortcut EOF. */
ls->n--; ls->p++;
return NULL;
}
bcread_want(ls, 5);
len = bcread_uleb128(ls);
if (!len) return NULL; /* EOF */
bcread_need(ls, len);
startn = ls->n;
/* Read prototype header. */
flags = bcread_byte(ls);
numparams = bcread_byte(ls);
framesize = bcread_byte(ls);
sizeuv = bcread_byte(ls);
sizekgc = bcread_uleb128(ls);
sizekn = bcread_uleb128(ls);
sizebc = bcread_uleb128(ls) + 1;
if (!(bcread_flags(ls) & BCDUMP_F_STRIP)) {
sizedbg = bcread_uleb128(ls);
if (sizedbg) {
firstline = bcread_uleb128(ls);
numline = bcread_uleb128(ls);
}
}
/* Calculate total size of prototype including all colocated arrays. */
sizept = (MSize)sizeof(GCproto) +
sizebc*(MSize)sizeof(BCIns) +
sizekgc*(MSize)sizeof(GCRef);
sizept = (sizept + (MSize)sizeof(TValue)-1) & ~((MSize)sizeof(TValue)-1);
ofsk = sizept; sizept += sizekn*(MSize)sizeof(TValue);
ofsuv = sizept; sizept += ((sizeuv+1)&~1)*2;
ofsdbg = sizept; sizept += sizedbg;
/* Allocate prototype object and initialize its fields. */
pt = (GCproto *)lj_mem_newgco(ls->L, (MSize)sizept);
pt->gct = ~LJ_TPROTO;
pt->numparams = (uint8_t)numparams;
pt->framesize = (uint8_t)framesize;
pt->sizebc = sizebc;
setmref(pt->k, (char *)pt + ofsk);
setmref(pt->uv, (char *)pt + ofsuv);
pt->sizekgc = 0; /* Set to zero until fully initialized. */
pt->sizekn = sizekn;
pt->sizept = sizept;
pt->sizeuv = (uint8_t)sizeuv;
pt->flags = (uint8_t)flags;
pt->trace = 0;
setgcref(pt->chunkname, obj2gco(ls->chunkname));
/* Close potentially uninitialized gap between bc and kgc. */
*(uint32_t *)((char *)pt + ofsk - sizeof(GCRef)*(sizekgc+1)) = 0;
/* Read bytecode instructions and upvalue refs. */
bcread_bytecode(ls, pt, sizebc);
bcread_uv(ls, pt, sizeuv);
/* Read constants. */
bcread_kgc(ls, pt, sizekgc);
pt->sizekgc = sizekgc;
bcread_knum(ls, pt, sizekn);
/* Read and initialize debug info. */
pt->firstline = firstline;
pt->numline = numline;
if (sizedbg) {
MSize sizeli = (sizebc-1) << (numline < 256 ? 0 : numline < 65536 ? 1 : 2);
setmref(pt->lineinfo, (char *)pt + ofsdbg);
setmref(pt->uvinfo, (char *)pt + ofsdbg + sizeli);
bcread_dbg(ls, pt, sizedbg);
setmref(pt->varinfo, bcread_varinfo(pt));
} else {
setmref(pt->lineinfo, NULL);
setmref(pt->uvinfo, NULL);
setmref(pt->varinfo, NULL);
}
if (len != startn - ls->n)
bcread_error(ls, LJ_ERR_BCBAD);
return pt;
}
/* Read and check header of bytecode dump. */
static int bcread_header(LexState *ls)
{
uint32_t flags;
bcread_want(ls, 3+5+5);
if (bcread_byte(ls) != BCDUMP_HEAD2 ||
bcread_byte(ls) != BCDUMP_HEAD3 ||
bcread_byte(ls) != BCDUMP_VERSION) return 0;
bcread_flags(ls) = flags = bcread_uleb128(ls);
if ((flags & ~(BCDUMP_F_KNOWN)) != 0) return 0;
if ((flags & BCDUMP_F_FFI)) {
#if LJ_HASFFI
lua_State *L = ls->L;
if (!ctype_ctsG(G(L))) {
ptrdiff_t oldtop = savestack(L, L->top);
luaopen_ffi(L); /* Load FFI library on-demand. */
L->top = restorestack(L, oldtop);
}
#else
return 0;
#endif
}
if ((flags & BCDUMP_F_STRIP)) {
ls->chunkname = lj_str_newz(ls->L, ls->chunkarg);
} else {
MSize len = bcread_uleb128(ls);
bcread_need(ls, len);
ls->chunkname = lj_str_new(ls->L, (const char *)bcread_mem(ls, len), len);
}
return 1; /* Ok. */
}
/* Read a bytecode dump. */
GCproto *lj_bcread(LexState *ls)
{
lua_State *L = ls->L;
lua_assert(ls->current == BCDUMP_HEAD1);
bcread_savetop(L, ls, L->top);
lj_str_resetbuf(&ls->sb);
/* Check for a valid bytecode dump header. */
if (!bcread_header(ls))
bcread_error(ls, LJ_ERR_BCFMT);
for (;;) { /* Process all prototypes in the bytecode dump. */
GCproto *pt = bcread_proto(ls);
if (!pt) break;
setprotoV(L, L->top, pt);
incr_top(L);
}
if ((int32_t)ls->n > 0 || L->top-1 != bcread_oldtop(L, ls))
bcread_error(ls, LJ_ERR_BCBAD);
/* Pop off last prototype. */
L->top--;
return protoV(L->top);
}

View File

@ -1,396 +0,0 @@
/*
** Bytecode writer.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_bcwrite_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_str.h"
#include "lj_bc.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#endif
#if LJ_HASJIT
#include "lj_dispatch.h"
#include "lj_jit.h"
#endif
#include "lj_bcdump.h"
#include "lj_vm.h"
/* Context for bytecode writer. */
typedef struct BCWriteCtx {
SBuf sb; /* Output buffer. */
lua_State *L; /* Lua state. */
GCproto *pt; /* Root prototype. */
lua_Writer wfunc; /* Writer callback. */
void *wdata; /* Writer callback data. */
int strip; /* Strip debug info. */
int status; /* Status from writer callback. */
} BCWriteCtx;
/* -- Output buffer handling ---------------------------------------------- */
/* Resize buffer if needed. */
static LJ_NOINLINE void bcwrite_resize(BCWriteCtx *ctx, MSize len)
{
MSize sz = ctx->sb.sz * 2;
while (ctx->sb.n + len > sz) sz = sz * 2;
lj_str_resizebuf(ctx->L, &ctx->sb, sz);
}
/* Need a certain amount of buffer space. */
static LJ_AINLINE void bcwrite_need(BCWriteCtx *ctx, MSize len)
{
if (LJ_UNLIKELY(ctx->sb.n + len > ctx->sb.sz))
bcwrite_resize(ctx, len);
}
/* Add memory block to buffer. */
static void bcwrite_block(BCWriteCtx *ctx, const void *p, MSize len)
{
uint8_t *q = (uint8_t *)(ctx->sb.buf + ctx->sb.n);
MSize i;
ctx->sb.n += len;
for (i = 0; i < len; i++) q[i] = ((uint8_t *)p)[i];
}
/* Add byte to buffer. */
static LJ_AINLINE void bcwrite_byte(BCWriteCtx *ctx, uint8_t b)
{
ctx->sb.buf[ctx->sb.n++] = b;
}
/* Add ULEB128 value to buffer. */
static void bcwrite_uleb128(BCWriteCtx *ctx, uint32_t v)
{
MSize n = ctx->sb.n;
uint8_t *p = (uint8_t *)ctx->sb.buf;
for (; v >= 0x80; v >>= 7)
p[n++] = (uint8_t)((v & 0x7f) | 0x80);
p[n++] = (uint8_t)v;
ctx->sb.n = n;
}
/* -- Bytecode writer ----------------------------------------------------- */
/* Write a single constant key/value of a template table. */
static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow)
{
bcwrite_need(ctx, 1+10);
if (tvisstr(o)) {
const GCstr *str = strV(o);
MSize len = str->len;
bcwrite_need(ctx, 5+len);
bcwrite_uleb128(ctx, BCDUMP_KTAB_STR+len);
bcwrite_block(ctx, strdata(str), len);
} else if (tvisint(o)) {
bcwrite_byte(ctx, BCDUMP_KTAB_INT);
bcwrite_uleb128(ctx, intV(o));
} else if (tvisnum(o)) {
if (!LJ_DUALNUM && narrow) { /* Narrow number constants to integers. */
lua_Number num = numV(o);
int32_t k = lj_num2int(num);
if (num == (lua_Number)k) { /* -0 is never a constant. */
bcwrite_byte(ctx, BCDUMP_KTAB_INT);
bcwrite_uleb128(ctx, k);
return;
}
}
bcwrite_byte(ctx, BCDUMP_KTAB_NUM);
bcwrite_uleb128(ctx, o->u32.lo);
bcwrite_uleb128(ctx, o->u32.hi);
} else {
lua_assert(tvispri(o));
bcwrite_byte(ctx, BCDUMP_KTAB_NIL+~itype(o));
}
}
/* Write a template table. */
static void bcwrite_ktab(BCWriteCtx *ctx, const GCtab *t)
{
MSize narray = 0, nhash = 0;
if (t->asize > 0) { /* Determine max. length of array part. */
ptrdiff_t i;
TValue *array = tvref(t->array);
for (i = (ptrdiff_t)t->asize-1; i >= 0; i--)
if (!tvisnil(&array[i]))
break;
narray = (MSize)(i+1);
}
if (t->hmask > 0) { /* Count number of used hash slots. */
MSize i, hmask = t->hmask;
Node *node = noderef(t->node);
for (i = 0; i <= hmask; i++)
nhash += !tvisnil(&node[i].val);
}
/* Write number of array slots and hash slots. */
bcwrite_uleb128(ctx, narray);
bcwrite_uleb128(ctx, nhash);
if (narray) { /* Write array entries (may contain nil). */
MSize i;
TValue *o = tvref(t->array);
for (i = 0; i < narray; i++, o++)
bcwrite_ktabk(ctx, o, 1);
}
if (nhash) { /* Write hash entries. */
MSize i = nhash;
Node *node = noderef(t->node) + t->hmask;
for (;; node--)
if (!tvisnil(&node->val)) {
bcwrite_ktabk(ctx, &node->key, 0);
bcwrite_ktabk(ctx, &node->val, 1);
if (--i == 0) break;
}
}
}
/* Write GC constants of a prototype. */
static void bcwrite_kgc(BCWriteCtx *ctx, GCproto *pt)
{
MSize i, sizekgc = pt->sizekgc;
GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc;
for (i = 0; i < sizekgc; i++, kr++) {
GCobj *o = gcref(*kr);
MSize tp, need = 1;
/* Determine constant type and needed size. */
if (o->gch.gct == ~LJ_TSTR) {
tp = BCDUMP_KGC_STR + gco2str(o)->len;
need = 5+gco2str(o)->len;
} else if (o->gch.gct == ~LJ_TPROTO) {
lua_assert((pt->flags & PROTO_CHILD));
tp = BCDUMP_KGC_CHILD;
#if LJ_HASFFI
} else if (o->gch.gct == ~LJ_TCDATA) {
CTypeID id = gco2cd(o)->ctypeid;
need = 1+4*5;
if (id == CTID_INT64) {
tp = BCDUMP_KGC_I64;
} else if (id == CTID_UINT64) {
tp = BCDUMP_KGC_U64;
} else {
lua_assert(id == CTID_COMPLEX_DOUBLE);
tp = BCDUMP_KGC_COMPLEX;
}
#endif
} else {
lua_assert(o->gch.gct == ~LJ_TTAB);
tp = BCDUMP_KGC_TAB;
need = 1+2*5;
}
/* Write constant type. */
bcwrite_need(ctx, need);
bcwrite_uleb128(ctx, tp);
/* Write constant data (if any). */
if (tp >= BCDUMP_KGC_STR) {
bcwrite_block(ctx, strdata(gco2str(o)), gco2str(o)->len);
} else if (tp == BCDUMP_KGC_TAB) {
bcwrite_ktab(ctx, gco2tab(o));
#if LJ_HASFFI
} else if (tp != BCDUMP_KGC_CHILD) {
cTValue *p = (TValue *)cdataptr(gco2cd(o));
bcwrite_uleb128(ctx, p[0].u32.lo);
bcwrite_uleb128(ctx, p[0].u32.hi);
if (tp == BCDUMP_KGC_COMPLEX) {
bcwrite_uleb128(ctx, p[1].u32.lo);
bcwrite_uleb128(ctx, p[1].u32.hi);
}
#endif
}
}
}
/* Write number constants of a prototype. */
static void bcwrite_knum(BCWriteCtx *ctx, GCproto *pt)
{
MSize i, sizekn = pt->sizekn;
cTValue *o = mref(pt->k, TValue);
bcwrite_need(ctx, 10*sizekn);
for (i = 0; i < sizekn; i++, o++) {
int32_t k;
if (tvisint(o)) {
k = intV(o);
goto save_int;
} else {
/* Write a 33 bit ULEB128 for the int (lsb=0) or loword (lsb=1). */
if (!LJ_DUALNUM) { /* Narrow number constants to integers. */
lua_Number num = numV(o);
k = lj_num2int(num);
if (num == (lua_Number)k) { /* -0 is never a constant. */
save_int:
bcwrite_uleb128(ctx, 2*(uint32_t)k | ((uint32_t)k & 0x80000000u));
if (k < 0) {
char *p = &ctx->sb.buf[ctx->sb.n-1];
*p = (*p & 7) | ((k>>27) & 0x18);
}
continue;
}
}
bcwrite_uleb128(ctx, 1+(2*o->u32.lo | (o->u32.lo & 0x80000000u)));
if (o->u32.lo >= 0x80000000u) {
char *p = &ctx->sb.buf[ctx->sb.n-1];
*p = (*p & 7) | ((o->u32.lo>>27) & 0x18);
}
bcwrite_uleb128(ctx, o->u32.hi);
}
}
}
/* Write bytecode instructions. */
static void bcwrite_bytecode(BCWriteCtx *ctx, GCproto *pt)
{
MSize nbc = pt->sizebc-1; /* Omit the [JI]FUNC* header. */
#if LJ_HASJIT
uint8_t *p = (uint8_t *)&ctx->sb.buf[ctx->sb.n];
#endif
bcwrite_block(ctx, proto_bc(pt)+1, nbc*(MSize)sizeof(BCIns));
#if LJ_HASJIT
/* Unpatch modified bytecode containing ILOOP/JLOOP etc. */
if ((pt->flags & PROTO_ILOOP) || pt->trace) {
jit_State *J = L2J(ctx->L);
MSize i;
for (i = 0; i < nbc; i++, p += sizeof(BCIns)) {
BCOp op = (BCOp)p[LJ_ENDIAN_SELECT(0, 3)];
if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP ||
op == BC_JFORI) {
p[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_IFORL+BC_FORL);
} else if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) {
BCReg rd = p[LJ_ENDIAN_SELECT(2, 1)] + (p[LJ_ENDIAN_SELECT(3, 0)] << 8);
BCIns ins = traceref(J, rd)->startins;
p[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_JFORL+BC_FORL);
p[LJ_ENDIAN_SELECT(2, 1)] = bc_c(ins);
p[LJ_ENDIAN_SELECT(3, 0)] = bc_b(ins);
}
}
}
#endif
}
/* Write prototype. */
static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt)
{
MSize sizedbg = 0;
/* Recursively write children of prototype. */
if ((pt->flags & PROTO_CHILD)) {
ptrdiff_t i, n = pt->sizekgc;
GCRef *kr = mref(pt->k, GCRef) - 1;
for (i = 0; i < n; i++, kr--) {
GCobj *o = gcref(*kr);
if (o->gch.gct == ~LJ_TPROTO)
bcwrite_proto(ctx, gco2pt(o));
}
}
/* Start writing the prototype info to a buffer. */
lj_str_resetbuf(&ctx->sb);
ctx->sb.n = 5; /* Leave room for final size. */
bcwrite_need(ctx, 4+6*5+(pt->sizebc-1)*(MSize)sizeof(BCIns)+pt->sizeuv*2);
/* Write prototype header. */
bcwrite_byte(ctx, (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI)));
bcwrite_byte(ctx, pt->numparams);
bcwrite_byte(ctx, pt->framesize);
bcwrite_byte(ctx, pt->sizeuv);
bcwrite_uleb128(ctx, pt->sizekgc);
bcwrite_uleb128(ctx, pt->sizekn);
bcwrite_uleb128(ctx, pt->sizebc-1);
if (!ctx->strip) {
if (proto_lineinfo(pt))
sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt);
bcwrite_uleb128(ctx, sizedbg);
if (sizedbg) {
bcwrite_uleb128(ctx, pt->firstline);
bcwrite_uleb128(ctx, pt->numline);
}
}
/* Write bytecode instructions and upvalue refs. */
bcwrite_bytecode(ctx, pt);
bcwrite_block(ctx, proto_uv(pt), pt->sizeuv*2);
/* Write constants. */
bcwrite_kgc(ctx, pt);
bcwrite_knum(ctx, pt);
/* Write debug info, if not stripped. */
if (sizedbg) {
bcwrite_need(ctx, sizedbg);
bcwrite_block(ctx, proto_lineinfo(pt), sizedbg);
}
/* Pass buffer to writer function. */
if (ctx->status == 0) {
MSize n = ctx->sb.n - 5;
MSize nn = (lj_fls(n)+8)*9 >> 6;
ctx->sb.n = 5 - nn;
bcwrite_uleb128(ctx, n); /* Fill in final size. */
lua_assert(ctx->sb.n == 5);
ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf+5-nn, nn+n, ctx->wdata);
}
}
/* Write header of bytecode dump. */
static void bcwrite_header(BCWriteCtx *ctx)
{
GCstr *chunkname = proto_chunkname(ctx->pt);
const char *name = strdata(chunkname);
MSize len = chunkname->len;
lj_str_resetbuf(&ctx->sb);
bcwrite_need(ctx, 5+5+len);
bcwrite_byte(ctx, BCDUMP_HEAD1);
bcwrite_byte(ctx, BCDUMP_HEAD2);
bcwrite_byte(ctx, BCDUMP_HEAD3);
bcwrite_byte(ctx, BCDUMP_VERSION);
bcwrite_byte(ctx, (ctx->strip ? BCDUMP_F_STRIP : 0) +
(LJ_BE ? BCDUMP_F_BE : 0) +
((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0));
if (!ctx->strip) {
bcwrite_uleb128(ctx, len);
bcwrite_block(ctx, name, len);
}
ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf, ctx->sb.n, ctx->wdata);
}
/* Write footer of bytecode dump. */
static void bcwrite_footer(BCWriteCtx *ctx)
{
if (ctx->status == 0) {
uint8_t zero = 0;
ctx->status = ctx->wfunc(ctx->L, &zero, 1, ctx->wdata);
}
}
/* Protected callback for bytecode writer. */
static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud)
{
BCWriteCtx *ctx = (BCWriteCtx *)ud;
UNUSED(dummy);
lj_str_resizebuf(L, &ctx->sb, 1024); /* Avoids resize for most prototypes. */
bcwrite_header(ctx);
bcwrite_proto(ctx, ctx->pt);
bcwrite_footer(ctx);
return NULL;
}
/* Write bytecode for a prototype. */
int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data,
int strip)
{
BCWriteCtx ctx;
int status;
ctx.L = L;
ctx.pt = pt;
ctx.wfunc = writer;
ctx.wdata = data;
ctx.strip = strip;
ctx.status = 0;
lj_str_initbuf(&ctx.sb);
status = lj_vm_cpcall(L, NULL, &ctx, cpwriter);
if (status == 0) status = ctx.status;
lj_str_freebuf(G(ctx.L), &ctx.sb);
return status;
}

View File

@ -1,353 +0,0 @@
/*
** C data arithmetic.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_tab.h"
#include "lj_meta.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_cdata.h"
#include "lj_carith.h"
/* -- C data arithmetic --------------------------------------------------- */
/* Binary operands of an operator converted to ctypes. */
typedef struct CDArith {
uint8_t *p[2];
CType *ct[2];
} CDArith;
/* Check arguments for arithmetic metamethods. */
static int carith_checkarg(lua_State *L, CTState *cts, CDArith *ca)
{
TValue *o = L->base;
int ok = 1;
MSize i;
if (o+1 >= L->top)
lj_err_argt(L, 1, LUA_TCDATA);
for (i = 0; i < 2; i++, o++) {
if (tviscdata(o)) {
GCcdata *cd = cdataV(o);
CTypeID id = (CTypeID)cd->ctypeid;
CType *ct = ctype_raw(cts, id);
uint8_t *p = (uint8_t *)cdataptr(cd);
if (ctype_isptr(ct->info)) {
p = (uint8_t *)cdata_getptr(p, ct->size);
if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct);
} else if (ctype_isfunc(ct->info)) {
p = (uint8_t *)*(void **)p;
ct = ctype_get(cts,
lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR));
}
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
ca->ct[i] = ct;
ca->p[i] = p;
} else if (tvisint(o)) {
ca->ct[i] = ctype_get(cts, CTID_INT32);
ca->p[i] = (uint8_t *)&o->i;
} else if (tvisnum(o)) {
ca->ct[i] = ctype_get(cts, CTID_DOUBLE);
ca->p[i] = (uint8_t *)&o->n;
} else if (tvisnil(o)) {
ca->ct[i] = ctype_get(cts, CTID_P_VOID);
ca->p[i] = (uint8_t *)0;
} else if (tvisstr(o)) {
TValue *o2 = i == 0 ? o+1 : o-1;
CType *ct = ctype_raw(cts, cdataV(o2)->ctypeid);
ca->ct[i] = NULL;
ca->p[i] = (uint8_t *)strVdata(o);
ok = 0;
if (ctype_isenum(ct->info)) {
CTSize ofs;
CType *cct = lj_ctype_getfield(cts, ct, strV(o), &ofs);
if (cct && ctype_isconstval(cct->info)) {
ca->ct[i] = ctype_child(cts, cct);
ca->p[i] = (uint8_t *)&cct->size; /* Assumes ct does not grow. */
ok = 1;
} else {
ca->ct[1-i] = ct; /* Use enum to improve error message. */
ca->p[1-i] = NULL;
break;
}
}
} else {
ca->ct[i] = NULL;
ca->p[i] = (void *)(intptr_t)1; /* To make it unequal. */
ok = 0;
}
}
return ok;
}
/* Pointer arithmetic. */
static int carith_ptr(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
{
CType *ctp = ca->ct[0];
uint8_t *pp = ca->p[0];
ptrdiff_t idx;
CTSize sz;
CTypeID id;
GCcdata *cd;
if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) {
if ((mm == MM_sub || mm == MM_eq || mm == MM_lt || mm == MM_le) &&
(ctype_isptr(ca->ct[1]->info) || ctype_isrefarray(ca->ct[1]->info))) {
uint8_t *pp2 = ca->p[1];
if (mm == MM_eq) { /* Pointer equality. Incompatible pointers are ok. */
setboolV(L->top-1, (pp == pp2));
return 1;
}
if (!lj_cconv_compatptr(cts, ctp, ca->ct[1], CCF_IGNQUAL))
return 0;
if (mm == MM_sub) { /* Pointer difference. */
intptr_t diff;
sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */
if (sz == 0 || sz == CTSIZE_INVALID)
return 0;
diff = ((intptr_t)pp - (intptr_t)pp2) / (int32_t)sz;
/* All valid pointer differences on x64 are in (-2^47, +2^47),
** which fits into a double without loss of precision.
*/
setintptrV(L->top-1, (int32_t)diff);
return 1;
} else if (mm == MM_lt) { /* Pointer comparison (unsigned). */
setboolV(L->top-1, ((uintptr_t)pp < (uintptr_t)pp2));
return 1;
} else {
lua_assert(mm == MM_le);
setboolV(L->top-1, ((uintptr_t)pp <= (uintptr_t)pp2));
return 1;
}
}
if (!((mm == MM_add || mm == MM_sub) && ctype_isnum(ca->ct[1]->info)))
return 0;
lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ca->ct[1],
(uint8_t *)&idx, ca->p[1], 0);
if (mm == MM_sub) idx = -idx;
} else if (mm == MM_add && ctype_isnum(ctp->info) &&
(ctype_isptr(ca->ct[1]->info) || ctype_isrefarray(ca->ct[1]->info))) {
/* Swap pointer and index. */
ctp = ca->ct[1]; pp = ca->p[1];
lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ca->ct[0],
(uint8_t *)&idx, ca->p[0], 0);
} else {
return 0;
}
sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */
if (sz == CTSIZE_INVALID)
return 0;
pp += idx*(int32_t)sz; /* Compute pointer + index. */
id = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ctp->info)),
CTSIZE_PTR);
cd = lj_cdata_new(cts, id, CTSIZE_PTR);
*(uint8_t **)cdataptr(cd) = pp;
setcdataV(L, L->top-1, cd);
lj_gc_check(L);
return 1;
}
/* 64 bit integer arithmetic. */
static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
{
if (ctype_isnum(ca->ct[0]->info) && ca->ct[0]->size <= 8 &&
ctype_isnum(ca->ct[1]->info) && ca->ct[1]->size <= 8) {
CTypeID id = (((ca->ct[0]->info & CTF_UNSIGNED) && ca->ct[0]->size == 8) ||
((ca->ct[1]->info & CTF_UNSIGNED) && ca->ct[1]->size == 8)) ?
CTID_UINT64 : CTID_INT64;
CType *ct = ctype_get(cts, id);
GCcdata *cd;
uint64_t u0, u1, *up;
lj_cconv_ct_ct(cts, ct, ca->ct[0], (uint8_t *)&u0, ca->p[0], 0);
if (mm != MM_unm)
lj_cconv_ct_ct(cts, ct, ca->ct[1], (uint8_t *)&u1, ca->p[1], 0);
switch (mm) {
case MM_eq:
setboolV(L->top-1, (u0 == u1));
return 1;
case MM_lt:
setboolV(L->top-1,
id == CTID_INT64 ? ((int64_t)u0 < (int64_t)u1) : (u0 < u1));
return 1;
case MM_le:
setboolV(L->top-1,
id == CTID_INT64 ? ((int64_t)u0 <= (int64_t)u1) : (u0 <= u1));
return 1;
default: break;
}
cd = lj_cdata_new(cts, id, 8);
up = (uint64_t *)cdataptr(cd);
setcdataV(L, L->top-1, cd);
switch (mm) {
case MM_add: *up = u0 + u1; break;
case MM_sub: *up = u0 - u1; break;
case MM_mul: *up = u0 * u1; break;
case MM_div:
if (id == CTID_INT64)
*up = (uint64_t)lj_carith_divi64((int64_t)u0, (int64_t)u1);
else
*up = lj_carith_divu64(u0, u1);
break;
case MM_mod:
if (id == CTID_INT64)
*up = (uint64_t)lj_carith_modi64((int64_t)u0, (int64_t)u1);
else
*up = lj_carith_modu64(u0, u1);
break;
case MM_pow:
if (id == CTID_INT64)
*up = (uint64_t)lj_carith_powi64((int64_t)u0, (int64_t)u1);
else
*up = lj_carith_powu64(u0, u1);
break;
case MM_unm: *up = (uint64_t)-(int64_t)u0; break;
default: lua_assert(0); break;
}
lj_gc_check(L);
return 1;
}
return 0;
}
/* Handle ctype arithmetic metamethods. */
static int lj_carith_meta(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
{
cTValue *tv = NULL;
if (tviscdata(L->base)) {
CTypeID id = cdataV(L->base)->ctypeid;
CType *ct = ctype_raw(cts, id);
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
tv = lj_ctype_meta(cts, id, mm);
}
if (!tv && L->base+1 < L->top && tviscdata(L->base+1)) {
CTypeID id = cdataV(L->base+1)->ctypeid;
CType *ct = ctype_raw(cts, id);
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
tv = lj_ctype_meta(cts, id, mm);
}
if (!tv) {
const char *repr[2];
int i, isenum = -1, isstr = -1;
if (mm == MM_eq) { /* Equality checks never raise an error. */
int eq = ca->p[0] == ca->p[1];
setboolV(L->top-1, eq);
setboolV(&G(L)->tmptv2, eq); /* Remember for trace recorder. */
return 1;
}
for (i = 0; i < 2; i++) {
if (ca->ct[i] && tviscdata(L->base+i)) {
if (ctype_isenum(ca->ct[i]->info)) isenum = i;
repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca->ct[i]), NULL));
} else {
if (tvisstr(&L->base[i])) isstr = i;
repr[i] = lj_typename(&L->base[i]);
}
}
if ((isenum ^ isstr) == 1)
lj_err_callerv(L, LJ_ERR_FFI_BADCONV, repr[isstr], repr[isenum]);
lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN :
mm == MM_concat ? LJ_ERR_FFI_BADCONCAT :
mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH,
repr[0], repr[1]);
}
return lj_meta_tailcall(L, tv);
}
/* Arithmetic operators for cdata. */
int lj_carith_op(lua_State *L, MMS mm)
{
CTState *cts = ctype_cts(L);
CDArith ca;
if (carith_checkarg(L, cts, &ca)) {
if (carith_int64(L, cts, &ca, mm) || carith_ptr(L, cts, &ca, mm)) {
copyTV(L, &G(L)->tmptv2, L->top-1); /* Remember for trace recorder. */
return 1;
}
}
return lj_carith_meta(L, cts, &ca, mm);
}
/* -- 64 bit integer arithmetic helpers ----------------------------------- */
#if LJ_32 && LJ_HASJIT
/* Signed/unsigned 64 bit multiplication. */
int64_t lj_carith_mul64(int64_t a, int64_t b)
{
return a * b;
}
#endif
/* Unsigned 64 bit division. */
uint64_t lj_carith_divu64(uint64_t a, uint64_t b)
{
if (b == 0) return U64x(80000000,00000000);
return a / b;
}
/* Signed 64 bit division. */
int64_t lj_carith_divi64(int64_t a, int64_t b)
{
if (b == 0 || (a == (int64_t)U64x(80000000,00000000) && b == -1))
return U64x(80000000,00000000);
return a / b;
}
/* Unsigned 64 bit modulo. */
uint64_t lj_carith_modu64(uint64_t a, uint64_t b)
{
if (b == 0) return U64x(80000000,00000000);
return a % b;
}
/* Signed 64 bit modulo. */
int64_t lj_carith_modi64(int64_t a, int64_t b)
{
if (b == 0) return U64x(80000000,00000000);
if (a == (int64_t)U64x(80000000,00000000) && b == -1) return 0;
return a % b;
}
/* Unsigned 64 bit x^k. */
uint64_t lj_carith_powu64(uint64_t x, uint64_t k)
{
uint64_t y;
if (k == 0)
return 1;
for (; (k & 1) == 0; k >>= 1) x *= x;
y = x;
if ((k >>= 1) != 0) {
for (;;) {
x *= x;
if (k == 1) break;
if (k & 1) y *= x;
k >>= 1;
}
y *= x;
}
return y;
}
/* Signed 64 bit x^k. */
int64_t lj_carith_powi64(int64_t x, int64_t k)
{
if (k == 0)
return 1;
if (k < 0) {
if (x == 0)
return U64x(7fffffff,ffffffff);
else if (x == 1)
return 1;
else if (x == -1)
return (k & 1) ? -1 : 1;
else
return 0;
}
return (int64_t)lj_carith_powu64((uint64_t)x, (uint64_t)k);
}
#endif

View File

@ -1,27 +0,0 @@
/*
** C data arithmetic.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CARITH_H
#define _LJ_CARITH_H
#include "lj_obj.h"
#if LJ_HASFFI
LJ_FUNC int lj_carith_op(lua_State *L, MMS mm);
#if LJ_32 && LJ_HASJIT
LJ_FUNC int64_t lj_carith_mul64(int64_t x, int64_t k);
#endif
LJ_FUNC uint64_t lj_carith_divu64(uint64_t a, uint64_t b);
LJ_FUNC int64_t lj_carith_divi64(int64_t a, int64_t b);
LJ_FUNC uint64_t lj_carith_modu64(uint64_t a, uint64_t b);
LJ_FUNC int64_t lj_carith_modi64(int64_t a, int64_t b);
LJ_FUNC uint64_t lj_carith_powu64(uint64_t x, uint64_t k);
LJ_FUNC int64_t lj_carith_powi64(int64_t x, int64_t k);
#endif
#endif

View File

@ -1,900 +0,0 @@
/*
** FFI C call handling.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_cdata.h"
#include "lj_ccall.h"
#include "lj_trace.h"
/* Target-specific handling of register arguments. */
#if LJ_TARGET_X86
/* -- x86 calling conventions --------------------------------------------- */
#if LJ_ABI_WIN
#define CCALL_HANDLE_STRUCTRET \
/* Return structs bigger than 8 by reference (on stack only). */ \
cc->retref = (sz > 8); \
if (cc->retref) cc->stack[nsp++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET CCALL_HANDLE_STRUCTRET
#else
#if LJ_TARGET_OSX
#define CCALL_HANDLE_STRUCTRET \
/* Return structs of size 1, 2, 4 or 8 in registers. */ \
cc->retref = !(sz == 1 || sz == 2 || sz == 4 || sz == 8); \
if (cc->retref) { \
if (ngpr < maxgpr) \
cc->gpr[ngpr++] = (GPRArg)dp; \
else \
cc->stack[nsp++] = (GPRArg)dp; \
} else { /* Struct with single FP field ends up in FPR. */ \
cc->resx87 = ccall_classify_struct(cts, ctr); \
}
#define CCALL_HANDLE_STRUCTRET2 \
if (cc->resx87) sp = (uint8_t *)&cc->fpr[0]; \
memcpy(dp, sp, ctr->size);
#else
#define CCALL_HANDLE_STRUCTRET \
cc->retref = 1; /* Return all structs by reference (in reg or on stack). */ \
if (ngpr < maxgpr) \
cc->gpr[ngpr++] = (GPRArg)dp; \
else \
cc->stack[nsp++] = (GPRArg)dp;
#endif
#define CCALL_HANDLE_COMPLEXRET \
/* Return complex float in GPRs and complex double by reference. */ \
cc->retref = (sz > 8); \
if (cc->retref) { \
if (ngpr < maxgpr) \
cc->gpr[ngpr++] = (GPRArg)dp; \
else \
cc->stack[nsp++] = (GPRArg)dp; \
}
#endif
#define CCALL_HANDLE_COMPLEXRET2 \
if (!cc->retref) \
*(int64_t *)dp = *(int64_t *)sp; /* Copy complex float from GPRs. */
#define CCALL_HANDLE_STRUCTARG \
ngpr = maxgpr; /* Pass all structs by value on the stack. */
#define CCALL_HANDLE_COMPLEXARG \
isfp = 1; /* Pass complex by value on stack. */
#define CCALL_HANDLE_REGARG \
if (!isfp) { /* Only non-FP values may be passed in registers. */ \
if (n > 1) { /* Anything > 32 bit is passed on the stack. */ \
if (!LJ_ABI_WIN) ngpr = maxgpr; /* Prevent reordering. */ \
} else if (ngpr + 1 <= maxgpr) { \
dp = &cc->gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#elif LJ_TARGET_X64 && LJ_ABI_WIN
/* -- Windows/x64 calling conventions ------------------------------------- */
#define CCALL_HANDLE_STRUCTRET \
/* Return structs of size 1, 2, 4 or 8 in a GPR. */ \
cc->retref = !(sz == 1 || sz == 2 || sz == 4 || sz == 8); \
if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET CCALL_HANDLE_STRUCTRET
#define CCALL_HANDLE_COMPLEXRET2 \
if (!cc->retref) \
*(int64_t *)dp = *(int64_t *)sp; /* Copy complex float from GPRs. */
#define CCALL_HANDLE_STRUCTARG \
/* Pass structs of size 1, 2, 4 or 8 in a GPR by value. */ \
if (!(sz == 1 || sz == 2 || sz == 4 || sz == 8)) { \
rp = cdataptr(lj_cdata_new(cts, did, sz)); \
sz = CTSIZE_PTR; /* Pass all other structs by reference. */ \
}
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex float in a GPR and complex double by reference. */ \
if (sz != 2*sizeof(float)) { \
rp = cdataptr(lj_cdata_new(cts, did, sz)); \
sz = CTSIZE_PTR; \
}
/* Windows/x64 argument registers are strictly positional (use ngpr). */
#define CCALL_HANDLE_REGARG \
if (isfp) { \
if (ngpr < maxgpr) { dp = &cc->fpr[ngpr++]; nfpr = ngpr; goto done; } \
} else { \
if (ngpr < maxgpr) { dp = &cc->gpr[ngpr++]; goto done; } \
}
#elif LJ_TARGET_X64
/* -- POSIX/x64 calling conventions --------------------------------------- */
#define CCALL_HANDLE_STRUCTRET \
int rcl[2]; rcl[0] = rcl[1] = 0; \
if (ccall_classify_struct(cts, ctr, rcl, 0)) { \
cc->retref = 1; /* Return struct by reference. */ \
cc->gpr[ngpr++] = (GPRArg)dp; \
} else { \
cc->retref = 0; /* Return small structs in registers. */ \
}
#define CCALL_HANDLE_STRUCTRET2 \
int rcl[2]; rcl[0] = rcl[1] = 0; \
ccall_classify_struct(cts, ctr, rcl, 0); \
ccall_struct_ret(cc, rcl, dp, ctr->size);
#define CCALL_HANDLE_COMPLEXRET \
/* Complex values are returned in one or two FPRs. */ \
cc->retref = 0;
#define CCALL_HANDLE_COMPLEXRET2 \
if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPR. */ \
*(int64_t *)dp = cc->fpr[0].l[0]; \
} else { /* Copy non-contiguous complex double from FPRs. */ \
((int64_t *)dp)[0] = cc->fpr[0].l[0]; \
((int64_t *)dp)[1] = cc->fpr[1].l[0]; \
}
#define CCALL_HANDLE_STRUCTARG \
int rcl[2]; rcl[0] = rcl[1] = 0; \
if (!ccall_classify_struct(cts, d, rcl, 0)) { \
cc->nsp = nsp; cc->ngpr = ngpr; cc->nfpr = nfpr; \
if (ccall_struct_arg(cc, cts, d, rcl, o, narg)) goto err_nyi; \
nsp = cc->nsp; ngpr = cc->ngpr; nfpr = cc->nfpr; \
continue; \
} /* Pass all other structs by value on stack. */
#define CCALL_HANDLE_COMPLEXARG \
isfp = 2; /* Pass complex in FPRs or on stack. Needs postprocessing. */
#define CCALL_HANDLE_REGARG \
if (isfp) { /* Try to pass argument in FPRs. */ \
int n2 = ctype_isvector(d->info) ? 1 : n; \
if (nfpr + n2 <= CCALL_NARG_FPR) { \
dp = &cc->fpr[nfpr]; \
nfpr += n2; \
goto done; \
} \
} else { /* Try to pass argument in GPRs. */ \
/* Note that reordering is explicitly allowed in the x64 ABI. */ \
if (n <= 2 && ngpr + n <= maxgpr) { \
dp = &cc->gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#elif LJ_TARGET_ARM
/* -- ARM calling conventions --------------------------------------------- */
#if LJ_ABI_SOFTFP
#define CCALL_HANDLE_STRUCTRET \
/* Return structs of size <= 4 in a GPR. */ \
cc->retref = !(sz <= 4); \
if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET \
cc->retref = 1; /* Return all complex values by reference. */ \
cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET2 \
UNUSED(dp); /* Nothing to do. */
#define CCALL_HANDLE_STRUCTARG \
/* Pass all structs by value in registers and/or on the stack. */
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex by value in 2 or 4 GPRs. */
#define CCALL_HANDLE_REGARG_FP1
#define CCALL_HANDLE_REGARG_FP2
#else
#define CCALL_HANDLE_STRUCTRET \
cc->retref = !ccall_classify_struct(cts, ctr, ct); \
if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_STRUCTRET2 \
if (ccall_classify_struct(cts, ctr, ct) > 1) sp = (uint8_t *)&cc->fpr[0]; \
memcpy(dp, sp, ctr->size);
#define CCALL_HANDLE_COMPLEXRET \
if (!(ct->info & CTF_VARARG)) cc->retref = 0; /* Return complex in FPRs. */
#define CCALL_HANDLE_COMPLEXRET2 \
if (!(ct->info & CTF_VARARG)) memcpy(dp, &cc->fpr[0], ctr->size);
#define CCALL_HANDLE_STRUCTARG \
isfp = (ccall_classify_struct(cts, d, ct) > 1);
/* Pass all structs by value in registers and/or on the stack. */
#define CCALL_HANDLE_COMPLEXARG \
isfp = 1; /* Pass complex by value in FPRs or on stack. */
#define CCALL_HANDLE_REGARG_FP1 \
if (isfp && !(ct->info & CTF_VARARG)) { \
if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \
if (nfpr + (n >> 1) <= CCALL_NARG_FPR) { \
dp = &cc->fpr[nfpr]; \
nfpr += (n >> 1); \
goto done; \
} \
} else { \
if (sz > 1 && fprodd != nfpr) fprodd = 0; \
if (fprodd) { \
if (2*nfpr+n <= 2*CCALL_NARG_FPR+1) { \
dp = (void *)&cc->fpr[fprodd-1].f[1]; \
nfpr += (n >> 1); \
if ((n & 1)) fprodd = 0; else fprodd = nfpr-1; \
goto done; \
} \
} else { \
if (2*nfpr+n <= 2*CCALL_NARG_FPR) { \
dp = (void *)&cc->fpr[nfpr]; \
nfpr += (n >> 1); \
if ((n & 1)) fprodd = ++nfpr; else fprodd = 0; \
goto done; \
} \
} \
} \
fprodd = 0; /* No reordering after the first FP value is on stack. */ \
} else {
#define CCALL_HANDLE_REGARG_FP2 }
#endif
#define CCALL_HANDLE_REGARG \
CCALL_HANDLE_REGARG_FP1 \
if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \
if (ngpr < maxgpr) \
ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
} \
if (ngpr < maxgpr) { \
dp = &cc->gpr[ngpr]; \
if (ngpr + n > maxgpr) { \
nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \
if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \
ngpr = maxgpr; \
} else { \
ngpr += n; \
} \
goto done; \
} CCALL_HANDLE_REGARG_FP2
#define CCALL_HANDLE_RET \
if ((ct->info & CTF_VARARG)) sp = (uint8_t *)&cc->gpr[0];
#elif LJ_TARGET_PPC
/* -- PPC calling conventions --------------------------------------------- */
#define CCALL_HANDLE_STRUCTRET \
cc->retref = 1; /* Return all structs by reference. */ \
cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET \
/* Complex values are returned in 2 or 4 GPRs. */ \
cc->retref = 0;
#define CCALL_HANDLE_COMPLEXRET2 \
memcpy(dp, sp, ctr->size); /* Copy complex from GPRs. */
#define CCALL_HANDLE_STRUCTARG \
rp = cdataptr(lj_cdata_new(cts, did, sz)); \
sz = CTSIZE_PTR; /* Pass all structs by reference. */
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex by value in 2 or 4 GPRs. */
#define CCALL_HANDLE_REGARG \
if (isfp) { /* Try to pass argument in FPRs. */ \
if (nfpr + 1 <= CCALL_NARG_FPR) { \
dp = &cc->fpr[nfpr]; \
nfpr += 1; \
d = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \
goto done; \
} \
} else { /* Try to pass argument in GPRs. */ \
if (n > 1) { \
lua_assert(n == 2 || n == 4); /* int64_t or complex (float). */ \
if (ctype_isinteger(d->info)) \
ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
else if (ngpr + n > maxgpr) \
ngpr = maxgpr; /* Prevent reordering. */ \
} \
if (ngpr + n <= maxgpr) { \
dp = &cc->gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#define CCALL_HANDLE_RET \
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */
#elif LJ_TARGET_PPCSPE
/* -- PPC/SPE calling conventions ----------------------------------------- */
#define CCALL_HANDLE_STRUCTRET \
cc->retref = 1; /* Return all structs by reference. */ \
cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET \
/* Complex values are returned in 2 or 4 GPRs. */ \
cc->retref = 0;
#define CCALL_HANDLE_COMPLEXRET2 \
memcpy(dp, sp, ctr->size); /* Copy complex from GPRs. */
#define CCALL_HANDLE_STRUCTARG \
rp = cdataptr(lj_cdata_new(cts, did, sz)); \
sz = CTSIZE_PTR; /* Pass all structs by reference. */
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex by value in 2 or 4 GPRs. */
/* PPC/SPE has a softfp ABI. */
#define CCALL_HANDLE_REGARG \
if (n > 1) { /* Doesn't fit in a single GPR? */ \
lua_assert(n == 2 || n == 4); /* int64_t, double or complex (float). */ \
if (n == 2) \
ngpr = (ngpr + 1u) & ~1u; /* Only align 64 bit value to regpair. */ \
else if (ngpr + n > maxgpr) \
ngpr = maxgpr; /* Prevent reordering. */ \
} \
if (ngpr + n <= maxgpr) { \
dp = &cc->gpr[ngpr]; \
ngpr += n; \
goto done; \
}
#elif LJ_TARGET_MIPS
/* -- MIPS calling conventions -------------------------------------------- */
#define CCALL_HANDLE_STRUCTRET \
cc->retref = 1; /* Return all structs by reference. */ \
cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_COMPLEXRET \
/* Complex values are returned in 1 or 2 FPRs. */ \
cc->retref = 0;
#define CCALL_HANDLE_COMPLEXRET2 \
if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \
((float *)dp)[0] = cc->fpr[0].f; \
((float *)dp)[1] = cc->fpr[1].f; \
} else { /* Copy complex double from FPRs. */ \
((double *)dp)[0] = cc->fpr[0].d; \
((double *)dp)[1] = cc->fpr[1].d; \
}
#define CCALL_HANDLE_STRUCTARG \
/* Pass all structs by value in registers and/or on the stack. */
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex by value in 2 or 4 GPRs. */
#define CCALL_HANDLE_REGARG \
if (isfp && nfpr < CCALL_NARG_FPR && !(ct->info & CTF_VARARG)) { \
/* Try to pass argument in FPRs. */ \
dp = n == 1 ? (void *)&cc->fpr[nfpr].f : (void *)&cc->fpr[nfpr].d; \
nfpr++; ngpr += n; \
goto done; \
} else { /* Try to pass argument in GPRs. */ \
nfpr = CCALL_NARG_FPR; \
if ((d->info & CTF_ALIGN) > CTALIGN_PTR) \
ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
if (ngpr < maxgpr) { \
dp = &cc->gpr[ngpr]; \
if (ngpr + n > maxgpr) { \
nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \
if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \
ngpr = maxgpr; \
} else { \
ngpr += n; \
} \
goto done; \
} \
}
#define CCALL_HANDLE_RET \
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
sp = (uint8_t *)&cc->fpr[0].f;
#else
#error "Missing calling convention definitions for this architecture"
#endif
#ifndef CCALL_HANDLE_STRUCTRET2
#define CCALL_HANDLE_STRUCTRET2 \
memcpy(dp, sp, ctr->size); /* Copy struct return value from GPRs. */
#endif
/* -- x86 OSX ABI struct classification ----------------------------------- */
#if LJ_TARGET_X86 && LJ_TARGET_OSX
/* Check for struct with single FP field. */
static int ccall_classify_struct(CTState *cts, CType *ct)
{
CTSize sz = ct->size;
if (!(sz == sizeof(float) || sz == sizeof(double))) return 0;
if ((ct->info & CTF_UNION)) return 0;
while (ct->sib) {
ct = ctype_get(cts, ct->sib);
if (ctype_isfield(ct->info)) {
CType *sct = ctype_rawchild(cts, ct);
if (ctype_isfp(sct->info)) {
if (sct->size == sz)
return (sz >> 2); /* Return 1 for float or 2 for double. */
} else if (ctype_isstruct(sct->info)) {
if (sct->size)
return ccall_classify_struct(cts, sct);
} else {
break;
}
} else if (ctype_isbitfield(ct->info)) {
break;
} else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
CType *sct = ctype_rawchild(cts, ct);
if (sct->size)
return ccall_classify_struct(cts, sct);
}
}
return 0;
}
#endif
/* -- x64 struct classification ------------------------------------------- */
#if LJ_TARGET_X64 && !LJ_ABI_WIN
/* Register classes for x64 struct classification. */
#define CCALL_RCL_INT 1
#define CCALL_RCL_SSE 2
#define CCALL_RCL_MEM 4
/* NYI: classify vectors. */
static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs);
/* Classify a C type. */
static void ccall_classify_ct(CTState *cts, CType *ct, int *rcl, CTSize ofs)
{
if (ctype_isarray(ct->info)) {
CType *cct = ctype_rawchild(cts, ct);
CTSize eofs, esz = cct->size, asz = ct->size;
for (eofs = 0; eofs < asz; eofs += esz)
ccall_classify_ct(cts, cct, rcl, ofs+eofs);
} else if (ctype_isstruct(ct->info)) {
ccall_classify_struct(cts, ct, rcl, ofs);
} else {
int cl = ctype_isfp(ct->info) ? CCALL_RCL_SSE : CCALL_RCL_INT;
lua_assert(ctype_hassize(ct->info));
if ((ofs & (ct->size-1))) cl = CCALL_RCL_MEM; /* Unaligned. */
rcl[(ofs >= 8)] |= cl;
}
}
/* Recursively classify a struct based on its fields. */
static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs)
{
if (ct->size > 16) return CCALL_RCL_MEM; /* Too big, gets memory class. */
while (ct->sib) {
CTSize fofs;
ct = ctype_get(cts, ct->sib);
fofs = ofs+ct->size;
if (ctype_isfield(ct->info))
ccall_classify_ct(cts, ctype_rawchild(cts, ct), rcl, fofs);
else if (ctype_isbitfield(ct->info))
rcl[(fofs >= 8)] |= CCALL_RCL_INT; /* NYI: unaligned bitfields? */
else if (ctype_isxattrib(ct->info, CTA_SUBTYPE))
ccall_classify_struct(cts, ctype_rawchild(cts, ct), rcl, fofs);
}
return ((rcl[0]|rcl[1]) & CCALL_RCL_MEM); /* Memory class? */
}
/* Try to split up a small struct into registers. */
static int ccall_struct_reg(CCallState *cc, GPRArg *dp, int *rcl)
{
MSize ngpr = cc->ngpr, nfpr = cc->nfpr;
uint32_t i;
for (i = 0; i < 2; i++) {
lua_assert(!(rcl[i] & CCALL_RCL_MEM));
if ((rcl[i] & CCALL_RCL_INT)) { /* Integer class takes precedence. */
if (ngpr >= CCALL_NARG_GPR) return 1; /* Register overflow. */
cc->gpr[ngpr++] = dp[i];
} else if ((rcl[i] & CCALL_RCL_SSE)) {
if (nfpr >= CCALL_NARG_FPR) return 1; /* Register overflow. */
cc->fpr[nfpr++].l[0] = dp[i];
}
}
cc->ngpr = ngpr; cc->nfpr = nfpr;
return 0; /* Ok. */
}
/* Pass a small struct argument. */
static int ccall_struct_arg(CCallState *cc, CTState *cts, CType *d, int *rcl,
TValue *o, int narg)
{
GPRArg dp[2];
dp[0] = dp[1] = 0;
/* Convert to temp. struct. */
lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg));
if (ccall_struct_reg(cc, dp, rcl)) { /* Register overflow? Pass on stack. */
MSize nsp = cc->nsp, n = rcl[1] ? 2 : 1;
if (nsp + n > CCALL_MAXSTACK) return 1; /* Too many arguments. */
cc->nsp = nsp + n;
memcpy(&cc->stack[nsp], dp, n*CTSIZE_PTR);
}
return 0; /* Ok. */
}
/* Combine returned small struct. */
static void ccall_struct_ret(CCallState *cc, int *rcl, uint8_t *dp, CTSize sz)
{
GPRArg sp[2];
MSize ngpr = 0, nfpr = 0;
uint32_t i;
for (i = 0; i < 2; i++) {
if ((rcl[i] & CCALL_RCL_INT)) { /* Integer class takes precedence. */
sp[i] = cc->gpr[ngpr++];
} else if ((rcl[i] & CCALL_RCL_SSE)) {
sp[i] = cc->fpr[nfpr++].l[0];
}
}
memcpy(dp, sp, sz);
}
#endif
/* -- ARM hard-float ABI struct classification ---------------------------- */
#if LJ_TARGET_ARM && !LJ_ABI_SOFTFP
/* Classify a struct based on its fields. */
static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf)
{
CTSize sz = ct->size;
unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION);
if ((ctf->info & CTF_VARARG)) goto noth;
while (ct->sib) {
CType *sct;
ct = ctype_get(cts, ct->sib);
if (ctype_isfield(ct->info)) {
sct = ctype_rawchild(cts, ct);
if (ctype_isfp(sct->info)) {
r |= sct->size;
if (!isu) n++; else if (n == 0) n = 1;
} else if (ctype_iscomplex(sct->info)) {
r |= (sct->size >> 1);
if (!isu) n += 2; else if (n < 2) n = 2;
} else if (ctype_isstruct(sct->info)) {
goto substruct;
} else {
goto noth;
}
} else if (ctype_isbitfield(ct->info)) {
goto noth;
} else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
sct = ctype_rawchild(cts, ct);
substruct:
if (sct->size > 0) {
unsigned int s = ccall_classify_struct(cts, sct, ctf);
if (s <= 1) goto noth;
r |= (s & 255);
if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8);
}
}
}
if ((r == 4 || r == 8) && n <= 4)
return r + (n << 8);
noth: /* Not a homogeneous float/double aggregate. */
return (sz <= 4); /* Return structs of size <= 4 in a GPR. */
}
#endif
/* -- Common C call handling ---------------------------------------------- */
/* Infer the destination CTypeID for a vararg argument. */
CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o)
{
if (tvisnumber(o)) {
return CTID_DOUBLE;
} else if (tviscdata(o)) {
CTypeID id = cdataV(o)->ctypeid;
CType *s = ctype_get(cts, id);
if (ctype_isrefarray(s->info)) {
return lj_ctype_intern(cts,
CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(s->info)), CTSIZE_PTR);
} else if (ctype_isstruct(s->info) || ctype_isfunc(s->info)) {
/* NYI: how to pass a struct by value in a vararg argument? */
return lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR);
} else if (ctype_isfp(s->info) && s->size == sizeof(float)) {
return CTID_DOUBLE;
} else {
return id;
}
} else if (tvisstr(o)) {
return CTID_P_CCHAR;
} else if (tvisbool(o)) {
return CTID_BOOL;
} else {
return CTID_P_VOID;
}
}
/* Setup arguments for C call. */
static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
CCallState *cc)
{
int gcsteps = 0;
TValue *o, *top = L->top;
CTypeID fid;
CType *ctr;
MSize maxgpr, ngpr = 0, nsp = 0, narg;
#if CCALL_NARG_FPR
MSize nfpr = 0;
#if LJ_TARGET_ARM
MSize fprodd = 0;
#endif
#endif
/* Clear unused regs to get some determinism in case of misdeclaration. */
memset(cc->gpr, 0, sizeof(cc->gpr));
#if CCALL_NUM_FPR
memset(cc->fpr, 0, sizeof(cc->fpr));
#endif
#if LJ_TARGET_X86
/* x86 has several different calling conventions. */
cc->resx87 = 0;
switch (ctype_cconv(ct->info)) {
case CTCC_FASTCALL: maxgpr = 2; break;
case CTCC_THISCALL: maxgpr = 1; break;
default: maxgpr = 0; break;
}
#else
maxgpr = CCALL_NARG_GPR;
#endif
/* Perform required setup for some result types. */
ctr = ctype_rawchild(cts, ct);
if (ctype_isvector(ctr->info)) {
if (!(CCALL_VECTOR_REG && (ctr->size == 8 || ctr->size == 16)))
goto err_nyi;
} else if (ctype_iscomplex(ctr->info) || ctype_isstruct(ctr->info)) {
/* Preallocate cdata object and anchor it after arguments. */
CTSize sz = ctr->size;
GCcdata *cd = lj_cdata_new(cts, ctype_cid(ct->info), sz);
void *dp = cdataptr(cd);
setcdataV(L, L->top++, cd);
if (ctype_isstruct(ctr->info)) {
CCALL_HANDLE_STRUCTRET
} else {
CCALL_HANDLE_COMPLEXRET
}
#if LJ_TARGET_X86
} else if (ctype_isfp(ctr->info)) {
cc->resx87 = ctr->size == sizeof(float) ? 1 : 2;
#endif
}
/* Skip initial attributes. */
fid = ct->sib;
while (fid) {
CType *ctf = ctype_get(cts, fid);
if (!ctype_isattrib(ctf->info)) break;
fid = ctf->sib;
}
/* Walk through all passed arguments. */
for (o = L->base+1, narg = 1; o < top; o++, narg++) {
CTypeID did;
CType *d;
CTSize sz;
MSize n, isfp = 0, isva = 0;
void *dp, *rp = NULL;
if (fid) { /* Get argument type from field. */
CType *ctf = ctype_get(cts, fid);
fid = ctf->sib;
lua_assert(ctype_isfield(ctf->info));
did = ctype_cid(ctf->info);
} else {
if (!(ct->info & CTF_VARARG))
lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too many arguments. */
did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */
isva = 1;
}
d = ctype_raw(cts, did);
sz = d->size;
/* Find out how (by value/ref) and where (GPR/FPR) to pass an argument. */
if (ctype_isnum(d->info)) {
if (sz > 8) goto err_nyi;
if ((d->info & CTF_FP))
isfp = 1;
} else if (ctype_isvector(d->info)) {
if (CCALL_VECTOR_REG && (sz == 8 || sz == 16))
isfp = 1;
else
goto err_nyi;
} else if (ctype_isstruct(d->info)) {
CCALL_HANDLE_STRUCTARG
} else if (ctype_iscomplex(d->info)) {
CCALL_HANDLE_COMPLEXARG
} else {
sz = CTSIZE_PTR;
}
sz = (sz + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */
CCALL_HANDLE_REGARG /* Handle register arguments. */
/* Otherwise pass argument on stack. */
if (CCALL_ALIGN_STACKARG && !rp && (d->info & CTF_ALIGN) > CTALIGN_PTR) {
MSize align = (1u << ctype_align(d->info-CTALIGN_PTR)) -1;
nsp = (nsp + align) & ~align; /* Align argument on stack. */
}
if (nsp + n > CCALL_MAXSTACK) { /* Too many arguments. */
err_nyi:
lj_err_caller(L, LJ_ERR_FFI_NYICALL);
}
dp = &cc->stack[nsp];
nsp += n;
isva = 0;
done:
if (rp) { /* Pass by reference. */
gcsteps++;
*(void **)dp = rp;
dp = rp;
}
lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg));
/* Extend passed integers to 32 bits at least. */
if (ctype_isinteger_or_bool(d->info) && d->size < 4) {
if (d->info & CTF_UNSIGNED)
*(uint32_t *)dp = d->size == 1 ? (uint32_t)*(uint8_t *)dp :
(uint32_t)*(uint16_t *)dp;
else
*(int32_t *)dp = d->size == 1 ? (int32_t)*(int8_t *)dp :
(int32_t)*(int16_t *)dp;
}
#if LJ_TARGET_X64 && LJ_ABI_WIN
if (isva) { /* Windows/x64 mirrors varargs in both register sets. */
if (nfpr == ngpr)
cc->gpr[ngpr-1] = cc->fpr[ngpr-1].l[0];
else
cc->fpr[ngpr-1].l[0] = cc->gpr[ngpr-1];
}
#else
UNUSED(isva);
#endif
#if LJ_TARGET_X64 && !LJ_ABI_WIN
if (isfp == 2 && n == 2 && (uint8_t *)dp == (uint8_t *)&cc->fpr[nfpr-2]) {
cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */
cc->fpr[nfpr-2].d[1] = 0;
}
#else
UNUSED(isfp);
#endif
}
if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */
#if LJ_TARGET_X64 || LJ_TARGET_PPC
cc->nfpr = nfpr; /* Required for vararg functions. */
#endif
cc->nsp = nsp;
cc->spadj = (CCALL_SPS_FREE + CCALL_SPS_EXTRA)*CTSIZE_PTR;
if (nsp > CCALL_SPS_FREE)
cc->spadj += (((nsp-CCALL_SPS_FREE)*CTSIZE_PTR + 15u) & ~15u);
return gcsteps;
}
/* Get results from C call. */
static int ccall_get_results(lua_State *L, CTState *cts, CType *ct,
CCallState *cc, int *ret)
{
CType *ctr = ctype_rawchild(cts, ct);
uint8_t *sp = (uint8_t *)&cc->gpr[0];
if (ctype_isvoid(ctr->info)) {
*ret = 0; /* Zero results. */
return 0; /* No additional GC step. */
}
*ret = 1; /* One result. */
if (ctype_isstruct(ctr->info)) {
/* Return cdata object which is already on top of stack. */
if (!cc->retref) {
void *dp = cdataptr(cdataV(L->top-1)); /* Use preallocated object. */
CCALL_HANDLE_STRUCTRET2
}
return 1; /* One GC step. */
}
if (ctype_iscomplex(ctr->info)) {
/* Return cdata object which is already on top of stack. */
void *dp = cdataptr(cdataV(L->top-1)); /* Use preallocated object. */
CCALL_HANDLE_COMPLEXRET2
return 1; /* One GC step. */
}
if (LJ_BE && ctype_isinteger_or_bool(ctr->info) && ctr->size < CTSIZE_PTR)
sp += (CTSIZE_PTR - ctr->size);
#if CCALL_NUM_FPR
if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info))
sp = (uint8_t *)&cc->fpr[0];
#endif
#ifdef CCALL_HANDLE_RET
CCALL_HANDLE_RET
#endif
/* No reference types end up here, so there's no need for the CTypeID. */
lua_assert(!(ctype_isrefarray(ctr->info) || ctype_isstruct(ctr->info)));
return lj_cconv_tv_ct(cts, ctr, 0, L->top-1, sp);
}
/* Call C function. */
int lj_ccall_func(lua_State *L, GCcdata *cd)
{
CTState *cts = ctype_cts(L);
CType *ct = ctype_raw(cts, cd->ctypeid);
CTSize sz = CTSIZE_PTR;
if (ctype_isptr(ct->info)) {
sz = ct->size;
ct = ctype_rawchild(cts, ct);
}
if (ctype_isfunc(ct->info)) {
CCallState cc;
int gcsteps, ret;
cc.func = (void (*)(void))cdata_getptr(cdataptr(cd), sz);
gcsteps = ccall_set_args(L, cts, ct, &cc);
ct = (CType *)((intptr_t)ct-(intptr_t)cts->tab);
cts->cb.slot = ~0u;
lj_vm_ffi_call(&cc);
if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */
TValue tv;
setlightudV(&tv, (void *)cc.func);
setboolV(lj_tab_set(L, cts->miscmap, &tv), 1);
}
ct = (CType *)((intptr_t)ct+(intptr_t)cts->tab); /* May be reallocated. */
gcsteps += ccall_get_results(L, cts, ct, &cc, &ret);
#if LJ_TARGET_X86 && LJ_ABI_WIN
/* Automatically detect __stdcall and fix up C function declaration. */
if (cc.spadj && ctype_cconv(ct->info) == CTCC_CDECL) {
CTF_INSERT(ct->info, CCONV, CTCC_STDCALL);
lj_trace_abort(G(L));
}
#endif
while (gcsteps-- > 0)
lj_gc_check(L);
return ret;
}
return -1; /* Not a function. */
}
#endif

View File

@ -1,171 +0,0 @@
/*
** FFI C call handling.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CCALL_H
#define _LJ_CCALL_H
#include "lj_obj.h"
#include "lj_ctype.h"
#if LJ_HASFFI
/* -- C calling conventions ----------------------------------------------- */
#if LJ_TARGET_X86ORX64
#if LJ_TARGET_X86
#define CCALL_NARG_GPR 2 /* For fastcall arguments. */
#define CCALL_NARG_FPR 0
#define CCALL_NRET_GPR 2
#define CCALL_NRET_FPR 1 /* For FP results on x87 stack. */
#define CCALL_ALIGN_STACKARG 0 /* Don't align argument on stack. */
#elif LJ_ABI_WIN
#define CCALL_NARG_GPR 4
#define CCALL_NARG_FPR 4
#define CCALL_NRET_GPR 1
#define CCALL_NRET_FPR 1
#define CCALL_SPS_EXTRA 4
#else
#define CCALL_NARG_GPR 6
#define CCALL_NARG_FPR 8
#define CCALL_NRET_GPR 2
#define CCALL_NRET_FPR 2
#define CCALL_VECTOR_REG 1 /* Pass vectors in registers. */
#endif
#define CCALL_SPS_FREE 1
#define CCALL_ALIGN_CALLSTATE 16
typedef LJ_ALIGN(16) union FPRArg {
double d[2];
float f[4];
uint8_t b[16];
uint16_t s[8];
int i[4];
int64_t l[2];
} FPRArg;
typedef intptr_t GPRArg;
#elif LJ_TARGET_ARM
#define CCALL_NARG_GPR 4
#define CCALL_NRET_GPR 2 /* For softfp double. */
#if LJ_ABI_SOFTFP
#define CCALL_NARG_FPR 0
#define CCALL_NRET_FPR 0
#else
#define CCALL_NARG_FPR 8
#define CCALL_NRET_FPR 4
#endif
#define CCALL_SPS_FREE 0
typedef intptr_t GPRArg;
typedef union FPRArg {
double d;
float f[2];
} FPRArg;
#elif LJ_TARGET_PPC
#define CCALL_NARG_GPR 8
#define CCALL_NARG_FPR 8
#define CCALL_NRET_GPR 4 /* For complex double. */
#define CCALL_NRET_FPR 1
#define CCALL_SPS_EXTRA 4
#define CCALL_SPS_FREE 0
typedef intptr_t GPRArg;
typedef double FPRArg;
#elif LJ_TARGET_PPCSPE
#define CCALL_NARG_GPR 8
#define CCALL_NARG_FPR 0
#define CCALL_NRET_GPR 4 /* For softfp complex double. */
#define CCALL_NRET_FPR 0
#define CCALL_SPS_FREE 0 /* NYI */
typedef intptr_t GPRArg;
#elif LJ_TARGET_MIPS
#define CCALL_NARG_GPR 4
#define CCALL_NARG_FPR 2
#define CCALL_NRET_GPR 2
#define CCALL_NRET_FPR 2
#define CCALL_SPS_EXTRA 7
#define CCALL_SPS_FREE 1
typedef intptr_t GPRArg;
typedef union FPRArg {
double d;
struct { LJ_ENDIAN_LOHI(float f; , float g;) };
} FPRArg;
#else
#error "Missing calling convention definitions for this architecture"
#endif
#ifndef CCALL_SPS_EXTRA
#define CCALL_SPS_EXTRA 0
#endif
#ifndef CCALL_VECTOR_REG
#define CCALL_VECTOR_REG 0
#endif
#ifndef CCALL_ALIGN_STACKARG
#define CCALL_ALIGN_STACKARG 1
#endif
#ifndef CCALL_ALIGN_CALLSTATE
#define CCALL_ALIGN_CALLSTATE 8
#endif
#define CCALL_NUM_GPR \
(CCALL_NARG_GPR > CCALL_NRET_GPR ? CCALL_NARG_GPR : CCALL_NRET_GPR)
#define CCALL_NUM_FPR \
(CCALL_NARG_FPR > CCALL_NRET_FPR ? CCALL_NARG_FPR : CCALL_NRET_FPR)
/* Check against constants in lj_ctype.h. */
LJ_STATIC_ASSERT(CCALL_NUM_GPR <= CCALL_MAX_GPR);
LJ_STATIC_ASSERT(CCALL_NUM_FPR <= CCALL_MAX_FPR);
#define CCALL_MAXSTACK 32
/* -- C call state -------------------------------------------------------- */
typedef LJ_ALIGN(CCALL_ALIGN_CALLSTATE) struct CCallState {
void (*func)(void); /* Pointer to called function. */
uint32_t spadj; /* Stack pointer adjustment. */
uint8_t nsp; /* Number of stack slots. */
uint8_t retref; /* Return value by reference. */
#if LJ_TARGET_X64
uint8_t ngpr; /* Number of arguments in GPRs. */
uint8_t nfpr; /* Number of arguments in FPRs. */
#elif LJ_TARGET_X86
uint8_t resx87; /* Result on x87 stack: 1:float, 2:double. */
#elif LJ_TARGET_PPC
uint8_t nfpr; /* Number of arguments in FPRs. */
#endif
#if LJ_32
int32_t align1;
#endif
#if CCALL_NUM_FPR
FPRArg fpr[CCALL_NUM_FPR]; /* Arguments/results in FPRs. */
#endif
GPRArg gpr[CCALL_NUM_GPR]; /* Arguments/results in GPRs. */
GPRArg stack[CCALL_MAXSTACK]; /* Stack slots. */
} CCallState;
/* -- C call handling ----------------------------------------------------- */
/* Really belongs to lj_vm.h. */
LJ_ASMF void LJ_FASTCALL lj_vm_ffi_call(CCallState *cc);
LJ_FUNC CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o);
LJ_FUNC int lj_ccall_func(lua_State *L, GCcdata *cd);
#endif
#endif

View File

@ -1,644 +0,0 @@
/*
** FFI C callback handling.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_tab.h"
#include "lj_state.h"
#include "lj_frame.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_ccall.h"
#include "lj_ccallback.h"
#include "lj_target.h"
#include "lj_mcode.h"
#include "lj_trace.h"
#include "lj_vm.h"
/* -- Target-specific handling of callback slots -------------------------- */
#define CALLBACK_MCODE_SIZE (LJ_PAGESIZE * LJ_NUM_CBPAGE)
#if LJ_OS_NOJIT
/* Disabled callback support. */
#define CALLBACK_SLOT2OFS(slot) (0*(slot))
#define CALLBACK_OFS2SLOT(ofs) (0*(ofs))
#define CALLBACK_MAX_SLOT 0
#elif LJ_TARGET_X86ORX64
#define CALLBACK_MCODE_HEAD (LJ_64 ? 8 : 0)
#define CALLBACK_MCODE_GROUP (-2+1+2+5+(LJ_64 ? 6 : 5))
#define CALLBACK_SLOT2OFS(slot) \
(CALLBACK_MCODE_HEAD + CALLBACK_MCODE_GROUP*((slot)/32) + 4*(slot))
static MSize CALLBACK_OFS2SLOT(MSize ofs)
{
MSize group;
ofs -= CALLBACK_MCODE_HEAD;
group = ofs / (32*4 + CALLBACK_MCODE_GROUP);
return (ofs % (32*4 + CALLBACK_MCODE_GROUP))/4 + group*32;
}
#define CALLBACK_MAX_SLOT \
(((CALLBACK_MCODE_SIZE-CALLBACK_MCODE_HEAD)/(CALLBACK_MCODE_GROUP+4*32))*32)
#elif LJ_TARGET_ARM
#define CALLBACK_MCODE_HEAD 32
#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot))
#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8)
#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE))
#elif LJ_TARGET_PPC
#define CALLBACK_MCODE_HEAD 24
#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot))
#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8)
#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE))
#elif LJ_TARGET_MIPS
#define CALLBACK_MCODE_HEAD 24
#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot))
#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8)
#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE))
#else
/* Missing support for this architecture. */
#define CALLBACK_SLOT2OFS(slot) (0*(slot))
#define CALLBACK_OFS2SLOT(ofs) (0*(ofs))
#define CALLBACK_MAX_SLOT 0
#endif
/* Convert callback slot number to callback function pointer. */
static void *callback_slot2ptr(CTState *cts, MSize slot)
{
return (uint8_t *)cts->cb.mcode + CALLBACK_SLOT2OFS(slot);
}
/* Convert callback function pointer to slot number. */
MSize lj_ccallback_ptr2slot(CTState *cts, void *p)
{
uintptr_t ofs = (uintptr_t)((uint8_t *)p -(uint8_t *)cts->cb.mcode);
if (ofs < CALLBACK_MCODE_SIZE) {
MSize slot = CALLBACK_OFS2SLOT((MSize)ofs);
if (CALLBACK_SLOT2OFS(slot) == (MSize)ofs)
return slot;
}
return ~0u; /* Not a known callback function pointer. */
}
/* Initialize machine code for callback function pointers. */
#if LJ_OS_NOJIT
/* Disabled callback support. */
#define callback_mcode_init(g, p) UNUSED(p)
#elif LJ_TARGET_X86ORX64
static void callback_mcode_init(global_State *g, uint8_t *page)
{
uint8_t *p = page;
uint8_t *target = (uint8_t *)(void *)lj_vm_ffi_callback;
MSize slot;
#if LJ_64
*(void **)p = target; p += 8;
#endif
for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
/* mov al, slot; jmp group */
*p++ = XI_MOVrib | RID_EAX; *p++ = (uint8_t)slot;
if ((slot & 31) == 31 || slot == CALLBACK_MAX_SLOT-1) {
/* push ebp/rbp; mov ah, slot>>8; mov ebp, &g. */
*p++ = XI_PUSH + RID_EBP;
*p++ = XI_MOVrib | (RID_EAX+4); *p++ = (uint8_t)(slot >> 8);
*p++ = XI_MOVri | RID_EBP;
*(int32_t *)p = i32ptr(g); p += 4;
#if LJ_64
/* jmp [rip-pageofs] where lj_vm_ffi_callback is stored. */
*p++ = XI_GROUP5; *p++ = XM_OFS0 + (XOg_JMP<<3) + RID_EBP;
*(int32_t *)p = (int32_t)(page-(p+4)); p += 4;
#else
/* jmp lj_vm_ffi_callback. */
*p++ = XI_JMP; *(int32_t *)p = target-(p+4); p += 4;
#endif
} else {
*p++ = XI_JMPs; *p++ = (uint8_t)((2+2)*(31-(slot&31)) - 2);
}
}
lua_assert(p - page <= CALLBACK_MCODE_SIZE);
}
#elif LJ_TARGET_ARM
static void callback_mcode_init(global_State *g, uint32_t *page)
{
uint32_t *p = page;
void *target = (void *)lj_vm_ffi_callback;
MSize slot;
/* This must match with the saveregs macro in buildvm_arm.dasc. */
*p++ = ARMI_SUB|ARMF_D(RID_R12)|ARMF_N(RID_R12)|ARMF_M(RID_PC);
*p++ = ARMI_PUSH|ARMF_N(RID_SP)|RSET_RANGE(RID_R4,RID_R11+1)|RID2RSET(RID_LR);
*p++ = ARMI_SUB|ARMI_K12|ARMF_D(RID_R12)|ARMF_N(RID_R12)|CALLBACK_MCODE_HEAD;
*p++ = ARMI_STR|ARMI_LS_P|ARMI_LS_W|ARMF_D(RID_R12)|ARMF_N(RID_SP)|(CFRAME_SIZE-4*9);
*p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_R12)|ARMF_N(RID_PC);
*p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_PC)|ARMF_N(RID_PC);
*p++ = u32ptr(g);
*p++ = u32ptr(target);
for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
*p++ = ARMI_MOV|ARMF_D(RID_R12)|ARMF_M(RID_PC);
*p = ARMI_B | ((page-p-2) & 0x00ffffffu);
p++;
}
lua_assert(p - page <= CALLBACK_MCODE_SIZE);
}
#elif LJ_TARGET_PPC
static void callback_mcode_init(global_State *g, uint32_t *page)
{
uint32_t *p = page;
void *target = (void *)lj_vm_ffi_callback;
MSize slot;
*p++ = PPCI_LIS | PPCF_T(RID_TMP) | (u32ptr(target) >> 16);
*p++ = PPCI_LIS | PPCF_T(RID_R12) | (u32ptr(g) >> 16);
*p++ = PPCI_ORI | PPCF_A(RID_TMP)|PPCF_T(RID_TMP) | (u32ptr(target) & 0xffff);
*p++ = PPCI_ORI | PPCF_A(RID_R12)|PPCF_T(RID_R12) | (u32ptr(g) & 0xffff);
*p++ = PPCI_MTCTR | PPCF_T(RID_TMP);
*p++ = PPCI_BCTR;
for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
*p++ = PPCI_LI | PPCF_T(RID_R11) | slot;
*p = PPCI_B | (((page-p) & 0x00ffffffu) << 2);
p++;
}
lua_assert(p - page <= CALLBACK_MCODE_SIZE);
}
#elif LJ_TARGET_MIPS
static void callback_mcode_init(global_State *g, uint32_t *page)
{
uint32_t *p = page;
void *target = (void *)lj_vm_ffi_callback;
MSize slot;
*p++ = MIPSI_SW | MIPSF_T(RID_R1)|MIPSF_S(RID_SP) | 0;
*p++ = MIPSI_LUI | MIPSF_T(RID_R3) | (u32ptr(target) >> 16);
*p++ = MIPSI_LUI | MIPSF_T(RID_R2) | (u32ptr(g) >> 16);
*p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) |(u32ptr(target)&0xffff);
*p++ = MIPSI_JR | MIPSF_S(RID_R3);
*p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | (u32ptr(g)&0xffff);
for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
*p = MIPSI_B | ((page-p-1) & 0x0000ffffu);
p++;
*p++ = MIPSI_LI | MIPSF_T(RID_R1) | slot;
}
lua_assert(p - page <= CALLBACK_MCODE_SIZE);
}
#else
/* Missing support for this architecture. */
#define callback_mcode_init(g, p) UNUSED(p)
#endif
/* -- Machine code management --------------------------------------------- */
#if LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif LJ_TARGET_POSIX
#include <sys/mman.h>
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif
/* Allocate and initialize area for callback function pointers. */
static void callback_mcode_new(CTState *cts)
{
size_t sz = (size_t)CALLBACK_MCODE_SIZE;
void *p;
if (CALLBACK_MAX_SLOT == 0)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#if LJ_TARGET_WINDOWS
p = VirtualAlloc(NULL, sz, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if (!p)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#elif LJ_TARGET_POSIX
p = mmap(NULL, sz, (PROT_READ|PROT_WRITE), MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0);
if (p == MAP_FAILED)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#else
/* Fallback allocator. Fails if memory is not executable by default. */
p = lj_mem_new(cts->L, sz);
#endif
cts->cb.mcode = p;
callback_mcode_init(cts->g, p);
lj_mcode_sync(p, (char *)p + sz);
#if LJ_TARGET_WINDOWS
{
DWORD oprot;
VirtualProtect(p, sz, PAGE_EXECUTE_READ, &oprot);
}
#elif LJ_TARGET_POSIX
mprotect(p, sz, (PROT_READ|PROT_EXEC));
#endif
}
/* Free area for callback function pointers. */
void lj_ccallback_mcode_free(CTState *cts)
{
size_t sz = (size_t)CALLBACK_MCODE_SIZE;
void *p = cts->cb.mcode;
if (p == NULL) return;
#if LJ_TARGET_WINDOWS
VirtualFree(p, 0, MEM_RELEASE);
UNUSED(sz);
#elif LJ_TARGET_POSIX
munmap(p, sz);
#else
lj_mem_free(cts->g, p, sz);
#endif
}
/* -- C callback entry ---------------------------------------------------- */
/* Target-specific handling of register arguments. Similar to lj_ccall.c. */
#if LJ_TARGET_X86
#define CALLBACK_HANDLE_REGARG \
if (!isfp) { /* Only non-FP values may be passed in registers. */ \
if (n > 1) { /* Anything > 32 bit is passed on the stack. */ \
if (!LJ_ABI_WIN) ngpr = maxgpr; /* Prevent reordering. */ \
} else if (ngpr + 1 <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#elif LJ_TARGET_X64 && LJ_ABI_WIN
/* Windows/x64 argument registers are strictly positional (use ngpr). */
#define CALLBACK_HANDLE_REGARG \
if (isfp) { \
if (ngpr < maxgpr) { sp = &cts->cb.fpr[ngpr++]; UNUSED(nfpr); goto done; } \
} else { \
if (ngpr < maxgpr) { sp = &cts->cb.gpr[ngpr++]; goto done; } \
}
#elif LJ_TARGET_X64
#define CALLBACK_HANDLE_REGARG \
if (isfp) { \
if (nfpr + n <= CCALL_NARG_FPR) { \
sp = &cts->cb.fpr[nfpr]; \
nfpr += n; \
goto done; \
} \
} else { \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#elif LJ_TARGET_ARM
#if LJ_ABI_SOFTFP
#define CALLBACK_HANDLE_REGARG_FP1 UNUSED(isfp);
#define CALLBACK_HANDLE_REGARG_FP2
#else
#define CALLBACK_HANDLE_REGARG_FP1 \
if (isfp) { \
if (n == 1) { \
if (fprodd) { \
sp = &cts->cb.fpr[fprodd-1]; \
fprodd = 0; \
goto done; \
} else if (nfpr + 1 <= CCALL_NARG_FPR) { \
sp = &cts->cb.fpr[nfpr++]; \
fprodd = nfpr; \
goto done; \
} \
} else { \
if (nfpr + 1 <= CCALL_NARG_FPR) { \
sp = &cts->cb.fpr[nfpr++]; \
goto done; \
} \
} \
fprodd = 0; /* No reordering after the first FP value is on stack. */ \
} else {
#define CALLBACK_HANDLE_REGARG_FP2 }
#endif
#define CALLBACK_HANDLE_REGARG \
CALLBACK_HANDLE_REGARG_FP1 \
if (n > 1) ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} CALLBACK_HANDLE_REGARG_FP2
#elif LJ_TARGET_PPC
#define CALLBACK_HANDLE_REGARG \
if (isfp) { \
if (nfpr + 1 <= CCALL_NARG_FPR) { \
sp = &cts->cb.fpr[nfpr++]; \
cta = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \
goto done; \
} \
} else { /* Try to pass argument in GPRs. */ \
if (n > 1) { \
lua_assert(ctype_isinteger(cta->info) && n == 2); /* int64_t. */ \
ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
} \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#define CALLBACK_HANDLE_RET \
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
*(double *)dp = *(float *)dp; /* FPRs always hold doubles. */
#elif LJ_TARGET_MIPS
#define CALLBACK_HANDLE_REGARG \
if (isfp && nfpr < CCALL_NARG_FPR) { /* Try to pass argument in FPRs. */ \
sp = (void *)((uint8_t *)&cts->cb.fpr[nfpr] + ((LJ_BE && n==1) ? 4 : 0)); \
nfpr++; ngpr += n; \
goto done; \
} else { /* Try to pass argument in GPRs. */ \
nfpr = CCALL_NARG_FPR; \
if (n > 1) ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#define CALLBACK_HANDLE_RET \
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
((float *)dp)[1] = *(float *)dp;
#else
#error "Missing calling convention definitions for this architecture"
#endif
/* Convert and push callback arguments to Lua stack. */
static void callback_conv_args(CTState *cts, lua_State *L)
{
TValue *o = L->top;
intptr_t *stack = cts->cb.stack;
MSize slot = cts->cb.slot;
CTypeID id = 0, rid, fid;
int gcsteps = 0;
CType *ct;
GCfunc *fn;
MSize ngpr = 0, nsp = 0, maxgpr = CCALL_NARG_GPR;
#if CCALL_NARG_FPR
MSize nfpr = 0;
#if LJ_TARGET_ARM
MSize fprodd = 0;
#endif
#endif
if (slot < cts->cb.sizeid && (id = cts->cb.cbid[slot]) != 0) {
ct = ctype_get(cts, id);
rid = ctype_cid(ct->info);
fn = funcV(lj_tab_getint(cts->miscmap, (int32_t)slot));
} else { /* Must set up frame first, before throwing the error. */
ct = NULL;
rid = 0;
fn = (GCfunc *)L;
}
o->u32.lo = LJ_CONT_FFI_CALLBACK; /* Continuation returns from callback. */
o->u32.hi = rid; /* Return type. x86: +(spadj<<16). */
o++;
setframe_gc(o, obj2gco(fn));
setframe_ftsz(o, (int)((char *)(o+1) - (char *)L->base) + FRAME_CONT);
L->top = L->base = ++o;
if (!ct)
lj_err_caller(cts->L, LJ_ERR_FFI_BADCBACK);
if (isluafunc(fn))
setcframe_pc(L->cframe, proto_bc(funcproto(fn))+1);
lj_state_checkstack(L, LUA_MINSTACK); /* May throw. */
o = L->base; /* Might have been reallocated. */
#if LJ_TARGET_X86
/* x86 has several different calling conventions. */
switch (ctype_cconv(ct->info)) {
case CTCC_FASTCALL: maxgpr = 2; break;
case CTCC_THISCALL: maxgpr = 1; break;
default: maxgpr = 0; break;
}
#endif
fid = ct->sib;
while (fid) {
CType *ctf = ctype_get(cts, fid);
if (!ctype_isattrib(ctf->info)) {
CType *cta;
void *sp;
CTSize sz;
int isfp;
MSize n;
lua_assert(ctype_isfield(ctf->info));
cta = ctype_rawchild(cts, ctf);
isfp = ctype_isfp(cta->info);
sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */
CALLBACK_HANDLE_REGARG /* Handle register arguments. */
/* Otherwise pass argument on stack. */
if (CCALL_ALIGN_STACKARG && LJ_32 && sz == 8)
nsp = (nsp + 1) & ~1u; /* Align 64 bit argument on stack. */
sp = &stack[nsp];
nsp += n;
done:
if (LJ_BE && cta->size < CTSIZE_PTR)
sp = (void *)((uint8_t *)sp + CTSIZE_PTR-cta->size);
gcsteps += lj_cconv_tv_ct(cts, cta, 0, o++, sp);
}
fid = ctf->sib;
}
L->top = o;
#if LJ_TARGET_X86
/* Store stack adjustment for returns from non-cdecl callbacks. */
if (ctype_cconv(ct->info) != CTCC_CDECL)
(L->base-2)->u32.hi |= (nsp << (16+2));
#endif
while (gcsteps-- > 0)
lj_gc_check(L);
}
/* Convert Lua object to callback result. */
static void callback_conv_result(CTState *cts, lua_State *L, TValue *o)
{
CType *ctr = ctype_raw(cts, (uint16_t)(L->base-2)->u32.hi);
#if LJ_TARGET_X86
cts->cb.gpr[2] = 0;
#endif
if (!ctype_isvoid(ctr->info)) {
uint8_t *dp = (uint8_t *)&cts->cb.gpr[0];
#if CCALL_NUM_FPR
if (ctype_isfp(ctr->info))
dp = (uint8_t *)&cts->cb.fpr[0];
#endif
lj_cconv_ct_tv(cts, ctr, dp, o, 0);
#ifdef CALLBACK_HANDLE_RET
CALLBACK_HANDLE_RET
#endif
/* Extend returned integers to (at least) 32 bits. */
if (ctype_isinteger_or_bool(ctr->info) && ctr->size < 4) {
if (ctr->info & CTF_UNSIGNED)
*(uint32_t *)dp = ctr->size == 1 ? (uint32_t)*(uint8_t *)dp :
(uint32_t)*(uint16_t *)dp;
else
*(int32_t *)dp = ctr->size == 1 ? (int32_t)*(int8_t *)dp :
(int32_t)*(int16_t *)dp;
}
#if LJ_TARGET_X86
if (ctype_isfp(ctr->info))
cts->cb.gpr[2] = ctr->size == sizeof(float) ? 1 : 2;
#endif
}
}
/* Enter callback. */
lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf)
{
lua_State *L = cts->L;
global_State *g = cts->g;
lua_assert(L != NULL);
if (gcref(g->jit_L)) {
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_FFI_BADCBACK));
if (g->panic) g->panic(L);
exit(EXIT_FAILURE);
}
lj_trace_abort(g); /* Never record across callback. */
/* Setup C frame. */
cframe_prev(cf) = L->cframe;
setcframe_L(cf, L);
cframe_errfunc(cf) = -1;
cframe_nres(cf) = 0;
L->cframe = cf;
callback_conv_args(cts, L);
return L; /* Now call the function on this stack. */
}
/* Leave callback. */
void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o)
{
lua_State *L = cts->L;
GCfunc *fn;
TValue *obase = L->base;
L->base = L->top; /* Keep continuation frame for throwing errors. */
if (o >= L->base) {
/* PC of RET* is lost. Point to last line for result conv. errors. */
fn = curr_func(L);
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
setcframe_pc(L->cframe, proto_bc(pt)+pt->sizebc+1);
}
}
callback_conv_result(cts, L, o);
/* Finally drop C frame and continuation frame. */
L->cframe = cframe_prev(L->cframe);
L->top -= 2;
L->base = obase;
cts->cb.slot = 0; /* Blacklist C function that called the callback. */
}
/* -- C callback management ----------------------------------------------- */
/* Get an unused slot in the callback slot table. */
static MSize callback_slot_new(CTState *cts, CType *ct)
{
CTypeID id = ctype_typeid(cts, ct);
CTypeID1 *cbid = cts->cb.cbid;
MSize top;
for (top = cts->cb.topid; top < cts->cb.sizeid; top++)
if (LJ_LIKELY(cbid[top] == 0))
goto found;
#if CALLBACK_MAX_SLOT
if (top >= CALLBACK_MAX_SLOT)
#endif
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
if (!cts->cb.mcode)
callback_mcode_new(cts);
lj_mem_growvec(cts->L, cbid, cts->cb.sizeid, CALLBACK_MAX_SLOT, CTypeID1);
cts->cb.cbid = cbid;
memset(cbid+top, 0, (cts->cb.sizeid-top)*sizeof(CTypeID1));
found:
cbid[top] = id;
cts->cb.topid = top+1;
return top;
}
/* Check for function pointer and supported argument/result types. */
static CType *callback_checkfunc(CTState *cts, CType *ct)
{
int narg = 0;
if (!ctype_isptr(ct->info) || (LJ_64 && ct->size != CTSIZE_PTR))
return NULL;
ct = ctype_rawchild(cts, ct);
if (ctype_isfunc(ct->info)) {
CType *ctr = ctype_rawchild(cts, ct);
CTypeID fid = ct->sib;
if (!(ctype_isvoid(ctr->info) || ctype_isenum(ctr->info) ||
ctype_isptr(ctr->info) || (ctype_isnum(ctr->info) && ctr->size <= 8)))
return NULL;
if ((ct->info & CTF_VARARG))
return NULL;
while (fid) {
CType *ctf = ctype_get(cts, fid);
if (!ctype_isattrib(ctf->info)) {
CType *cta;
lua_assert(ctype_isfield(ctf->info));
cta = ctype_rawchild(cts, ctf);
if (!(ctype_isenum(cta->info) || ctype_isptr(cta->info) ||
(ctype_isnum(cta->info) && cta->size <= 8)) ||
++narg >= LUA_MINSTACK-3)
return NULL;
}
fid = ctf->sib;
}
return ct;
}
return NULL;
}
/* Create a new callback and return the callback function pointer. */
void *lj_ccallback_new(CTState *cts, CType *ct, GCfunc *fn)
{
ct = callback_checkfunc(cts, ct);
if (ct) {
MSize slot = callback_slot_new(cts, ct);
GCtab *t = cts->miscmap;
setfuncV(cts->L, lj_tab_setint(cts->L, t, (int32_t)slot), fn);
lj_gc_anybarriert(cts->L, t);
return callback_slot2ptr(cts, slot);
}
return NULL; /* Bad conversion. */
}
#endif

View File

@ -1,25 +0,0 @@
/*
** FFI C callback handling.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CCALLBACK_H
#define _LJ_CCALLBACK_H
#include "lj_obj.h"
#include "lj_ctype.h"
#if LJ_HASFFI
/* Really belongs to lj_vm.h. */
LJ_ASMF void lj_vm_ffi_callback(void);
LJ_FUNC MSize lj_ccallback_ptr2slot(CTState *cts, void *p);
LJ_FUNCA lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf);
LJ_FUNCA void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o);
LJ_FUNC void *lj_ccallback_new(CTState *cts, CType *ct, GCfunc *fn);
LJ_FUNC void lj_ccallback_mcode_free(CTState *cts);
#endif
#endif

View File

@ -1,752 +0,0 @@
/*
** C type conversions.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_err.h"
#include "lj_tab.h"
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lj_cconv.h"
#include "lj_ccallback.h"
/* -- Conversion errors --------------------------------------------------- */
/* Bad conversion. */
LJ_NORET static void cconv_err_conv(CTState *cts, CType *d, CType *s,
CTInfo flags)
{
const char *dst = strdata(lj_ctype_repr(cts->L, ctype_typeid(cts, d), NULL));
const char *src;
if ((flags & CCF_FROMTV))
src = lj_obj_typename[1+(ctype_isnum(s->info) ? LUA_TNUMBER :
ctype_isarray(s->info) ? LUA_TSTRING : LUA_TNIL)];
else
src = strdata(lj_ctype_repr(cts->L, ctype_typeid(cts, s), NULL));
if (CCF_GETARG(flags))
lj_err_argv(cts->L, CCF_GETARG(flags), LJ_ERR_FFI_BADCONV, src, dst);
else
lj_err_callerv(cts->L, LJ_ERR_FFI_BADCONV, src, dst);
}
/* Bad conversion from TValue. */
LJ_NORET static void cconv_err_convtv(CTState *cts, CType *d, TValue *o,
CTInfo flags)
{
const char *dst = strdata(lj_ctype_repr(cts->L, ctype_typeid(cts, d), NULL));
const char *src = lj_typename(o);
if (CCF_GETARG(flags))
lj_err_argv(cts->L, CCF_GETARG(flags), LJ_ERR_FFI_BADCONV, src, dst);
else
lj_err_callerv(cts->L, LJ_ERR_FFI_BADCONV, src, dst);
}
/* Initializer overflow. */
LJ_NORET static void cconv_err_initov(CTState *cts, CType *d)
{
const char *dst = strdata(lj_ctype_repr(cts->L, ctype_typeid(cts, d), NULL));
lj_err_callerv(cts->L, LJ_ERR_FFI_INITOV, dst);
}
/* -- C type compatibility checks ----------------------------------------- */
/* Get raw type and qualifiers for a child type. Resolves enums, too. */
static CType *cconv_childqual(CTState *cts, CType *ct, CTInfo *qual)
{
ct = ctype_child(cts, ct);
for (;;) {
if (ctype_isattrib(ct->info)) {
if (ctype_attrib(ct->info) == CTA_QUAL) *qual |= ct->size;
} else if (!ctype_isenum(ct->info)) {
break;
}
ct = ctype_child(cts, ct);
}
*qual |= (ct->info & CTF_QUAL);
return ct;
}
/* Check for compatible types when converting to a pointer.
** Note: these checks are more relaxed than what C99 mandates.
*/
int lj_cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags)
{
if (!((flags & CCF_CAST) || d == s)) {
CTInfo dqual = 0, squal = 0;
d = cconv_childqual(cts, d, &dqual);
if (!ctype_isstruct(s->info))
s = cconv_childqual(cts, s, &squal);
if ((flags & CCF_SAME)) {
if (dqual != squal)
return 0; /* Different qualifiers. */
} else if (!(flags & CCF_IGNQUAL)) {
if ((dqual & squal) != squal)
return 0; /* Discarded qualifiers. */
if (ctype_isvoid(d->info) || ctype_isvoid(s->info))
return 1; /* Converting to/from void * is always ok. */
}
if (ctype_type(d->info) != ctype_type(s->info) ||
d->size != s->size)
return 0; /* Different type or different size. */
if (ctype_isnum(d->info)) {
if (((d->info ^ s->info) & (CTF_BOOL|CTF_FP)))
return 0; /* Different numeric types. */
} else if (ctype_ispointer(d->info)) {
/* Check child types for compatibility. */
return lj_cconv_compatptr(cts, d, s, flags|CCF_SAME);
} else if (ctype_isstruct(d->info)) {
if (d != s)
return 0; /* Must be exact same type for struct/union. */
} else if (ctype_isfunc(d->info)) {
/* NYI: structural equality of functions. */
}
}
return 1; /* Types are compatible. */
}
/* -- C type to C type conversion ----------------------------------------- */
/* Convert C type to C type. Caveat: expects to get the raw CType!
**
** Note: This is only used by the interpreter and not optimized at all.
** The JIT compiler will do a much better job specializing for each case.
*/
void lj_cconv_ct_ct(CTState *cts, CType *d, CType *s,
uint8_t *dp, uint8_t *sp, CTInfo flags)
{
CTSize dsize = d->size, ssize = s->size;
CTInfo dinfo = d->info, sinfo = s->info;
void *tmpptr;
lua_assert(!ctype_isenum(dinfo) && !ctype_isenum(sinfo));
lua_assert(!ctype_isattrib(dinfo) && !ctype_isattrib(sinfo));
if (ctype_type(dinfo) > CT_MAYCONVERT || ctype_type(sinfo) > CT_MAYCONVERT)
goto err_conv;
/* Some basic sanity checks. */
lua_assert(!ctype_isnum(dinfo) || dsize > 0);
lua_assert(!ctype_isnum(sinfo) || ssize > 0);
lua_assert(!ctype_isbool(dinfo) || dsize == 1 || dsize == 4);
lua_assert(!ctype_isbool(sinfo) || ssize == 1 || ssize == 4);
lua_assert(!ctype_isinteger(dinfo) || (1u<<lj_fls(dsize)) == dsize);
lua_assert(!ctype_isinteger(sinfo) || (1u<<lj_fls(ssize)) == ssize);
switch (cconv_idx2(dinfo, sinfo)) {
/* Destination is a bool. */
case CCX(B, B):
/* Source operand is already normalized. */
if (dsize == 1) *dp = *sp; else *(int *)dp = *sp;
break;
case CCX(B, I): {
MSize i;
uint8_t b = 0;
for (i = 0; i < ssize; i++) b |= sp[i];
b = (b != 0);
if (dsize == 1) *dp = b; else *(int *)dp = b;
break;
}
case CCX(B, F): {
uint8_t b;
if (ssize == sizeof(double)) b = (*(double *)sp != 0);
else if (ssize == sizeof(float)) b = (*(float *)sp != 0);
else goto err_conv; /* NYI: long double. */
if (dsize == 1) *dp = b; else *(int *)dp = b;
break;
}
/* Destination is an integer. */
case CCX(I, B):
case CCX(I, I):
conv_I_I:
if (dsize > ssize) { /* Zero-extend or sign-extend LSB. */
#if LJ_LE
uint8_t fill = (!(sinfo & CTF_UNSIGNED) && (sp[ssize-1]&0x80)) ? 0xff : 0;
memcpy(dp, sp, ssize);
memset(dp + ssize, fill, dsize-ssize);
#else
uint8_t fill = (!(sinfo & CTF_UNSIGNED) && (sp[0]&0x80)) ? 0xff : 0;
memset(dp, fill, dsize-ssize);
memcpy(dp + (dsize-ssize), sp, ssize);
#endif
} else { /* Copy LSB. */
#if LJ_LE
memcpy(dp, sp, dsize);
#else
memcpy(dp, sp + (ssize-dsize), dsize);
#endif
}
break;
case CCX(I, F): {
double n; /* Always convert via double. */
conv_I_F:
/* Convert source to double. */
if (ssize == sizeof(double)) n = *(double *)sp;
else if (ssize == sizeof(float)) n = (double)*(float *)sp;
else goto err_conv; /* NYI: long double. */
/* Then convert double to integer. */
/* The conversion must exactly match the semantics of JIT-compiled code! */
if (dsize < 4 || (dsize == 4 && !(dinfo & CTF_UNSIGNED))) {
int32_t i = (int32_t)n;
if (dsize == 4) *(int32_t *)dp = i;
else if (dsize == 2) *(int16_t *)dp = (int16_t)i;
else *(int8_t *)dp = (int8_t)i;
} else if (dsize == 4) {
*(uint32_t *)dp = (uint32_t)n;
} else if (dsize == 8) {
if (!(dinfo & CTF_UNSIGNED))
*(int64_t *)dp = (int64_t)n;
else
*(uint64_t *)dp = lj_num2u64(n);
} else {
goto err_conv; /* NYI: conversion to >64 bit integers. */
}
break;
}
case CCX(I, C):
s = ctype_child(cts, s);
sinfo = s->info;
ssize = s->size;
goto conv_I_F; /* Just convert re. */
case CCX(I, P):
if (!(flags & CCF_CAST)) goto err_conv;
sinfo = CTINFO(CT_NUM, CTF_UNSIGNED);
goto conv_I_I;
case CCX(I, A):
if (!(flags & CCF_CAST)) goto err_conv;
sinfo = CTINFO(CT_NUM, CTF_UNSIGNED);
ssize = CTSIZE_PTR;
tmpptr = sp;
sp = (uint8_t *)&tmpptr;
goto conv_I_I;
/* Destination is a floating-point number. */
case CCX(F, B):
case CCX(F, I): {
double n; /* Always convert via double. */
conv_F_I:
/* First convert source to double. */
/* The conversion must exactly match the semantics of JIT-compiled code! */
if (ssize < 4 || (ssize == 4 && !(sinfo & CTF_UNSIGNED))) {
int32_t i;
if (ssize == 4) {
i = *(int32_t *)sp;
} else if (!(sinfo & CTF_UNSIGNED)) {
if (ssize == 2) i = *(int16_t *)sp;
else i = *(int8_t *)sp;
} else {
if (ssize == 2) i = *(uint16_t *)sp;
else i = *(uint8_t *)sp;
}
n = (double)i;
} else if (ssize == 4) {
n = (double)*(uint32_t *)sp;
} else if (ssize == 8) {
if (!(sinfo & CTF_UNSIGNED)) n = (double)*(int64_t *)sp;
else n = (double)*(uint64_t *)sp;
} else {
goto err_conv; /* NYI: conversion from >64 bit integers. */
}
/* Convert double to destination. */
if (dsize == sizeof(double)) *(double *)dp = n;
else if (dsize == sizeof(float)) *(float *)dp = (float)n;
else goto err_conv; /* NYI: long double. */
break;
}
case CCX(F, F): {
double n; /* Always convert via double. */
conv_F_F:
if (ssize == dsize) goto copyval;
/* Convert source to double. */
if (ssize == sizeof(double)) n = *(double *)sp;
else if (ssize == sizeof(float)) n = (double)*(float *)sp;
else goto err_conv; /* NYI: long double. */
/* Convert double to destination. */
if (dsize == sizeof(double)) *(double *)dp = n;
else if (dsize == sizeof(float)) *(float *)dp = (float)n;
else goto err_conv; /* NYI: long double. */
break;
}
case CCX(F, C):
s = ctype_child(cts, s);
sinfo = s->info;
ssize = s->size;
goto conv_F_F; /* Ignore im, and convert from re. */
/* Destination is a complex number. */
case CCX(C, I):
d = ctype_child(cts, d);
dinfo = d->info;
dsize = d->size;
memset(dp + dsize, 0, dsize); /* Clear im. */
goto conv_F_I; /* Convert to re. */
case CCX(C, F):
d = ctype_child(cts, d);
dinfo = d->info;
dsize = d->size;
memset(dp + dsize, 0, dsize); /* Clear im. */
goto conv_F_F; /* Convert to re. */
case CCX(C, C):
if (dsize != ssize) { /* Different types: convert re/im separately. */
CType *dc = ctype_child(cts, d);
CType *sc = ctype_child(cts, s);
lj_cconv_ct_ct(cts, dc, sc, dp, sp, flags);
lj_cconv_ct_ct(cts, dc, sc, dp + dc->size, sp + sc->size, flags);
return;
}
goto copyval; /* Otherwise this is easy. */
/* Destination is a vector. */
case CCX(V, I):
case CCX(V, F):
case CCX(V, C): {
CType *dc = ctype_child(cts, d);
CTSize esize;
/* First convert the scalar to the first element. */
lj_cconv_ct_ct(cts, dc, s, dp, sp, flags);
/* Then replicate it to the other elements (splat). */
for (sp = dp, esize = dc->size; dsize > esize; dsize -= esize) {
dp += esize;
memcpy(dp, sp, esize);
}
break;
}
case CCX(V, V):
/* Copy same-sized vectors, even for different lengths/element-types. */
if (dsize != ssize) goto err_conv;
goto copyval;
/* Destination is a pointer. */
case CCX(P, I):
if (!(flags & CCF_CAST)) goto err_conv;
dinfo = CTINFO(CT_NUM, CTF_UNSIGNED);
goto conv_I_I;
case CCX(P, F):
if (!(flags & CCF_CAST) || !(flags & CCF_FROMTV)) goto err_conv;
/* The signed conversion is cheaper. x64 really has 47 bit pointers. */
dinfo = CTINFO(CT_NUM, (LJ_64 && dsize == 8) ? 0 : CTF_UNSIGNED);
goto conv_I_F;
case CCX(P, P):
if (!lj_cconv_compatptr(cts, d, s, flags)) goto err_conv;
cdata_setptr(dp, dsize, cdata_getptr(sp, ssize));
break;
case CCX(P, A):
case CCX(P, S):
if (!lj_cconv_compatptr(cts, d, s, flags)) goto err_conv;
cdata_setptr(dp, dsize, sp);
break;
/* Destination is an array. */
case CCX(A, A):
if ((flags & CCF_CAST) || (d->info & CTF_VLA) || dsize != ssize ||
d->size == CTSIZE_INVALID || !lj_cconv_compatptr(cts, d, s, flags))
goto err_conv;
goto copyval;
/* Destination is a struct/union. */
case CCX(S, S):
if ((flags & CCF_CAST) || (d->info & CTF_VLA) || d != s)
goto err_conv; /* Must be exact same type. */
copyval: /* Copy value. */
lua_assert(dsize == ssize);
memcpy(dp, sp, dsize);
break;
default:
err_conv:
cconv_err_conv(cts, d, s, flags);
}
}
/* -- C type to TValue conversion ----------------------------------------- */
/* Convert C type to TValue. Caveat: expects to get the raw CType! */
int lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid,
TValue *o, uint8_t *sp)
{
CTInfo sinfo = s->info;
if (ctype_isnum(sinfo)) {
if (!ctype_isbool(sinfo)) {
if (ctype_isinteger(sinfo) && s->size > 4) goto copyval;
if (LJ_DUALNUM && ctype_isinteger(sinfo)) {
int32_t i;
lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT32), s,
(uint8_t *)&i, sp, 0);
if ((sinfo & CTF_UNSIGNED) && i < 0)
setnumV(o, (lua_Number)(uint32_t)i);
else
setintV(o, i);
} else {
lj_cconv_ct_ct(cts, ctype_get(cts, CTID_DOUBLE), s,
(uint8_t *)&o->n, sp, 0);
/* Numbers are NOT canonicalized here! Beware of uninitialized data. */
lua_assert(tvisnum(o));
}
} else {
uint32_t b = s->size == 1 ? (*sp != 0) : (*(int *)sp != 0);
setboolV(o, b);
setboolV(&cts->g->tmptv2, b); /* Remember for trace recorder. */
}
return 0;
} else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) {
/* Create reference. */
setcdataV(cts->L, o, lj_cdata_newref(cts, sp, sid));
return 1; /* Need GC step. */
} else {
GCcdata *cd;
CTSize sz;
copyval: /* Copy value. */
sz = s->size;
lua_assert(sz != CTSIZE_INVALID);
/* Attributes are stripped, qualifiers are kept (but mostly ignored). */
cd = lj_cdata_new(cts, ctype_typeid(cts, s), sz);
setcdataV(cts->L, o, cd);
memcpy(cdataptr(cd), sp, sz);
return 1; /* Need GC step. */
}
}
/* Convert bitfield to TValue. */
int lj_cconv_tv_bf(CTState *cts, CType *s, TValue *o, uint8_t *sp)
{
CTInfo info = s->info;
CTSize pos, bsz;
uint32_t val;
lua_assert(ctype_isbitfield(info));
/* NYI: packed bitfields may cause misaligned reads. */
switch (ctype_bitcsz(info)) {
case 4: val = *(uint32_t *)sp; break;
case 2: val = *(uint16_t *)sp; break;
case 1: val = *(uint8_t *)sp; break;
default: lua_assert(0); val = 0; break;
}
/* Check if a packed bitfield crosses a container boundary. */
pos = ctype_bitpos(info);
bsz = ctype_bitbsz(info);
lua_assert(pos < 8*ctype_bitcsz(info));
lua_assert(bsz > 0 && bsz <= 8*ctype_bitcsz(info));
if (pos + bsz > 8*ctype_bitcsz(info))
lj_err_caller(cts->L, LJ_ERR_FFI_NYIPACKBIT);
if (!(info & CTF_BOOL)) {
CTSize shift = 32 - bsz;
if (!(info & CTF_UNSIGNED)) {
setintV(o, (int32_t)(val << (shift-pos)) >> shift);
} else {
val = (val << (shift-pos)) >> shift;
if (!LJ_DUALNUM || (int32_t)val < 0)
setnumV(o, (lua_Number)(uint32_t)val);
else
setintV(o, (int32_t)val);
}
} else {
lua_assert(bsz == 1);
setboolV(o, (val >> pos) & 1);
}
return 0; /* No GC step needed. */
}
/* -- TValue to C type conversion ----------------------------------------- */
/* Convert table to array. */
static void cconv_array_tab(CTState *cts, CType *d,
uint8_t *dp, GCtab *t, CTInfo flags)
{
int32_t i;
CType *dc = ctype_rawchild(cts, d); /* Array element type. */
CTSize size = d->size, esize = dc->size, ofs = 0;
for (i = 0; ; i++) {
TValue *tv = (TValue *)lj_tab_getint(t, i);
if (!tv || tvisnil(tv)) {
if (i == 0) continue; /* Try again for 1-based tables. */
break; /* Stop at first nil. */
}
if (ofs >= size)
cconv_err_initov(cts, d);
lj_cconv_ct_tv(cts, dc, dp + ofs, tv, flags);
ofs += esize;
}
if (size != CTSIZE_INVALID) { /* Only fill up arrays with known size. */
if (ofs == esize) { /* Replicate a single element. */
for (; ofs < size; ofs += esize) memcpy(dp + ofs, dp, esize);
} else { /* Otherwise fill the remainder with zero. */
memset(dp + ofs, 0, size - ofs);
}
}
}
/* Convert table to sub-struct/union. */
static void cconv_substruct_tab(CTState *cts, CType *d, uint8_t *dp,
GCtab *t, int32_t *ip, CTInfo flags)
{
CTypeID id = d->sib;
while (id) {
CType *df = ctype_get(cts, id);
id = df->sib;
if (ctype_isfield(df->info) || ctype_isbitfield(df->info)) {
TValue *tv;
int32_t i = *ip, iz = i;
if (!gcref(df->name)) continue; /* Ignore unnamed fields. */
if (i >= 0) {
retry:
tv = (TValue *)lj_tab_getint(t, i);
if (!tv || tvisnil(tv)) {
if (i == 0) { i = 1; goto retry; } /* 1-based tables. */
if (iz == 0) { *ip = i = -1; goto tryname; } /* Init named fields. */
break; /* Stop at first nil. */
}
*ip = i + 1;
} else {
tryname:
tv = (TValue *)lj_tab_getstr(t, gco2str(gcref(df->name)));
if (!tv || tvisnil(tv)) continue;
}
if (ctype_isfield(df->info))
lj_cconv_ct_tv(cts, ctype_rawchild(cts, df), dp+df->size, tv, flags);
else
lj_cconv_bf_tv(cts, df, dp+df->size, tv);
if ((d->info & CTF_UNION)) break;
} else if (ctype_isxattrib(df->info, CTA_SUBTYPE)) {
cconv_substruct_tab(cts, ctype_rawchild(cts, df),
dp+df->size, t, ip, flags);
} /* Ignore all other entries in the chain. */
}
}
/* Convert table to struct/union. */
static void cconv_struct_tab(CTState *cts, CType *d,
uint8_t *dp, GCtab *t, CTInfo flags)
{
int32_t i = 0;
memset(dp, 0, d->size); /* Much simpler to clear the struct first. */
cconv_substruct_tab(cts, d, dp, t, &i, flags);
}
/* Convert TValue to C type. Caveat: expects to get the raw CType! */
void lj_cconv_ct_tv(CTState *cts, CType *d,
uint8_t *dp, TValue *o, CTInfo flags)
{
CTypeID sid = CTID_P_VOID;
CType *s;
void *tmpptr;
uint8_t tmpbool, *sp = (uint8_t *)&tmpptr;
if (LJ_LIKELY(tvisint(o))) {
sp = (uint8_t *)&o->i;
sid = CTID_INT32;
flags |= CCF_FROMTV;
} else if (LJ_LIKELY(tvisnum(o))) {
sp = (uint8_t *)&o->n;
sid = CTID_DOUBLE;
flags |= CCF_FROMTV;
} else if (tviscdata(o)) {
sp = cdataptr(cdataV(o));
sid = cdataV(o)->ctypeid;
s = ctype_get(cts, sid);
if (ctype_isref(s->info)) { /* Resolve reference for value. */
lua_assert(s->size == CTSIZE_PTR);
sp = *(void **)sp;
sid = ctype_cid(s->info);
}
s = ctype_raw(cts, sid);
if (ctype_isfunc(s->info)) {
sid = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|sid), CTSIZE_PTR);
} else {
if (ctype_isenum(s->info)) s = ctype_child(cts, s);
goto doconv;
}
} else if (tvisstr(o)) {
GCstr *str = strV(o);
if (ctype_isenum(d->info)) { /* Match string against enum constant. */
CTSize ofs;
CType *cct = lj_ctype_getfield(cts, d, str, &ofs);
if (!cct || !ctype_isconstval(cct->info))
goto err_conv;
lua_assert(d->size == 4);
sp = (uint8_t *)&cct->size;
sid = ctype_cid(cct->info);
} else if (ctype_isrefarray(d->info)) { /* Copy string to array. */
CType *dc = ctype_rawchild(cts, d);
CTSize sz = str->len+1;
if (!ctype_isinteger(dc->info) || dc->size != 1)
goto err_conv;
if (d->size != 0 && d->size < sz)
sz = d->size;
memcpy(dp, strdata(str), sz);
return;
} else { /* Otherwise pass it as a const char[]. */
sp = (uint8_t *)strdata(str);
sid = CTID_A_CCHAR;
flags |= CCF_FROMTV;
}
} else if (tvistab(o)) {
if (ctype_isarray(d->info)) {
cconv_array_tab(cts, d, dp, tabV(o), flags);
return;
} else if (ctype_isstruct(d->info)) {
cconv_struct_tab(cts, d, dp, tabV(o), flags);
return;
} else {
goto err_conv;
}
} else if (tvisbool(o)) {
tmpbool = boolV(o);
sp = &tmpbool;
sid = CTID_BOOL;
} else if (tvisnil(o)) {
tmpptr = (void *)0;
flags |= CCF_FROMTV;
} else if (tvisudata(o)) {
GCudata *ud = udataV(o);
tmpptr = uddata(ud);
if (ud->udtype == UDTYPE_IO_FILE)
tmpptr = *(void **)tmpptr;
} else if (tvislightud(o)) {
tmpptr = lightudV(o);
} else if (tvisfunc(o)) {
void *p = lj_ccallback_new(cts, d, funcV(o));
if (p) {
*(void **)dp = p;
return;
}
goto err_conv;
} else {
err_conv:
cconv_err_convtv(cts, d, o, flags);
}
s = ctype_get(cts, sid);
doconv:
if (ctype_isenum(d->info)) d = ctype_child(cts, d);
lj_cconv_ct_ct(cts, d, s, dp, sp, flags);
}
/* Convert TValue to bitfield. */
void lj_cconv_bf_tv(CTState *cts, CType *d, uint8_t *dp, TValue *o)
{
CTInfo info = d->info;
CTSize pos, bsz;
uint32_t val, mask;
lua_assert(ctype_isbitfield(info));
if ((info & CTF_BOOL)) {
uint8_t tmpbool;
lua_assert(ctype_bitbsz(info) == 1);
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_BOOL), &tmpbool, o, 0);
val = tmpbool;
} else {
CTypeID did = (info & CTF_UNSIGNED) ? CTID_UINT32 : CTID_INT32;
lj_cconv_ct_tv(cts, ctype_get(cts, did), (uint8_t *)&val, o, 0);
}
pos = ctype_bitpos(info);
bsz = ctype_bitbsz(info);
lua_assert(pos < 8*ctype_bitcsz(info));
lua_assert(bsz > 0 && bsz <= 8*ctype_bitcsz(info));
/* Check if a packed bitfield crosses a container boundary. */
if (pos + bsz > 8*ctype_bitcsz(info))
lj_err_caller(cts->L, LJ_ERR_FFI_NYIPACKBIT);
mask = ((1u << bsz) - 1u) << pos;
val = (val << pos) & mask;
/* NYI: packed bitfields may cause misaligned reads/writes. */
switch (ctype_bitcsz(info)) {
case 4: *(uint32_t *)dp = (*(uint32_t *)dp & ~mask) | (uint32_t)val; break;
case 2: *(uint16_t *)dp = (*(uint16_t *)dp & ~mask) | (uint16_t)val; break;
case 1: *(uint8_t *)dp = (*(uint8_t *)dp & ~mask) | (uint8_t)val; break;
default: lua_assert(0); break;
}
}
/* -- Initialize C type with TValues -------------------------------------- */
/* Initialize an array with TValues. */
static void cconv_array_init(CTState *cts, CType *d, CTSize sz, uint8_t *dp,
TValue *o, MSize len)
{
CType *dc = ctype_rawchild(cts, d); /* Array element type. */
CTSize ofs, esize = dc->size;
MSize i;
if (len*esize > sz)
cconv_err_initov(cts, d);
for (i = 0, ofs = 0; i < len; i++, ofs += esize)
lj_cconv_ct_tv(cts, dc, dp + ofs, o + i, 0);
if (ofs == esize) { /* Replicate a single element. */
for (; ofs < sz; ofs += esize) memcpy(dp + ofs, dp, esize);
} else { /* Otherwise fill the remainder with zero. */
memset(dp + ofs, 0, sz - ofs);
}
}
/* Initialize a sub-struct/union with TValues. */
static void cconv_substruct_init(CTState *cts, CType *d, uint8_t *dp,
TValue *o, MSize len, MSize *ip)
{
CTypeID id = d->sib;
while (id) {
CType *df = ctype_get(cts, id);
id = df->sib;
if (ctype_isfield(df->info) || ctype_isbitfield(df->info)) {
MSize i = *ip;
if (!gcref(df->name)) continue; /* Ignore unnamed fields. */
if (i >= len) break;
*ip = i + 1;
if (ctype_isfield(df->info))
lj_cconv_ct_tv(cts, ctype_rawchild(cts, df), dp+df->size, o + i, 0);
else
lj_cconv_bf_tv(cts, df, dp+df->size, o + i);
if ((d->info & CTF_UNION)) break;
} else if (ctype_isxattrib(df->info, CTA_SUBTYPE)) {
cconv_substruct_init(cts, ctype_rawchild(cts, df),
dp+df->size, o, len, ip);
if ((d->info & CTF_UNION)) break;
} /* Ignore all other entries in the chain. */
}
}
/* Initialize a struct/union with TValues. */
static void cconv_struct_init(CTState *cts, CType *d, CTSize sz, uint8_t *dp,
TValue *o, MSize len)
{
MSize i = 0;
memset(dp, 0, sz); /* Much simpler to clear the struct first. */
cconv_substruct_init(cts, d, dp, o, len, &i);
if (i < len)
cconv_err_initov(cts, d);
}
/* Check whether to use a multi-value initializer.
** This is true if an aggregate is to be initialized with a value.
** Valarrays are treated as values here so ct_tv handles (V|C, I|F).
*/
int lj_cconv_multi_init(CTState *cts, CType *d, TValue *o)
{
if (!(ctype_isrefarray(d->info) || ctype_isstruct(d->info)))
return 0; /* Destination is not an aggregate. */
if (tvistab(o) || (tvisstr(o) && !ctype_isstruct(d->info)))
return 0; /* Initializer is not a value. */
if (tviscdata(o) && lj_ctype_rawref(cts, cdataV(o)->ctypeid) == d)
return 0; /* Source and destination are identical aggregates. */
return 1; /* Otherwise the initializer is a value. */
}
/* Initialize C type with TValues. Caveat: expects to get the raw CType! */
void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz,
uint8_t *dp, TValue *o, MSize len)
{
if (len == 0)
memset(dp, 0, sz);
else if (len == 1 && !lj_cconv_multi_init(cts, d, o))
lj_cconv_ct_tv(cts, d, dp, o, 0);
else if (ctype_isarray(d->info)) /* Also handles valarray init with len>1. */
cconv_array_init(cts, d, sz, dp, o, len);
else if (ctype_isstruct(d->info))
cconv_struct_init(cts, d, sz, dp, o, len);
else
cconv_err_initov(cts, d);
}
#endif

View File

@ -1,70 +0,0 @@
/*
** C type conversions.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CCONV_H
#define _LJ_CCONV_H
#include "lj_obj.h"
#include "lj_ctype.h"
#if LJ_HASFFI
/* Compressed C type index. ORDER CCX. */
enum {
CCX_B, /* Bool. */
CCX_I, /* Integer. */
CCX_F, /* Floating-point number. */
CCX_C, /* Complex. */
CCX_V, /* Vector. */
CCX_P, /* Pointer. */
CCX_A, /* Refarray. */
CCX_S /* Struct/union. */
};
/* Convert C type info to compressed C type index. ORDER CT. ORDER CCX. */
static LJ_AINLINE uint32_t cconv_idx(CTInfo info)
{
uint32_t idx = ((info >> 26) & 15u); /* Dispatch bits. */
lua_assert(ctype_type(info) <= CT_MAYCONVERT);
#if LJ_64
idx = ((uint32_t)(U64x(f436fff5,fff7f021) >> 4*idx) & 15u);
#else
idx = (((idx < 8 ? 0xfff7f021u : 0xf436fff5) >> 4*(idx & 7u)) & 15u);
#endif
lua_assert(idx < 8);
return idx;
}
#define cconv_idx2(dinfo, sinfo) \
((cconv_idx((dinfo)) << 3) + cconv_idx((sinfo)))
#define CCX(dst, src) ((CCX_##dst << 3) + CCX_##src)
/* Conversion flags. */
#define CCF_CAST 0x00000001u
#define CCF_FROMTV 0x00000002u
#define CCF_SAME 0x00000004u
#define CCF_IGNQUAL 0x00000008u
#define CCF_ARG_SHIFT 8
#define CCF_ARG(n) ((n) << CCF_ARG_SHIFT)
#define CCF_GETARG(f) ((f) >> CCF_ARG_SHIFT)
LJ_FUNC int lj_cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags);
LJ_FUNC void lj_cconv_ct_ct(CTState *cts, CType *d, CType *s,
uint8_t *dp, uint8_t *sp, CTInfo flags);
LJ_FUNC int lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid,
TValue *o, uint8_t *sp);
LJ_FUNC int lj_cconv_tv_bf(CTState *cts, CType *s, TValue *o, uint8_t *sp);
LJ_FUNC void lj_cconv_ct_tv(CTState *cts, CType *d,
uint8_t *dp, TValue *o, CTInfo flags);
LJ_FUNC void lj_cconv_bf_tv(CTState *cts, CType *d, uint8_t *dp, TValue *o);
LJ_FUNC int lj_cconv_multi_init(CTState *cts, CType *d, TValue *o);
LJ_FUNC void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz,
uint8_t *dp, TValue *o, MSize len);
#endif
#endif

View File

@ -1,285 +0,0 @@
/*
** C data management.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_cdata.h"
/* -- C data allocation --------------------------------------------------- */
/* Allocate a new C data object holding a reference to another object. */
GCcdata *lj_cdata_newref(CTState *cts, const void *p, CTypeID id)
{
CTypeID refid = lj_ctype_intern(cts, CTINFO_REF(id), CTSIZE_PTR);
GCcdata *cd = lj_cdata_new(cts, refid, CTSIZE_PTR);
*(const void **)cdataptr(cd) = p;
return cd;
}
/* Allocate variable-sized or specially aligned C data object. */
GCcdata *lj_cdata_newv(CTState *cts, CTypeID id, CTSize sz, CTSize align)
{
global_State *g;
MSize extra = sizeof(GCcdataVar) + sizeof(GCcdata) +
(align > CT_MEMALIGN ? (1u<<align) - (1u<<CT_MEMALIGN) : 0);
char *p = lj_mem_newt(cts->L, extra + sz, char);
uintptr_t adata = (uintptr_t)p + sizeof(GCcdataVar) + sizeof(GCcdata);
uintptr_t almask = (1u << align) - 1u;
GCcdata *cd = (GCcdata *)(((adata + almask) & ~almask) - sizeof(GCcdata));
lua_assert((char *)cd - p < 65536);
cdatav(cd)->offset = (uint16_t)((char *)cd - p);
cdatav(cd)->extra = extra;
cdatav(cd)->len = sz;
g = cts->g;
setgcrefr(cd->nextgc, g->gc.root);
setgcref(g->gc.root, obj2gco(cd));
newwhite(g, obj2gco(cd));
cd->marked |= 0x80;
cd->gct = ~LJ_TCDATA;
cd->ctypeid = id;
return cd;
}
/* Free a C data object. */
void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd)
{
if (LJ_UNLIKELY(cd->marked & LJ_GC_CDATA_FIN)) {
GCobj *root;
makewhite(g, obj2gco(cd));
markfinalized(obj2gco(cd));
if ((root = gcref(g->gc.mmudata)) != NULL) {
setgcrefr(cd->nextgc, root->gch.nextgc);
setgcref(root->gch.nextgc, obj2gco(cd));
setgcref(g->gc.mmudata, obj2gco(cd));
} else {
setgcref(cd->nextgc, obj2gco(cd));
setgcref(g->gc.mmudata, obj2gco(cd));
}
} else if (LJ_LIKELY(!cdataisv(cd))) {
CType *ct = ctype_raw(ctype_ctsG(g), cd->ctypeid);
CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR;
lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) ||
ctype_isextern(ct->info));
lj_mem_free(g, cd, sizeof(GCcdata) + sz);
} else {
lj_mem_free(g, memcdatav(cd), sizecdatav(cd));
}
}
TValue * LJ_FASTCALL lj_cdata_setfin(lua_State *L, GCcdata *cd)
{
global_State *g = G(L);
GCtab *t = ctype_ctsG(g)->finalizer;
if (gcref(t->metatable)) {
/* Add cdata to finalizer table, if still enabled. */
TValue *tv, tmp;
setcdataV(L, &tmp, cd);
lj_gc_anybarriert(L, t);
tv = lj_tab_set(L, t, &tmp);
cd->marked |= LJ_GC_CDATA_FIN;
return tv;
} else {
/* Otherwise return dummy TValue. */
return &g->tmptv;
}
}
/* -- C data indexing ----------------------------------------------------- */
/* Index C data by a TValue. Return CType and pointer. */
CType *lj_cdata_index(CTState *cts, GCcdata *cd, cTValue *key, uint8_t **pp,
CTInfo *qual)
{
uint8_t *p = (uint8_t *)cdataptr(cd);
CType *ct = ctype_get(cts, cd->ctypeid);
ptrdiff_t idx;
/* Resolve reference for cdata object. */
if (ctype_isref(ct->info)) {
lua_assert(ct->size == CTSIZE_PTR);
p = *(uint8_t **)p;
ct = ctype_child(cts, ct);
}
collect_attrib:
/* Skip attributes and collect qualifiers. */
while (ctype_isattrib(ct->info)) {
if (ctype_attrib(ct->info) == CTA_QUAL) *qual |= ct->size;
ct = ctype_child(cts, ct);
}
lua_assert(!ctype_isref(ct->info)); /* Interning rejects refs to refs. */
if (tvisint(key)) {
idx = (ptrdiff_t)intV(key);
goto integer_key;
} else if (tvisnum(key)) { /* Numeric key. */
idx = LJ_64 ? (ptrdiff_t)numV(key) : (ptrdiff_t)lj_num2int(numV(key));
integer_key:
if (ctype_ispointer(ct->info)) {
CTSize sz = lj_ctype_size(cts, ctype_cid(ct->info)); /* Element size. */
if (sz == CTSIZE_INVALID)
lj_err_caller(cts->L, LJ_ERR_FFI_INVSIZE);
if (ctype_isptr(ct->info)) {
p = (uint8_t *)cdata_getptr(p, ct->size);
} else if ((ct->info & (CTF_VECTOR|CTF_COMPLEX))) {
if ((ct->info & CTF_COMPLEX)) idx &= 1;
*qual |= CTF_CONST; /* Valarray elements are constant. */
}
*pp = p + idx*(int32_t)sz;
return ct;
}
} else if (tviscdata(key)) { /* Integer cdata key. */
GCcdata *cdk = cdataV(key);
CType *ctk = ctype_raw(cts, cdk->ctypeid);
if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk);
if (ctype_isinteger(ctk->info)) {
lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ctk,
(uint8_t *)&idx, cdataptr(cdk), 0);
goto integer_key;
}
} else if (tvisstr(key)) { /* String key. */
GCstr *name = strV(key);
if (ctype_isstruct(ct->info)) {
CTSize ofs;
CType *fct = lj_ctype_getfieldq(cts, ct, name, &ofs, qual);
if (fct) {
*pp = p + ofs;
return fct;
}
} else if (ctype_iscomplex(ct->info)) {
if (name->len == 2) {
*qual |= CTF_CONST; /* Complex fields are constant. */
if (strdata(name)[0] == 'r' && strdata(name)[1] == 'e') {
*pp = p;
return ct;
} else if (strdata(name)[0] == 'i' && strdata(name)[1] == 'm') {
*pp = p + (ct->size >> 1);
return ct;
}
}
} else if (cd->ctypeid == CTID_CTYPEID) {
/* Allow indexing a (pointer to) struct constructor to get constants. */
CType *sct = ctype_raw(cts, *(CTypeID *)p);
if (ctype_isptr(sct->info))
sct = ctype_rawchild(cts, sct);
if (ctype_isstruct(sct->info)) {
CTSize ofs;
CType *fct = lj_ctype_getfield(cts, sct, name, &ofs);
if (fct && ctype_isconstval(fct->info))
return fct;
}
ct = sct; /* Allow resolving metamethods for constructors, too. */
}
}
if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */
if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) {
p = (uint8_t *)cdata_getptr(p, ct->size);
ct = ctype_child(cts, ct);
goto collect_attrib;
}
}
*qual |= 1; /* Lookup failed. */
return ct; /* But return the resolved raw type. */
}
/* -- C data getters ------------------------------------------------------ */
/* Get constant value and convert to TValue. */
static void cdata_getconst(CTState *cts, TValue *o, CType *ct)
{
CType *ctt = ctype_child(cts, ct);
lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
/* Constants are already zero-extended/sign-extended to 32 bits. */
if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
setnumV(o, (lua_Number)(uint32_t)ct->size);
else
setintV(o, (int32_t)ct->size);
}
/* Get C data value and convert to TValue. */
int lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp)
{
CTypeID sid;
if (ctype_isconstval(s->info)) {
cdata_getconst(cts, o, s);
return 0; /* No GC step needed. */
} else if (ctype_isbitfield(s->info)) {
return lj_cconv_tv_bf(cts, s, o, sp);
}
/* Get child type of pointer/array/field. */
lua_assert(ctype_ispointer(s->info) || ctype_isfield(s->info));
sid = ctype_cid(s->info);
s = ctype_get(cts, sid);
/* Resolve reference for field. */
if (ctype_isref(s->info)) {
lua_assert(s->size == CTSIZE_PTR);
sp = *(uint8_t **)sp;
sid = ctype_cid(s->info);
s = ctype_get(cts, sid);
}
/* Skip attributes. */
while (ctype_isattrib(s->info))
s = ctype_child(cts, s);
return lj_cconv_tv_ct(cts, s, sid, o, sp);
}
/* -- C data setters ------------------------------------------------------ */
/* Convert TValue and set C data value. */
void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, CTInfo qual)
{
if (ctype_isconstval(d->info)) {
goto err_const;
} else if (ctype_isbitfield(d->info)) {
if (((d->info|qual) & CTF_CONST)) goto err_const;
lj_cconv_bf_tv(cts, d, dp, o);
return;
}
/* Get child type of pointer/array/field. */
lua_assert(ctype_ispointer(d->info) || ctype_isfield(d->info));
d = ctype_child(cts, d);
/* Resolve reference for field. */
if (ctype_isref(d->info)) {
lua_assert(d->size == CTSIZE_PTR);
dp = *(uint8_t **)dp;
d = ctype_child(cts, d);
}
/* Skip attributes and collect qualifiers. */
for (;;) {
if (ctype_isattrib(d->info)) {
if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
} else {
break;
}
d = ctype_child(cts, d);
}
lua_assert(ctype_hassize(d->info) && !ctype_isvoid(d->info));
if (((d->info|qual) & CTF_CONST)) {
err_const:
lj_err_caller(cts->L, LJ_ERR_FFI_WRCONST);
}
lj_cconv_ct_tv(cts, d, dp, o, 0);
}
#endif

View File

@ -1,75 +0,0 @@
/*
** C data management.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CDATA_H
#define _LJ_CDATA_H
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_ctype.h"
#if LJ_HASFFI
/* Get C data pointer. */
static LJ_AINLINE void *cdata_getptr(void *p, CTSize sz)
{
if (LJ_64 && sz == 4) { /* Support 32 bit pointers on 64 bit targets. */
return ((void *)(uintptr_t)*(uint32_t *)p);
} else {
lua_assert(sz == CTSIZE_PTR);
return *(void **)p;
}
}
/* Set C data pointer. */
static LJ_AINLINE void cdata_setptr(void *p, CTSize sz, const void *v)
{
if (LJ_64 && sz == 4) { /* Support 32 bit pointers on 64 bit targets. */
*(uint32_t *)p = (uint32_t)(uintptr_t)v;
} else {
lua_assert(sz == CTSIZE_PTR);
*(void **)p = (void *)v;
}
}
/* Allocate fixed-size C data object. */
static LJ_AINLINE GCcdata *lj_cdata_new(CTState *cts, CTypeID id, CTSize sz)
{
GCcdata *cd;
#ifdef LUA_USE_ASSERT
CType *ct = ctype_raw(cts, id);
lua_assert((ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR) == sz);
#endif
cd = (GCcdata *)lj_mem_newgco(cts->L, sizeof(GCcdata) + sz);
cd->gct = ~LJ_TCDATA;
cd->ctypeid = ctype_check(cts, id);
return cd;
}
/* Variant which works without a valid CTState. */
static LJ_AINLINE GCcdata *lj_cdata_new_(lua_State *L, CTypeID id, CTSize sz)
{
GCcdata *cd = (GCcdata *)lj_mem_newgco(L, sizeof(GCcdata) + sz);
cd->gct = ~LJ_TCDATA;
cd->ctypeid = id;
return cd;
}
LJ_FUNC GCcdata *lj_cdata_newref(CTState *cts, const void *pp, CTypeID id);
LJ_FUNC GCcdata *lj_cdata_newv(CTState *cts, CTypeID id, CTSize sz,
CTSize align);
LJ_FUNC void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd);
LJ_FUNCA TValue * LJ_FASTCALL lj_cdata_setfin(lua_State *L, GCcdata *cd);
LJ_FUNC CType *lj_cdata_index(CTState *cts, GCcdata *cd, cTValue *key,
uint8_t **pp, CTInfo *qual);
LJ_FUNC int lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp);
LJ_FUNC void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o,
CTInfo qual);
#endif
#endif

View File

@ -1,43 +0,0 @@
/*
** Character types.
** Donated to the public domain.
**
** This is intended to replace the problematic libc single-byte NLS functions.
** These just don't make sense anymore with UTF-8 locales becoming the norm
** on POSIX systems. It never worked too well on Windows systems since hardly
** anyone bothered to call setlocale().
**
** This table is hardcoded for ASCII. Identifiers include the characters
** 128-255, too. This allows for the use of all non-ASCII chars as identifiers
** in the lexer. This is a broad definition, but works well in practice
** for both UTF-8 locales and most single-byte locales (such as ISO-8859-*).
**
** If you really need proper character types for UTF-8 strings, please use
** an add-on library such as slnunicode: http://luaforge.net/projects/sln/
*/
#define lj_char_c
#define LUA_CORE
#include "lj_char.h"
LJ_DATADEF const uint8_t lj_char_bits[257] = {
0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
152,152,152,152,152,152,152,152,152,152, 4, 4, 4, 4, 4, 4,
4,176,176,176,176,176,176,160,160,160,160,160,160,160,160,160,
160,160,160,160,160,160,160,160,160,160,160, 4, 4, 4, 4,132,
4,208,208,208,208,208,208,192,192,192,192,192,192,192,192,192,
192,192,192,192,192,192,192,192,192,192,192, 4, 4, 4, 4, 1,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
};

View File

@ -1,42 +0,0 @@
/*
** Character types.
** Donated to the public domain.
*/
#ifndef _LJ_CHAR_H
#define _LJ_CHAR_H
#include "lj_def.h"
#define LJ_CHAR_CNTRL 0x01
#define LJ_CHAR_SPACE 0x02
#define LJ_CHAR_PUNCT 0x04
#define LJ_CHAR_DIGIT 0x08
#define LJ_CHAR_XDIGIT 0x10
#define LJ_CHAR_UPPER 0x20
#define LJ_CHAR_LOWER 0x40
#define LJ_CHAR_IDENT 0x80
#define LJ_CHAR_ALPHA (LJ_CHAR_LOWER|LJ_CHAR_UPPER)
#define LJ_CHAR_ALNUM (LJ_CHAR_ALPHA|LJ_CHAR_DIGIT)
#define LJ_CHAR_GRAPH (LJ_CHAR_ALNUM|LJ_CHAR_PUNCT)
/* Only pass -1 or 0..255 to these macros. Never pass a signed char! */
#define lj_char_isa(c, t) ((lj_char_bits+1)[(c)] & t)
#define lj_char_iscntrl(c) lj_char_isa((c), LJ_CHAR_CNTRL)
#define lj_char_isspace(c) lj_char_isa((c), LJ_CHAR_SPACE)
#define lj_char_ispunct(c) lj_char_isa((c), LJ_CHAR_PUNCT)
#define lj_char_isdigit(c) lj_char_isa((c), LJ_CHAR_DIGIT)
#define lj_char_isxdigit(c) lj_char_isa((c), LJ_CHAR_XDIGIT)
#define lj_char_isupper(c) lj_char_isa((c), LJ_CHAR_UPPER)
#define lj_char_islower(c) lj_char_isa((c), LJ_CHAR_LOWER)
#define lj_char_isident(c) lj_char_isa((c), LJ_CHAR_IDENT)
#define lj_char_isalpha(c) lj_char_isa((c), LJ_CHAR_ALPHA)
#define lj_char_isalnum(c) lj_char_isa((c), LJ_CHAR_ALNUM)
#define lj_char_isgraph(c) lj_char_isa((c), LJ_CHAR_GRAPH)
#define lj_char_toupper(c) ((c) - (lj_char_islower(c) >> 1))
#define lj_char_tolower(c) ((c) + lj_char_isupper(c))
LJ_DATA const uint8_t lj_char_bits[257];
#endif

View File

@ -1,409 +0,0 @@
/*
** FFI C library loader.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_tab.h"
#include "lj_str.h"
#include "lj_udata.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_cdata.h"
#include "lj_clib.h"
/* -- OS-specific functions ----------------------------------------------- */
#if LJ_TARGET_DLOPEN
#include <dlfcn.h>
#include <stdio.h>
#if defined(RTLD_DEFAULT)
#define CLIB_DEFHANDLE RTLD_DEFAULT
#elif LJ_TARGET_OSX || LJ_TARGET_BSD
#define CLIB_DEFHANDLE ((void *)(intptr_t)-2)
#else
#define CLIB_DEFHANDLE NULL
#endif
LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L)
{
lj_err_callermsg(L, dlerror());
}
#define clib_error(L, fmt, name) clib_error_(L)
#if LJ_TARGET_CYGWIN
#define CLIB_SOPREFIX "cyg"
#else
#define CLIB_SOPREFIX "lib"
#endif
#if LJ_TARGET_OSX
#define CLIB_SOEXT "%s.dylib"
#elif LJ_TARGET_CYGWIN
#define CLIB_SOEXT "%s.dll"
#else
#define CLIB_SOEXT "%s.so"
#endif
static const char *clib_extname(lua_State *L, const char *name)
{
if (!strchr(name, '/')
#if LJ_TARGET_CYGWIN
&& !strchr(name, '\\')
#endif
) {
if (!strchr(name, '.')) {
name = lj_str_pushf(L, CLIB_SOEXT, name);
L->top--;
#if LJ_TARGET_CYGWIN
} else {
return name;
#endif
}
if (!(name[0] == CLIB_SOPREFIX[0] && name[1] == CLIB_SOPREFIX[1] &&
name[2] == CLIB_SOPREFIX[2])) {
name = lj_str_pushf(L, CLIB_SOPREFIX "%s", name);
L->top--;
}
}
return name;
}
/* Check for a recognized ld script line. */
static const char *clib_check_lds(lua_State *L, const char *buf)
{
char *p, *e;
if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) &&
(p = strchr(buf, '('))) {
while (*++p == ' ') ;
for (e = p; *e && *e != ' ' && *e != ')'; e++) ;
return strdata(lj_str_new(L, p, e-p));
}
return NULL;
}
/* Quick and dirty solution to resolve shared library name from ld script. */
static const char *clib_resolve_lds(lua_State *L, const char *name)
{
FILE *fp = fopen(name, "r");
const char *p = NULL;
if (fp) {
char buf[256];
if (fgets(buf, sizeof(buf), fp)) {
if (!strncmp(buf, "/* GNU ld script", 16)) { /* ld script magic? */
while (fgets(buf, sizeof(buf), fp)) { /* Check all lines. */
p = clib_check_lds(L, buf);
if (p) break;
}
} else { /* Otherwise check only the first line. */
p = clib_check_lds(L, buf);
}
}
fclose(fp);
}
return p;
}
static void *clib_loadlib(lua_State *L, const char *name, int global)
{
void *h = dlopen(clib_extname(L, name),
RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
if (!h) {
const char *e, *err = dlerror();
if (*err == '/' && (e = strchr(err, ':')) &&
(name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) {
h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
if (h) return h;
err = dlerror();
}
lj_err_callermsg(L, err);
}
return h;
}
static void clib_unloadlib(CLibrary *cl)
{
if (cl->handle && cl->handle != CLIB_DEFHANDLE)
dlclose(cl->handle);
}
static void *clib_getsym(CLibrary *cl, const char *name)
{
void *p = dlsym(cl->handle, name);
return p;
}
#elif LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
#endif
#define CLIB_DEFHANDLE ((void *)-1)
/* Default libraries. */
enum {
CLIB_HANDLE_EXE,
CLIB_HANDLE_DLL,
CLIB_HANDLE_CRT,
CLIB_HANDLE_KERNEL32,
CLIB_HANDLE_USER32,
CLIB_HANDLE_GDI32,
CLIB_HANDLE_MAX
};
static void *clib_def_handle[CLIB_HANDLE_MAX];
LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
const char *name)
{
DWORD err = GetLastError();
char buf[128];
if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err, 0, buf, sizeof(buf), NULL))
buf[0] = '\0';
lj_err_callermsg(L, lj_str_pushf(L, fmt, name, buf));
}
static int clib_needext(const char *s)
{
while (*s) {
if (*s == '/' || *s == '\\' || *s == '.') return 0;
s++;
}
return 1;
}
static const char *clib_extname(lua_State *L, const char *name)
{
if (clib_needext(name)) {
name = lj_str_pushf(L, "%s.dll", name);
L->top--;
}
return name;
}
static void *clib_loadlib(lua_State *L, const char *name, int global)
{
DWORD oldwerr = GetLastError();
void *h = (void *)LoadLibraryA(clib_extname(L, name));
if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name);
SetLastError(oldwerr);
UNUSED(global);
return h;
}
static void clib_unloadlib(CLibrary *cl)
{
if (cl->handle == CLIB_DEFHANDLE) {
MSize i;
for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) {
void *h = clib_def_handle[i];
if (h) {
clib_def_handle[i] = NULL;
FreeLibrary((HINSTANCE)h);
}
}
} else if (cl->handle) {
FreeLibrary((HINSTANCE)cl->handle);
}
}
static void *clib_getsym(CLibrary *cl, const char *name)
{
void *p = NULL;
if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */
MSize i;
for (i = 0; i < CLIB_HANDLE_MAX; i++) {
HINSTANCE h = (HINSTANCE)clib_def_handle[i];
if (!(void *)h) { /* Resolve default library handles (once). */
switch (i) {
case CLIB_HANDLE_EXE: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &h); break;
case CLIB_HANDLE_DLL:
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(const char *)clib_def_handle, &h);
break;
case CLIB_HANDLE_CRT:
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(const char *)&_fmode, &h);
break;
case CLIB_HANDLE_KERNEL32: h = LoadLibraryA("kernel32.dll"); break;
case CLIB_HANDLE_USER32: h = LoadLibraryA("user32.dll"); break;
case CLIB_HANDLE_GDI32: h = LoadLibraryA("gdi32.dll"); break;
}
if (!h) continue;
clib_def_handle[i] = (void *)h;
}
p = (void *)GetProcAddress(h, name);
if (p) break;
}
} else {
p = (void *)GetProcAddress((HINSTANCE)cl->handle, name);
}
return p;
}
#else
#define CLIB_DEFHANDLE NULL
LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
const char *name)
{
lj_err_callermsg(L, lj_str_pushf(L, fmt, name, "no support for this OS"));
}
static void *clib_loadlib(lua_State *L, const char *name, int global)
{
lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
UNUSED(name); UNUSED(global);
return NULL;
}
static void clib_unloadlib(CLibrary *cl)
{
UNUSED(cl);
}
static void *clib_getsym(CLibrary *cl, const char *name)
{
UNUSED(cl); UNUSED(name);
return NULL;
}
#endif
/* -- C library indexing -------------------------------------------------- */
#if LJ_TARGET_X86 && LJ_ABI_WIN
/* Compute argument size for fastcall/stdcall functions. */
static CTSize clib_func_argsize(CTState *cts, CType *ct)
{
CTSize n = 0;
while (ct->sib) {
CType *d;
ct = ctype_get(cts, ct->sib);
if (ctype_isfield(ct->info)) {
d = ctype_rawchild(cts, ct);
n += ((d->size + 3) & ~3);
}
}
return n;
}
#endif
/* Get redirected or mangled external symbol. */
static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name)
{
if (ct->sib) {
CType *ctf = ctype_get(cts, ct->sib);
if (ctype_isxattrib(ctf->info, CTA_REDIR))
return strdata(gco2str(gcref(ctf->name)));
}
return strdata(name);
}
/* Index a C library by name. */
TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
{
TValue *tv = lj_tab_setstr(L, cl->cache, name);
if (LJ_UNLIKELY(tvisnil(tv))) {
CTState *cts = ctype_cts(L);
CType *ct;
CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX);
if (!id)
lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name));
if (ctype_isconstval(ct->info)) {
CType *ctt = ctype_child(cts, ct);
lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
setnumV(tv, (lua_Number)(uint32_t)ct->size);
else
setintV(tv, (int32_t)ct->size);
} else {
const char *sym = clib_extsym(cts, ct, name);
#if LJ_TARGET_WINDOWS
DWORD oldwerr = GetLastError();
#endif
void *p = clib_getsym(cl, sym);
GCcdata *cd;
lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info));
#if LJ_TARGET_X86 && LJ_ABI_WIN
/* Retry with decorated name for fastcall/stdcall functions. */
if (!p && ctype_isfunc(ct->info)) {
CTInfo cconv = ctype_cconv(ct->info);
if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) {
CTSize sz = clib_func_argsize(cts, ct);
const char *symd = lj_str_pushf(L,
cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d",
sym, sz);
L->top--;
p = clib_getsym(cl, symd);
}
}
#endif
if (!p)
clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym);
#if LJ_TARGET_WINDOWS
SetLastError(oldwerr);
#endif
cd = lj_cdata_new(cts, id, CTSIZE_PTR);
*(void **)cdataptr(cd) = p;
setcdataV(L, tv, cd);
}
}
return tv;
}
/* -- C library management ------------------------------------------------ */
/* Create a new CLibrary object and push it on the stack. */
static CLibrary *clib_new(lua_State *L, GCtab *mt)
{
GCtab *t = lj_tab_new(L, 0, 0);
GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t);
CLibrary *cl = (CLibrary *)uddata(ud);
cl->cache = t;
ud->udtype = UDTYPE_FFI_CLIB;
/* NOBARRIER: The GCudata is new (marked white). */
setgcref(ud->metatable, obj2gco(mt));
setudataV(L, L->top++, ud);
return cl;
}
/* Load a C library. */
void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
{
void *handle = clib_loadlib(L, strdata(name), global);
CLibrary *cl = clib_new(L, mt);
cl->handle = handle;
}
/* Unload a C library. */
void lj_clib_unload(CLibrary *cl)
{
clib_unloadlib(cl);
cl->handle = NULL;
}
/* Create the default C library object. */
void lj_clib_default(lua_State *L, GCtab *mt)
{
CLibrary *cl = clib_new(L, mt);
cl->handle = CLIB_DEFHANDLE;
}
#endif

View File

@ -1,29 +0,0 @@
/*
** FFI C library loader.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CLIB_H
#define _LJ_CLIB_H
#include "lj_obj.h"
#if LJ_HASFFI
/* Namespace for C library indexing. */
#define CLNS_INDEX ((1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL))
/* C library namespace. */
typedef struct CLibrary {
void *handle; /* Opaque handle for dynamic library loader. */
GCtab *cache; /* Cache for resolved symbols. Anchored in ud->env. */
} CLibrary;
LJ_FUNC TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name);
LJ_FUNC void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global);
LJ_FUNC void lj_clib_unload(CLibrary *cl);
LJ_FUNC void lj_clib_default(lua_State *L, GCtab *mt);
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +0,0 @@
/*
** C declaration parser.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CPARSE_H
#define _LJ_CPARSE_H
#include "lj_obj.h"
#include "lj_ctype.h"
#if LJ_HASFFI
/* C parser limits. */
#define CPARSE_MAX_BUF 32768 /* Max. token buffer size. */
#define CPARSE_MAX_DECLSTACK 100 /* Max. declaration stack depth. */
#define CPARSE_MAX_DECLDEPTH 20 /* Max. recursive declaration depth. */
#define CPARSE_MAX_PACKSTACK 7 /* Max. pack pragma stack depth. */
/* Flags for C parser mode. */
#define CPARSE_MODE_MULTI 1 /* Process multiple declarations. */
#define CPARSE_MODE_ABSTRACT 2 /* Accept abstract declarators. */
#define CPARSE_MODE_DIRECT 4 /* Accept direct declarators. */
#define CPARSE_MODE_FIELD 8 /* Accept field width in bits, too. */
#define CPARSE_MODE_NOIMPLICIT 16 /* Reject implicit declarations. */
#define CPARSE_MODE_SKIP 32 /* Skip definitions, ignore errors. */
typedef int CPChar; /* C parser character. Unsigned ext. from char. */
typedef int CPToken; /* C parser token. */
/* C parser internal value representation. */
typedef struct CPValue {
union {
int32_t i32; /* Value for CTID_INT32. */
uint32_t u32; /* Value for CTID_UINT32. */
};
CTypeID id; /* C Type ID of the value. */
} CPValue;
/* C parser state. */
typedef struct CPState {
CPChar c; /* Current character. */
CPToken tok; /* Current token. */
CPValue val; /* Token value. */
GCstr *str; /* Interned string of identifier/keyword. */
CType *ct; /* C type table entry. */
const char *p; /* Current position in input buffer. */
SBuf sb; /* String buffer for tokens. */
lua_State *L; /* Lua state. */
CTState *cts; /* C type state. */
TValue *param; /* C type parameters. */
const char *srcname; /* Current source name. */
BCLine linenumber; /* Input line counter. */
int depth; /* Recursive declaration depth. */
uint32_t tmask; /* Type mask for next identifier. */
uint32_t mode; /* C parser mode. */
uint8_t packstack[CPARSE_MAX_PACKSTACK]; /* Stack for pack pragmas. */
uint8_t curpack; /* Current position in pack pragma stack. */
} CPState;
LJ_FUNC int lj_cparse(CPState *cp);
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +0,0 @@
/*
** Trace recorder for C data operations.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CRECORD_H
#define _LJ_CRECORD_H
#include "lj_obj.h"
#include "lj_jit.h"
#include "lj_ffrecord.h"
#if LJ_HASJIT && LJ_HASFFI
LJ_FUNC void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_clib_index(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_new(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_errno(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_string(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_copy(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_fill(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_typeof(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_istype(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_abi(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_xof(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL recff_ffi_gc(jit_State *J, RecordFFData *rd);
LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd);
#endif
#endif

View File

@ -1,634 +0,0 @@
/*
** C type management.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_ctype.h"
#include "lj_ccallback.h"
/* -- C type definitions -------------------------------------------------- */
/* Predefined typedefs. */
#define CTTDDEF(_) \
/* Vararg handling. */ \
_("va_list", P_VOID) \
_("__builtin_va_list", P_VOID) \
_("__gnuc_va_list", P_VOID) \
/* From stddef.h. */ \
_("ptrdiff_t", INT_PSZ) \
_("size_t", UINT_PSZ) \
_("wchar_t", WCHAR) \
/* Subset of stdint.h. */ \
_("int8_t", INT8) \
_("int16_t", INT16) \
_("int32_t", INT32) \
_("int64_t", INT64) \
_("uint8_t", UINT8) \
_("uint16_t", UINT16) \
_("uint32_t", UINT32) \
_("uint64_t", UINT64) \
_("intptr_t", INT_PSZ) \
_("uintptr_t", UINT_PSZ) \
/* End of typedef list. */
/* Keywords (only the ones we actually care for). */
#define CTKWDEF(_) \
/* Type specifiers. */ \
_("void", -1, CTOK_VOID) \
_("_Bool", 0, CTOK_BOOL) \
_("bool", 1, CTOK_BOOL) \
_("char", 1, CTOK_CHAR) \
_("int", 4, CTOK_INT) \
_("__int8", 1, CTOK_INT) \
_("__int16", 2, CTOK_INT) \
_("__int32", 4, CTOK_INT) \
_("__int64", 8, CTOK_INT) \
_("float", 4, CTOK_FP) \
_("double", 8, CTOK_FP) \
_("long", 0, CTOK_LONG) \
_("short", 0, CTOK_SHORT) \
_("_Complex", 0, CTOK_COMPLEX) \
_("complex", 0, CTOK_COMPLEX) \
_("__complex", 0, CTOK_COMPLEX) \
_("__complex__", 0, CTOK_COMPLEX) \
_("signed", 0, CTOK_SIGNED) \
_("__signed", 0, CTOK_SIGNED) \
_("__signed__", 0, CTOK_SIGNED) \
_("unsigned", 0, CTOK_UNSIGNED) \
/* Type qualifiers. */ \
_("const", 0, CTOK_CONST) \
_("__const", 0, CTOK_CONST) \
_("__const__", 0, CTOK_CONST) \
_("volatile", 0, CTOK_VOLATILE) \
_("__volatile", 0, CTOK_VOLATILE) \
_("__volatile__", 0, CTOK_VOLATILE) \
_("restrict", 0, CTOK_RESTRICT) \
_("__restrict", 0, CTOK_RESTRICT) \
_("__restrict__", 0, CTOK_RESTRICT) \
_("inline", 0, CTOK_INLINE) \
_("__inline", 0, CTOK_INLINE) \
_("__inline__", 0, CTOK_INLINE) \
/* Storage class specifiers. */ \
_("typedef", 0, CTOK_TYPEDEF) \
_("extern", 0, CTOK_EXTERN) \
_("static", 0, CTOK_STATIC) \
_("auto", 0, CTOK_AUTO) \
_("register", 0, CTOK_REGISTER) \
/* GCC Attributes. */ \
_("__extension__", 0, CTOK_EXTENSION) \
_("__attribute", 0, CTOK_ATTRIBUTE) \
_("__attribute__", 0, CTOK_ATTRIBUTE) \
_("asm", 0, CTOK_ASM) \
_("__asm", 0, CTOK_ASM) \
_("__asm__", 0, CTOK_ASM) \
/* MSVC Attributes. */ \
_("__declspec", 0, CTOK_DECLSPEC) \
_("__cdecl", CTCC_CDECL, CTOK_CCDECL) \
_("__thiscall", CTCC_THISCALL, CTOK_CCDECL) \
_("__fastcall", CTCC_FASTCALL, CTOK_CCDECL) \
_("__stdcall", CTCC_STDCALL, CTOK_CCDECL) \
_("__ptr32", 4, CTOK_PTRSZ) \
_("__ptr64", 8, CTOK_PTRSZ) \
/* Other type specifiers. */ \
_("struct", 0, CTOK_STRUCT) \
_("union", 0, CTOK_UNION) \
_("enum", 0, CTOK_ENUM) \
/* Operators. */ \
_("sizeof", 0, CTOK_SIZEOF) \
_("__alignof", 0, CTOK_ALIGNOF) \
_("__alignof__", 0, CTOK_ALIGNOF) \
/* End of keyword list. */
/* Type info for predefined types. Size merged in. */
static CTInfo lj_ctype_typeinfo[] = {
#define CTTYINFODEF(id, sz, ct, info) CTINFO((ct),(((sz)&0x3fu)<<10)+(info)),
#define CTTDINFODEF(name, id) CTINFO(CT_TYPEDEF, CTID_##id),
#define CTKWINFODEF(name, sz, kw) CTINFO(CT_KW,(((sz)&0x3fu)<<10)+(kw)),
CTTYDEF(CTTYINFODEF)
CTTDDEF(CTTDINFODEF)
CTKWDEF(CTKWINFODEF)
#undef CTTYINFODEF
#undef CTTDINFODEF
#undef CTKWINFODEF
0
};
/* Predefined type names collected in a single string. */
static const char * const lj_ctype_typenames =
#define CTTDNAMEDEF(name, id) name "\0"
#define CTKWNAMEDEF(name, sz, cds) name "\0"
CTTDDEF(CTTDNAMEDEF)
CTKWDEF(CTKWNAMEDEF)
#undef CTTDNAMEDEF
#undef CTKWNAMEDEF
;
#define CTTYPEINFO_NUM (sizeof(lj_ctype_typeinfo)/sizeof(CTInfo)-1)
#ifdef LUAJIT_CTYPE_CHECK_ANCHOR
#define CTTYPETAB_MIN CTTYPEINFO_NUM
#else
#define CTTYPETAB_MIN 128
#endif
/* -- C type interning ---------------------------------------------------- */
#define ct_hashtype(info, size) (hashrot(info, size) & CTHASH_MASK)
#define ct_hashname(name) \
(hashrot(u32ptr(name), u32ptr(name) + HASH_BIAS) & CTHASH_MASK)
/* Create new type element. */
CTypeID lj_ctype_new(CTState *cts, CType **ctp)
{
CTypeID id = cts->top;
CType *ct;
lua_assert(cts->L);
if (LJ_UNLIKELY(id >= cts->sizetab)) {
if (id >= CTID_MAX) lj_err_msg(cts->L, LJ_ERR_TABOV);
#ifdef LUAJIT_CTYPE_CHECK_ANCHOR
ct = lj_mem_newvec(cts->L, id+1, CType);
memcpy(ct, cts->tab, id*sizeof(CType));
memset(cts->tab, 0, id*sizeof(CType));
lj_mem_freevec(cts->g, cts->tab, cts->sizetab, CType);
cts->tab = ct;
cts->sizetab = id+1;
#else
lj_mem_growvec(cts->L, cts->tab, cts->sizetab, CTID_MAX, CType);
#endif
}
cts->top = id+1;
*ctp = ct = &cts->tab[id];
ct->info = 0;
ct->size = 0;
ct->sib = 0;
ct->next = 0;
setgcrefnull(ct->name);
return id;
}
/* Intern a type element. */
CTypeID lj_ctype_intern(CTState *cts, CTInfo info, CTSize size)
{
uint32_t h = ct_hashtype(info, size);
CTypeID id = cts->hash[h];
lua_assert(cts->L);
while (id) {
CType *ct = ctype_get(cts, id);
if (ct->info == info && ct->size == size)
return id;
id = ct->next;
}
id = cts->top;
if (LJ_UNLIKELY(id >= cts->sizetab)) {
if (id >= CTID_MAX) lj_err_msg(cts->L, LJ_ERR_TABOV);
lj_mem_growvec(cts->L, cts->tab, cts->sizetab, CTID_MAX, CType);
}
cts->top = id+1;
cts->tab[id].info = info;
cts->tab[id].size = size;
cts->tab[id].sib = 0;
cts->tab[id].next = cts->hash[h];
setgcrefnull(cts->tab[id].name);
cts->hash[h] = (CTypeID1)id;
return id;
}
/* Add type element to hash table. */
static void ctype_addtype(CTState *cts, CType *ct, CTypeID id)
{
uint32_t h = ct_hashtype(ct->info, ct->size);
ct->next = cts->hash[h];
cts->hash[h] = (CTypeID1)id;
}
/* Add named element to hash table. */
void lj_ctype_addname(CTState *cts, CType *ct, CTypeID id)
{
uint32_t h = ct_hashname(gcref(ct->name));
ct->next = cts->hash[h];
cts->hash[h] = (CTypeID1)id;
}
/* Get a C type by name, matching the type mask. */
CTypeID lj_ctype_getname(CTState *cts, CType **ctp, GCstr *name, uint32_t tmask)
{
CTypeID id = cts->hash[ct_hashname(name)];
while (id) {
CType *ct = ctype_get(cts, id);
if (gcref(ct->name) == obj2gco(name) &&
((tmask >> ctype_type(ct->info)) & 1)) {
*ctp = ct;
return id;
}
id = ct->next;
}
*ctp = &cts->tab[0]; /* Simplify caller logic. ctype_get() would assert. */
return 0;
}
/* Get a struct/union/enum/function field by name. */
CType *lj_ctype_getfieldq(CTState *cts, CType *ct, GCstr *name, CTSize *ofs,
CTInfo *qual)
{
while (ct->sib) {
ct = ctype_get(cts, ct->sib);
if (gcref(ct->name) == obj2gco(name)) {
*ofs = ct->size;
return ct;
}
if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
CType *fct, *cct = ctype_child(cts, ct);
CTInfo q = 0;
while (ctype_isattrib(cct->info)) {
if (ctype_attrib(cct->info) == CTA_QUAL) q |= cct->size;
cct = ctype_child(cts, cct);
}
fct = lj_ctype_getfieldq(cts, cct, name, ofs, qual);
if (fct) {
if (qual) *qual |= q;
*ofs += ct->size;
return fct;
}
}
}
return NULL; /* Not found. */
}
/* -- C type information -------------------------------------------------- */
/* Follow references and get raw type for a C type ID. */
CType *lj_ctype_rawref(CTState *cts, CTypeID id)
{
CType *ct = ctype_get(cts, id);
while (ctype_isattrib(ct->info) || ctype_isref(ct->info))
ct = ctype_child(cts, ct);
return ct;
}
/* Get size for a C type ID. Does NOT support VLA/VLS. */
CTSize lj_ctype_size(CTState *cts, CTypeID id)
{
CType *ct = ctype_raw(cts, id);
return ctype_hassize(ct->info) ? ct->size : CTSIZE_INVALID;
}
/* Get size for a variable-length C type. Does NOT support other C types. */
CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem)
{
uint64_t xsz = 0;
if (ctype_isstruct(ct->info)) {
CTypeID arrid = 0, fid = ct->sib;
xsz = ct->size; /* Add the struct size. */
while (fid) {
CType *ctf = ctype_get(cts, fid);
if (ctype_type(ctf->info) == CT_FIELD)
arrid = ctype_cid(ctf->info); /* Remember last field of VLS. */
fid = ctf->sib;
}
ct = ctype_raw(cts, arrid);
}
lua_assert(ctype_isvlarray(ct->info)); /* Must be a VLA. */
ct = ctype_rawchild(cts, ct); /* Get array element. */
lua_assert(ctype_hassize(ct->info));
/* Calculate actual size of VLA and check for overflow. */
xsz += (uint64_t)ct->size * nelem;
return xsz < 0x80000000u ? (CTSize)xsz : CTSIZE_INVALID;
}
/* Get type, qualifiers, size and alignment for a C type ID. */
CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp)
{
CTInfo qual = 0;
CType *ct = ctype_get(cts, id);
for (;;) {
CTInfo info = ct->info;
if (ctype_isenum(info)) {
/* Follow child. Need to look at its attributes, too. */
} else if (ctype_isattrib(info)) {
if (ctype_isxattrib(info, CTA_QUAL))
qual |= ct->size;
else if (ctype_isxattrib(info, CTA_ALIGN) && !(qual & CTFP_ALIGNED))
qual |= CTFP_ALIGNED + CTALIGN(ct->size);
} else {
if (!(qual & CTFP_ALIGNED)) qual |= (info & CTF_ALIGN);
qual |= (info & ~(CTF_ALIGN|CTMASK_CID));
lua_assert(ctype_hassize(info) || ctype_isfunc(info));
*szp = ctype_isfunc(info) ? CTSIZE_INVALID : ct->size;
break;
}
ct = ctype_get(cts, ctype_cid(info));
}
return qual;
}
/* Get ctype metamethod. */
cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm)
{
CType *ct = ctype_get(cts, id);
cTValue *tv;
while (ctype_isattrib(ct->info) || ctype_isref(ct->info)) {
id = ctype_cid(ct->info);
ct = ctype_get(cts, id);
}
if (ctype_isptr(ct->info) &&
ctype_isfunc(ctype_get(cts, ctype_cid(ct->info))->info))
tv = lj_tab_getstr(cts->miscmap, &cts->g->strempty);
else
tv = lj_tab_getinth(cts->miscmap, -(int32_t)id);
if (tv && tvistab(tv) &&
(tv = lj_tab_getstr(tabV(tv), mmname_str(cts->g, mm))) && !tvisnil(tv))
return tv;
return NULL;
}
/* -- C type representation ----------------------------------------------- */
/* Fixed max. length of a C type representation. */
#define CTREPR_MAX 512
typedef struct CTRepr {
char *pb, *pe;
CTState *cts;
lua_State *L;
int needsp;
int ok;
char buf[CTREPR_MAX];
} CTRepr;
/* Prepend string. */
static void ctype_prepstr(CTRepr *ctr, const char *str, MSize len)
{
char *p = ctr->pb;
if (ctr->buf + len+1 > p) { ctr->ok = 0; return; }
if (ctr->needsp) *--p = ' ';
ctr->needsp = 1;
p -= len;
while (len-- > 0) p[len] = str[len];
ctr->pb = p;
}
#define ctype_preplit(ctr, str) ctype_prepstr((ctr), "" str, sizeof(str)-1)
/* Prepend char. */
static void ctype_prepc(CTRepr *ctr, int c)
{
if (ctr->buf >= ctr->pb) { ctr->ok = 0; return; }
*--ctr->pb = c;
}
/* Prepend number. */
static void ctype_prepnum(CTRepr *ctr, uint32_t n)
{
char *p = ctr->pb;
if (ctr->buf + 10+1 > p) { ctr->ok = 0; return; }
do { *--p = (char)('0' + n % 10); } while (n /= 10);
ctr->pb = p;
ctr->needsp = 0;
}
/* Append char. */
static void ctype_appc(CTRepr *ctr, int c)
{
if (ctr->pe >= ctr->buf + CTREPR_MAX) { ctr->ok = 0; return; }
*ctr->pe++ = c;
}
/* Append number. */
static void ctype_appnum(CTRepr *ctr, uint32_t n)
{
char buf[10];
char *p = buf+sizeof(buf);
char *q = ctr->pe;
if (q > ctr->buf + CTREPR_MAX - 10) { ctr->ok = 0; return; }
do { *--p = (char)('0' + n % 10); } while (n /= 10);
do { *q++ = *p++; } while (p < buf+sizeof(buf));
ctr->pe = q;
}
/* Prepend qualifiers. */
static void ctype_prepqual(CTRepr *ctr, CTInfo info)
{
if ((info & CTF_VOLATILE)) ctype_preplit(ctr, "volatile");
if ((info & CTF_CONST)) ctype_preplit(ctr, "const");
}
/* Prepend named type. */
static void ctype_preptype(CTRepr *ctr, CType *ct, CTInfo qual, const char *t)
{
if (gcref(ct->name)) {
GCstr *str = gco2str(gcref(ct->name));
ctype_prepstr(ctr, strdata(str), str->len);
} else {
if (ctr->needsp) ctype_prepc(ctr, ' ');
ctype_prepnum(ctr, ctype_typeid(ctr->cts, ct));
ctr->needsp = 1;
}
ctype_prepstr(ctr, t, (MSize)strlen(t));
ctype_prepqual(ctr, qual);
}
static void ctype_repr(CTRepr *ctr, CTypeID id)
{
CType *ct = ctype_get(ctr->cts, id);
CTInfo qual = 0;
int ptrto = 0;
for (;;) {
CTInfo info = ct->info;
CTSize size = ct->size;
switch (ctype_type(info)) {
case CT_NUM:
if ((info & CTF_BOOL)) {
ctype_preplit(ctr, "bool");
} else if ((info & CTF_FP)) {
if (size == sizeof(double)) ctype_preplit(ctr, "double");
else if (size == sizeof(float)) ctype_preplit(ctr, "float");
else ctype_preplit(ctr, "long double");
} else if (size == 1) {
if (!((info ^ CTF_UCHAR) & CTF_UNSIGNED)) ctype_preplit(ctr, "char");
else if (CTF_UCHAR) ctype_preplit(ctr, "signed char");
else ctype_preplit(ctr, "unsigned char");
} else if (size < 8) {
if (size == 4) ctype_preplit(ctr, "int");
else ctype_preplit(ctr, "short");
if ((info & CTF_UNSIGNED)) ctype_preplit(ctr, "unsigned");
} else {
ctype_preplit(ctr, "_t");
ctype_prepnum(ctr, size*8);
ctype_preplit(ctr, "int");
if ((info & CTF_UNSIGNED)) ctype_prepc(ctr, 'u');
}
ctype_prepqual(ctr, (qual|info));
return;
case CT_VOID:
ctype_preplit(ctr, "void");
ctype_prepqual(ctr, (qual|info));
return;
case CT_STRUCT:
ctype_preptype(ctr, ct, qual, (info & CTF_UNION) ? "union" : "struct");
return;
case CT_ENUM:
if (id == CTID_CTYPEID) {
ctype_preplit(ctr, "ctype");
return;
}
ctype_preptype(ctr, ct, qual, "enum");
return;
case CT_ATTRIB:
if (ctype_attrib(info) == CTA_QUAL) qual |= size;
break;
case CT_PTR:
if ((info & CTF_REF)) {
ctype_prepc(ctr, '&');
} else {
ctype_prepqual(ctr, (qual|info));
if (LJ_64 && size == 4) ctype_preplit(ctr, "__ptr32");
ctype_prepc(ctr, '*');
}
qual = 0;
ptrto = 1;
ctr->needsp = 1;
break;
case CT_ARRAY:
if (ctype_isrefarray(info)) {
ctr->needsp = 1;
if (ptrto) { ptrto = 0; ctype_prepc(ctr, '('); ctype_appc(ctr, ')'); }
ctype_appc(ctr, '[');
if (size != CTSIZE_INVALID) {
CTSize csize = ctype_child(ctr->cts, ct)->size;
ctype_appnum(ctr, csize ? size/csize : 0);
} else if ((info & CTF_VLA)) {
ctype_appc(ctr, '?');
}
ctype_appc(ctr, ']');
} else if ((info & CTF_COMPLEX)) {
if (size == 2*sizeof(float)) ctype_preplit(ctr, "float");
ctype_preplit(ctr, "complex");
return;
} else {
ctype_preplit(ctr, ")))");
ctype_prepnum(ctr, size);
ctype_preplit(ctr, "__attribute__((vector_size(");
}
break;
case CT_FUNC:
ctr->needsp = 1;
if (ptrto) { ptrto = 0; ctype_prepc(ctr, '('); ctype_appc(ctr, ')'); }
ctype_appc(ctr, '(');
ctype_appc(ctr, ')');
break;
default:
lua_assert(0);
break;
}
ct = ctype_get(ctr->cts, ctype_cid(info));
}
}
/* Return a printable representation of a C type. */
GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name)
{
global_State *g = G(L);
CTRepr ctr;
ctr.pb = ctr.pe = &ctr.buf[CTREPR_MAX/2];
ctr.cts = ctype_ctsG(g);
ctr.L = L;
ctr.ok = 1;
ctr.needsp = 0;
if (name) ctype_prepstr(&ctr, strdata(name), name->len);
ctype_repr(&ctr, id);
if (LJ_UNLIKELY(!ctr.ok)) return lj_str_newlit(L, "?");
return lj_str_new(L, ctr.pb, ctr.pe - ctr.pb);
}
/* Convert int64_t/uint64_t to string with 'LL' or 'ULL' suffix. */
GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned)
{
char buf[1+20+3];
char *p = buf+sizeof(buf);
int sign = 0;
*--p = 'L'; *--p = 'L';
if (isunsigned) {
*--p = 'U';
} else if ((int64_t)n < 0) {
n = (uint64_t)-(int64_t)n;
sign = 1;
}
do { *--p = (char)('0' + n % 10); } while (n /= 10);
if (sign) *--p = '-';
return lj_str_new(L, p, (size_t)(buf+sizeof(buf)-p));
}
/* Convert complex to string with 'i' or 'I' suffix. */
GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size)
{
char buf[2*LJ_STR_NUMBUF+2+1];
TValue re, im;
size_t len;
if (size == 2*sizeof(double)) {
re.n = *(double *)sp; im.n = ((double *)sp)[1];
} else {
re.n = (double)*(float *)sp; im.n = (double)((float *)sp)[1];
}
len = lj_str_bufnum(buf, &re);
if (!(im.u32.hi & 0x80000000u) || im.n != im.n) buf[len++] = '+';
len += lj_str_bufnum(buf+len, &im);
buf[len] = buf[len-1] >= 'a' ? 'I' : 'i';
return lj_str_new(L, buf, len+1);
}
/* -- C type state -------------------------------------------------------- */
/* Initialize C type table and state. */
CTState *lj_ctype_init(lua_State *L)
{
CTState *cts = lj_mem_newt(L, sizeof(CTState), CTState);
CType *ct = lj_mem_newvec(L, CTTYPETAB_MIN, CType);
const char *name = lj_ctype_typenames;
CTypeID id;
memset(cts, 0, sizeof(CTState));
cts->tab = ct;
cts->sizetab = CTTYPETAB_MIN;
cts->top = CTTYPEINFO_NUM;
cts->L = NULL;
cts->g = G(L);
for (id = 0; id < CTTYPEINFO_NUM; id++, ct++) {
CTInfo info = lj_ctype_typeinfo[id];
ct->size = (CTSize)((int32_t)(info << 16) >> 26);
ct->info = info & 0xffff03ffu;
ct->sib = 0;
if (ctype_type(info) == CT_KW || ctype_istypedef(info)) {
size_t len = strlen(name);
GCstr *str = lj_str_new(L, name, len);
ctype_setname(ct, str);
name += len+1;
lj_ctype_addname(cts, ct, id);
} else {
setgcrefnull(ct->name);
ct->next = 0;
if (!ctype_isenum(info)) ctype_addtype(cts, ct, id);
}
}
setmref(G(L)->ctype_state, cts);
return cts;
}
/* Free C type table and state. */
void lj_ctype_freestate(global_State *g)
{
CTState *cts = ctype_ctsG(g);
if (cts) {
lj_ccallback_mcode_free(cts);
lj_mem_freevec(g, cts->tab, cts->sizetab, CType);
lj_mem_freevec(g, cts->cb.cbid, cts->cb.sizeid, CTypeID1);
lj_mem_freet(g, cts);
}
}
#endif

View File

@ -1,461 +0,0 @@
/*
** C type management.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CTYPE_H
#define _LJ_CTYPE_H
#include "lj_obj.h"
#include "lj_gc.h"
#if LJ_HASFFI
/* -- C type definitions -------------------------------------------------- */
/* C type numbers. Highest 4 bits of C type info. ORDER CT. */
enum {
/* Externally visible types. */
CT_NUM, /* Integer or floating-point numbers. */
CT_STRUCT, /* Struct or union. */
CT_PTR, /* Pointer or reference. */
CT_ARRAY, /* Array or complex type. */
CT_MAYCONVERT = CT_ARRAY,
CT_VOID, /* Void type. */
CT_ENUM, /* Enumeration. */
CT_HASSIZE = CT_ENUM, /* Last type where ct->size holds the actual size. */
CT_FUNC, /* Function. */
CT_TYPEDEF, /* Typedef. */
CT_ATTRIB, /* Miscellaneous attributes. */
/* Internal element types. */
CT_FIELD, /* Struct/union field or function parameter. */
CT_BITFIELD, /* Struct/union bitfield. */
CT_CONSTVAL, /* Constant value. */
CT_EXTERN, /* External reference. */
CT_KW /* Keyword. */
};
LJ_STATIC_ASSERT(((int)CT_PTR & (int)CT_ARRAY) == CT_PTR);
LJ_STATIC_ASSERT(((int)CT_STRUCT & (int)CT_ARRAY) == CT_STRUCT);
/*
** ---------- info ------------
** |type flags... A cid | size | sib | next | name |
** +----------------------------+--------+-------+-------+-------+--
** |NUM BFcvUL.. A | size | | type | |
** |STRUCT ..cvU..V A | size | field | name? | name? |
** |PTR ..cvR... A cid | size | | type | |
** |ARRAY VCcv...V A cid | size | | type | |
** |VOID ..cv.... A | size | | type | |
** |ENUM A cid | size | const | name? | name? |
** |FUNC ....VS.. cc cid | nargs | field | name? | name? |
** |TYPEDEF cid | | | name | name |
** |ATTRIB attrnum cid | attr | sib? | type? | |
** |FIELD cid | offset | field | | name? |
** |BITFIELD B.cvU csz bsz pos | offset | field | | name? |
** |CONSTVAL c cid | value | const | name | name |
** |EXTERN cid | | sib? | name | name |
** |KW tok | size | | name | name |
** +----------------------------+--------+-------+-------+-------+--
** ^^ ^^--- bits used for C type conversion dispatch
*/
/* C type info flags. TFFArrrr */
#define CTF_BOOL 0x08000000u /* Boolean: NUM, BITFIELD. */
#define CTF_FP 0x04000000u /* Floating-point: NUM. */
#define CTF_CONST 0x02000000u /* Const qualifier. */
#define CTF_VOLATILE 0x01000000u /* Volatile qualifier. */
#define CTF_UNSIGNED 0x00800000u /* Unsigned: NUM, BITFIELD. */
#define CTF_LONG 0x00400000u /* Long: NUM. */
#define CTF_VLA 0x00100000u /* Variable-length: ARRAY, STRUCT. */
#define CTF_REF 0x00800000u /* Reference: PTR. */
#define CTF_VECTOR 0x08000000u /* Vector: ARRAY. */
#define CTF_COMPLEX 0x04000000u /* Complex: ARRAY. */
#define CTF_UNION 0x00800000u /* Union: STRUCT. */
#define CTF_VARARG 0x00800000u /* Vararg: FUNC. */
#define CTF_SSEREGPARM 0x00400000u /* SSE register parameters: FUNC. */
#define CTF_QUAL (CTF_CONST|CTF_VOLATILE)
#define CTF_ALIGN (CTMASK_ALIGN<<CTSHIFT_ALIGN)
#define CTF_UCHAR ((char)-1 > 0 ? CTF_UNSIGNED : 0)
/* Flags used in parser. .F.Ammvf cp->attr */
#define CTFP_ALIGNED 0x00000001u /* cp->attr + ALIGN */
#define CTFP_PACKED 0x00000002u /* cp->attr */
/* ...C...f cp->fattr */
#define CTFP_CCONV 0x00000001u /* cp->fattr + CCONV/[SSE]REGPARM */
/* C type info bitfields. */
#define CTMASK_CID 0x0000ffffu /* Max. 65536 type IDs. */
#define CTMASK_NUM 0xf0000000u /* Max. 16 type numbers. */
#define CTSHIFT_NUM 28
#define CTMASK_ALIGN 15 /* Max. alignment is 2^15. */
#define CTSHIFT_ALIGN 16
#define CTMASK_ATTRIB 255 /* Max. 256 attributes. */
#define CTSHIFT_ATTRIB 16
#define CTMASK_CCONV 3 /* Max. 4 calling conventions. */
#define CTSHIFT_CCONV 16
#define CTMASK_REGPARM 3 /* Max. 0-3 regparms. */
#define CTSHIFT_REGPARM 18
/* Bitfields only used in parser. */
#define CTMASK_VSIZEP 15 /* Max. vector size is 2^15. */
#define CTSHIFT_VSIZEP 4
#define CTMASK_MSIZEP 255 /* Max. type size (via mode) is 128. */
#define CTSHIFT_MSIZEP 8
/* Info bits for BITFIELD. Max. size of bitfield is 64 bits. */
#define CTBSZ_MAX 32 /* Max. size of bitfield is 32 bit. */
#define CTBSZ_FIELD 127 /* Temp. marker for regular field. */
#define CTMASK_BITPOS 127
#define CTMASK_BITBSZ 127
#define CTMASK_BITCSZ 127
#define CTSHIFT_BITPOS 0
#define CTSHIFT_BITBSZ 8
#define CTSHIFT_BITCSZ 16
#define CTF_INSERT(info, field, val) \
info = (info & ~(CTMASK_##field<<CTSHIFT_##field)) | \
(((CTSize)(val) & CTMASK_##field) << CTSHIFT_##field)
/* Calling conventions. ORDER CC */
enum { CTCC_CDECL, CTCC_THISCALL, CTCC_FASTCALL, CTCC_STDCALL };
/* Attribute numbers. */
enum {
CTA_NONE, /* Ignored attribute. Must be zero. */
CTA_QUAL, /* Unmerged qualifiers. */
CTA_ALIGN, /* Alignment override. */
CTA_SUBTYPE, /* Transparent sub-type. */
CTA_REDIR, /* Redirected symbol name. */
CTA_BAD, /* To catch bad IDs. */
CTA__MAX
};
/* Special sizes. */
#define CTSIZE_INVALID 0xffffffffu
typedef uint32_t CTInfo; /* Type info. */
typedef uint32_t CTSize; /* Type size. */
typedef uint32_t CTypeID; /* Type ID. */
typedef uint16_t CTypeID1; /* Minimum-sized type ID. */
/* C type table element. */
typedef struct CType {
CTInfo info; /* Type info. */
CTSize size; /* Type size or other info. */
CTypeID1 sib; /* Sibling element. */
CTypeID1 next; /* Next element in hash chain. */
GCRef name; /* Element name (GCstr). */
} CType;
#define CTHASH_SIZE 128 /* Number of hash anchors. */
#define CTHASH_MASK (CTHASH_SIZE-1)
/* Simplify target-specific configuration. Checked in lj_ccall.h. */
#define CCALL_MAX_GPR 8
#define CCALL_MAX_FPR 8
typedef LJ_ALIGN(8) union FPRCBArg { double d; float f[2]; } FPRCBArg;
/* C callback state. Defined here, to avoid dragging in lj_ccall.h. */
typedef LJ_ALIGN(8) struct CCallback {
FPRCBArg fpr[CCALL_MAX_FPR]; /* Arguments/results in FPRs. */
intptr_t gpr[CCALL_MAX_GPR]; /* Arguments/results in GPRs. */
intptr_t *stack; /* Pointer to arguments on stack. */
void *mcode; /* Machine code for callback func. pointers. */
CTypeID1 *cbid; /* Callback type table. */
MSize sizeid; /* Size of callback type table. */
MSize topid; /* Highest unused callback type table slot. */
MSize slot; /* Current callback slot. */
} CCallback;
/* C type state. */
typedef struct CTState {
CType *tab; /* C type table. */
CTypeID top; /* Current top of C type table. */
MSize sizetab; /* Size of C type table. */
lua_State *L; /* Lua state (needed for errors and allocations). */
global_State *g; /* Global state. */
GCtab *finalizer; /* Map of cdata to finalizer. */
GCtab *miscmap; /* Map of -CTypeID to metatable and cb slot to func. */
CCallback cb; /* Temporary callback state. */
CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */
} CTState;
#define CTINFO(ct, flags) (((CTInfo)(ct) << CTSHIFT_NUM) + (flags))
#define CTALIGN(al) ((CTSize)(al) << CTSHIFT_ALIGN)
#define CTATTRIB(at) ((CTInfo)(at) << CTSHIFT_ATTRIB)
#define ctype_type(info) ((info) >> CTSHIFT_NUM)
#define ctype_cid(info) ((CTypeID)((info) & CTMASK_CID))
#define ctype_align(info) (((info) >> CTSHIFT_ALIGN) & CTMASK_ALIGN)
#define ctype_attrib(info) (((info) >> CTSHIFT_ATTRIB) & CTMASK_ATTRIB)
#define ctype_bitpos(info) (((info) >> CTSHIFT_BITPOS) & CTMASK_BITPOS)
#define ctype_bitbsz(info) (((info) >> CTSHIFT_BITBSZ) & CTMASK_BITBSZ)
#define ctype_bitcsz(info) (((info) >> CTSHIFT_BITCSZ) & CTMASK_BITCSZ)
#define ctype_vsizeP(info) (((info) >> CTSHIFT_VSIZEP) & CTMASK_VSIZEP)
#define ctype_msizeP(info) (((info) >> CTSHIFT_MSIZEP) & CTMASK_MSIZEP)
#define ctype_cconv(info) (((info) >> CTSHIFT_CCONV) & CTMASK_CCONV)
/* Simple type checks. */
#define ctype_isnum(info) (ctype_type((info)) == CT_NUM)
#define ctype_isvoid(info) (ctype_type((info)) == CT_VOID)
#define ctype_isptr(info) (ctype_type((info)) == CT_PTR)
#define ctype_isarray(info) (ctype_type((info)) == CT_ARRAY)
#define ctype_isstruct(info) (ctype_type((info)) == CT_STRUCT)
#define ctype_isfunc(info) (ctype_type((info)) == CT_FUNC)
#define ctype_isenum(info) (ctype_type((info)) == CT_ENUM)
#define ctype_istypedef(info) (ctype_type((info)) == CT_TYPEDEF)
#define ctype_isattrib(info) (ctype_type((info)) == CT_ATTRIB)
#define ctype_isfield(info) (ctype_type((info)) == CT_FIELD)
#define ctype_isbitfield(info) (ctype_type((info)) == CT_BITFIELD)
#define ctype_isconstval(info) (ctype_type((info)) == CT_CONSTVAL)
#define ctype_isextern(info) (ctype_type((info)) == CT_EXTERN)
#define ctype_hassize(info) (ctype_type((info)) <= CT_HASSIZE)
/* Combined type and flag checks. */
#define ctype_isinteger(info) \
(((info) & (CTMASK_NUM|CTF_BOOL|CTF_FP)) == CTINFO(CT_NUM, 0))
#define ctype_isinteger_or_bool(info) \
(((info) & (CTMASK_NUM|CTF_FP)) == CTINFO(CT_NUM, 0))
#define ctype_isbool(info) \
(((info) & (CTMASK_NUM|CTF_BOOL)) == CTINFO(CT_NUM, CTF_BOOL))
#define ctype_isfp(info) \
(((info) & (CTMASK_NUM|CTF_FP)) == CTINFO(CT_NUM, CTF_FP))
#define ctype_ispointer(info) \
((ctype_type(info) >> 1) == (CT_PTR >> 1)) /* Pointer or array. */
#define ctype_isref(info) \
(((info) & (CTMASK_NUM|CTF_REF)) == CTINFO(CT_PTR, CTF_REF))
#define ctype_isrefarray(info) \
(((info) & (CTMASK_NUM|CTF_VECTOR|CTF_COMPLEX)) == CTINFO(CT_ARRAY, 0))
#define ctype_isvector(info) \
(((info) & (CTMASK_NUM|CTF_VECTOR)) == CTINFO(CT_ARRAY, CTF_VECTOR))
#define ctype_iscomplex(info) \
(((info) & (CTMASK_NUM|CTF_COMPLEX)) == CTINFO(CT_ARRAY, CTF_COMPLEX))
#define ctype_isvltype(info) \
(((info) & ((CTMASK_NUM|CTF_VLA) - (2u<<CTSHIFT_NUM))) == \
CTINFO(CT_STRUCT, CTF_VLA)) /* VL array or VL struct. */
#define ctype_isvlarray(info) \
(((info) & (CTMASK_NUM|CTF_VLA)) == CTINFO(CT_ARRAY, CTF_VLA))
#define ctype_isxattrib(info, at) \
(((info) & (CTMASK_NUM|CTATTRIB(CTMASK_ATTRIB))) == \
CTINFO(CT_ATTRIB, CTATTRIB(at)))
/* Target-dependent sizes and alignments. */
#if LJ_64
#define CTSIZE_PTR 8
#define CTALIGN_PTR CTALIGN(3)
#else
#define CTSIZE_PTR 4
#define CTALIGN_PTR CTALIGN(2)
#endif
#define CTINFO_REF(ref) \
CTINFO(CT_PTR, (CTF_CONST|CTF_REF|CTALIGN_PTR) + (ref))
#define CT_MEMALIGN 3 /* Alignment guaranteed by memory allocator. */
/* -- Predefined types ---------------------------------------------------- */
/* Target-dependent types. */
#if LJ_TARGET_PPC || LJ_TARGET_PPCSPE
#define CTTYDEFP(_) \
_(LINT32, 4, CT_NUM, CTF_LONG|CTALIGN(2))
#else
#define CTTYDEFP(_)
#endif
/* Common types. */
#define CTTYDEF(_) \
_(NONE, 0, CT_ATTRIB, CTATTRIB(CTA_BAD)) \
_(VOID, -1, CT_VOID, CTALIGN(0)) \
_(CVOID, -1, CT_VOID, CTF_CONST|CTALIGN(0)) \
_(BOOL, 1, CT_NUM, CTF_BOOL|CTF_UNSIGNED|CTALIGN(0)) \
_(CCHAR, 1, CT_NUM, CTF_CONST|CTF_UCHAR|CTALIGN(0)) \
_(INT8, 1, CT_NUM, CTALIGN(0)) \
_(UINT8, 1, CT_NUM, CTF_UNSIGNED|CTALIGN(0)) \
_(INT16, 2, CT_NUM, CTALIGN(1)) \
_(UINT16, 2, CT_NUM, CTF_UNSIGNED|CTALIGN(1)) \
_(INT32, 4, CT_NUM, CTALIGN(2)) \
_(UINT32, 4, CT_NUM, CTF_UNSIGNED|CTALIGN(2)) \
_(INT64, 8, CT_NUM, CTF_LONG|CTALIGN(3)) \
_(UINT64, 8, CT_NUM, CTF_UNSIGNED|CTF_LONG|CTALIGN(3)) \
_(FLOAT, 4, CT_NUM, CTF_FP|CTALIGN(2)) \
_(DOUBLE, 8, CT_NUM, CTF_FP|CTALIGN(3)) \
_(COMPLEX_FLOAT, 8, CT_ARRAY, CTF_COMPLEX|CTALIGN(2)|CTID_FLOAT) \
_(COMPLEX_DOUBLE, 16, CT_ARRAY, CTF_COMPLEX|CTALIGN(3)|CTID_DOUBLE) \
_(P_VOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_VOID) \
_(P_CVOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CVOID) \
_(P_CCHAR, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CCHAR) \
_(A_CCHAR, -1, CT_ARRAY, CTF_CONST|CTALIGN(0)|CTID_CCHAR) \
_(CTYPEID, 4, CT_ENUM, CTALIGN(2)|CTID_INT32) \
CTTYDEFP(_) \
/* End of type list. */
/* Public predefined type IDs. */
enum {
#define CTTYIDDEF(id, sz, ct, info) CTID_##id,
CTTYDEF(CTTYIDDEF)
#undef CTTYIDDEF
/* Predefined typedefs and keywords follow. */
CTID_MAX = 65536
};
/* Target-dependent type IDs. */
#if LJ_64
#define CTID_INT_PSZ CTID_INT64
#define CTID_UINT_PSZ CTID_UINT64
#else
#define CTID_INT_PSZ CTID_INT32
#define CTID_UINT_PSZ CTID_UINT32
#endif
#if LJ_ABI_WIN
#define CTID_WCHAR CTID_UINT16
#elif LJ_TARGET_PPC
#define CTID_WCHAR CTID_LINT32
#else
#define CTID_WCHAR CTID_INT32
#endif
/* -- C tokens and keywords ----------------------------------------------- */
/* C lexer keywords. */
#define CTOKDEF(_) \
_(IDENT, "<identifier>") _(STRING, "<string>") \
_(INTEGER, "<integer>") _(EOF, "<eof>") \
_(OROR, "||") _(ANDAND, "&&") _(EQ, "==") _(NE, "!=") \
_(LE, "<=") _(GE, ">=") _(SHL, "<<") _(SHR, ">>") _(DEREF, "->")
/* Simple declaration specifiers. */
#define CDSDEF(_) \
_(VOID) _(BOOL) _(CHAR) _(INT) _(FP) \
_(LONG) _(LONGLONG) _(SHORT) _(COMPLEX) _(SIGNED) _(UNSIGNED) \
_(CONST) _(VOLATILE) _(RESTRICT) _(INLINE) \
_(TYPEDEF) _(EXTERN) _(STATIC) _(AUTO) _(REGISTER)
/* C keywords. */
#define CKWDEF(_) \
CDSDEF(_) _(EXTENSION) _(ASM) _(ATTRIBUTE) \
_(DECLSPEC) _(CCDECL) _(PTRSZ) \
_(STRUCT) _(UNION) _(ENUM) \
_(SIZEOF) _(ALIGNOF)
/* C token numbers. */
enum {
CTOK_OFS = 255,
#define CTOKNUM(name, sym) CTOK_##name,
#define CKWNUM(name) CTOK_##name,
CTOKDEF(CTOKNUM)
CKWDEF(CKWNUM)
#undef CTOKNUM
#undef CKWNUM
CTOK_FIRSTDECL = CTOK_VOID,
CTOK_FIRSTSCL = CTOK_TYPEDEF,
CTOK_LASTDECLFLAG = CTOK_REGISTER,
CTOK_LASTDECL = CTOK_ENUM
};
/* Declaration specifier flags. */
enum {
#define CDSFLAG(name) CDF_##name = (1u << (CTOK_##name - CTOK_FIRSTDECL)),
CDSDEF(CDSFLAG)
#undef CDSFLAG
CDF__END
};
#define CDF_SCL (CDF_TYPEDEF|CDF_EXTERN|CDF_STATIC|CDF_AUTO|CDF_REGISTER)
/* -- C type management --------------------------------------------------- */
#define ctype_ctsG(g) (mref((g)->ctype_state, CTState))
/* Get C type state. */
static LJ_AINLINE CTState *ctype_cts(lua_State *L)
{
CTState *cts = ctype_ctsG(G(L));
cts->L = L; /* Save L for errors and allocations. */
return cts;
}
/* Save and restore state of C type table. */
#define LJ_CTYPE_SAVE(cts) CTState savects_ = *(cts)
#define LJ_CTYPE_RESTORE(cts) \
((cts)->top = savects_.top, \
memcpy((cts)->hash, savects_.hash, sizeof(savects_.hash)))
/* Check C type ID for validity when assertions are enabled. */
static LJ_AINLINE CTypeID ctype_check(CTState *cts, CTypeID id)
{
lua_assert(id > 0 && id < cts->top); UNUSED(cts);
return id;
}
/* Get C type for C type ID. */
static LJ_AINLINE CType *ctype_get(CTState *cts, CTypeID id)
{
return &cts->tab[ctype_check(cts, id)];
}
/* Get C type ID for a C type. */
#define ctype_typeid(cts, ct) ((CTypeID)((ct) - (cts)->tab))
/* Get child C type. */
static LJ_AINLINE CType *ctype_child(CTState *cts, CType *ct)
{
lua_assert(!(ctype_isvoid(ct->info) || ctype_isstruct(ct->info) ||
ctype_isbitfield(ct->info))); /* These don't have children. */
return ctype_get(cts, ctype_cid(ct->info));
}
/* Get raw type for a C type ID. */
static LJ_AINLINE CType *ctype_raw(CTState *cts, CTypeID id)
{
CType *ct = ctype_get(cts, id);
while (ctype_isattrib(ct->info)) ct = ctype_child(cts, ct);
return ct;
}
/* Get raw type of the child of a C type. */
static LJ_AINLINE CType *ctype_rawchild(CTState *cts, CType *ct)
{
do { ct = ctype_child(cts, ct); } while (ctype_isattrib(ct->info));
return ct;
}
/* Set the name of a C type table element. */
static LJ_AINLINE void ctype_setname(CType *ct, GCstr *s)
{
/* NOBARRIER: mark string as fixed -- the C type table is never collected. */
fixstring(s);
setgcref(ct->name, obj2gco(s));
}
LJ_FUNC CTypeID lj_ctype_new(CTState *cts, CType **ctp);
LJ_FUNC CTypeID lj_ctype_intern(CTState *cts, CTInfo info, CTSize size);
LJ_FUNC void lj_ctype_addname(CTState *cts, CType *ct, CTypeID id);
LJ_FUNC CTypeID lj_ctype_getname(CTState *cts, CType **ctp, GCstr *name,
uint32_t tmask);
LJ_FUNC CType *lj_ctype_getfieldq(CTState *cts, CType *ct, GCstr *name,
CTSize *ofs, CTInfo *qual);
#define lj_ctype_getfield(cts, ct, name, ofs) \
lj_ctype_getfieldq((cts), (ct), (name), (ofs), NULL)
LJ_FUNC CType *lj_ctype_rawref(CTState *cts, CTypeID id);
LJ_FUNC CTSize lj_ctype_size(CTState *cts, CTypeID id);
LJ_FUNC CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem);
LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp);
LJ_FUNC cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm);
LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name);
LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned);
LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size);
LJ_FUNC CTState *lj_ctype_init(lua_State *L);
LJ_FUNC void lj_ctype_freestate(global_State *g);
#endif
#endif

View File

@ -1,605 +0,0 @@
/*
** Debugging and introspection.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_debug_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_debug.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_state.h"
#include "lj_frame.h"
#include "lj_bc.h"
#include "lj_vm.h"
#if LJ_HASJIT
#include "lj_jit.h"
#endif
/* -- Frames -------------------------------------------------------------- */
/* Get frame corresponding to a level. */
cTValue *lj_debug_frame(lua_State *L, int level, int *size)
{
cTValue *frame, *nextframe, *bot = tvref(L->stack);
/* Traverse frames backwards. */
for (nextframe = frame = L->base-1; frame > bot; ) {
if (frame_gc(frame) == obj2gco(L))
level++; /* Skip dummy frames. See lj_meta_call(). */
if (level-- == 0) {
*size = (int)(nextframe - frame);
return frame; /* Level found. */
}
nextframe = frame;
if (frame_islua(frame)) {
frame = frame_prevl(frame);
} else {
if (frame_isvarg(frame))
level++; /* Skip vararg pseudo-frame. */
frame = frame_prevd(frame);
}
}
*size = level;
return NULL; /* Level not found. */
}
/* Invalid bytecode position. */
#define NO_BCPOS (~(BCPos)0)
/* Return bytecode position for function/frame or NO_BCPOS. */
static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe)
{
const BCIns *ins;
GCproto *pt;
BCPos pos;
lua_assert(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD);
if (!isluafunc(fn)) { /* Cannot derive a PC for non-Lua functions. */
return NO_BCPOS;
} else if (nextframe == NULL) { /* Lua function on top. */
void *cf = cframe_raw(L->cframe);
if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf))
return NO_BCPOS;
ins = cframe_pc(cf); /* Only happens during error/hook handling. */
} else {
if (frame_islua(nextframe)) {
ins = frame_pc(nextframe);
} else if (frame_iscont(nextframe)) {
ins = frame_contpc(nextframe);
} else {
/* Lua function below errfunc/gc/hook: find cframe to get the PC. */
void *cf = cframe_raw(L->cframe);
TValue *f = L->base-1;
for (;;) {
if (cf == NULL)
return NO_BCPOS;
while (cframe_nres(cf) < 0) {
if (f >= restorestack(L, -cframe_nres(cf)))
break;
cf = cframe_raw(cframe_prev(cf));
if (cf == NULL)
return NO_BCPOS;
}
if (f < nextframe)
break;
if (frame_islua(f)) {
f = frame_prevl(f);
} else {
if (frame_isc(f) || (LJ_HASFFI && frame_iscont(f) &&
(f-1)->u32.lo == LJ_CONT_FFI_CALLBACK))
cf = cframe_raw(cframe_prev(cf));
f = frame_prevd(f);
}
}
ins = cframe_pc(cf);
}
}
pt = funcproto(fn);
pos = proto_bcpos(pt, ins) - 1;
#if LJ_HASJIT
if (pos > pt->sizebc) { /* Undo the effects of lj_trace_exit for JLOOP. */
GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins));
lua_assert(bc_isret(bc_op(ins[-1])));
pos = proto_bcpos(pt, mref(T->startpc, const BCIns));
}
#endif
return pos;
}
/* -- Line numbers -------------------------------------------------------- */
/* Get line number for a bytecode position. */
BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc)
{
const void *lineinfo = proto_lineinfo(pt);
if (pc <= pt->sizebc && lineinfo) {
BCLine first = pt->firstline;
if (pc == pt->sizebc) return first + pt->numline;
if (pc-- == 0) return first;
if (pt->numline < 256)
return first + (BCLine)((const uint8_t *)lineinfo)[pc];
else if (pt->numline < 65536)
return first + (BCLine)((const uint16_t *)lineinfo)[pc];
else
return first + (BCLine)((const uint32_t *)lineinfo)[pc];
}
return 0;
}
/* Get line number for function/frame. */
static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe)
{
BCPos pc = debug_framepc(L, fn, nextframe);
if (pc != NO_BCPOS) {
GCproto *pt = funcproto(fn);
lua_assert(pc <= pt->sizebc);
return lj_debug_line(pt, pc);
}
return -1;
}
/* -- Variable names ------------------------------------------------------ */
/* Read ULEB128 value. */
static uint32_t debug_read_uleb128(const uint8_t **pp)
{
const uint8_t *p = *pp;
uint32_t v = *p++;
if (LJ_UNLIKELY(v >= 0x80)) {
int sh = 0;
v &= 0x7f;
do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80);
}
*pp = p;
return v;
}
/* Get name of a local variable from slot number and PC. */
static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot)
{
const uint8_t *p = proto_varinfo(pt);
if (p) {
BCPos lastpc = 0;
for (;;) {
const char *name = (const char *)p;
uint32_t vn = *p++;
BCPos startpc, endpc;
if (vn < VARNAME__MAX) {
if (vn == VARNAME_END) break; /* End of varinfo. */
} else {
while (*p++) ; /* Skip over variable name string. */
}
lastpc = startpc = lastpc + debug_read_uleb128(&p);
if (startpc > pc) break;
endpc = startpc + debug_read_uleb128(&p);
if (pc < endpc && slot-- == 0) {
if (vn < VARNAME__MAX) {
#define VARNAMESTR(name, str) str "\0"
name = VARNAMEDEF(VARNAMESTR);
#undef VARNAMESTR
if (--vn) while (*name++ || --vn) ;
}
return name;
}
}
}
return NULL;
}
/* Get name of local variable from 1-based slot number and function/frame. */
static TValue *debug_localname(lua_State *L, const lua_Debug *ar,
const char **name, BCReg slot1)
{
uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
uint32_t size = (uint32_t)ar->i_ci >> 16;
TValue *frame = tvref(L->stack) + offset;
TValue *nextframe = size ? frame + size : NULL;
GCfunc *fn = frame_func(frame);
BCPos pc = debug_framepc(L, fn, nextframe);
if (!nextframe) nextframe = L->top;
if ((int)slot1 < 0) { /* Negative slot number is for varargs. */
if (pc != NO_BCPOS) {
GCproto *pt = funcproto(fn);
if ((pt->flags & PROTO_VARARG)) {
slot1 = pt->numparams + (BCReg)(-(int)slot1);
if (frame_isvarg(frame)) { /* Vararg frame has been set up? (pc!=0) */
nextframe = frame;
frame = frame_prevd(frame);
}
if (frame + slot1 < nextframe) {
*name = "(*vararg)";
return frame+slot1;
}
}
}
return NULL;
}
if (pc != NO_BCPOS &&
(*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL)
;
else if (slot1 > 0 && frame + slot1 < nextframe)
*name = "(*temporary)";
return frame+slot1;
}
/* Get name of upvalue. */
const char *lj_debug_uvname(GCproto *pt, uint32_t idx)
{
const uint8_t *p = proto_uvinfo(pt);
lua_assert(idx < pt->sizeuv);
if (!p) return "";
if (idx) while (*p++ || --idx) ;
return (const char *)p;
}
/* Get name and value of upvalue. */
const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp)
{
if (tvisfunc(o)) {
GCfunc *fn = funcV(o);
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
if (idx < pt->sizeuv) {
*tvp = uvval(&gcref(fn->l.uvptr[idx])->uv);
return lj_debug_uvname(pt, idx);
}
} else {
if (idx < fn->c.nupvalues) {
*tvp = &fn->c.upvalue[idx];
return "";
}
}
}
return NULL;
}
/* Deduce name of an object from slot number and PC. */
const char *lj_debug_slotname(GCproto *pt, const BCIns *ip, BCReg slot,
const char **name)
{
const char *lname;
restart:
lname = debug_varname(pt, proto_bcpos(pt, ip), slot);
if (lname != NULL) { *name = lname; return "local"; }
while (--ip > proto_bc(pt)) {
BCIns ins = *ip;
BCOp op = bc_op(ins);
BCReg ra = bc_a(ins);
if (bcmode_a(op) == BCMbase) {
if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins)))
return NULL;
} else if (bcmode_a(op) == BCMdst && ra == slot) {
switch (bc_op(ins)) {
case BC_MOV:
if (ra == slot) { slot = bc_d(ins); goto restart; }
break;
case BC_GGET:
*name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_d(ins))));
return "global";
case BC_TGETS:
*name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins))));
if (ip > proto_bc(pt)) {
BCIns insp = ip[-1];
if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1 &&
bc_d(insp) == bc_b(ins))
return "method";
}
return "field";
case BC_UGET:
*name = lj_debug_uvname(pt, bc_d(ins));
return "upvalue";
default:
return NULL;
}
}
}
return NULL;
}
/* Deduce function name from caller of a frame. */
const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name)
{
TValue *pframe;
GCfunc *fn;
BCPos pc;
if (frame <= tvref(L->stack))
return NULL;
if (frame_isvarg(frame))
frame = frame_prevd(frame);
pframe = frame_prev(frame);
fn = frame_func(pframe);
pc = debug_framepc(L, fn, frame);
if (pc != NO_BCPOS) {
GCproto *pt = funcproto(fn);
const BCIns *ip = &proto_bc(pt)[check_exp(pc < pt->sizebc, pc)];
MMS mm = bcmode_mm(bc_op(*ip));
if (mm == MM_call) {
BCReg slot = bc_a(*ip);
if (bc_op(*ip) == BC_ITERC) slot -= 3;
return lj_debug_slotname(pt, ip, slot, name);
} else if (mm != MM__MAX) {
*name = strdata(mmname_str(G(L), mm));
return "metamethod";
}
}
return NULL;
}
/* -- Source code locations ----------------------------------------------- */
/* Generate shortened source name. */
void lj_debug_shortname(char *out, GCstr *str)
{
const char *src = strdata(str);
if (*src == '=') {
strncpy(out, src+1, LUA_IDSIZE); /* Remove first char. */
out[LUA_IDSIZE-1] = '\0'; /* Ensures null termination. */
} else if (*src == '@') { /* Output "source", or "...source". */
size_t len = str->len-1;
src++; /* Skip the `@' */
if (len >= LUA_IDSIZE) {
src += len-(LUA_IDSIZE-4); /* Get last part of file name. */
*out++ = '.'; *out++ = '.'; *out++ = '.';
}
strcpy(out, src);
} else { /* Output [string "string"]. */
size_t len; /* Length, up to first control char. */
for (len = 0; len < LUA_IDSIZE-12; len++)
if (((const unsigned char *)src)[len] < ' ') break;
strcpy(out, "[string \""); out += 9;
if (src[len] != '\0') { /* Must truncate? */
if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
strncpy(out, src, len); out += len;
strcpy(out, "..."); out += 3;
} else {
strcpy(out, src); out += len;
}
strcpy(out, "\"]");
}
}
/* Add current location of a frame to error message. */
void lj_debug_addloc(lua_State *L, const char *msg,
cTValue *frame, cTValue *nextframe)
{
if (frame) {
GCfunc *fn = frame_func(frame);
if (isluafunc(fn)) {
BCLine line = debug_frameline(L, fn, nextframe);
if (line >= 0) {
char buf[LUA_IDSIZE];
lj_debug_shortname(buf, proto_chunkname(funcproto(fn)));
lj_str_pushf(L, "%s:%d: %s", buf, line, msg);
return;
}
}
}
lj_str_pushf(L, "%s", msg);
}
/* Push location string for a bytecode position to Lua stack. */
void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc)
{
GCstr *name = proto_chunkname(pt);
const char *s = strdata(name);
MSize i, len = name->len;
BCLine line = lj_debug_line(pt, pc);
if (*s == '@') {
s++; len--;
for (i = len; i > 0; i--)
if (s[i] == '/' || s[i] == '\\') {
s += i+1;
break;
}
lj_str_pushf(L, "%s:%d", s, line);
} else if (len > 40) {
lj_str_pushf(L, "%p:%d", pt, line);
} else if (*s == '=') {
lj_str_pushf(L, "%s:%d", s+1, line);
} else {
lj_str_pushf(L, "\"%s\":%d", s, line);
}
}
/* -- Public debug API ---------------------------------------------------- */
/* lua_getupvalue() and lua_setupvalue() are in lj_api.c. */
LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n)
{
const char *name = NULL;
if (ar) {
TValue *o = debug_localname(L, ar, &name, (BCReg)n);
if (name) {
copyTV(L, L->top, o);
incr_top(L);
}
} else if (tvisfunc(L->top-1) && isluafunc(funcV(L->top-1))) {
name = debug_varname(funcproto(funcV(L->top-1)), 0, (BCReg)n-1);
}
return name;
}
LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n)
{
const char *name = NULL;
TValue *o = debug_localname(L, ar, &name, (BCReg)n);
if (name)
copyTV(L, o, L->top-1);
L->top--;
return name;
}
int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext)
{
int opt_f = 0, opt_L = 0;
TValue *frame = NULL;
TValue *nextframe = NULL;
GCfunc *fn;
if (*what == '>') {
TValue *func = L->top - 1;
api_check(L, tvisfunc(func));
fn = funcV(func);
L->top--;
what++;
} else {
uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
uint32_t size = (uint32_t)ar->i_ci >> 16;
lua_assert(offset != 0);
frame = tvref(L->stack) + offset;
if (size) nextframe = frame + size;
lua_assert(frame <= tvref(L->maxstack) &&
(!nextframe || nextframe <= tvref(L->maxstack)));
fn = frame_func(frame);
lua_assert(fn->c.gct == ~LJ_TFUNC);
}
for (; *what; what++) {
if (*what == 'S') {
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
BCLine firstline = pt->firstline;
GCstr *name = proto_chunkname(pt);
ar->source = strdata(name);
lj_debug_shortname(ar->short_src, name);
ar->linedefined = (int)firstline;
ar->lastlinedefined = (int)(firstline + pt->numline);
ar->what = (firstline || !pt->numline) ? "Lua" : "main";
} else {
ar->source = "=[C]";
ar->short_src[0] = '[';
ar->short_src[1] = 'C';
ar->short_src[2] = ']';
ar->short_src[3] = '\0';
ar->linedefined = -1;
ar->lastlinedefined = -1;
ar->what = "C";
}
} else if (*what == 'l') {
ar->currentline = frame ? debug_frameline(L, fn, nextframe) : -1;
} else if (*what == 'u') {
ar->nups = fn->c.nupvalues;
if (ext) {
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
ar->nparams = pt->numparams;
ar->isvararg = !!(pt->flags & PROTO_VARARG);
} else {
ar->nparams = 0;
ar->isvararg = 1;
}
}
} else if (*what == 'n') {
ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL;
if (ar->namewhat == NULL) {
ar->namewhat = "";
ar->name = NULL;
}
} else if (*what == 'f') {
opt_f = 1;
} else if (*what == 'L') {
opt_L = 1;
} else {
return 0; /* Bad option. */
}
}
if (opt_f) {
setfuncV(L, L->top, fn);
incr_top(L);
}
if (opt_L) {
if (isluafunc(fn)) {
GCtab *t = lj_tab_new(L, 0, 0);
GCproto *pt = funcproto(fn);
const void *lineinfo = proto_lineinfo(pt);
if (lineinfo) {
BCLine first = pt->firstline;
int sz = pt->numline < 256 ? 1 : pt->numline < 65536 ? 2 : 4;
MSize i, szl = pt->sizebc-1;
for (i = 0; i < szl; i++) {
BCLine line = first +
(sz == 1 ? (BCLine)((const uint8_t *)lineinfo)[i] :
sz == 2 ? (BCLine)((const uint16_t *)lineinfo)[i] :
(BCLine)((const uint32_t *)lineinfo)[i]);
setboolV(lj_tab_setint(L, t, line), 1);
}
}
settabV(L, L->top, t);
} else {
setnilV(L->top);
}
incr_top(L);
}
return 1; /* Ok. */
}
LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar)
{
return lj_debug_getinfo(L, what, (lj_Debug *)ar, 0);
}
LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
{
int size;
cTValue *frame = lj_debug_frame(L, level, &size);
if (frame) {
ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack));
return 1;
} else {
ar->i_ci = level - size;
return 0;
}
}
/* Number of frames for the leading and trailing part of a traceback. */
#define TRACEBACK_LEVELS1 12
#define TRACEBACK_LEVELS2 10
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
int level)
{
int top = (int)(L->top - L->base);
int lim = TRACEBACK_LEVELS1;
lua_Debug ar;
if (msg) lua_pushfstring(L, "%s\n", msg);
lua_pushliteral(L, "stack traceback:");
while (lua_getstack(L1, level++, &ar)) {
GCfunc *fn;
if (level > lim) {
if (!lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) {
level--;
} else {
lua_pushliteral(L, "\n\t...");
lua_getstack(L1, -10, &ar);
level = ar.i_ci - TRACEBACK_LEVELS2;
}
lim = 2147483647;
continue;
}
lua_getinfo(L1, "Snlf", &ar);
fn = funcV(L1->top-1); L1->top--;
if (isffunc(fn) && !*ar.namewhat)
lua_pushfstring(L, "\n\t[builtin#%d]:", fn->c.ffid);
else
lua_pushfstring(L, "\n\t%s:", ar.short_src);
if (ar.currentline > 0)
lua_pushfstring(L, "%d:", ar.currentline);
if (*ar.namewhat) {
lua_pushfstring(L, " in function " LUA_QS, ar.name);
} else {
if (*ar.what == 'm') {
lua_pushliteral(L, " in main chunk");
} else if (*ar.what == 'C') {
lua_pushfstring(L, " at %p", fn->c.f);
} else {
lua_pushfstring(L, " in function <%s:%d>",
ar.short_src, ar.linedefined);
}
}
if ((int)(L->top - L->base) - top >= 15)
lua_concat(L, (int)(L->top - L->base) - top);
}
lua_concat(L, (int)(L->top - L->base) - top);
}

View File

@ -1,61 +0,0 @@
/*
** Debugging and introspection.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_DEBUG_H
#define _LJ_DEBUG_H
#include "lj_obj.h"
typedef struct lj_Debug {
/* Common fields. Must be in the same order as in lua.h. */
int event;
const char *name;
const char *namewhat;
const char *what;
const char *source;
int currentline;
int nups;
int linedefined;
int lastlinedefined;
char short_src[LUA_IDSIZE];
int i_ci;
/* Extended fields. Only valid if lj_debug_getinfo() is called with ext = 1.*/
int nparams;
int isvararg;
} lj_Debug;
LJ_FUNC cTValue *lj_debug_frame(lua_State *L, int level, int *size);
LJ_FUNC BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc);
LJ_FUNC const char *lj_debug_uvname(GCproto *pt, uint32_t idx);
LJ_FUNC const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp);
LJ_FUNC const char *lj_debug_slotname(GCproto *pt, const BCIns *pc,
BCReg slot, const char **name);
LJ_FUNC const char *lj_debug_funcname(lua_State *L, TValue *frame,
const char **name);
LJ_FUNC void lj_debug_shortname(char *out, GCstr *str);
LJ_FUNC void lj_debug_addloc(lua_State *L, const char *msg,
cTValue *frame, cTValue *nextframe);
LJ_FUNC void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc);
LJ_FUNC int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar,
int ext);
/* Fixed internal variable names. */
#define VARNAMEDEF(_) \
_(FOR_IDX, "(for index)") \
_(FOR_STOP, "(for limit)") \
_(FOR_STEP, "(for step)") \
_(FOR_GEN, "(for generator)") \
_(FOR_STATE, "(for state)") \
_(FOR_CTL, "(for control)")
enum {
VARNAME_END,
#define VARNAMEENUM(name, str) VARNAME_##name,
VARNAMEDEF(VARNAMEENUM)
#undef VARNAMEENUM
VARNAME__MAX
};
#endif

View File

@ -1,353 +0,0 @@
/*
** LuaJIT common internal definitions.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_DEF_H
#define _LJ_DEF_H
#include "lua.h"
#if defined(_MSC_VER)
/* MSVC is stuck in the last century and doesn't have C99's stdint.h. */
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#ifdef _WIN64
typedef __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
#else
typedef __int32 intptr_t;
typedef unsigned __int32 uintptr_t;
#endif
#elif defined(__symbian__)
/* Cough. */
typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef int intptr_t;
typedef unsigned int uintptr_t;
#else
#include <stdint.h>
#endif
/* Needed everywhere. */
#include <string.h>
#include <stdlib.h>
/* Various VM limits. */
#define LJ_MAX_MEM 0x7fffff00 /* Max. total memory allocation. */
#define LJ_MAX_ALLOC LJ_MAX_MEM /* Max. individual allocation length. */
#define LJ_MAX_STR LJ_MAX_MEM /* Max. string length. */
#define LJ_MAX_UDATA LJ_MAX_MEM /* Max. userdata length. */
#define LJ_MAX_STRTAB (1<<26) /* Max. string table size. */
#define LJ_MAX_HBITS 26 /* Max. hash bits. */
#define LJ_MAX_ABITS 28 /* Max. bits of array key. */
#define LJ_MAX_ASIZE ((1<<(LJ_MAX_ABITS-1))+1) /* Max. array part size. */
#define LJ_MAX_COLOSIZE 16 /* Max. elems for colocated array. */
#define LJ_MAX_LINE LJ_MAX_MEM /* Max. source code line number. */
#define LJ_MAX_XLEVEL 200 /* Max. syntactic nesting level. */
#define LJ_MAX_BCINS (1<<26) /* Max. # of bytecode instructions. */
#define LJ_MAX_SLOTS 250 /* Max. # of slots in a Lua func. */
#define LJ_MAX_LOCVAR 200 /* Max. # of local variables. */
#define LJ_MAX_UPVAL 60 /* Max. # of upvalues. */
#define LJ_MAX_IDXCHAIN 100 /* __index/__newindex chain limit. */
#define LJ_STACK_EXTRA 5 /* Extra stack space (metamethods). */
#define LJ_NUM_CBPAGE 1 /* Number of FFI callback pages. */
/* Minimum table/buffer sizes. */
#define LJ_MIN_GLOBAL 6 /* Min. global table size (hbits). */
#define LJ_MIN_REGISTRY 2 /* Min. registry size (hbits). */
#define LJ_MIN_STRTAB 256 /* Min. string table size (pow2). */
#define LJ_MIN_SBUF 32 /* Min. string buffer length. */
#define LJ_MIN_VECSZ 8 /* Min. size for growable vectors. */
#define LJ_MIN_IRSZ 32 /* Min. size for growable IR. */
#define LJ_MIN_K64SZ 16 /* Min. size for chained K64Array. */
/* JIT compiler limits. */
#define LJ_MAX_JSLOTS 250 /* Max. # of stack slots for a trace. */
#define LJ_MAX_PHI 64 /* Max. # of PHIs for a loop. */
#define LJ_MAX_EXITSTUBGR 16 /* Max. # of exit stub groups. */
/* Various macros. */
#ifndef UNUSED
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
#endif
#define U64x(hi, lo) (((uint64_t)0x##hi << 32) + (uint64_t)0x##lo)
#define i32ptr(p) ((int32_t)(intptr_t)(void *)(p))
#define u32ptr(p) ((uint32_t)(intptr_t)(void *)(p))
#define checki8(x) ((x) == (int32_t)(int8_t)(x))
#define checku8(x) ((x) == (int32_t)(uint8_t)(x))
#define checki16(x) ((x) == (int32_t)(int16_t)(x))
#define checku16(x) ((x) == (int32_t)(uint16_t)(x))
#define checki32(x) ((x) == (int32_t)(x))
#define checku32(x) ((x) == (uint32_t)(x))
#define checkptr32(x) ((uintptr_t)(x) == (uint32_t)(uintptr_t)(x))
/* Every half-decent C compiler transforms this into a rotate instruction. */
#define lj_rol(x, n) (((x)<<(n)) | ((x)>>(-(int)(n)&(8*sizeof(x)-1))))
#define lj_ror(x, n) (((x)<<(-(int)(n)&(8*sizeof(x)-1))) | ((x)>>(n)))
/* A really naive Bloom filter. But sufficient for our needs. */
typedef uintptr_t BloomFilter;
#define BLOOM_MASK (8*sizeof(BloomFilter) - 1)
#define bloombit(x) ((uintptr_t)1 << ((x) & BLOOM_MASK))
#define bloomset(b, x) ((b) |= bloombit((x)))
#define bloomtest(b, x) ((b) & bloombit((x)))
#if defined(__GNUC__) || defined(__psp2__)
#define LJ_NORET __attribute__((noreturn))
#define LJ_ALIGN(n) __attribute__((aligned(n)))
#define LJ_INLINE inline
#define LJ_AINLINE inline __attribute__((always_inline))
#define LJ_NOINLINE __attribute__((noinline))
#if defined(__ELF__) || defined(__MACH__) || defined(__psp2__)
#if !((defined(__sun__) && defined(__svr4__)) || defined(__CELLOS_LV2__))
#define LJ_NOAPI extern __attribute__((visibility("hidden")))
#endif
#endif
/* Note: it's only beneficial to use fastcall on x86 and then only for up to
** two non-FP args. The amalgamated compile covers all LJ_FUNC cases. Only
** indirect calls and related tail-called C functions are marked as fastcall.
*/
#if defined(__i386__)
#define LJ_FASTCALL __attribute__((fastcall))
#endif
#define LJ_LIKELY(x) __builtin_expect(!!(x), 1)
#define LJ_UNLIKELY(x) __builtin_expect(!!(x), 0)
#define lj_ffs(x) ((uint32_t)__builtin_ctz(x))
/* Don't ask ... */
#if defined(__INTEL_COMPILER) && (defined(__i386__) || defined(__x86_64__))
static LJ_AINLINE uint32_t lj_fls(uint32_t x)
{
uint32_t r; __asm__("bsrl %1, %0" : "=r" (r) : "rm" (x) : "cc"); return r;
}
#else
#define lj_fls(x) ((uint32_t)(__builtin_clz(x)^31))
#endif
#if defined(__arm__)
static LJ_AINLINE uint32_t lj_bswap(uint32_t x)
{
#if defined(__psp2__)
return __builtin_rev(x);
#else
uint32_t r;
#if __ARM_ARCH_6__ || __ARM_ARCH_6J__ || __ARM_ARCH_6T2__ || __ARM_ARCH_6Z__ ||\
__ARM_ARCH_6ZK__ || __ARM_ARCH_7__ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__
__asm__("rev %0, %1" : "=r" (r) : "r" (x));
return r;
#else
#ifdef __thumb__
r = x ^ lj_ror(x, 16);
#else
__asm__("eor %0, %1, %1, ror #16" : "=r" (r) : "r" (x));
#endif
return ((r & 0xff00ffffu) >> 8) ^ lj_ror(x, 8);
#endif
#endif
}
static LJ_AINLINE uint64_t lj_bswap64(uint64_t x)
{
return ((uint64_t)lj_bswap((uint32_t)x)<<32) | lj_bswap((uint32_t)(x>>32));
}
#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
static LJ_AINLINE uint32_t lj_bswap(uint32_t x)
{
return (uint32_t)__builtin_bswap32((int32_t)x);
}
static LJ_AINLINE uint64_t lj_bswap64(uint64_t x)
{
return (uint64_t)__builtin_bswap64((int64_t)x);
}
#elif defined(__i386__) || defined(__x86_64__)
static LJ_AINLINE uint32_t lj_bswap(uint32_t x)
{
uint32_t r; __asm__("bswap %0" : "=r" (r) : "0" (x)); return r;
}
#if defined(__i386__)
static LJ_AINLINE uint64_t lj_bswap64(uint64_t x)
{
return ((uint64_t)lj_bswap((uint32_t)x)<<32) | lj_bswap((uint32_t)(x>>32));
}
#else
static LJ_AINLINE uint64_t lj_bswap64(uint64_t x)
{
uint64_t r; __asm__("bswap %0" : "=r" (r) : "0" (x)); return r;
}
#endif
#else
static LJ_AINLINE uint32_t lj_bswap(uint32_t x)
{
return (x << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) | (x >> 24);
}
static LJ_AINLINE uint64_t lj_bswap64(uint64_t x)
{
return (uint64_t)lj_bswap((uint32_t)(x >> 32)) |
((uint64_t)lj_bswap((uint32_t)x) << 32);
}
#endif
typedef union __attribute__((packed)) Unaligned16 {
uint16_t u;
uint8_t b[2];
} Unaligned16;
typedef union __attribute__((packed)) Unaligned32 {
uint32_t u;
uint8_t b[4];
} Unaligned32;
/* Unaligned load of uint16_t. */
static LJ_AINLINE uint16_t lj_getu16(const void *p)
{
return ((const Unaligned16 *)p)->u;
}
/* Unaligned load of uint32_t. */
static LJ_AINLINE uint32_t lj_getu32(const void *p)
{
return ((const Unaligned32 *)p)->u;
}
#elif defined(_MSC_VER)
#define LJ_NORET __declspec(noreturn)
#define LJ_ALIGN(n) __declspec(align(n))
#define LJ_INLINE __inline
#define LJ_AINLINE __forceinline
#define LJ_NOINLINE __declspec(noinline)
#if defined(_M_IX86)
#define LJ_FASTCALL __fastcall
#endif
#ifdef _M_PPC
unsigned int _CountLeadingZeros(long);
#pragma intrinsic(_CountLeadingZeros)
static LJ_AINLINE uint32_t lj_fls(uint32_t x)
{
return _CountLeadingZeros(x) ^ 31;
}
#else
unsigned char _BitScanForward(uint32_t *, unsigned long);
unsigned char _BitScanReverse(uint32_t *, unsigned long);
#pragma intrinsic(_BitScanForward)
#pragma intrinsic(_BitScanReverse)
static LJ_AINLINE uint32_t lj_ffs(uint32_t x)
{
uint32_t r; _BitScanForward(&r, x); return r;
}
static LJ_AINLINE uint32_t lj_fls(uint32_t x)
{
uint32_t r; _BitScanReverse(&r, x); return r;
}
#endif
unsigned long _byteswap_ulong(unsigned long);
uint64_t _byteswap_uint64(uint64_t);
#define lj_bswap(x) (_byteswap_ulong((x)))
#define lj_bswap64(x) (_byteswap_uint64((x)))
#if defined(_M_PPC) && defined(LUAJIT_NO_UNALIGNED)
/*
** Replacement for unaligned loads on Xbox 360. Disabled by default since it's
** usually more costly than the occasional stall when crossing a cache-line.
*/
static LJ_AINLINE uint16_t lj_getu16(const void *v)
{
const uint8_t *p = (const uint8_t *)v;
return (uint16_t)((p[0]<<8) | p[1]);
}
static LJ_AINLINE uint32_t lj_getu32(const void *v)
{
const uint8_t *p = (const uint8_t *)v;
return (uint32_t)((p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]);
}
#else
/* Unaligned loads are generally ok on x86/x64. */
#define lj_getu16(p) (*(uint16_t *)(p))
#define lj_getu32(p) (*(uint32_t *)(p))
#endif
#else
#error "missing defines for your compiler"
#endif
/* Optional defines. */
#ifndef LJ_FASTCALL
#define LJ_FASTCALL
#endif
#ifndef LJ_NORET
#define LJ_NORET
#endif
#ifndef LJ_NOAPI
#define LJ_NOAPI extern
#endif
#ifndef LJ_LIKELY
#define LJ_LIKELY(x) (x)
#define LJ_UNLIKELY(x) (x)
#endif
/* Attributes for internal functions. */
#define LJ_DATA LJ_NOAPI
#define LJ_DATADEF
#define LJ_ASMF LJ_NOAPI
#define LJ_FUNCA LJ_NOAPI
#if defined(ljamalg_c)
#define LJ_FUNC static
#else
#define LJ_FUNC LJ_NOAPI
#endif
#define LJ_FUNC_NORET LJ_FUNC LJ_NORET
#define LJ_FUNCA_NORET LJ_FUNCA LJ_NORET
#define LJ_ASMF_NORET LJ_ASMF LJ_NORET
/* Runtime assertions. */
#ifdef lua_assert
#define check_exp(c, e) (lua_assert(c), (e))
#define api_check(l, e) lua_assert(e)
#else
#define lua_assert(c) ((void)0)
#define check_exp(c, e) (e)
#define api_check luai_apicheck
#endif
/* Static assertions. */
#define LJ_ASSERT_NAME2(name, line) name ## line
#define LJ_ASSERT_NAME(line) LJ_ASSERT_NAME2(lj_assert_, line)
#ifdef __COUNTER__
#define LJ_STATIC_ASSERT(cond) \
extern void LJ_ASSERT_NAME(__COUNTER__)(int STATIC_ASSERTION_FAILED[(cond)?1:-1])
#else
#define LJ_STATIC_ASSERT(cond) \
extern void LJ_ASSERT_NAME(__LINE__)(int STATIC_ASSERTION_FAILED[(cond)?1:-1])
#endif
#endif

View File

@ -1,494 +0,0 @@
/*
** Instruction dispatch handling.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_dispatch_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_func.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_meta.h"
#include "lj_debug.h"
#include "lj_state.h"
#include "lj_frame.h"
#include "lj_bc.h"
#include "lj_ff.h"
#if LJ_HASJIT
#include "lj_jit.h"
#endif
#if LJ_HASFFI
#include "lj_ccallback.h"
#endif
#include "lj_trace.h"
#include "lj_dispatch.h"
#include "lj_vm.h"
#include "luajit.h"
/* Bump GG_NUM_ASMFF in lj_dispatch.h as needed. Ugly. */
LJ_STATIC_ASSERT(GG_NUM_ASMFF == FF_NUM_ASMFUNC);
/* -- Dispatch table management ------------------------------------------- */
#if LJ_TARGET_MIPS
#include <math.h>
LJ_FUNCA_NORET void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L,
lua_State *co);
#define GOTFUNC(name) (ASMFunction)name,
static const ASMFunction dispatch_got[] = {
GOTDEF(GOTFUNC)
};
#undef GOTFUNC
#endif
/* Initialize instruction dispatch table and hot counters. */
void lj_dispatch_init(GG_State *GG)
{
uint32_t i;
ASMFunction *disp = GG->dispatch;
for (i = 0; i < GG_LEN_SDISP; i++)
disp[GG_LEN_DDISP+i] = disp[i] = makeasmfunc(lj_bc_ofs[i]);
for (i = GG_LEN_SDISP; i < GG_LEN_DDISP; i++)
disp[i] = makeasmfunc(lj_bc_ofs[i]);
/* The JIT engine is off by default. luaopen_jit() turns it on. */
disp[BC_FORL] = disp[BC_IFORL];
disp[BC_ITERL] = disp[BC_IITERL];
disp[BC_LOOP] = disp[BC_ILOOP];
disp[BC_FUNCF] = disp[BC_IFUNCF];
disp[BC_FUNCV] = disp[BC_IFUNCV];
GG->g.bc_cfunc_ext = GG->g.bc_cfunc_int = BCINS_AD(BC_FUNCC, LUA_MINSTACK, 0);
for (i = 0; i < GG_NUM_ASMFF; i++)
GG->bcff[i] = BCINS_AD(BC__MAX+i, 0, 0);
#if LJ_TARGET_MIPS
memcpy(GG->got, dispatch_got, LJ_GOT__MAX*4);
#endif
}
#if LJ_HASJIT
/* Initialize hotcount table. */
void lj_dispatch_init_hotcount(global_State *g)
{
int32_t hotloop = G2J(g)->param[JIT_P_hotloop];
HotCount start = (HotCount)(hotloop*HOTCOUNT_LOOP - 1);
HotCount *hotcount = G2GG(g)->hotcount;
uint32_t i;
for (i = 0; i < HOTCOUNT_SIZE; i++)
hotcount[i] = start;
}
#endif
/* Internal dispatch mode bits. */
#define DISPMODE_JIT 0x01 /* JIT compiler on. */
#define DISPMODE_REC 0x02 /* Recording active. */
#define DISPMODE_INS 0x04 /* Override instruction dispatch. */
#define DISPMODE_CALL 0x08 /* Override call dispatch. */
#define DISPMODE_RET 0x10 /* Override return dispatch. */
/* Update dispatch table depending on various flags. */
void lj_dispatch_update(global_State *g)
{
uint8_t oldmode = g->dispatchmode;
uint8_t mode = 0;
#if LJ_HASJIT
mode |= (G2J(g)->flags & JIT_F_ON) ? DISPMODE_JIT : 0;
mode |= G2J(g)->state != LJ_TRACE_IDLE ?
(DISPMODE_REC|DISPMODE_INS|DISPMODE_CALL) : 0;
#endif
mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT)) ? DISPMODE_INS : 0;
mode |= (g->hookmask & LUA_MASKCALL) ? DISPMODE_CALL : 0;
mode |= (g->hookmask & LUA_MASKRET) ? DISPMODE_RET : 0;
if (oldmode != mode) { /* Mode changed? */
ASMFunction *disp = G2GG(g)->dispatch;
ASMFunction f_forl, f_iterl, f_loop, f_funcf, f_funcv;
g->dispatchmode = mode;
/* Hotcount if JIT is on, but not while recording. */
if ((mode & (DISPMODE_JIT|DISPMODE_REC)) == DISPMODE_JIT) {
f_forl = makeasmfunc(lj_bc_ofs[BC_FORL]);
f_iterl = makeasmfunc(lj_bc_ofs[BC_ITERL]);
f_loop = makeasmfunc(lj_bc_ofs[BC_LOOP]);
f_funcf = makeasmfunc(lj_bc_ofs[BC_FUNCF]);
f_funcv = makeasmfunc(lj_bc_ofs[BC_FUNCV]);
} else { /* Otherwise use the non-hotcounting instructions. */
f_forl = disp[GG_LEN_DDISP+BC_IFORL];
f_iterl = disp[GG_LEN_DDISP+BC_IITERL];
f_loop = disp[GG_LEN_DDISP+BC_ILOOP];
f_funcf = makeasmfunc(lj_bc_ofs[BC_IFUNCF]);
f_funcv = makeasmfunc(lj_bc_ofs[BC_IFUNCV]);
}
/* Init static counting instruction dispatch first (may be copied below). */
disp[GG_LEN_DDISP+BC_FORL] = f_forl;
disp[GG_LEN_DDISP+BC_ITERL] = f_iterl;
disp[GG_LEN_DDISP+BC_LOOP] = f_loop;
/* Set dynamic instruction dispatch. */
if ((oldmode ^ mode) & (DISPMODE_REC|DISPMODE_INS)) {
/* Need to update the whole table. */
if (!(mode & (DISPMODE_REC|DISPMODE_INS))) { /* No ins dispatch? */
/* Copy static dispatch table to dynamic dispatch table. */
memcpy(&disp[0], &disp[GG_LEN_DDISP], GG_LEN_SDISP*sizeof(ASMFunction));
/* Overwrite with dynamic return dispatch. */
if ((mode & DISPMODE_RET)) {
disp[BC_RETM] = lj_vm_rethook;
disp[BC_RET] = lj_vm_rethook;
disp[BC_RET0] = lj_vm_rethook;
disp[BC_RET1] = lj_vm_rethook;
}
} else {
/* The recording dispatch also checks for hooks. */
ASMFunction f = (mode & DISPMODE_REC) ? lj_vm_record : lj_vm_inshook;
uint32_t i;
for (i = 0; i < GG_LEN_SDISP; i++)
disp[i] = f;
}
} else if (!(mode & (DISPMODE_REC|DISPMODE_INS))) {
/* Otherwise set dynamic counting ins. */
disp[BC_FORL] = f_forl;
disp[BC_ITERL] = f_iterl;
disp[BC_LOOP] = f_loop;
/* Set dynamic return dispatch. */
if ((mode & DISPMODE_RET)) {
disp[BC_RETM] = lj_vm_rethook;
disp[BC_RET] = lj_vm_rethook;
disp[BC_RET0] = lj_vm_rethook;
disp[BC_RET1] = lj_vm_rethook;
} else {
disp[BC_RETM] = disp[GG_LEN_DDISP+BC_RETM];
disp[BC_RET] = disp[GG_LEN_DDISP+BC_RET];
disp[BC_RET0] = disp[GG_LEN_DDISP+BC_RET0];
disp[BC_RET1] = disp[GG_LEN_DDISP+BC_RET1];
}
}
/* Set dynamic call dispatch. */
if ((oldmode ^ mode) & DISPMODE_CALL) { /* Update the whole table? */
uint32_t i;
if ((mode & DISPMODE_CALL) == 0) { /* No call hooks? */
for (i = GG_LEN_SDISP; i < GG_LEN_DDISP; i++)
disp[i] = makeasmfunc(lj_bc_ofs[i]);
} else {
for (i = GG_LEN_SDISP; i < GG_LEN_DDISP; i++)
disp[i] = lj_vm_callhook;
}
}
if (!(mode & DISPMODE_CALL)) { /* Overwrite dynamic counting ins. */
disp[BC_FUNCF] = f_funcf;
disp[BC_FUNCV] = f_funcv;
}
#if LJ_HASJIT
/* Reset hotcounts for JIT off to on transition. */
if ((mode & DISPMODE_JIT) && !(oldmode & DISPMODE_JIT))
lj_dispatch_init_hotcount(g);
#endif
}
}
/* -- JIT mode setting ---------------------------------------------------- */
#if LJ_HASJIT
/* Set JIT mode for a single prototype. */
static void setptmode(global_State *g, GCproto *pt, int mode)
{
if ((mode & LUAJIT_MODE_ON)) { /* (Re-)enable JIT compilation. */
pt->flags &= ~PROTO_NOJIT;
lj_trace_reenableproto(pt); /* Unpatch all ILOOP etc. bytecodes. */
} else { /* Flush and/or disable JIT compilation. */
if (!(mode & LUAJIT_MODE_FLUSH))
pt->flags |= PROTO_NOJIT;
lj_trace_flushproto(g, pt); /* Flush all traces of prototype. */
}
}
/* Recursively set the JIT mode for all children of a prototype. */
static void setptmode_all(global_State *g, GCproto *pt, int mode)
{
ptrdiff_t i;
if (!(pt->flags & PROTO_CHILD)) return;
for (i = -(ptrdiff_t)pt->sizekgc; i < 0; i++) {
GCobj *o = proto_kgc(pt, i);
if (o->gch.gct == ~LJ_TPROTO) {
setptmode(g, gco2pt(o), mode);
setptmode_all(g, gco2pt(o), mode);
}
}
}
#endif
/* Public API function: control the JIT engine. */
int luaJIT_setmode(lua_State *L, int idx, int mode)
{
global_State *g = G(L);
int mm = mode & LUAJIT_MODE_MASK;
lj_trace_abort(g); /* Abort recording on any state change. */
/* Avoid pulling the rug from under our own feet. */
if ((g->hookmask & HOOK_GC))
lj_err_caller(L, LJ_ERR_NOGCMM);
switch (mm) {
#if LJ_HASJIT
case LUAJIT_MODE_ENGINE:
if ((mode & LUAJIT_MODE_FLUSH)) {
lj_trace_flushall(L);
} else {
if (!(mode & LUAJIT_MODE_ON))
G2J(g)->flags &= ~(uint32_t)JIT_F_ON;
#if LJ_TARGET_X86ORX64
else if ((G2J(g)->flags & JIT_F_SSE2))
G2J(g)->flags |= (uint32_t)JIT_F_ON;
else
return 0; /* Don't turn on JIT compiler without SSE2 support. */
#else
else
G2J(g)->flags |= (uint32_t)JIT_F_ON;
#endif
lj_dispatch_update(g);
}
break;
case LUAJIT_MODE_FUNC:
case LUAJIT_MODE_ALLFUNC:
case LUAJIT_MODE_ALLSUBFUNC: {
cTValue *tv = idx == 0 ? frame_prev(L->base-1) :
idx > 0 ? L->base + (idx-1) : L->top + idx;
GCproto *pt;
if ((idx == 0 || tvisfunc(tv)) && isluafunc(&gcval(tv)->fn))
pt = funcproto(&gcval(tv)->fn); /* Cannot use funcV() for frame slot. */
else if (tvisproto(tv))
pt = protoV(tv);
else
return 0; /* Failed. */
if (mm != LUAJIT_MODE_ALLSUBFUNC)
setptmode(g, pt, mode);
if (mm != LUAJIT_MODE_FUNC)
setptmode_all(g, pt, mode);
break;
}
case LUAJIT_MODE_TRACE:
if (!(mode & LUAJIT_MODE_FLUSH))
return 0; /* Failed. */
lj_trace_flush(G2J(g), idx);
break;
#else
case LUAJIT_MODE_ENGINE:
case LUAJIT_MODE_FUNC:
case LUAJIT_MODE_ALLFUNC:
case LUAJIT_MODE_ALLSUBFUNC:
UNUSED(idx);
if ((mode & LUAJIT_MODE_ON))
return 0; /* Failed. */
break;
#endif
case LUAJIT_MODE_WRAPCFUNC:
if ((mode & LUAJIT_MODE_ON)) {
if (idx != 0) {
cTValue *tv = idx > 0 ? L->base + (idx-1) : L->top + idx;
if (tvislightud(tv))
g->wrapf = (lua_CFunction)lightudV(tv);
else
return 0; /* Failed. */
} else {
return 0; /* Failed. */
}
g->bc_cfunc_ext = BCINS_AD(BC_FUNCCW, 0, 0);
} else {
g->bc_cfunc_ext = BCINS_AD(BC_FUNCC, 0, 0);
}
break;
default:
return 0; /* Failed. */
}
return 1; /* OK. */
}
/* Enforce (dynamic) linker error for version mismatches. See luajit.c. */
LUA_API void LUAJIT_VERSION_SYM(void)
{
}
/* -- Hooks --------------------------------------------------------------- */
/* This function can be called asynchronously (e.g. during a signal). */
LUA_API int lua_sethook(lua_State *L, lua_Hook func, int mask, int count)
{
global_State *g = G(L);
mask &= HOOK_EVENTMASK;
if (func == NULL || mask == 0) { mask = 0; func = NULL; } /* Consistency. */
g->hookf = func;
g->hookcount = g->hookcstart = (int32_t)count;
g->hookmask = (uint8_t)((g->hookmask & ~HOOK_EVENTMASK) | mask);
lj_trace_abort(g); /* Abort recording on any hook change. */
lj_dispatch_update(g);
return 1;
}
LUA_API lua_Hook lua_gethook(lua_State *L)
{
return G(L)->hookf;
}
LUA_API int lua_gethookmask(lua_State *L)
{
return G(L)->hookmask & HOOK_EVENTMASK;
}
LUA_API int lua_gethookcount(lua_State *L)
{
return (int)G(L)->hookcstart;
}
/* Call a hook. */
static void callhook(lua_State *L, int event, BCLine line)
{
global_State *g = G(L);
lua_Hook hookf = g->hookf;
if (hookf && !hook_active(g)) {
lua_Debug ar;
lj_trace_abort(g); /* Abort recording on any hook call. */
ar.event = event;
ar.currentline = line;
/* Top frame, nextframe = NULL. */
ar.i_ci = (int)((L->base-1) - tvref(L->stack));
lj_state_checkstack(L, 1+LUA_MINSTACK);
hook_enter(g);
hookf(L, &ar);
lua_assert(hook_active(g));
hook_leave(g);
}
}
/* -- Dispatch callbacks -------------------------------------------------- */
/* Calculate number of used stack slots in the current frame. */
static BCReg cur_topslot(GCproto *pt, const BCIns *pc, uint32_t nres)
{
BCIns ins = pc[-1];
if (bc_op(ins) == BC_UCLO)
ins = pc[bc_j(ins)];
switch (bc_op(ins)) {
case BC_CALLM: case BC_CALLMT: return bc_a(ins) + bc_c(ins) + nres-1+1;
case BC_RETM: return bc_a(ins) + bc_d(ins) + nres-1;
case BC_TSETM: return bc_a(ins) + nres-1;
default: return pt->framesize;
}
}
/* Instruction dispatch. Used by instr/line/return hooks or when recording. */
void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc)
{
ERRNO_SAVE
GCfunc *fn = curr_func(L);
GCproto *pt = funcproto(fn);
void *cf = cframe_raw(L->cframe);
const BCIns *oldpc = cframe_pc(cf);
global_State *g = G(L);
BCReg slots;
setcframe_pc(cf, pc);
slots = cur_topslot(pt, pc, cframe_multres_n(cf));
L->top = L->base + slots; /* Fix top. */
#if LJ_HASJIT
{
jit_State *J = G2J(g);
if (J->state != LJ_TRACE_IDLE) {
#ifdef LUA_USE_ASSERT
ptrdiff_t delta = L->top - L->base;
#endif
J->L = L;
lj_trace_ins(J, pc-1); /* The interpreter bytecode PC is offset by 1. */
lua_assert(L->top - L->base == delta);
}
}
#endif
if ((g->hookmask & LUA_MASKCOUNT) && g->hookcount == 0) {
g->hookcount = g->hookcstart;
callhook(L, LUA_HOOKCOUNT, -1);
L->top = L->base + slots; /* Fix top again. */
}
if ((g->hookmask & LUA_MASKLINE)) {
BCPos npc = proto_bcpos(pt, pc) - 1;
BCPos opc = proto_bcpos(pt, oldpc) - 1;
BCLine line = lj_debug_line(pt, npc);
if (pc <= oldpc || opc >= pt->sizebc || line != lj_debug_line(pt, opc)) {
callhook(L, LUA_HOOKLINE, line);
L->top = L->base + slots; /* Fix top again. */
}
}
if ((g->hookmask & LUA_MASKRET) && bc_isret(bc_op(pc[-1])))
callhook(L, LUA_HOOKRET, -1);
ERRNO_RESTORE
}
/* Initialize call. Ensure stack space and return # of missing parameters. */
static int call_init(lua_State *L, GCfunc *fn)
{
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
int numparams = pt->numparams;
int gotparams = (int)(L->top - L->base);
int need = pt->framesize;
if ((pt->flags & PROTO_VARARG)) need += 1+gotparams;
lj_state_checkstack(L, (MSize)need);
numparams -= gotparams;
return numparams >= 0 ? numparams : 0;
} else {
lj_state_checkstack(L, LUA_MINSTACK);
return 0;
}
}
/* Call dispatch. Used by call hooks, hot calls or when recording. */
ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns *pc)
{
ERRNO_SAVE
GCfunc *fn = curr_func(L);
BCOp op;
global_State *g = G(L);
#if LJ_HASJIT
jit_State *J = G2J(g);
#endif
int missing = call_init(L, fn);
#if LJ_HASJIT
J->L = L;
if ((uintptr_t)pc & 1) { /* Marker for hot call. */
#ifdef LUA_USE_ASSERT
ptrdiff_t delta = L->top - L->base;
#endif
pc = (const BCIns *)((uintptr_t)pc & ~(uintptr_t)1);
lj_trace_hot(J, pc);
lua_assert(L->top - L->base == delta);
goto out;
} else if (J->state != LJ_TRACE_IDLE &&
!(g->hookmask & (HOOK_GC|HOOK_VMEVENT))) {
#ifdef LUA_USE_ASSERT
ptrdiff_t delta = L->top - L->base;
#endif
/* Record the FUNC* bytecodes, too. */
lj_trace_ins(J, pc-1); /* The interpreter bytecode PC is offset by 1. */
lua_assert(L->top - L->base == delta);
}
#endif
if ((g->hookmask & LUA_MASKCALL)) {
int i;
for (i = 0; i < missing; i++) /* Add missing parameters. */
setnilV(L->top++);
callhook(L, LUA_HOOKCALL, -1);
/* Preserve modifications of missing parameters by lua_setlocal(). */
while (missing-- > 0 && tvisnil(L->top - 1))
L->top--;
}
#if LJ_HASJIT
out:
#endif
op = bc_op(pc[-1]); /* Get FUNC* op. */
#if LJ_HASJIT
/* Use the non-hotcounting variants if JIT is off or while recording. */
if ((!(J->flags & JIT_F_ON) || J->state != LJ_TRACE_IDLE) &&
(op == BC_FUNCF || op == BC_FUNCV))
op = (BCOp)((int)op+(int)BC_IFUNCF-(int)BC_FUNCF);
#endif
ERRNO_RESTORE
return makeasmfunc(lj_bc_ofs[op]); /* Return static dispatch target. */
}

View File

@ -1,131 +0,0 @@
/*
** Instruction dispatch handling.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_DISPATCH_H
#define _LJ_DISPATCH_H
#include "lj_obj.h"
#include "lj_bc.h"
#if LJ_HASJIT
#include "lj_jit.h"
#endif
#if LJ_TARGET_MIPS
/* Need our own global offset table for the dreaded MIPS calling conventions. */
#if LJ_HASJIT
#define JITGOTDEF(_) _(lj_trace_exit) _(lj_trace_hot)
#else
#define JITGOTDEF(_)
#endif
#if LJ_HASFFI
#define FFIGOTDEF(_) \
_(lj_meta_equal_cd) _(lj_ccallback_enter) _(lj_ccallback_leave)
#else
#define FFIGOTDEF(_)
#endif
#define GOTDEF(_) \
_(floor) _(ceil) _(trunc) _(log) _(log10) _(exp) _(sin) _(cos) _(tan) \
_(asin) _(acos) _(atan) _(sinh) _(cosh) _(tanh) _(frexp) _(modf) _(atan2) \
_(pow) _(fmod) _(ldexp) \
_(lj_dispatch_call) _(lj_dispatch_ins) _(lj_err_throw) \
_(lj_ffh_coroutine_wrap_err) _(lj_func_closeuv) _(lj_func_newL_gc) \
_(lj_gc_barrieruv) _(lj_gc_step) _(lj_gc_step_fixtop) _(lj_meta_arith) \
_(lj_meta_call) _(lj_meta_cat) _(lj_meta_comp) _(lj_meta_equal) \
_(lj_meta_for) _(lj_meta_len) _(lj_meta_tget) _(lj_meta_tset) \
_(lj_state_growstack) _(lj_str_fromnum) _(lj_str_fromnumber) _(lj_str_new) \
_(lj_tab_dup) _(lj_tab_get) _(lj_tab_getinth) _(lj_tab_len) _(lj_tab_new) \
_(lj_tab_newkey) _(lj_tab_next) _(lj_tab_reasize) \
JITGOTDEF(_) FFIGOTDEF(_)
enum {
#define GOTENUM(name) LJ_GOT_##name,
GOTDEF(GOTENUM)
#undef GOTENUM
LJ_GOT__MAX
};
#endif
/* Type of hot counter. Must match the code in the assembler VM. */
/* 16 bits are sufficient. Only 0.0015% overhead with maximum slot penalty. */
typedef uint16_t HotCount;
/* Number of hot counter hash table entries (must be a power of two). */
#define HOTCOUNT_SIZE 64
#define HOTCOUNT_PCMASK ((HOTCOUNT_SIZE-1)*sizeof(HotCount))
/* Hotcount decrements. */
#define HOTCOUNT_LOOP 2
#define HOTCOUNT_CALL 1
/* This solves a circular dependency problem -- bump as needed. Sigh. */
#define GG_NUM_ASMFF 62
#define GG_LEN_DDISP (BC__MAX + GG_NUM_ASMFF)
#define GG_LEN_SDISP BC_FUNCF
#define GG_LEN_DISP (GG_LEN_DDISP + GG_LEN_SDISP)
/* Global state, main thread and extra fields are allocated together. */
typedef struct GG_State {
lua_State L; /* Main thread. */
global_State g; /* Global state. */
#if LJ_TARGET_MIPS
ASMFunction got[LJ_GOT__MAX]; /* Global offset table. */
#endif
#if LJ_HASJIT
jit_State J; /* JIT state. */
HotCount hotcount[HOTCOUNT_SIZE]; /* Hot counters. */
#endif
ASMFunction dispatch[GG_LEN_DISP]; /* Instruction dispatch tables. */
BCIns bcff[GG_NUM_ASMFF]; /* Bytecode for ASM fast functions. */
} GG_State;
#define GG_OFS(field) ((int)offsetof(GG_State, field))
#define G2GG(gl) ((GG_State *)((char *)(gl) - GG_OFS(g)))
#define J2GG(j) ((GG_State *)((char *)(j) - GG_OFS(J)))
#define L2GG(L) (G2GG(G(L)))
#define J2G(J) (&J2GG(J)->g)
#define G2J(gl) (&G2GG(gl)->J)
#define L2J(L) (&L2GG(L)->J)
#define GG_G2DISP (GG_OFS(dispatch) - GG_OFS(g))
#define GG_DISP2G (GG_OFS(g) - GG_OFS(dispatch))
#define GG_DISP2J (GG_OFS(J) - GG_OFS(dispatch))
#define GG_DISP2HOT (GG_OFS(hotcount) - GG_OFS(dispatch))
#define GG_DISP2STATIC (GG_LEN_DDISP*(int)sizeof(ASMFunction))
#define hotcount_get(gg, pc) \
(gg)->hotcount[(u32ptr(pc)>>2) & (HOTCOUNT_SIZE-1)]
#define hotcount_set(gg, pc, val) \
(hotcount_get((gg), (pc)) = (HotCount)(val))
/* Dispatch table management. */
LJ_FUNC void lj_dispatch_init(GG_State *GG);
#if LJ_HASJIT
LJ_FUNC void lj_dispatch_init_hotcount(global_State *g);
#endif
LJ_FUNC void lj_dispatch_update(global_State *g);
/* Instruction dispatch callback for hooks or when recording. */
LJ_FUNCA void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc);
LJ_FUNCA ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns*pc);
LJ_FUNCA void LJ_FASTCALL lj_dispatch_return(lua_State *L, const BCIns *pc);
#if LJ_HASFFI && !defined(_BUILDVM_H)
/* Save/restore errno and GetLastError() around hooks, exits and recording. */
#include <errno.h>
#if LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define ERRNO_SAVE int olderr = errno; DWORD oldwerr = GetLastError();
#define ERRNO_RESTORE errno = olderr; SetLastError(oldwerr);
#else
#define ERRNO_SAVE int olderr = errno;
#define ERRNO_RESTORE errno = olderr;
#endif
#else
#define ERRNO_SAVE
#define ERRNO_RESTORE
#endif
#endif

View File

@ -1,356 +0,0 @@
/*
** ARM instruction emitter.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
/* -- Constant encoding --------------------------------------------------- */
static uint8_t emit_invai[16] = {
/* AND */ (ARMI_AND^ARMI_BIC) >> 21,
/* EOR */ 0,
/* SUB */ (ARMI_SUB^ARMI_ADD) >> 21,
/* RSB */ 0,
/* ADD */ (ARMI_ADD^ARMI_SUB) >> 21,
/* ADC */ (ARMI_ADC^ARMI_SBC) >> 21,
/* SBC */ (ARMI_SBC^ARMI_ADC) >> 21,
/* RSC */ 0,
/* TST */ 0,
/* TEQ */ 0,
/* CMP */ (ARMI_CMP^ARMI_CMN) >> 21,
/* CMN */ (ARMI_CMN^ARMI_CMP) >> 21,
/* ORR */ 0,
/* MOV */ (ARMI_MOV^ARMI_MVN) >> 21,
/* BIC */ (ARMI_BIC^ARMI_AND) >> 21,
/* MVN */ (ARMI_MVN^ARMI_MOV) >> 21
};
/* Encode constant in K12 format for data processing instructions. */
static uint32_t emit_isk12(ARMIns ai, int32_t n)
{
uint32_t invai, i, m = (uint32_t)n;
/* K12: unsigned 8 bit value, rotated in steps of two bits. */
for (i = 0; i < 4096; i += 256, m = lj_rol(m, 2))
if (m <= 255) return ARMI_K12|m|i;
/* Otherwise try negation/complement with the inverse instruction. */
invai = emit_invai[((ai >> 21) & 15)];
if (!invai) return 0; /* Failed. No inverse instruction. */
m = ~(uint32_t)n;
if (invai == ((ARMI_SUB^ARMI_ADD) >> 21) ||
invai == (ARMI_CMP^ARMI_CMN) >> 21) m++;
for (i = 0; i < 4096; i += 256, m = lj_rol(m, 2))
if (m <= 255) return ARMI_K12|(invai<<21)|m|i;
return 0; /* Failed. */
}
/* -- Emit basic instructions --------------------------------------------- */
static void emit_dnm(ASMState *as, ARMIns ai, Reg rd, Reg rn, Reg rm)
{
*--as->mcp = ai | ARMF_D(rd) | ARMF_N(rn) | ARMF_M(rm);
}
static void emit_dm(ASMState *as, ARMIns ai, Reg rd, Reg rm)
{
*--as->mcp = ai | ARMF_D(rd) | ARMF_M(rm);
}
static void emit_dn(ASMState *as, ARMIns ai, Reg rd, Reg rn)
{
*--as->mcp = ai | ARMF_D(rd) | ARMF_N(rn);
}
static void emit_nm(ASMState *as, ARMIns ai, Reg rn, Reg rm)
{
*--as->mcp = ai | ARMF_N(rn) | ARMF_M(rm);
}
static void emit_d(ASMState *as, ARMIns ai, Reg rd)
{
*--as->mcp = ai | ARMF_D(rd);
}
static void emit_n(ASMState *as, ARMIns ai, Reg rn)
{
*--as->mcp = ai | ARMF_N(rn);
}
static void emit_m(ASMState *as, ARMIns ai, Reg rm)
{
*--as->mcp = ai | ARMF_M(rm);
}
static void emit_lsox(ASMState *as, ARMIns ai, Reg rd, Reg rn, int32_t ofs)
{
lua_assert(ofs >= -255 && ofs <= 255);
if (ofs < 0) ofs = -ofs; else ai |= ARMI_LS_U;
*--as->mcp = ai | ARMI_LS_P | ARMI_LSX_I | ARMF_D(rd) | ARMF_N(rn) |
((ofs & 0xf0) << 4) | (ofs & 0x0f);
}
static void emit_lso(ASMState *as, ARMIns ai, Reg rd, Reg rn, int32_t ofs)
{
lua_assert(ofs >= -4095 && ofs <= 4095);
/* Combine LDR/STR pairs to LDRD/STRD. */
if (*as->mcp == (ai|ARMI_LS_P|ARMI_LS_U|ARMF_D(rd^1)|ARMF_N(rn)|(ofs^4)) &&
(ai & ~(ARMI_LDR^ARMI_STR)) == ARMI_STR && rd != rn &&
(uint32_t)ofs <= 252 && !(ofs & 3) && !((rd ^ (ofs >>2)) & 1) &&
as->mcp != as->mcloop) {
as->mcp++;
emit_lsox(as, ai == ARMI_LDR ? ARMI_LDRD : ARMI_STRD, rd&~1, rn, ofs&~4);
return;
}
if (ofs < 0) ofs = -ofs; else ai |= ARMI_LS_U;
*--as->mcp = ai | ARMI_LS_P | ARMF_D(rd) | ARMF_N(rn) | ofs;
}
#if !LJ_SOFTFP
static void emit_vlso(ASMState *as, ARMIns ai, Reg rd, Reg rn, int32_t ofs)
{
lua_assert(ofs >= -1020 && ofs <= 1020 && (ofs&3) == 0);
if (ofs < 0) ofs = -ofs; else ai |= ARMI_LS_U;
*--as->mcp = ai | ARMI_LS_P | ARMF_D(rd & 15) | ARMF_N(rn) | (ofs >> 2);
}
#endif
/* -- Emit loads/stores --------------------------------------------------- */
/* Prefer spills of BASE/L. */
#define emit_canremat(ref) ((ref) < ASMREF_L)
/* Try to find a one step delta relative to another constant. */
static int emit_kdelta1(ASMState *as, Reg d, int32_t i)
{
RegSet work = ~as->freeset & RSET_GPR;
while (work) {
Reg r = rset_picktop(work);
IRRef ref = regcost_ref(as->cost[r]);
lua_assert(r != d);
if (emit_canremat(ref)) {
int32_t delta = i - (ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i);
uint32_t k = emit_isk12(ARMI_ADD, delta);
if (k) {
if (k == ARMI_K12)
emit_dm(as, ARMI_MOV, d, r);
else
emit_dn(as, ARMI_ADD^k, d, r);
return 1;
}
}
rset_clear(work, r);
}
return 0; /* Failed. */
}
/* Try to find a two step delta relative to another constant. */
static int emit_kdelta2(ASMState *as, Reg d, int32_t i)
{
RegSet work = ~as->freeset & RSET_GPR;
while (work) {
Reg r = rset_picktop(work);
IRRef ref = regcost_ref(as->cost[r]);
lua_assert(r != d);
if (emit_canremat(ref)) {
int32_t other = ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i;
if (other) {
int32_t delta = i - other;
uint32_t sh, inv = 0, k2, k;
if (delta < 0) { delta = -delta; inv = ARMI_ADD^ARMI_SUB; }
sh = lj_ffs(delta) & ~1;
k2 = emit_isk12(0, delta & (255 << sh));
k = emit_isk12(0, delta & ~(255 << sh));
if (k) {
emit_dn(as, ARMI_ADD^k2^inv, d, d);
emit_dn(as, ARMI_ADD^k^inv, d, r);
return 1;
}
}
}
rset_clear(work, r);
}
return 0; /* Failed. */
}
/* Load a 32 bit constant into a GPR. */
static void emit_loadi(ASMState *as, Reg r, int32_t i)
{
uint32_t k = emit_isk12(ARMI_MOV, i);
lua_assert(rset_test(as->freeset, r) || r == RID_TMP);
if (k) {
/* Standard K12 constant. */
emit_d(as, ARMI_MOV^k, r);
} else if ((as->flags & JIT_F_ARMV6T2) && (uint32_t)i < 0x00010000u) {
/* 16 bit loword constant for ARMv6T2. */
emit_d(as, ARMI_MOVW|(i & 0x0fff)|((i & 0xf000)<<4), r);
} else if (emit_kdelta1(as, r, i)) {
/* One step delta relative to another constant. */
} else if ((as->flags & JIT_F_ARMV6T2)) {
/* 32 bit hiword/loword constant for ARMv6T2. */
emit_d(as, ARMI_MOVT|((i>>16) & 0x0fff)|(((i>>16) & 0xf000)<<4), r);
emit_d(as, ARMI_MOVW|(i & 0x0fff)|((i & 0xf000)<<4), r);
} else if (emit_kdelta2(as, r, i)) {
/* Two step delta relative to another constant. */
} else {
/* Otherwise construct the constant with up to 4 instructions. */
/* NYI: use mvn+bic, use pc-relative loads. */
for (;;) {
uint32_t sh = lj_ffs(i) & ~1;
int32_t m = i & (255 << sh);
i &= ~(255 << sh);
if (i == 0) {
emit_d(as, ARMI_MOV ^ emit_isk12(0, m), r);
break;
}
emit_dn(as, ARMI_ORR ^ emit_isk12(0, m), r, r);
}
}
}
#define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr)))
static Reg ra_allock(ASMState *as, int32_t k, RegSet allow);
/* Get/set from constant pointer. */
static void emit_lsptr(ASMState *as, ARMIns ai, Reg r, void *p)
{
int32_t i = i32ptr(p);
emit_lso(as, ai, r, ra_allock(as, (i & ~4095), rset_exclude(RSET_GPR, r)),
(i & 4095));
}
#if !LJ_SOFTFP
/* Load a number constant into an FPR. */
static void emit_loadn(ASMState *as, Reg r, cTValue *tv)
{
int32_t i;
if ((as->flags & JIT_F_VFPV3) && !tv->u32.lo) {
uint32_t hi = tv->u32.hi;
uint32_t b = ((hi >> 22) & 0x1ff);
if (!(hi & 0xffff) && (b == 0x100 || b == 0x0ff)) {
*--as->mcp = ARMI_VMOVI_D | ARMF_D(r & 15) |
((tv->u32.hi >> 12) & 0x00080000) |
((tv->u32.hi >> 4) & 0x00070000) |
((tv->u32.hi >> 16) & 0x0000000f);
return;
}
}
i = i32ptr(tv);
emit_vlso(as, ARMI_VLDR_D, r,
ra_allock(as, (i & ~1020), RSET_GPR), (i & 1020));
}
#endif
/* Get/set global_State fields. */
#define emit_getgl(as, r, field) \
emit_lsptr(as, ARMI_LDR, (r), (void *)&J2G(as->J)->field)
#define emit_setgl(as, r, field) \
emit_lsptr(as, ARMI_STR, (r), (void *)&J2G(as->J)->field)
/* Trace number is determined from pc of exit instruction. */
#define emit_setvmstate(as, i) UNUSED(i)
/* -- Emit control-flow instructions -------------------------------------- */
/* Label for internal jumps. */
typedef MCode *MCLabel;
/* Return label pointing to current PC. */
#define emit_label(as) ((as)->mcp)
static void emit_branch(ASMState *as, ARMIns ai, MCode *target)
{
MCode *p = as->mcp;
ptrdiff_t delta = (target - p) - 1;
lua_assert(((delta + 0x00800000) >> 24) == 0);
*--p = ai | ((uint32_t)delta & 0x00ffffffu);
as->mcp = p;
}
#define emit_jmp(as, target) emit_branch(as, ARMI_B, (target))
static void emit_call(ASMState *as, void *target)
{
MCode *p = --as->mcp;
ptrdiff_t delta = ((char *)target - (char *)p) - 8;
if ((((delta>>2) + 0x00800000) >> 24) == 0) {
if ((delta & 1))
*p = ARMI_BLX | ((uint32_t)(delta>>2) & 0x00ffffffu) | ((delta&2) << 23);
else
*p = ARMI_BL | ((uint32_t)(delta>>2) & 0x00ffffffu);
} else { /* Target out of range: need indirect call. But don't use R0-R3. */
Reg r = ra_allock(as, i32ptr(target), RSET_RANGE(RID_R4, RID_R12+1));
*p = ARMI_BLXr | ARMF_M(r);
}
}
/* -- Emit generic operations --------------------------------------------- */
/* Generic move between two regs. */
static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src)
{
#if LJ_SOFTFP
lua_assert(!irt_isnum(ir->t)); UNUSED(ir);
#else
if (dst >= RID_MAX_GPR) {
emit_dm(as, irt_isnum(ir->t) ? ARMI_VMOV_D : ARMI_VMOV_S,
(dst & 15), (src & 15));
return;
}
#endif
if (as->mcp != as->mcloop) { /* Swap early registers for loads/stores. */
MCode ins = *as->mcp, swp = (src^dst);
if ((ins & 0x0c000000) == 0x04000000 && (ins & 0x02000010) != 0x02000010) {
if (!((ins ^ (dst << 16)) & 0x000f0000))
*as->mcp = ins ^ (swp << 16); /* Swap N in load/store. */
if (!(ins & 0x00100000) && !((ins ^ (dst << 12)) & 0x0000f000))
*as->mcp = ins ^ (swp << 12); /* Swap D in store. */
}
}
emit_dm(as, ARMI_MOV, dst, src);
}
/* Generic load of register from stack slot. */
static void emit_spload(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
#if LJ_SOFTFP
lua_assert(!irt_isnum(ir->t)); UNUSED(ir);
#else
if (r >= RID_MAX_GPR)
emit_vlso(as, irt_isnum(ir->t) ? ARMI_VLDR_D : ARMI_VLDR_S, r, RID_SP, ofs);
else
#endif
emit_lso(as, ARMI_LDR, r, RID_SP, ofs);
}
/* Generic store of register to stack slot. */
static void emit_spstore(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
#if LJ_SOFTFP
lua_assert(!irt_isnum(ir->t)); UNUSED(ir);
#else
if (r >= RID_MAX_GPR)
emit_vlso(as, irt_isnum(ir->t) ? ARMI_VSTR_D : ARMI_VSTR_S, r, RID_SP, ofs);
else
#endif
emit_lso(as, ARMI_STR, r, RID_SP, ofs);
}
/* Emit an arithmetic/logic operation with a constant operand. */
static void emit_opk(ASMState *as, ARMIns ai, Reg dest, Reg src,
int32_t i, RegSet allow)
{
uint32_t k = emit_isk12(ai, i);
if (k)
emit_dn(as, ai^k, dest, src);
else
emit_dnm(as, ai, dest, src, ra_allock(as, i, allow));
}
/* Add offset to pointer. */
static void emit_addptr(ASMState *as, Reg r, int32_t ofs)
{
if (ofs)
emit_opk(as, ARMI_ADD, r, r, ofs, rset_exclude(RSET_GPR, r));
}
#define emit_spsub(as, ofs) emit_addptr(as, RID_SP, -(ofs))

View File

@ -1,211 +0,0 @@
/*
** MIPS instruction emitter.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
/* -- Emit basic instructions --------------------------------------------- */
static void emit_dst(ASMState *as, MIPSIns mi, Reg rd, Reg rs, Reg rt)
{
*--as->mcp = mi | MIPSF_D(rd) | MIPSF_S(rs) | MIPSF_T(rt);
}
static void emit_dta(ASMState *as, MIPSIns mi, Reg rd, Reg rt, uint32_t a)
{
*--as->mcp = mi | MIPSF_D(rd) | MIPSF_T(rt) | MIPSF_A(a);
}
#define emit_ds(as, mi, rd, rs) emit_dst(as, (mi), (rd), (rs), 0)
#define emit_tg(as, mi, rt, rg) emit_dst(as, (mi), (rg)&31, 0, (rt))
static void emit_tsi(ASMState *as, MIPSIns mi, Reg rt, Reg rs, int32_t i)
{
*--as->mcp = mi | MIPSF_T(rt) | MIPSF_S(rs) | (i & 0xffff);
}
#define emit_ti(as, mi, rt, i) emit_tsi(as, (mi), (rt), 0, (i))
#define emit_hsi(as, mi, rh, rs, i) emit_tsi(as, (mi), (rh) & 31, (rs), (i))
static void emit_fgh(ASMState *as, MIPSIns mi, Reg rf, Reg rg, Reg rh)
{
*--as->mcp = mi | MIPSF_F(rf&31) | MIPSF_G(rg&31) | MIPSF_H(rh&31);
}
#define emit_fg(as, mi, rf, rg) emit_fgh(as, (mi), (rf), (rg), 0)
static void emit_rotr(ASMState *as, Reg dest, Reg src, Reg tmp, uint32_t shift)
{
if ((as->flags & JIT_F_MIPS32R2)) {
emit_dta(as, MIPSI_ROTR, dest, src, shift);
} else {
emit_dst(as, MIPSI_OR, dest, dest, tmp);
emit_dta(as, MIPSI_SLL, dest, src, (-shift)&31);
emit_dta(as, MIPSI_SRL, tmp, src, shift);
}
}
/* -- Emit loads/stores --------------------------------------------------- */
/* Prefer rematerialization of BASE/L from global_State over spills. */
#define emit_canremat(ref) ((ref) <= REF_BASE)
/* Try to find a one step delta relative to another constant. */
static int emit_kdelta1(ASMState *as, Reg t, int32_t i)
{
RegSet work = ~as->freeset & RSET_GPR;
while (work) {
Reg r = rset_picktop(work);
IRRef ref = regcost_ref(as->cost[r]);
lua_assert(r != t);
if (ref < ASMREF_L) {
int32_t delta = i - (ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i);
if (checki16(delta)) {
emit_tsi(as, MIPSI_ADDIU, t, r, delta);
return 1;
}
}
rset_clear(work, r);
}
return 0; /* Failed. */
}
/* Load a 32 bit constant into a GPR. */
static void emit_loadi(ASMState *as, Reg r, int32_t i)
{
if (checki16(i)) {
emit_ti(as, MIPSI_LI, r, i);
} else {
if ((i & 0xffff)) {
int32_t jgl = i32ptr(J2G(as->J));
if ((uint32_t)(i-jgl) < 65536) {
emit_tsi(as, MIPSI_ADDIU, r, RID_JGL, i-jgl-32768);
return;
} else if (emit_kdelta1(as, r, i)) {
return;
} else if ((i >> 16) == 0) {
emit_tsi(as, MIPSI_ORI, r, RID_ZERO, i);
return;
}
emit_tsi(as, MIPSI_ORI, r, r, i);
}
emit_ti(as, MIPSI_LUI, r, (i >> 16));
}
}
#define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr)))
static Reg ra_allock(ASMState *as, int32_t k, RegSet allow);
static void ra_allockreg(ASMState *as, int32_t k, Reg r);
/* Get/set from constant pointer. */
static void emit_lsptr(ASMState *as, MIPSIns mi, Reg r, void *p, RegSet allow)
{
int32_t jgl = i32ptr(J2G(as->J));
int32_t i = i32ptr(p);
Reg base;
if ((uint32_t)(i-jgl) < 65536) {
i = i-jgl-32768;
base = RID_JGL;
} else {
base = ra_allock(as, i-(int16_t)i, allow);
}
emit_tsi(as, mi, r, base, i);
}
#define emit_loadn(as, r, tv) \
emit_lsptr(as, MIPSI_LDC1, ((r) & 31), (void *)(tv), RSET_GPR)
/* Get/set global_State fields. */
static void emit_lsglptr(ASMState *as, MIPSIns mi, Reg r, int32_t ofs)
{
emit_tsi(as, mi, r, RID_JGL, ofs-32768);
}
#define emit_getgl(as, r, field) \
emit_lsglptr(as, MIPSI_LW, (r), (int32_t)offsetof(global_State, field))
#define emit_setgl(as, r, field) \
emit_lsglptr(as, MIPSI_SW, (r), (int32_t)offsetof(global_State, field))
/* Trace number is determined from per-trace exit stubs. */
#define emit_setvmstate(as, i) UNUSED(i)
/* -- Emit control-flow instructions -------------------------------------- */
/* Label for internal jumps. */
typedef MCode *MCLabel;
/* Return label pointing to current PC. */
#define emit_label(as) ((as)->mcp)
static void emit_branch(ASMState *as, MIPSIns mi, Reg rs, Reg rt, MCode *target)
{
MCode *p = as->mcp;
ptrdiff_t delta = target - p;
lua_assert(((delta + 0x8000) >> 16) == 0);
*--p = mi | MIPSF_S(rs) | MIPSF_T(rt) | ((uint32_t)delta & 0xffffu);
as->mcp = p;
}
static void emit_jmp(ASMState *as, MCode *target)
{
*--as->mcp = MIPSI_NOP;
emit_branch(as, MIPSI_B, RID_ZERO, RID_ZERO, (target));
}
static void emit_call(ASMState *as, void *target)
{
MCode *p = as->mcp;
*--p = MIPSI_NOP;
if ((((uintptr_t)target ^ (uintptr_t)p) >> 28) == 0)
*--p = MIPSI_JAL | (((uintptr_t)target >>2) & 0x03ffffffu);
else /* Target out of range: need indirect call. */
*--p = MIPSI_JALR | MIPSF_S(RID_CFUNCADDR);
as->mcp = p;
ra_allockreg(as, i32ptr(target), RID_CFUNCADDR);
}
/* -- Emit generic operations --------------------------------------------- */
#define emit_move(as, dst, src) \
emit_ds(as, MIPSI_MOVE, (dst), (src))
/* Generic move between two regs. */
static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src)
{
if (dst < RID_MAX_GPR)
emit_move(as, dst, src);
else
emit_fg(as, irt_isnum(ir->t) ? MIPSI_MOV_D : MIPSI_MOV_S, dst, src);
}
/* Generic load of register from stack slot. */
static void emit_spload(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
if (r < RID_MAX_GPR)
emit_tsi(as, MIPSI_LW, r, RID_SP, ofs);
else
emit_tsi(as, irt_isnum(ir->t) ? MIPSI_LDC1 : MIPSI_LWC1,
(r & 31), RID_SP, ofs);
}
/* Generic store of register to stack slot. */
static void emit_spstore(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
if (r < RID_MAX_GPR)
emit_tsi(as, MIPSI_SW, r, RID_SP, ofs);
else
emit_tsi(as, irt_isnum(ir->t) ? MIPSI_SDC1 : MIPSI_SWC1,
(r&31), RID_SP, ofs);
}
/* Add offset to pointer. */
static void emit_addptr(ASMState *as, Reg r, int32_t ofs)
{
if (ofs) {
lua_assert(checki16(ofs));
emit_tsi(as, MIPSI_ADDIU, r, r, ofs);
}
}
#define emit_spsub(as, ofs) emit_addptr(as, RID_SP, -(ofs))

View File

@ -1,238 +0,0 @@
/*
** PPC instruction emitter.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
/* -- Emit basic instructions --------------------------------------------- */
static void emit_tab(ASMState *as, PPCIns pi, Reg rt, Reg ra, Reg rb)
{
*--as->mcp = pi | PPCF_T(rt) | PPCF_A(ra) | PPCF_B(rb);
}
#define emit_asb(as, pi, ra, rs, rb) emit_tab(as, (pi), (rs), (ra), (rb))
#define emit_as(as, pi, ra, rs) emit_tab(as, (pi), (rs), (ra), 0)
#define emit_ab(as, pi, ra, rb) emit_tab(as, (pi), 0, (ra), (rb))
static void emit_tai(ASMState *as, PPCIns pi, Reg rt, Reg ra, int32_t i)
{
*--as->mcp = pi | PPCF_T(rt) | PPCF_A(ra) | (i & 0xffff);
}
#define emit_ti(as, pi, rt, i) emit_tai(as, (pi), (rt), 0, (i))
#define emit_ai(as, pi, ra, i) emit_tai(as, (pi), 0, (ra), (i))
#define emit_asi(as, pi, ra, rs, i) emit_tai(as, (pi), (rs), (ra), (i))
#define emit_fab(as, pi, rf, ra, rb) \
emit_tab(as, (pi), (rf)&31, (ra)&31, (rb)&31)
#define emit_fb(as, pi, rf, rb) emit_tab(as, (pi), (rf)&31, 0, (rb)&31)
#define emit_fac(as, pi, rf, ra, rc) \
emit_tab(as, (pi) | PPCF_C((rc) & 31), (rf)&31, (ra)&31, 0)
#define emit_facb(as, pi, rf, ra, rc, rb) \
emit_tab(as, (pi) | PPCF_C((rc) & 31), (rf)&31, (ra)&31, (rb)&31)
#define emit_fai(as, pi, rf, ra, i) emit_tai(as, (pi), (rf)&31, (ra), (i))
static void emit_rot(ASMState *as, PPCIns pi, Reg ra, Reg rs,
int32_t n, int32_t b, int32_t e)
{
*--as->mcp = pi | PPCF_T(rs) | PPCF_A(ra) | PPCF_B(n) |
PPCF_MB(b) | PPCF_ME(e);
}
static void emit_slwi(ASMState *as, Reg ra, Reg rs, int32_t n)
{
lua_assert(n >= 0 && n < 32);
emit_rot(as, PPCI_RLWINM, ra, rs, n, 0, 31-n);
}
static void emit_rotlwi(ASMState *as, Reg ra, Reg rs, int32_t n)
{
lua_assert(n >= 0 && n < 32);
emit_rot(as, PPCI_RLWINM, ra, rs, n, 0, 31);
}
/* -- Emit loads/stores --------------------------------------------------- */
/* Prefer rematerialization of BASE/L from global_State over spills. */
#define emit_canremat(ref) ((ref) <= REF_BASE)
/* Try to find a one step delta relative to another constant. */
static int emit_kdelta1(ASMState *as, Reg t, int32_t i)
{
RegSet work = ~as->freeset & RSET_GPR;
while (work) {
Reg r = rset_picktop(work);
IRRef ref = regcost_ref(as->cost[r]);
lua_assert(r != t);
if (ref < ASMREF_L) {
int32_t delta = i - (ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i);
if (checki16(delta)) {
emit_tai(as, PPCI_ADDI, t, r, delta);
return 1;
}
}
rset_clear(work, r);
}
return 0; /* Failed. */
}
/* Load a 32 bit constant into a GPR. */
static void emit_loadi(ASMState *as, Reg r, int32_t i)
{
if (checki16(i)) {
emit_ti(as, PPCI_LI, r, i);
} else {
if ((i & 0xffff)) {
int32_t jgl = i32ptr(J2G(as->J));
if ((uint32_t)(i-jgl) < 65536) {
emit_tai(as, PPCI_ADDI, r, RID_JGL, i-jgl-32768);
return;
} else if (emit_kdelta1(as, r, i)) {
return;
}
emit_asi(as, PPCI_ORI, r, r, i);
}
emit_ti(as, PPCI_LIS, r, (i >> 16));
}
}
#define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr)))
static Reg ra_allock(ASMState *as, int32_t k, RegSet allow);
/* Get/set from constant pointer. */
static void emit_lsptr(ASMState *as, PPCIns pi, Reg r, void *p, RegSet allow)
{
int32_t jgl = i32ptr(J2G(as->J));
int32_t i = i32ptr(p);
Reg base;
if ((uint32_t)(i-jgl) < 65536) {
i = i-jgl-32768;
base = RID_JGL;
} else {
base = ra_allock(as, i-(int16_t)i, allow);
}
emit_tai(as, pi, r, base, i);
}
#define emit_loadn(as, r, tv) \
emit_lsptr(as, PPCI_LFD, ((r) & 31), (void *)(tv), RSET_GPR)
/* Get/set global_State fields. */
static void emit_lsglptr(ASMState *as, PPCIns pi, Reg r, int32_t ofs)
{
emit_tai(as, pi, r, RID_JGL, ofs-32768);
}
#define emit_getgl(as, r, field) \
emit_lsglptr(as, PPCI_LWZ, (r), (int32_t)offsetof(global_State, field))
#define emit_setgl(as, r, field) \
emit_lsglptr(as, PPCI_STW, (r), (int32_t)offsetof(global_State, field))
/* Trace number is determined from per-trace exit stubs. */
#define emit_setvmstate(as, i) UNUSED(i)
/* -- Emit control-flow instructions -------------------------------------- */
/* Label for internal jumps. */
typedef MCode *MCLabel;
/* Return label pointing to current PC. */
#define emit_label(as) ((as)->mcp)
static void emit_condbranch(ASMState *as, PPCIns pi, PPCCC cc, MCode *target)
{
MCode *p = --as->mcp;
ptrdiff_t delta = (char *)target - (char *)p;
lua_assert(((delta + 0x8000) >> 16) == 0);
pi ^= (delta & 0x8000) * (PPCF_Y/0x8000);
*p = pi | PPCF_CC(cc) | ((uint32_t)delta & 0xffffu);
}
static void emit_jmp(ASMState *as, MCode *target)
{
MCode *p = --as->mcp;
ptrdiff_t delta = (char *)target - (char *)p;
*p = PPCI_B | (delta & 0x03fffffcu);
}
static void emit_call(ASMState *as, void *target)
{
MCode *p = --as->mcp;
ptrdiff_t delta = (char *)target - (char *)p;
if ((((delta>>2) + 0x00800000) >> 24) == 0) {
*p = PPCI_BL | (delta & 0x03fffffcu);
} else { /* Target out of range: need indirect call. Don't use arg reg. */
RegSet allow = RSET_GPR & ~RSET_RANGE(RID_R0, REGARG_LASTGPR+1);
Reg r = ra_allock(as, i32ptr(target), allow);
*p = PPCI_BCTRL;
p[-1] = PPCI_MTCTR | PPCF_T(r);
as->mcp = p-1;
}
}
/* -- Emit generic operations --------------------------------------------- */
#define emit_mr(as, dst, src) \
emit_asb(as, PPCI_MR, (dst), (src), (src))
/* Generic move between two regs. */
static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src)
{
UNUSED(ir);
if (dst < RID_MAX_GPR)
emit_mr(as, dst, src);
else
emit_fb(as, PPCI_FMR, dst, src);
}
/* Generic load of register from stack slot. */
static void emit_spload(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
if (r < RID_MAX_GPR)
emit_tai(as, PPCI_LWZ, r, RID_SP, ofs);
else
emit_fai(as, irt_isnum(ir->t) ? PPCI_LFD : PPCI_LFS, r, RID_SP, ofs);
}
/* Generic store of register to stack slot. */
static void emit_spstore(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
if (r < RID_MAX_GPR)
emit_tai(as, PPCI_STW, r, RID_SP, ofs);
else
emit_fai(as, irt_isnum(ir->t) ? PPCI_STFD : PPCI_STFS, r, RID_SP, ofs);
}
/* Emit a compare (for equality) with a constant operand. */
static void emit_cmpi(ASMState *as, Reg r, int32_t k)
{
if (checki16(k)) {
emit_ai(as, PPCI_CMPWI, r, k);
} else if (checku16(k)) {
emit_ai(as, PPCI_CMPLWI, r, k);
} else {
emit_ai(as, PPCI_CMPLWI, RID_TMP, k);
emit_asi(as, PPCI_XORIS, RID_TMP, r, (k >> 16));
}
}
/* Add offset to pointer. */
static void emit_addptr(ASMState *as, Reg r, int32_t ofs)
{
if (ofs) {
emit_tai(as, PPCI_ADDI, r, r, ofs);
if (!checki16(ofs))
emit_tai(as, PPCI_ADDIS, r, r, (ofs + 32768) >> 16);
}
}
static void emit_spsub(ASMState *as, int32_t ofs)
{
if (ofs) {
emit_tai(as, PPCI_STWU, RID_TMP, RID_SP, -ofs);
emit_tai(as, PPCI_ADDI, RID_TMP, RID_SP,
CFRAME_SIZE + (as->parent ? as->parent->spadjust : 0));
}
}

View File

@ -1,466 +0,0 @@
/*
** x86/x64 instruction emitter.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
/* -- Emit basic instructions --------------------------------------------- */
#define MODRM(mode, r1, r2) ((MCode)((mode)+(((r1)&7)<<3)+((r2)&7)))
#if LJ_64
#define REXRB(p, rr, rb) \
{ MCode rex = 0x40 + (((rr)>>1)&4) + (((rb)>>3)&1); \
if (rex != 0x40) *--(p) = rex; }
#define FORCE_REX 0x200
#define REX_64 (FORCE_REX|0x080000)
#else
#define REXRB(p, rr, rb) ((void)0)
#define FORCE_REX 0
#define REX_64 0
#endif
#define emit_i8(as, i) (*--as->mcp = (MCode)(i))
#define emit_i32(as, i) (*(int32_t *)(as->mcp-4) = (i), as->mcp -= 4)
#define emit_u32(as, u) (*(uint32_t *)(as->mcp-4) = (u), as->mcp -= 4)
#define emit_x87op(as, xo) \
(*(uint16_t *)(as->mcp-2) = (uint16_t)(xo), as->mcp -= 2)
/* op */
static LJ_AINLINE MCode *emit_op(x86Op xo, Reg rr, Reg rb, Reg rx,
MCode *p, int delta)
{
int n = (int8_t)xo;
#if defined(__GNUC__)
if (__builtin_constant_p(xo) && n == -2)
p[delta-2] = (MCode)(xo >> 24);
else if (__builtin_constant_p(xo) && n == -3)
*(uint16_t *)(p+delta-3) = (uint16_t)(xo >> 16);
else
#endif
*(uint32_t *)(p+delta-5) = (uint32_t)xo;
p += n + delta;
#if LJ_64
{
uint32_t rex = 0x40 + ((rr>>1)&(4+(FORCE_REX>>1)))+((rx>>2)&2)+((rb>>3)&1);
if (rex != 0x40) {
rex |= (rr >> 16);
if (n == -4) { *p = (MCode)rex; rex = (MCode)(xo >> 8); }
else if ((xo & 0xffffff) == 0x6600fd) { *p = (MCode)rex; rex = 0x66; }
*--p = (MCode)rex;
}
}
#else
UNUSED(rr); UNUSED(rb); UNUSED(rx);
#endif
return p;
}
/* op + modrm */
#define emit_opm(xo, mode, rr, rb, p, delta) \
(p[(delta)-1] = MODRM((mode), (rr), (rb)), \
emit_op((xo), (rr), (rb), 0, (p), (delta)))
/* op + modrm + sib */
#define emit_opmx(xo, mode, scale, rr, rb, rx, p) \
(p[-1] = MODRM((scale), (rx), (rb)), \
p[-2] = MODRM((mode), (rr), RID_ESP), \
emit_op((xo), (rr), (rb), (rx), (p), -1))
/* op r1, r2 */
static void emit_rr(ASMState *as, x86Op xo, Reg r1, Reg r2)
{
MCode *p = as->mcp;
as->mcp = emit_opm(xo, XM_REG, r1, r2, p, 0);
}
#if LJ_64 && defined(LUA_USE_ASSERT)
/* [addr] is sign-extended in x64 and must be in lower 2G (not 4G). */
static int32_t ptr2addr(const void *p)
{
lua_assert((uintptr_t)p < (uintptr_t)0x80000000);
return i32ptr(p);
}
#else
#define ptr2addr(p) (i32ptr((p)))
#endif
/* op r, [addr] */
static void emit_rma(ASMState *as, x86Op xo, Reg rr, const void *addr)
{
MCode *p = as->mcp;
*(int32_t *)(p-4) = ptr2addr(addr);
#if LJ_64
p[-5] = MODRM(XM_SCALE1, RID_ESP, RID_EBP);
as->mcp = emit_opm(xo, XM_OFS0, rr, RID_ESP, p, -5);
#else
as->mcp = emit_opm(xo, XM_OFS0, rr, RID_EBP, p, -4);
#endif
}
/* op r, [base+ofs] */
static void emit_rmro(ASMState *as, x86Op xo, Reg rr, Reg rb, int32_t ofs)
{
MCode *p = as->mcp;
x86Mode mode;
if (ra_hasreg(rb)) {
if (ofs == 0 && (rb&7) != RID_EBP) {
mode = XM_OFS0;
} else if (checki8(ofs)) {
*--p = (MCode)ofs;
mode = XM_OFS8;
} else {
p -= 4;
*(int32_t *)p = ofs;
mode = XM_OFS32;
}
if ((rb&7) == RID_ESP)
*--p = MODRM(XM_SCALE1, RID_ESP, RID_ESP);
} else {
*(int32_t *)(p-4) = ofs;
#if LJ_64
p[-5] = MODRM(XM_SCALE1, RID_ESP, RID_EBP);
p -= 5;
rb = RID_ESP;
#else
p -= 4;
rb = RID_EBP;
#endif
mode = XM_OFS0;
}
as->mcp = emit_opm(xo, mode, rr, rb, p, 0);
}
/* op r, [base+idx*scale+ofs] */
static void emit_rmrxo(ASMState *as, x86Op xo, Reg rr, Reg rb, Reg rx,
x86Mode scale, int32_t ofs)
{
MCode *p = as->mcp;
x86Mode mode;
if (ofs == 0 && (rb&7) != RID_EBP) {
mode = XM_OFS0;
} else if (checki8(ofs)) {
mode = XM_OFS8;
*--p = (MCode)ofs;
} else {
mode = XM_OFS32;
p -= 4;
*(int32_t *)p = ofs;
}
as->mcp = emit_opmx(xo, mode, scale, rr, rb, rx, p);
}
/* op r, i */
static void emit_gri(ASMState *as, x86Group xg, Reg rb, int32_t i)
{
MCode *p = as->mcp;
x86Op xo;
if (checki8(i)) {
*--p = (MCode)i;
xo = XG_TOXOi8(xg);
} else {
p -= 4;
*(int32_t *)p = i;
xo = XG_TOXOi(xg);
}
as->mcp = emit_opm(xo, XM_REG, (Reg)(xg & 7) | (rb & REX_64), rb, p, 0);
}
/* op [base+ofs], i */
static void emit_gmroi(ASMState *as, x86Group xg, Reg rb, int32_t ofs,
int32_t i)
{
x86Op xo;
if (checki8(i)) {
emit_i8(as, i);
xo = XG_TOXOi8(xg);
} else {
emit_i32(as, i);
xo = XG_TOXOi(xg);
}
emit_rmro(as, xo, (Reg)(xg & 7), rb, ofs);
}
#define emit_shifti(as, xg, r, i) \
(emit_i8(as, (i)), emit_rr(as, XO_SHIFTi, (Reg)(xg), (r)))
/* op r, rm/mrm */
static void emit_mrm(ASMState *as, x86Op xo, Reg rr, Reg rb)
{
MCode *p = as->mcp;
x86Mode mode = XM_REG;
if (rb == RID_MRM) {
rb = as->mrm.base;
if (rb == RID_NONE) {
rb = RID_EBP;
mode = XM_OFS0;
p -= 4;
*(int32_t *)p = as->mrm.ofs;
if (as->mrm.idx != RID_NONE)
goto mrmidx;
#if LJ_64
*--p = MODRM(XM_SCALE1, RID_ESP, RID_EBP);
rb = RID_ESP;
#endif
} else {
if (as->mrm.ofs == 0 && (rb&7) != RID_EBP) {
mode = XM_OFS0;
} else if (checki8(as->mrm.ofs)) {
*--p = (MCode)as->mrm.ofs;
mode = XM_OFS8;
} else {
p -= 4;
*(int32_t *)p = as->mrm.ofs;
mode = XM_OFS32;
}
if (as->mrm.idx != RID_NONE) {
mrmidx:
as->mcp = emit_opmx(xo, mode, as->mrm.scale, rr, rb, as->mrm.idx, p);
return;
}
if ((rb&7) == RID_ESP)
*--p = MODRM(XM_SCALE1, RID_ESP, RID_ESP);
}
}
as->mcp = emit_opm(xo, mode, rr, rb, p, 0);
}
/* op rm/mrm, i */
static void emit_gmrmi(ASMState *as, x86Group xg, Reg rb, int32_t i)
{
x86Op xo;
if (checki8(i)) {
emit_i8(as, i);
xo = XG_TOXOi8(xg);
} else {
emit_i32(as, i);
xo = XG_TOXOi(xg);
}
emit_mrm(as, xo, (Reg)(xg & 7) | (rb & REX_64), (rb & ~REX_64));
}
/* -- Emit loads/stores --------------------------------------------------- */
/* Instruction selection for XMM moves. */
#define XMM_MOVRR(as) ((as->flags & JIT_F_SPLIT_XMM) ? XO_MOVSD : XO_MOVAPS)
#define XMM_MOVRM(as) ((as->flags & JIT_F_SPLIT_XMM) ? XO_MOVLPD : XO_MOVSD)
/* mov [base+ofs], i */
static void emit_movmroi(ASMState *as, Reg base, int32_t ofs, int32_t i)
{
emit_i32(as, i);
emit_rmro(as, XO_MOVmi, 0, base, ofs);
}
/* mov [base+ofs], r */
#define emit_movtomro(as, r, base, ofs) \
emit_rmro(as, XO_MOVto, (r), (base), (ofs))
/* Get/set global_State fields. */
#define emit_opgl(as, xo, r, field) \
emit_rma(as, (xo), (r), (void *)&J2G(as->J)->field)
#define emit_getgl(as, r, field) emit_opgl(as, XO_MOV, (r), field)
#define emit_setgl(as, r, field) emit_opgl(as, XO_MOVto, (r), field)
#define emit_setvmstate(as, i) \
(emit_i32(as, i), emit_opgl(as, XO_MOVmi, 0, vmstate))
/* mov r, i / xor r, r */
static void emit_loadi(ASMState *as, Reg r, int32_t i)
{
/* XOR r,r is shorter, but modifies the flags. This is bad for HIOP. */
if (i == 0 && !(LJ_32 && (IR(as->curins)->o == IR_HIOP ||
(as->curins+1 < as->T->nins &&
IR(as->curins+1)->o == IR_HIOP)))) {
emit_rr(as, XO_ARITH(XOg_XOR), r, r);
} else {
MCode *p = as->mcp;
*(int32_t *)(p-4) = i;
p[-5] = (MCode)(XI_MOVri+(r&7));
p -= 5;
REXRB(p, 0, r);
as->mcp = p;
}
}
/* mov r, addr */
#define emit_loada(as, r, addr) \
emit_loadi(as, (r), ptr2addr((addr)))
#if LJ_64
/* mov r, imm64 or shorter 32 bit extended load. */
static void emit_loadu64(ASMState *as, Reg r, uint64_t u64)
{
if (checku32(u64)) { /* 32 bit load clears upper 32 bits. */
emit_loadi(as, r, (int32_t)u64);
} else if (checki32((int64_t)u64)) { /* Sign-extended 32 bit load. */
MCode *p = as->mcp;
*(int32_t *)(p-4) = (int32_t)u64;
as->mcp = emit_opm(XO_MOVmi, XM_REG, REX_64, r, p, -4);
} else { /* Full-size 64 bit load. */
MCode *p = as->mcp;
*(uint64_t *)(p-8) = u64;
p[-9] = (MCode)(XI_MOVri+(r&7));
p[-10] = 0x48 + ((r>>3)&1);
p -= 10;
as->mcp = p;
}
}
#endif
/* movsd r, [&tv->n] / xorps r, r */
static void emit_loadn(ASMState *as, Reg r, cTValue *tv)
{
if (tvispzero(tv)) /* Use xor only for +0. */
emit_rr(as, XO_XORPS, r, r);
else
emit_rma(as, XMM_MOVRM(as), r, &tv->n);
}
/* -- Emit control-flow instructions -------------------------------------- */
/* Label for short jumps. */
typedef MCode *MCLabel;
#if LJ_32 && LJ_HASFFI
/* jmp short target */
static void emit_sjmp(ASMState *as, MCLabel target)
{
MCode *p = as->mcp;
ptrdiff_t delta = target - p;
lua_assert(delta == (int8_t)delta);
p[-1] = (MCode)(int8_t)delta;
p[-2] = XI_JMPs;
as->mcp = p - 2;
}
#endif
/* jcc short target */
static void emit_sjcc(ASMState *as, int cc, MCLabel target)
{
MCode *p = as->mcp;
ptrdiff_t delta = target - p;
lua_assert(delta == (int8_t)delta);
p[-1] = (MCode)(int8_t)delta;
p[-2] = (MCode)(XI_JCCs+(cc&15));
as->mcp = p - 2;
}
/* jcc short (pending target) */
static MCLabel emit_sjcc_label(ASMState *as, int cc)
{
MCode *p = as->mcp;
p[-1] = 0;
p[-2] = (MCode)(XI_JCCs+(cc&15));
as->mcp = p - 2;
return p;
}
/* Fixup jcc short target. */
static void emit_sfixup(ASMState *as, MCLabel source)
{
source[-1] = (MCode)(as->mcp-source);
}
/* Return label pointing to current PC. */
#define emit_label(as) ((as)->mcp)
/* Compute relative 32 bit offset for jump and call instructions. */
static LJ_AINLINE int32_t jmprel(MCode *p, MCode *target)
{
ptrdiff_t delta = target - p;
lua_assert(delta == (int32_t)delta);
return (int32_t)delta;
}
/* jcc target */
static void emit_jcc(ASMState *as, int cc, MCode *target)
{
MCode *p = as->mcp;
*(int32_t *)(p-4) = jmprel(p, target);
p[-5] = (MCode)(XI_JCCn+(cc&15));
p[-6] = 0x0f;
as->mcp = p - 6;
}
/* jmp target */
static void emit_jmp(ASMState *as, MCode *target)
{
MCode *p = as->mcp;
*(int32_t *)(p-4) = jmprel(p, target);
p[-5] = XI_JMP;
as->mcp = p - 5;
}
/* call target */
static void emit_call_(ASMState *as, MCode *target)
{
MCode *p = as->mcp;
#if LJ_64
if (target-p != (int32_t)(target-p)) {
/* Assumes RID_RET is never an argument to calls and always clobbered. */
emit_rr(as, XO_GROUP5, XOg_CALL, RID_RET);
emit_loadu64(as, RID_RET, (uint64_t)target);
return;
}
#endif
*(int32_t *)(p-4) = jmprel(p, target);
p[-5] = XI_CALL;
as->mcp = p - 5;
}
#define emit_call(as, f) emit_call_(as, (MCode *)(void *)(f))
/* -- Emit generic operations --------------------------------------------- */
/* Use 64 bit operations to handle 64 bit IR types. */
#if LJ_64
#define REX_64IR(ir, r) ((r) + (irt_is64((ir)->t) ? REX_64 : 0))
#else
#define REX_64IR(ir, r) (r)
#endif
/* Generic move between two regs. */
static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src)
{
UNUSED(ir);
if (dst < RID_MAX_GPR)
emit_rr(as, XO_MOV, REX_64IR(ir, dst), src);
else
emit_rr(as, XMM_MOVRR(as), dst, src);
}
/* Generic load of register from stack slot. */
static void emit_spload(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
if (r < RID_MAX_GPR)
emit_rmro(as, XO_MOV, REX_64IR(ir, r), RID_ESP, ofs);
else
emit_rmro(as, irt_isnum(ir->t) ? XMM_MOVRM(as) : XO_MOVSS, r, RID_ESP, ofs);
}
/* Generic store of register to stack slot. */
static void emit_spstore(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
{
if (r < RID_MAX_GPR)
emit_rmro(as, XO_MOVto, REX_64IR(ir, r), RID_ESP, ofs);
else
emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSDto : XO_MOVSSto, r, RID_ESP, ofs);
}
/* Add offset to pointer. */
static void emit_addptr(ASMState *as, Reg r, int32_t ofs)
{
if (ofs) {
if ((as->flags & JIT_F_LEA_AGU))
emit_rmro(as, XO_LEA, r, r, ofs);
else
emit_gri(as, XG_ARITHi(XOg_ADD), r, ofs);
}
}
#define emit_spsub(as, ofs) emit_addptr(as, RID_ESP|REX_64, -(ofs))
/* Prefer rematerialization of BASE/L from global_State over spills. */
#define emit_canremat(ref) ((ref) <= REF_BASE)

Some files were not shown because too many files have changed in this diff Show More