FFI: Add C data handling and C type conversions.

This commit is contained in:
Mike Pall 2010-12-05 00:18:07 +01:00
parent 05973ee440
commit 526e087e63
9 changed files with 1149 additions and 17 deletions

View File

@ -327,7 +327,7 @@ LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o \
lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \ lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
lj_opt_dce.o lj_opt_loop.o \ lj_opt_dce.o lj_opt_loop.o \
lj_mcode.o lj_snap.o lj_record.o lj_asm.o lj_trace.o lj_gdbjit.o \ lj_mcode.o lj_snap.o lj_record.o lj_asm.o lj_trace.o lj_gdbjit.o \
lj_ctype.o \ lj_ctype.o lj_cdata.o lj_cconv.o \
lj_lib.o lj_alloc.o lib_aux.o \ lj_lib.o lj_alloc.o lib_aux.o \
$(LJLIB_O) lib_init.o $(LJLIB_O) lib_init.o

View File

@ -52,6 +52,10 @@ lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_vm.h lj_target.h lj_target_*.h lj_vm.h lj_target.h lj_target_*.h
lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \ lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
lj_bcdef.h lj_bcdef.h
lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_gc.h lj_cdata.h lj_cconv.h
lj_cdata.o: lj_cdata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cconv.h lj_cdata.h
lj_char.o: lj_char.c lj_char.h lj_def.h lua.h luaconf.h lj_char.o: lj_char.c lj_char.h lj_def.h lua.h luaconf.h
lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h
@ -66,8 +70,8 @@ lj_func.o: lj_func.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_traceerr.h lj_vm.h lj_traceerr.h lj_vm.h
lj_gc.o: lj_gc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ lj_gc.o: lj_gc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_udata.h lj_meta.h \ lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_udata.h lj_meta.h \
lj_state.h lj_frame.h lj_bc.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \ lj_state.h lj_frame.h lj_bc.h lj_cdata.h lj_ctype.h lj_trace.h lj_jit.h \
lj_traceerr.h lj_vm.h lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h
lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_frame.h lj_bc.h lj_jit.h lj_ir.h \ lj_gc.h lj_err.h lj_errmsg.h lj_frame.h lj_bc.h lj_jit.h lj_ir.h \
lj_dispatch.h lj_dispatch.h
@ -129,17 +133,17 @@ lj_vmevent.o: lj_vmevent.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_vm.h lj_vmevent.h lj_vm.h lj_vmevent.h
ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \ ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h \ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h \
lj_udata.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_trace.h lj_jit.h \ lj_udata.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_cdata.h lj_ctype.h \
lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_err.c lj_char.c lj_char.h \ lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_err.c \
lj_bc.c lj_bcdef.h lj_obj.c lj_str.c lj_tab.c lj_func.c lj_udata.c \ lj_char.c lj_char.h lj_bc.c lj_bcdef.h lj_obj.c lj_str.c lj_tab.c \
lj_meta.c lj_state.c lj_ctype.h lj_lex.h lj_alloc.h lj_dispatch.c \ lj_func.c lj_udata.c lj_meta.c lj_state.c lj_lex.h lj_alloc.h \
lj_ff.h lj_ffdef.h luajit.h lj_vmevent.c lj_vmevent.h lj_api.c \ lj_dispatch.c lj_ff.h lj_ffdef.h luajit.h lj_vmevent.c lj_vmevent.h \
lj_parse.h lj_lex.c lj_parse.c lj_ctype.c lj_lib.c lj_lib.h lj_ir.c \ lj_api.c lj_parse.h lj_lex.c lj_parse.c lj_ctype.c lj_cdata.c lj_cconv.h \
lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c \ lj_cconv.c lj_lib.c lj_lib.h lj_ir.c lj_iropt.h lj_opt_mem.c \
lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_mcode.c lj_mcode.h lj_snap.c \ lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c \
lj_target.h lj_target_*.h lj_record.c lj_record.h lj_asm.h lj_recdef.h \ lj_snap.h lj_mcode.c lj_mcode.h lj_snap.c lj_target.h lj_target_*.h \
lj_asm.c lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c \ lj_record.c lj_record.h lj_asm.h lj_recdef.h lj_asm.c lj_trace.c \
lib_base.c lualib.h lj_libdef.h lib_math.c lib_string.c lib_table.c \ lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c lib_base.c lualib.h \
lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c \ lj_libdef.h lib_math.c lib_string.c lib_table.c lib_io.c lib_os.c \
lib_init.c lib_package.c lib_debug.c lib_bit.c lib_jit.c lib_init.c
luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h

741
src/lj_cconv.c Normal file
View File

@ -0,0 +1,741 @@
/*
** C type conversions.
** Copyright (C) 2005-2010 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"
/* -- 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 : LUA_TSTRING)];
else
src = strdata(lj_ctype_repr(cts->L, ctype_typeid(cts, s), NULL));
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)
{
const char *dst = strdata(lj_ctype_repr(cts->L, ctype_typeid(cts, d), NULL));
lj_err_callerv(cts->L, LJ_ERR_FFI_BADCONV, typename(o), 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.
*/
static int 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 ((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 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);
lua_assert(!ctype_isbool(sinfo) || ssize == 1);
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):
*dp = *sp; /* Source operand already normalized. */
break;
case CCX(B, I):
case CCX(B, P): {
MSize i;
uint8_t b = 0;
for (i = 0; i < ssize; i++) b |= sp[i];
*dp = (b != 0);
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. */
*dp = b;
break;
}
case CCX(B, C): {
CType *sc = ctype_child(cts, s);
uint8_t c;
lj_cconv_ct_ct(cts, d, sc, &c, sp, flags);
lj_cconv_ct_ct(cts, d, sc, dp, sp + sc->size, flags);
*dp = (*dp | c);
break;
}
case CCX(B, A):
*dp = (sp != (uint8_t *)0);
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;
#ifdef _MSC_VER
else if (n >= 9223372036854775808.0) /* They think it's a feature. */
*(uint64_t *)dp = (uint64_t)(int64_t)(n - 9223372036854775808.0) +
U64x(80000000,00000000);
#endif
else
*(uint64_t *)dp = (uint64_t)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;
dinfo = CTINFO(CT_NUM, CTF_UNSIGNED);
goto conv_I_F;
case CCX(P, P):
if (!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 (!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) || d->size != s->size ||
d->size == CTSIZE_INVALID || !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 ----------------------------------------- */
/* Copy value to new cdata. Strip attributes and qualifiers. */
static GCcdata *cconv_copyval(CTState *cts, CTypeID id, void *sp)
{
CType *ct = ctype_raw(cts, id);
CTInfo info = ct->info;
CTSize size = ct->size;
GCcdata *cd;
lua_assert(ctype_isnum(info) || ctype_isenum(info) ||
ctype_isptr(info) || ctype_isvalarray(info));
if (LJ_UNLIKELY((info & CTF_QUAL))) { /* Any qualifiers to strip? */
if (ctype_isarray(info)) {
CType *cct = ctype_child(cts, ct);
id = lj_ctype_intern(cts, (cct->info & ~CTF_QUAL), cct->size);
info = ((info & ~CTMASK_CID) + id);
}
id = lj_ctype_intern(cts, (info & ~CTF_QUAL), size);
}
cd = lj_cdata_new(cts, id, size);
memcpy(cdataptr(cd), sp, size);
return cd;
}
/* Convert C type to TValue. Caveat: expects to get the raw CType! */
void lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid,
TValue *o, uint8_t *sp)
{
CTInfo sinfo = s->info;
lua_assert(!ctype_isenum(sinfo));
if (ctype_isnum(sinfo)) {
uint8_t tmpbool;
uint8_t *dp;
CTypeID did;
if (!ctype_isbool(sinfo)) {
if (ctype_isinteger(sinfo) && s->size > 4) goto copyval;
dp = (uint8_t *)&o->n;
did = CTID_DOUBLE;
} else {
dp = &tmpbool;
did = CTID_BOOL;
}
lj_cconv_ct_ct(cts, ctype_get(cts, did), s, dp, sp, 0);
/* Numbers are NOT canonicalized here! Beware of uninitialized data. */
if (did == CTID_BOOL)
setboolV(o, tmpbool);
else
lua_assert(tvisnum(o));
} else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) {
/* Create reference. */
setcdataV(cts->L, o, lj_cdata_newref(cts, sp, sid));
} else {
copyval: /* Copy value. */
setcdataV(cts->L, o, cconv_copyval(cts, sid, sp));
}
}
/* Convert bitfield to TValue. */
void 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))
setnumV(o, (lua_Number)((int32_t)(val << (shift-pos)) >> shift));
else
setnumV(o, (lua_Number)((val << (shift-pos)) >> shift));
} else {
lua_assert(bsz == 1);
setboolV(o, (val >> pos) & 1);
}
}
/* -- 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;
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. */
break; /* Stop at first nil. */
}
*ip = i + 1;
} else {
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_child(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. */
if (t->hmask) i = -1; else if (t->asize == 0) return; /* Fast exit. */
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(tvisnum(o))) {
sp = (uint8_t *)&o->n;
sid = CTID_DOUBLE;
flags |= CCF_FROMTV;
} else if (tviscdata(o)) {
sp = cdataptr(cdataV(o));
sid = cdataV(o)->typeid;
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_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-1;
dp[sz] = '\0';
}
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;
} else if (tvisudata(o)) {
tmpptr = uddata(udataV(o));
} else if (tvislightud(o)) {
tmpptr = lightudV(o);
} else {
err_conv:
cconv_err_convtv(cts, d, o);
}
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_child(cts, df), dp+df->size, o, len, ip);
} /* 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).
*/
static int 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)) {
CTInfo info = lj_ctype_rawref(cts, cdataV(o)->typeid)->info;
if (ctype_isrefarray(info) || ctype_isstruct(info))
return 0; /* Initializer is not a value. */
}
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 && !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

64
src/lj_cconv.h Normal file
View File

@ -0,0 +1,64 @@
/*
** C type conversions.
** Copyright (C) 2005-2010 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 = ((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
LJ_FUNC void lj_cconv_ct_ct(CTState *cts, CType *d, CType *s,
uint8_t *dp, uint8_t *sp, CTInfo flags);
LJ_FUNC void lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid,
TValue *o, uint8_t *sp);
LJ_FUNC void 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 void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz,
uint8_t *dp, TValue *o, MSize len);
#endif
#endif

235
src/lj_cdata.c Normal file
View File

@ -0,0 +1,235 @@
/*
** C data management.
** Copyright (C) 2005-2010 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_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->typeid = id;
return cd;
}
/* Free a C data object. */
void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd)
{
if (LJ_LIKELY(!cdataisv(cd))) {
CType *ct = ctype_raw(ctype_ctsG(g), cd->typeid);
CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR;
lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info));
lj_mem_free(g, cd, sizeof(GCcdata) + sz);
} else {
lj_mem_free(g, memcdatav(cd), sizecdatav(cd));
}
}
/* -- 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->typeid);
/* 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);
}
/* 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 (tvisnum(key)) { /* Numeric key. */
ptrdiff_t idx = LJ_64 ? (ptrdiff_t)numV(key) :
(ptrdiff_t)lj_num2int(numV(key));
if (ctype_ispointer(ct->info)) {
CTSize sz = lj_ctype_size(cts, ctype_cid(ct->info));
if (sz != CTSIZE_INVALID) {
if (ctype_isptr(ct->info))
p = (uint8_t *)cdata_getptr(p, ct->size);
else if ((ct->info & (CTF_VECTOR|CTF_COMPLEX)))
*qual |= CTF_CONST; /* Valarray elements are constant. */
*pp = p + idx*(int32_t)sz;
return ct;
}
}
} else if (tvisstr(key)) { /* String key. */
GCstr *name = strV(key);
if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */
CType *cct = ctype_child(cts, ct);
if (ctype_isstruct(cct->info)) {
p = (uint8_t *)cdata_getptr(p, ct->size);
ct = cct;
goto index_struct;
}
} if (ctype_isstruct(ct->info)) {
CTSize ofs;
CType *fct;
index_struct:
fct = lj_ctype_getfield(cts, ct, name, &ofs);
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;
}
}
}
{
GCstr *s = lj_ctype_repr(cts->L, ctype_typeid(cts, ct), NULL);
lj_err_callerv(cts->L, LJ_ERR_FFI_BADMEMBER, strdata(s), strdata(name));
}
}
{
GCstr *s = lj_ctype_repr(cts->L, ctype_typeid(cts, ct), NULL);
lj_err_callerv(cts->L, LJ_ERR_FFI_BADIDX, strdata(s));
}
return NULL; /* unreachable */
}
/* -- 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))
setintV(o, (int32_t)ct->size);
else
setnumV(o, (lua_Number)(uint32_t)ct->size);
}
/* Get C data value and convert to TValue. */
void 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;
} else if (ctype_isbitfield(s->info)) {
lj_cconv_tv_bf(cts, s, o, sp);
return;
}
/* 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 and enums. */
while (ctype_isattrib(s->info) || ctype_isenum(s->info))
s = ctype_child(cts, s);
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

62
src/lj_cdata.h Normal file
View File

@ -0,0 +1,62 @@
/*
** C data management.
** Copyright (C) 2005-2010 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;
lua_assert(lj_ctype_size(cts, id) == sz);
cd = (GCcdata *)lj_mem_newgco(cts->L, sizeof(GCcdata) + sz);
cd->gct = ~LJ_TCDATA;
cd->typeid = ctype_check(cts, 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_FUNC CType *lj_cdata_index(CTState *cts, GCcdata *cd, cTValue *key,
uint8_t **pp, CTInfo *qual);
LJ_FUNC void 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

@ -137,6 +137,23 @@ ERRDEF(XSYNTAX, "syntax error")
ERRDEF(XBREAK, "no loop to break") ERRDEF(XBREAK, "no loop to break")
ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected") ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected")
#if LJ_HASFFI
/* FFI errors. */
ERRDEF(FFI_INVTYPE, "invalid C type")
ERRDEF(FFI_INVSIZE, "size of C type is unknown or too large")
ERRDEF(FFI_BADSCL, "bad storage class")
ERRDEF(FFI_DECLSPEC, "declaration specifier expected")
ERRDEF(FFI_BADTAG, "undeclared or implicit tag " LUA_QS)
ERRDEF(FFI_REDEF, "attempt to redefine " LUA_QS)
ERRDEF(FFI_INITOV, "too many initializers for " LUA_QS)
ERRDEF(FFI_BADCONV, "cannot convert " LUA_QS " to " LUA_QS)
ERRDEF(FFI_BADMEMBER, LUA_QS " has no member named " LUA_QS)
ERRDEF(FFI_BADIDX, LUA_QS " cannot be indexed")
ERRDEF(FFI_WRCONST, "attempt to write to constant location")
ERRDEF(FFI_NYIPACKBIT, "NYI: packed bit fields")
ERRDEF(FFI_NYICALL, "NYI: C function calls")
#endif
#undef ERRDEF #undef ERRDEF
/* Detecting unused error messages: /* Detecting unused error messages:

View File

@ -19,6 +19,9 @@
#include "lj_meta.h" #include "lj_meta.h"
#include "lj_state.h" #include "lj_state.h"
#include "lj_frame.h" #include "lj_frame.h"
#if LJ_HASFFI
#include "lj_cdata.h"
#endif
#include "lj_trace.h" #include "lj_trace.h"
#include "lj_vm.h" #include "lj_vm.h"
@ -373,7 +376,11 @@ static const GCFreeFunc gc_freefunc[] = {
#else #else
(GCFreeFunc)0, (GCFreeFunc)0,
#endif #endif
(GCFreeFunc)0, /* Placeholder for C data. */ #if LJ_HASFFI
(GCFreeFunc)lj_cdata_free,
#else
(GCFreeFunc)0,
#endif
(GCFreeFunc)lj_tab_free, (GCFreeFunc)lj_tab_free,
(GCFreeFunc)lj_udata_free (GCFreeFunc)lj_udata_free
}; };

View File

@ -41,6 +41,8 @@
#include "lj_lex.c" #include "lj_lex.c"
#include "lj_parse.c" #include "lj_parse.c"
#include "lj_ctype.c" #include "lj_ctype.c"
#include "lj_cdata.c"
#include "lj_cconv.c"
#include "lj_lib.c" #include "lj_lib.c"
#include "lj_ir.c" #include "lj_ir.c"
#include "lj_opt_mem.c" #include "lj_opt_mem.c"