/* 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; }
/* Check for compatible types when converting to a pointer. ** Note: these checks are more relaxed than what C99 mandates. */ int lj_cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags) { if (!((flags & CCF_CAST) || d == s)) { CTInfo dqual = 0, squal = 0; d = cconv_childqual(cts, d, &dqual); if (!ctype_isstruct(s->info)) s = cconv_childqual(cts, s, &squal); if ((flags & CCF_SAME)) { if (dqual != squal) return 0; /* Different qualifiers. */ } else if (!(flags & CCF_IGNQUAL)) { if ((dqual & squal) != squal) return 0; /* Discarded qualifiers. */ if (ctype_isvoid(d->info) || ctype_isvoid(s->info)) return 1; /* Converting to/from void * is always ok. */ } if (ctype_type(d->info) != ctype_type(s->info) || d->size != s->size) return 0; /* Different type or different size. */ if (ctype_isnum(d->info)) { if (((d->info ^ s->info) & (CTF_BOOL|CTF_FP))) return 0; /* Different numeric types. */ } else if (ctype_ispointer(d->info)) { /* Check child types for compatibility. */ return lj_cconv_compatptr(cts, d, s, flags|CCF_SAME); } else if (ctype_isstruct(d->info)) { if (d != s) return 0; /* Must be exact same type for struct/union. */ } else if (ctype_isfunc(d->info)) { /* NYI: structural equality of functions. */ } } return 1; /* Types are compatible. */ }
/* Infer the destination CTypeID for a vararg argument. */ static CTypeID ccall_ctid_vararg(CTState *cts, cTValue *o) { if (tvisnumber(o)) { return CTID_DOUBLE; } else if (tviscdata(o)) { CTypeID id = cdataV(o)->typeid; 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); } if (ctype_isfp(s->info) && s->size == sizeof(float)) { return CTID_DOUBLE; } else { return id; } } else if (tvisstr(o)) {
/* Free a C data object. */ void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd) { if (LJ_UNLIKELY(cd->marked & LJ_GC_CDATA_FIN)) { GCobj *root; makewhite(g, obj2gco(cd)); markfinalized(obj2gco(cd)); if ((root = gcref(g->gc.mmudata)) != NULL) { setgcrefr(cd->nextgc, root->gch.nextgc); setgcref(root->gch.nextgc, obj2gco(cd)); setgcref(g->gc.mmudata, obj2gco(cd)); } else { setgcref(cd->nextgc, obj2gco(cd)); setgcref(g->gc.mmudata, obj2gco(cd)); } } else if (LJ_LIKELY(!cdataisv(cd))) { CType *ct = ctype_raw(ctype_ctsG(g), cd->ctypeid); CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR; lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) || ctype_isextern(ct->info)); lj_mem_free(g, cd, sizeof(GCcdata) + sz); } else { lj_mem_free(g, memcdatav(cd), sizecdatav(cd)); } }