Exemplo n.º 1
0
/* 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;
}
Exemplo n.º 2
0
/* 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;
}
Exemplo n.º 3
0
/* 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_child(cts, ct), rcl, fofs);
  }
  return ((rcl[0]|rcl[1]) & CCALL_RCL_MEM);  /* Memory class? */
}
Exemplo n.º 4
0
/* 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) {
Exemplo n.º 5
0
/* 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 || dsize == 4);
  lua_assert(!ctype_isbool(sinfo) || ssize == 1 || ssize == 4);
  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):
    /* Source operand is already normalized. */
    if (dsize == 1) *dp = *sp; else *(int *)dp = *sp;
    break;
  case CCX(B, I): {
    MSize i;
    uint8_t b = 0;
    for (i = 0; i < ssize; i++) b |= sp[i];
    b = (b != 0);
    if (dsize == 1) *dp = b; else *(int *)dp = b;
    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. */
    if (dsize == 1) *dp = b; else *(int *)dp = b;
    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;
      else
	*(uint64_t *)dp = lj_num2u64(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;
    /* The signed conversion is cheaper. x64 really has 47 bit pointers. */
    dinfo = CTINFO(CT_NUM, (LJ_64 && dsize == 8) ? 0 : CTF_UNSIGNED);
    goto conv_I_F;

  case CCX(P, P):
    if (!lj_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 (!lj_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) || dsize != ssize ||
	d->size == CTSIZE_INVALID || !lj_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);
  }
}