/* 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. */ }
void luaL_setcdatagc(struct lua_State *L, int idx) { /* Calculate absolute value in the stack. */ if (idx < 0) idx = lua_gettop(L) + idx + 1; /* Code below is based on ffi_gc() from luajit/src/lib_ffi.c */ /* Get cdata from the stack */ assert(lua_type(L, idx) == LUA_TCDATA); GCcdata *cd = cdataV(L->base + idx - 1); /* Get finalizer from the stack */ TValue *fin = lj_lib_checkany(L, lua_gettop(L)); #if !defined(NDEBUG) CTState *cts = ctype_cts(L); CType *ct = ctype_raw(cts, cd->ctypeid); (void) ct; assert(ctype_isptr(ct->info) || ctype_isstruct(ct->info) || ctype_isrefarray(ct->info)); #endif /* !defined(NDEBUG) */ /* Set finalizer */ lj_cdata_setfin(L, cd, gcval(fin), itype(fin)); /* Pop finalizer */ lua_pop(L, 1); }
/* 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; } }
static TRef crec_tv_ct(jit_State *J, CType *s, CTypeID sid, TRef sp) { CTState *cts = ctype_ctsG(J2G(J)); CTInfo sinfo = s->info; lua_assert(!ctype_isenum(sinfo)); if (ctype_isnum(sinfo)) { IRType t = crec_ct2irt(s); TRef tr; if (t == IRT_CDATA) goto err_nyi; /* NYI: copyval of >64 bit integers. */ tr = emitir(IRT(IR_XLOAD, t), sp, 0); if (t == IRT_FLOAT || t == IRT_U32) { /* Keep uint32_t/float as numbers. */ tr = emitconv(tr, IRT_NUM, t, 0); } else if (t == IRT_I64 || t == IRT_U64) { /* Box 64 bit integer. */ TRef dp = emitir(IRTG(IR_CNEW, IRT_CDATA), lj_ir_kint(J, sid), TREF_NIL); TRef ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, sizeof(GCcdata))); emitir(IRT(IR_XSTORE, t), ptr, tr); return dp; } else if ((sinfo & CTF_BOOL)) { /* Assume not equal to zero. Fixup and emit pending guard later. */ lj_ir_set(J, IRTGI(IR_NE), tr, lj_ir_kint(J, 0)); J->postproc = LJ_POST_FIXGUARD; tr = TREF_TRUE; } return tr; } else if (ctype_isptr(sinfo)) { IRType t = (LJ_64 && s->size == 8) ? IRT_P64 : IRT_P32; sp = emitir(IRT(IR_XLOAD, t), sp, 0); } else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) { cts->L = J->L; sid = lj_ctype_intern(cts, CTINFO_REF(sid), CTSIZE_PTR); /* Create ref. */ } else if (ctype_iscomplex(sinfo)) { /* Unbox/box complex. */ IRType t = s->size == 2*sizeof(double) ? IRT_NUM : IRT_FLOAT; ptrdiff_t esz = (ptrdiff_t)(s->size >> 1); TRef ptr, tr1, tr2, dp; dp = emitir(IRTG(IR_CNEW, IRT_CDATA), lj_ir_kint(J, sid), TREF_NIL); tr1 = emitir(IRT(IR_XLOAD, t), sp, 0); ptr = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, esz)); tr2 = emitir(IRT(IR_XLOAD, t), ptr, 0); ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, sizeof(GCcdata))); emitir(IRT(IR_XSTORE, t), ptr, tr1); ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, sizeof(GCcdata)+esz)); emitir(IRT(IR_XSTORE, t), ptr, tr2); return dp; } else {
/* 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. */ } }
/* 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)) {
/* 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)) {
/* Index C data by a TValue. Return CType and pointer. */ CType *lj_cdata_index(CTState *cts, GCcdata *cd, cTValue *key, uint8_t **pp, CTInfo *qual) { uint8_t *p = (uint8_t *)cdataptr(cd); CType *ct = ctype_get(cts, cd->ctypeid); ptrdiff_t idx; /* Resolve reference for cdata object. */ if (ctype_isref(ct->info)) { lua_assert(ct->size == CTSIZE_PTR); p = *(uint8_t **)p; ct = ctype_child(cts, ct); } collect_attrib: /* Skip attributes and collect qualifiers. */ while (ctype_isattrib(ct->info)) { if (ctype_attrib(ct->info) == CTA_QUAL) *qual |= ct->size; ct = ctype_child(cts, ct); } lua_assert(!ctype_isref(ct->info)); /* Interning rejects refs to refs. */ if (tvisint(key)) { idx = (ptrdiff_t)intV(key); goto integer_key; } else if (tvisnum(key)) { /* Numeric key. */ #ifdef _MSC_VER /* Workaround for MSVC bug. */ volatile #endif lua_Number n = numV(key); idx = LJ_64 ? (ptrdiff_t)n : (ptrdiff_t)lj_num2int(n); integer_key: if (ctype_ispointer(ct->info)) { CTSize sz = lj_ctype_size(cts, ctype_cid(ct->info)); /* Element size. */ if (sz == CTSIZE_INVALID) lj_err_caller(cts->L, LJ_ERR_FFI_INVSIZE); if (ctype_isptr(ct->info)) { p = (uint8_t *)cdata_getptr(p, ct->size); } else if ((ct->info & (CTF_VECTOR|CTF_COMPLEX))) { if ((ct->info & CTF_COMPLEX)) idx &= 1; *qual |= CTF_CONST; /* Valarray elements are constant. */ } *pp = p + idx*(int32_t)sz; return ct; } } else if (tviscdata(key)) { /* Integer cdata key. */ GCcdata *cdk = cdataV(key); CType *ctk = ctype_raw(cts, cdk->ctypeid); if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk); if (ctype_isinteger(ctk->info)) { lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ctk, (uint8_t *)&idx, cdataptr(cdk), 0); goto integer_key; } } else if (tvisstr(key)) { /* String key. */ GCstr *name = strV(key); if (ctype_isstruct(ct->info)) { CTSize ofs; CType *fct = lj_ctype_getfieldq(cts, ct, name, &ofs, qual); if (fct) { *pp = p + ofs; return fct; } } else if (ctype_iscomplex(ct->info)) { if (name->len == 2) { *qual |= CTF_CONST; /* Complex fields are constant. */ if (strdata(name)[0] == 'r' && strdata(name)[1] == 'e') { *pp = p; return ct; } else if (strdata(name)[0] == 'i' && strdata(name)[1] == 'm') { *pp = p + (ct->size >> 1); return ct; } } } else if (cd->ctypeid == CTID_CTYPEID) {