http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_bc.c ---------------------------------------------------------------------- diff --git a/lib/luajit/src/lj_bc.c b/lib/luajit/src/lj_bc.c new file mode 100644 index 0000000..a8f444c --- /dev/null +++ b/lib/luajit/src/lj_bc.c @@ -0,0 +1,14 @@ +/* +** Bytecode instruction modes. +** Copyright (C) 2005-2015 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" +
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_bc.h ---------------------------------------------------------------------- diff --git a/lib/luajit/src/lj_bc.h b/lib/luajit/src/lj_bc.h new file mode 100644 index 0000000..7436fab --- /dev/null +++ b/lib/luajit/src/lj_bc.h @@ -0,0 +1,261 @@ +/* +** Bytecode instruction format. +** Copyright (C) 2005-2015 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 http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_bcdump.h ---------------------------------------------------------------------- diff --git a/lib/luajit/src/lj_bcdump.h b/lib/luajit/src/lj_bcdump.h new file mode 100644 index 0000000..812d0e1 --- /dev/null +++ b/lib/luajit/src/lj_bcdump.h @@ -0,0 +1,66 @@ +/* +** Bytecode dump definitions. +** Copyright (C) 2005-2015 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 http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_bcread.c ---------------------------------------------------------------------- diff --git a/lib/luajit/src/lj_bcread.c b/lib/luajit/src/lj_bcread.c new file mode 100644 index 0000000..25859d2 --- /dev/null +++ b/lib/luajit/src/lj_bcread.c @@ -0,0 +1,476 @@ +/* +** Bytecode reader. +** Copyright (C) 2005-2015 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); +} + http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_bcwrite.c ---------------------------------------------------------------------- diff --git a/lib/luajit/src/lj_bcwrite.c b/lib/luajit/src/lj_bcwrite.c new file mode 100644 index 0000000..ff97450 --- /dev/null +++ b/lib/luajit/src/lj_bcwrite.c @@ -0,0 +1,396 @@ +/* +** Bytecode writer. +** Copyright (C) 2005-2015 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; +} + http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_carith.c ---------------------------------------------------------------------- diff --git a/lib/luajit/src/lj_carith.c b/lib/luajit/src/lj_carith.c new file mode 100644 index 0000000..2a358a9 --- /dev/null +++ b/lib/luajit/src/lj_carith.c @@ -0,0 +1,353 @@ +/* +** C data arithmetic. +** Copyright (C) 2005-2015 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 http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_carith.h ---------------------------------------------------------------------- diff --git a/lib/luajit/src/lj_carith.h b/lib/luajit/src/lj_carith.h new file mode 100644 index 0000000..8c4bdbb --- /dev/null +++ b/lib/luajit/src/lj_carith.h @@ -0,0 +1,27 @@ +/* +** C data arithmetic. +** Copyright (C) 2005-2015 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 http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_ccall.c ---------------------------------------------------------------------- diff --git a/lib/luajit/src/lj_ccall.c b/lib/luajit/src/lj_ccall.c new file mode 100644 index 0000000..998417c --- /dev/null +++ b/lib/luajit/src/lj_ccall.c @@ -0,0 +1,900 @@ +/* +** FFI C call handling. +** Copyright (C) 2005-2015 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 http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_ccall.h ---------------------------------------------------------------------- diff --git a/lib/luajit/src/lj_ccall.h b/lib/luajit/src/lj_ccall.h new file mode 100644 index 0000000..f553010 --- /dev/null +++ b/lib/luajit/src/lj_ccall.h @@ -0,0 +1,171 @@ +/* +** FFI C call handling. +** Copyright (C) 2005-2015 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