/* Allocate arbitrary C data object. */ GCcdata *lj_cdata_newx(CTState *cts, CTypeID id, CTSize sz, CTInfo info) { if (!(info & CTF_VLA) && ctype_align(info) <= CT_MEMALIGN) return lj_cdata_new(cts, id, sz); else return lj_cdata_newv(cts->L, id, sz, ctype_align(info)); }
/* 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; }
/* Index a C library by name. */ TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) { TValue *tv = lj_tab_setstr(L, cl->cache, name); if (LJ_UNLIKELY(tvisnil(tv))) { CTState *cts = ctype_cts(L); CType *ct; CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX); if (!id) lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name)); if (ctype_isconstval(ct->info)) { CType *ctt = ctype_child(cts, ct); lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4); if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0) setnumV(tv, (lua_Number)(uint32_t)ct->size); else setintV(tv, (int32_t)ct->size); } else { const char *sym = clib_extsym(cts, ct, name); #if LJ_TARGET_WINDOWS DWORD oldwerr = GetLastError(); #endif void *p = clib_getsym(cl, sym); GCcdata *cd; lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info)); #if LJ_TARGET_X86 && LJ_ABI_WIN /* Retry with decorated name for fastcall/stdcall functions. */ if (!p && ctype_isfunc(ct->info)) { CTInfo cconv = ctype_cconv(ct->info); if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) { CTSize sz = clib_func_argsize(cts, ct); const char *symd = lj_str_pushf(L, cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d", sym, sz); L->top--; p = clib_getsym(cl, symd); } } #endif if (!p) clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym); #if LJ_TARGET_WINDOWS SetLastError(oldwerr); #endif cd = lj_cdata_new(cts, id, CTSIZE_PTR); *(void **)cdataptr(cd) = p; setcdataV(L, tv, cd); } } return tv; }
/* Convert C type to TValue. Caveat: expects to get the raw CType! */ int lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid, TValue *o, uint8_t *sp) { CTInfo sinfo = s->info; lua_assert(!ctype_isenum(sinfo)); if (ctype_isnum(sinfo)) { if (!ctype_isbool(sinfo)) { if (ctype_isinteger(sinfo) && s->size > 4) goto copyval; if (LJ_DUALNUM && ctype_isinteger(sinfo)) { int32_t i; lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT32), s, (uint8_t *)&i, sp, 0); if ((sinfo & CTF_UNSIGNED) && i < 0) setnumV(o, (lua_Number)(uint32_t)i); else setintV(o, i); } else { lj_cconv_ct_ct(cts, ctype_get(cts, CTID_DOUBLE), s, (uint8_t *)&o->n, sp, 0); /* Numbers are NOT canonicalized here! Beware of uninitialized data. */ lua_assert(tvisnum(o)); } } else { uint32_t b = ((*sp) & 1); setboolV(o, b); setboolV(&cts->g->tmptv2, b); /* Remember for trace recorder. */ } return 0; } else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) { /* Create reference. */ setcdataV(cts->L, o, lj_cdata_newref(cts, sp, sid)); return 1; /* Need GC step. */ } else { GCcdata *cd; CTSize sz; copyval: /* Copy value. */ sz = s->size; lua_assert(sz != CTSIZE_INVALID); /* Attributes are stripped, qualifiers are kept (but mostly ignored). */ cd = lj_cdata_new(cts, ctype_typeid(cts, s), sz); setcdataV(cts->L, o, cd); memcpy(cdataptr(cd), sp, sz); return 1; /* Need GC step. */ } }
void * luaL_pushcdata(struct lua_State *L, uint32_t ctypeid) { /* * ctypeid is actually has CTypeID type. * CTypeId is defined somewhere inside luajit's internal * headers. */ assert(sizeof(ctypeid) == sizeof(CTypeID)); /* Code below is based on ffi_new() from luajit/src/lib_ffi.c */ /* Get information about ctype */ CTSize size; CTState *cts = ctype_cts(L); CTInfo info = lj_ctype_info(cts, ctypeid, &size); /* Only numbers and pointers are implemented */ assert(ctype_isnum(info) || ctype_isptr(info)); (void) info; assert(size != CTSIZE_INVALID); /* Allocate a new cdata */ GCcdata *cd = lj_cdata_new(cts, ctypeid, size); /* Anchor the uninitialized cdata with the stack. */ TValue *o = L->top; setcdataV(L, o, cd); incr_top(L); /* * lj_cconv_ct_init is omitted because it actually does memset() * Caveats: cdata memory is returned uninitialized */ /* * __gc is omitted because it is only needed for structs. * Caveats: struct are not supported by this function. * Please set finalizer using luaL_setcdatagc() if you need. */ lj_gc_check(L); return cdataptr(cd); }
/* Unsink allocation from the trace exit state. Unsink sunk stores. */ static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex, SnapNo snapno, BloomFilter rfilt, IRIns *ir, TValue *o) { lua_assert(ir->o == IR_TNEW || ir->o == IR_TDUP || ir->o == IR_CNEW || ir->o == IR_CNEWI); #if LJ_HASFFI if (ir->o == IR_CNEW || ir->o == IR_CNEWI) { CTState *cts = ctype_ctsG(J2G(J)); CTypeID id = (CTypeID)T->ir[ir->op1].i; CTSize sz = lj_ctype_size(cts, id); GCcdata *cd = lj_cdata_new(cts, id, sz); setcdataV(J->L, o, cd); if (ir->o == IR_CNEWI) { uint8_t *p = (uint8_t *)cdataptr(cd); lua_assert(sz == 4 || sz == 8); if (LJ_32 && sz == 8 && ir+1 < T->ir + T->nins && (ir+1)->o == IR_HIOP) { snap_restoredata(T, ex, snapno, rfilt, (ir+1)->op2, LJ_LE?p+4:p, 4); if (LJ_BE) p += 4; sz = 4; } snap_restoredata(T, ex, snapno, rfilt, ir->op2, p, sz); } else { IRIns *irs, *irlast = &T->ir[T->snap[snapno].ref]; for (irs = ir+1; irs < irlast; irs++) if (irs->r == RID_SINK && snap_sunk_store(J, ir, irs)) { IRIns *iro = &T->ir[T->ir[irs->op1].op2]; uint8_t *p = (uint8_t *)cd; CTSize szs; lua_assert(irs->o == IR_XSTORE && T->ir[irs->op1].o == IR_ADD); lua_assert(iro->o == IR_KINT || iro->o == IR_KINT64); if (irt_is64(irs->t)) szs = 8; else if (irt_isi8(irs->t) || irt_isu8(irs->t)) szs = 1; else if (irt_isi16(irs->t) || irt_isu16(irs->t)) szs = 2; else szs = 4; if (LJ_64 && iro->o == IR_KINT64) p += (int64_t)ir_k64(iro)->u64; else p += iro->i; lua_assert(p >= (uint8_t *)cdataptr(cd) && p + szs <= (uint8_t *)cdataptr(cd) + sz); if (LJ_32 && irs+1 < T->ir + T->nins && (irs+1)->o == IR_HIOP) { lua_assert(szs == 4); snap_restoredata(T, ex, snapno, rfilt, (irs+1)->op2, LJ_LE?p+4:p,4); if (LJ_BE) p += 4; } snap_restoredata(T, ex, snapno, rfilt, irs->op2, p, szs); } } } else #endif { IRIns *irs, *irlast; GCtab *t = ir->o == IR_TNEW ? lj_tab_new(J->L, ir->op1, ir->op2) : lj_tab_dup(J->L, ir_ktab(&T->ir[ir->op1])); settabV(J->L, o, t); irlast = &T->ir[T->snap[snapno].ref]; for (irs = ir+1; irs < irlast; irs++) if (irs->r == RID_SINK && snap_sunk_store(J, ir, irs)) { IRIns *irk = &T->ir[irs->op1]; TValue tmp, *val; lua_assert(irs->o == IR_ASTORE || irs->o == IR_HSTORE || irs->o == IR_FSTORE); if (irk->o == IR_FREF) { lua_assert(irk->op2 == IRFL_TAB_META); snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, &tmp); /* NOBARRIER: The table is new (marked white). */ setgcref(t->metatable, obj2gco(tabV(&tmp))); } else { irk = &T->ir[irk->op2]; if (irk->o == IR_KSLOT) irk = &T->ir[irk->op1]; lj_ir_kvalue(J->L, &tmp, irk); val = lj_tab_set(J->L, t, &tmp); /* NOBARRIER: The table is new (marked white). */ snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, val); if (LJ_SOFTFP && irs+1 < T->ir + T->nins && (irs+1)->o == IR_HIOP) { snap_restoreval(J, T, ex, snapno, rfilt, (irs+1)->op2, &tmp); val->u32.hi = tmp.u32.lo; } } } } }