2
0
Эх сурвалжийг харах

FFI: Add ffi.load() and ffi.C default namespace.

Mike Pall 14 жил өмнө
parent
commit
ddf6596333
11 өөрчлөгдсөн 435 нэмэгдсэн , 15 устгасан
  1. 1 1
      src/Makefile
  2. 14 10
      src/Makefile.dep
  3. 86 2
      src/lib_ffi.c
  4. 2 1
      src/lj_cdata.c
  5. 4 1
      src/lj_cdata.h
  6. 294 0
      src/lj_clib.c
  7. 26 0
      src/lj_clib.h
  8. 1 0
      src/lj_ctype.h
  9. 1 0
      src/lj_errmsg.h
  10. 1 0
      src/lj_obj.h
  11. 5 0
      src/ljamalg.c

+ 1 - 1
src/Makefile

@@ -328,7 +328,7 @@ LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o \
 	  lj_opt_dce.o lj_opt_loop.o \
 	  lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \
 	  lj_asm.o lj_trace.o lj_gdbjit.o \
-	  lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_cparse.o \
+	  lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_clib.o lj_cparse.o \
 	  lj_lib.o lj_alloc.o lib_aux.o \
 	  $(LJLIB_O) lib_init.o
 

+ 14 - 10
src/Makefile.dep

@@ -22,7 +22,8 @@ lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
  lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h
 lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
  lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cparse.h \
- lj_cdata.h lj_cconv.h lj_ccall.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
+ lj_cdata.h lj_cconv.h lj_ccall.h lj_clib.h lj_ff.h lj_ffdef.h lj_lib.h \
+ lj_libdef.h
 lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
 lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
  lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \
@@ -63,6 +64,9 @@ lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.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_clib.o: lj_clib.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_err.h lj_errmsg.h lj_tab.h lj_str.h lj_udata.h lj_ctype.h lj_cconv.h \
+ lj_cdata.h lj_clib.h
 lj_cparse.o: lj_cparse.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_cparse.h lj_frame.h \
  lj_bc.h lj_vm.h lj_char.h
@@ -156,13 +160,13 @@ ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \
  lj_func.c lj_udata.c lj_meta.c lj_state.c lj_lex.h lj_alloc.h \
  lj_dispatch.c lj_ff.h lj_ffdef.h luajit.h lj_vmevent.c lj_vmevent.h \
  lj_api.c lj_parse.h lj_lex.c lualib.h lj_parse.c lj_ctype.c lj_cdata.c \
- lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_cparse.c lj_cparse.h \
- lj_lib.c lj_lib.h lj_ir.c lj_iropt.h lj_opt_mem.c lj_opt_fold.c \
- lj_folddef.h lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c lj_snap.h \
- lj_mcode.c lj_mcode.h lj_snap.c lj_target.h lj_target_*.h lj_record.c \
- lj_record.h lj_ffrecord.h lj_crecord.c lj_crecord.h lj_ffrecord.c \
- lj_recdef.h lj_asm.c lj_asm.h lj_trace.c lj_gdbjit.h lj_gdbjit.c \
- lj_alloc.c lib_aux.c lib_base.c lj_libdef.h lib_math.c lib_string.c \
- lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c \
- lib_jit.c lib_ffi.c lib_init.c
+ lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_clib.c lj_clib.h \
+ lj_cparse.c lj_cparse.h lj_lib.c lj_lib.h lj_ir.c lj_iropt.h \
+ lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c \
+ lj_opt_loop.c lj_snap.h lj_mcode.c lj_mcode.h lj_snap.c lj_target.h \
+ lj_target_*.h lj_record.c lj_record.h lj_ffrecord.h lj_crecord.c \
+ lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h lj_trace.c \
+ lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c lib_base.c lj_libdef.h \
+ lib_math.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c \
+ lib_debug.c lib_bit.c lib_jit.c lib_ffi.c lib_init.c
 luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h

+ 86 - 2
src/lib_ffi.c

@@ -22,6 +22,7 @@
 #include "lj_cdata.h"
 #include "lj_cconv.h"
 #include "lj_ccall.h"
+#include "lj_clib.h"
 #include "lj_ff.h"
 #include "lj_lib.h"
 
@@ -357,6 +358,77 @@ checkgc:
 
 #include "lj_libdef.h"
 
+/* -- C library metamethods ----------------------------------------------- */
+
+#define LJLIB_MODULE_ffi_clib
+
+/* Index C library by a name. */
+static TValue *ffi_clib_index(lua_State *L)
+{
+  TValue *o = L->base;
+  CLibrary *cl;
+  if (!(o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB))
+    lj_err_argt(L, 1, LUA_TUSERDATA);
+  cl = (CLibrary *)uddata(udataV(o));
+  if (!(o+1 < L->top && tvisstr(o+1)))
+    lj_err_argt(L, 2, LUA_TSTRING);
+  return lj_clib_index(L, cl, strV(o+1));
+}
+
+LJLIB_CF(ffi_clib___index)
+{
+  TValue *tv = ffi_clib_index(L);
+  if (tviscdata(tv)) {
+    CTState *cts = ctype_cts(L);
+    GCcdata *cd = cdataV(tv);
+    CType *s = ctype_get(cts, cd->typeid);
+    if (ctype_isextern(s->info)) {
+      CTypeID sid = ctype_cid(s->info);
+      void *sp = *(void **)cdataptr(cd);
+      if (lj_cconv_tv_ct(cts, ctype_raw(cts, sid), sid, L->top-1, sp))
+	lj_gc_check(L);
+      return 1;
+    }
+  }
+  copyTV(L, L->top-1, tv);
+  return 1;
+}
+
+LJLIB_CF(ffi_clib___newindex)
+{
+  TValue *tv = ffi_clib_index(L);
+  TValue *o = L->base+2;
+  if (o < L->top && tviscdata(tv)) {
+    CTState *cts = ctype_cts(L);
+    GCcdata *cd = cdataV(tv);
+    CType *d = ctype_get(cts, cd->typeid);
+    if (ctype_isextern(d->info)) {
+      CTInfo qual = 0;
+      for (;;) {  /* Skip attributes and collect qualifiers. */
+	d = ctype_child(cts, d);
+	if (!ctype_isattrib(d->info)) break;
+	if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
+      }
+      if (!((d->info|qual) & CTF_CONST)) {
+	lj_cconv_ct_tv(cts, d, *(void **)cdataptr(cd), o, 0);
+	return 0;
+      }
+    }
+  }
+  lj_err_caller(L, LJ_ERR_FFI_WRCONST);
+  return 0;  /* unreachable */
+}
+
+LJLIB_CF(ffi_clib___gc)
+{
+  TValue *o = L->base;
+  if (o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB)
+    lj_clib_unload((CLibrary *)uddata(udataV(o)));
+  return 0;
+}
+
+#include "lj_libdef.h"
+
 /* -- FFI library functions ----------------------------------------------- */
 
 #define LJLIB_MODULE_ffi
@@ -567,6 +639,17 @@ LJLIB_CF(ffi_abi)
 
 #undef H_
 
+LJLIB_PUSH(top-5) LJLIB_SET(!)  /* Store clib metatable in func environment. */
+
+LJLIB_CF(ffi_load)
+{
+  GCstr *name = lj_lib_checkstr(L, 1);
+  int global = (L->base+1 < L->top && tvistruecond(L->base+1));
+  lj_clib_load(L, tabref(curr_func(L)->c.env), name, global);
+  return 1;
+}
+
+LJLIB_PUSH(top-4) LJLIB_SET(C)
 LJLIB_PUSH(top-3) LJLIB_SET(os)
 LJLIB_PUSH(top-2) LJLIB_SET(arch)
 
@@ -579,8 +662,9 @@ LUALIB_API int luaopen_ffi(lua_State *L)
   lj_ctype_init(L);
   LJ_LIB_REG_(L, NULL, ffi_meta);
   /* NOBARRIER: basemt is a GC root. */
-  L->top--;
-  setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top)));
+  setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
+  LJ_LIB_REG_(L, NULL, ffi_clib);
+  lj_clib_default(L, tabV(L->top-1));  /* Create ffi.C default namespace. */
   lua_pushliteral(L, LJ_OS_NAME);
   lua_pushliteral(L, LJ_ARCH_NAME);
   LJ_LIB_REG_(L, NULL, ffi);  /* Note: no global "ffi" created! */

+ 2 - 1
src/lj_cdata.c

@@ -55,7 +55,8 @@ 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));
+    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));

+ 4 - 1
src/lj_cdata.h

@@ -38,7 +38,10 @@ static LJ_AINLINE void cdata_setptr(void *p, CTSize sz, const void *v)
 static LJ_AINLINE GCcdata *lj_cdata_new(CTState *cts, CTypeID id, CTSize sz)
 {
   GCcdata *cd;
-  lua_assert(lj_ctype_size(cts, id) == sz);
+#ifdef LUA_USE_ASSERT
+  CType *ct = ctype_raw(cts, id);
+  lua_assert((ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR) == sz);
+#endif
   cd = (GCcdata *)lj_mem_newgco(cts->L, sizeof(GCcdata) + sz);
   cd->gct = ~LJ_TCDATA;
   cd->typeid = ctype_check(cts, id);

+ 294 - 0
src/lj_clib.c

@@ -0,0 +1,294 @@
+/*
+** FFI C library loader.
+** Copyright (C) 2005-2011 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_tab.h"
+#include "lj_str.h"
+#include "lj_udata.h"
+#include "lj_ctype.h"
+#include "lj_cconv.h"
+#include "lj_cdata.h"
+#include "lj_clib.h"
+
+/* -- OS-specific functions ----------------------------------------------- */
+
+#if LJ_TARGET_DLOPEN
+
+#include <dlfcn.h>
+
+#if defined(RTLD_DEFAULT)
+#define CLIB_DEFHANDLE	RTLD_DEFAULT
+#elif LJ_TARGET_OSX || LJ_TARGET_BSD
+#define CLIB_DEFHANDLE	((void *)-2)
+#else
+#define CLIB_DEFHANDLE	NULL
+#endif
+
+LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L)
+{
+  lj_err_callermsg(L, dlerror());
+}
+
+#if LJ_TARGET_OSX
+#define CLIB_SOEXT	"%s.dylib"
+#else
+#define CLIB_SOEXT	"%s.so"
+#endif
+
+static const char *clib_extname(lua_State *L, GCstr *name)
+{
+  const char *s = strdata(name);
+  if (!strchr(s, '/')) {
+    if (!strchr(s, '.')) {
+      s = lj_str_pushf(L, CLIB_SOEXT, s);
+      L->top--;
+    }
+    if (!(s[0] == 'l' && s[1] == 'i' && s[2] == 'b')) {
+      s = lj_str_pushf(L, "lib%s", s);
+      L->top--;
+    }
+  }
+  return s;
+}
+
+static void *clib_loadlib(lua_State *L, GCstr *name, int global)
+{
+  void *h = dlopen(clib_extname(L, name),
+		   RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
+  if (!h) clib_error(L);
+  return h;
+}
+
+static void clib_unloadlib(CLibrary *cl)
+{
+  if (!cl->handle && cl->handle != CLIB_DEFHANDLE)
+    dlclose(cl->handle);
+}
+
+static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name)
+{
+  void *p = dlsym(cl->handle, strdata(name));
+  if (!p) clib_error(L);
+  return p;
+}
+
+#elif LJ_TARGET_WINDOWS
+
+#define WIN32_LEAN_AND_MEAN
+#ifndef WINVER
+#define WINVER 0x0500
+#endif
+#include <windows.h>
+
+#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
+#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS	4
+BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
+#endif
+
+#define CLIB_DEFHANDLE	((void *)-1)
+
+/* Default libraries. */
+enum {
+  CLIB_HANDLE_EXE,
+  CLIB_HANDLE_DLL,
+  CLIB_HANDLE_CRT,
+  CLIB_HANDLE_KERNEL32,
+  CLIB_HANDLE_USER32,
+  CLIB_HANDLE_GDI32,
+  CLIB_HANDLE_MAX
+};
+
+static void *clib_def_handle[CLIB_HANDLE_MAX];
+
+LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
+					    const char *name)
+{
+  DWORD err = GetLastError();
+  char buf[128];
+  if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
+		      NULL, err, 0, buf, sizeof(buf), NULL))
+    buf[0] = '\0';
+  lj_err_callermsg(L, lj_str_pushf(L, fmt, name, buf));
+}
+
+static int clib_needext(const char *s)
+{
+  while (*s) {
+    if (*s == '/' || *s == '\\' || *s == '.') return 0;
+    s++;
+  }
+  return 1;
+}
+
+static const char *clib_extname(lua_State *L, GCstr *name)
+{
+  const char *s = strdata(name);
+  if (clib_needext(s)) {
+    s = lj_str_pushf(L, "%s.dll", s);
+    L->top--;
+  }
+  return s;
+}
+
+static void *clib_loadlib(lua_State *L, GCstr *name, int global)
+{
+  void *h = (void *)LoadLibraryA(clib_extname(L, name));
+  if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", strdata(name));
+  UNUSED(global);
+  return h;
+}
+
+static void clib_unloadlib(CLibrary *cl)
+{
+  if (cl->handle == CLIB_DEFHANDLE) {
+    MSize i;
+    for (i = 0; i < CLIB_HANDLE_MAX; i++)
+      if (clib_def_handle[i])
+	FreeLibrary((HINSTANCE)clib_def_handle[i]);
+  } else if (!cl->handle) {
+    FreeLibrary((HINSTANCE)cl->handle);
+  }
+}
+
+static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name)
+{
+  const char *sym = strdata(name);
+  void *p;
+  if (cl->handle == CLIB_DEFHANDLE) {  /* Search default libraries. */
+    MSize i;
+    for (i = 0; i < CLIB_HANDLE_MAX; i++) {
+      HINSTANCE h = (HINSTANCE)clib_def_handle[i];
+      if (!(void *)h) {  /* Resolve default library handles (once). */
+	switch (i) {
+	case CLIB_HANDLE_EXE: GetModuleHandleExA(0, NULL, &h); break;
+	case CLIB_HANDLE_DLL:
+	  GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+			     (const char *)clib_def_handle, &h);
+	  break;
+	case CLIB_HANDLE_CRT:
+	  GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+			     (const char *)&_fmode, &h);
+	  break;
+	case CLIB_HANDLE_KERNEL32: h = LoadLibraryA("kernel32.dll"); break;
+	case CLIB_HANDLE_USER32: h = LoadLibraryA("user32.dll"); break;
+	case CLIB_HANDLE_GDI32: h = LoadLibraryA("gdi32.dll"); break;
+	}
+	if (!h) continue;
+	clib_def_handle[i] = (void *)h;
+      }
+      p = (void *)GetProcAddress(h, sym);
+      if (p) break;
+    }
+  } else {
+    p = (void *)GetProcAddress((HINSTANCE)cl->handle, sym);
+  }
+  if (!p) clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym);
+  return p;
+}
+
+#else
+
+#define CLIB_DEFHANDLE	NULL
+
+static void *clib_loadlib(lua_State *L, GCstr *name, int global)
+{
+  lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
+  UNUSED(name); UNUSED(global);
+  return NULL;
+}
+
+static void clib_unloadlib(CLibrary *cl)
+{
+  UNUSED(cl);
+}
+
+static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name)
+{
+  lj_err_callermsg(L, "no support for resolving symbols for this OS");
+  UNUSED(cl); UNUSED(name);
+  return NULL;
+}
+
+#endif
+
+/* -- C library indexing -------------------------------------------------- */
+
+/* Namespace for C library indexing. */
+#define CLNS_INDEX \
+  ((1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL))
+
+/* 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) && ctt->size == 4)
+	setnumV(tv, (lua_Number)(uint32_t)ct->size);
+      else
+	setnumV(tv, (lua_Number)(int32_t)ct->size);
+    } else {
+      void *p = clib_getsym(L, cl, name);
+      GCcdata *cd;
+      lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info));
+      cd = lj_cdata_new(cts, id, CTSIZE_PTR);
+      *(void **)cdataptr(cd) = p;
+      setcdataV(L, tv, cd);
+    }
+  }
+  return tv;
+}
+
+/* -- C library management ------------------------------------------------ */
+
+/* Create a new CLibrary object and push it on the stack. */
+static CLibrary *clib_new(lua_State *L, GCtab *mt)
+{
+  GCtab *t = lj_tab_new(L, 0, 0);
+  GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t);
+  CLibrary *cl = (CLibrary *)uddata(ud);
+  cl->cache = t;
+  ud->udtype = UDTYPE_FFI_CLIB;
+  /* NOBARRIER: The GCudata is new (marked white). */
+  setgcref(ud->metatable, obj2gco(mt));
+  setudataV(L, L->top++, ud);
+  return cl;
+}
+
+/* Load a C library. */
+void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
+{
+  void *handle = clib_loadlib(L, name, global);
+  CLibrary *cl = clib_new(L, mt);
+  cl->handle = handle;
+}
+
+/* Unload a C library. */
+void lj_clib_unload(CLibrary *cl)
+{
+  clib_unloadlib(cl);
+  cl->handle = NULL;
+}
+
+/* Create the default C library object. */
+void lj_clib_default(lua_State *L, GCtab *mt)
+{
+  CLibrary *cl = clib_new(L, mt);
+  cl->handle = CLIB_DEFHANDLE;
+}
+
+#endif

+ 26 - 0
src/lj_clib.h

@@ -0,0 +1,26 @@
+/*
+** FFI C library loader.
+** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#ifndef _LJ_CLIB_H
+#define _LJ_CLIB_H
+
+#include "lj_obj.h"
+
+#if LJ_HASFFI
+
+/* C library namespace. */
+typedef struct CLibrary {
+  void *handle;		/* Opaque handle for dynamic library loader. */
+  GCtab *cache;		/* Cache for resolved symbols. Anchored in ud->env. */
+} CLibrary;
+
+LJ_FUNC TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name);
+LJ_FUNC void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global);
+LJ_FUNC void lj_clib_unload(CLibrary *cl);
+LJ_FUNC void lj_clib_default(lua_State *L, GCtab *mt);
+
+#endif
+
+#endif

+ 1 - 0
src/lj_ctype.h

@@ -187,6 +187,7 @@ typedef struct CTState {
 #define ctype_isfield(info)	(ctype_type((info)) == CT_FIELD)
 #define ctype_isbitfield(info)	(ctype_type((info)) == CT_BITFIELD)
 #define ctype_isconstval(info)	(ctype_type((info)) == CT_CONSTVAL)
+#define ctype_isextern(info)	(ctype_type((info)) == CT_EXTERN)
 #define ctype_hassize(info)	(ctype_type((info)) <= CT_HASSIZE)
 
 /* Combined type and flag checks. */

+ 1 - 0
src/lj_errmsg.h

@@ -153,6 +153,7 @@ ERRDEF(FFI_NUMARG,	"wrong number of arguments for function call")
 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_NODECL,	"missing declaration for symbol " LUA_QS)
 ERRDEF(FFI_NYIPACKBIT,	"NYI: packed bit fields")
 ERRDEF(FFI_NYICALL,	"NYI: cannot call this C function (yet)")
 #endif

+ 1 - 0
src/lj_obj.h

@@ -247,6 +247,7 @@ typedef struct GCudata {
 enum {
   UDTYPE_USERDATA,	/* Regular userdata. */
   UDTYPE_IO_FILE,	/* I/O library FILE. */
+  UDTYPE_FFI_CLIB,	/* FFI C library namespace. */
   UDTYPE__MAX
 };
 

+ 5 - 0
src/ljamalg.c

@@ -21,6 +21,10 @@
 #define _GNU_SOURCE
 #endif
 
+#ifndef WINVER
+#define WINVER 0x0500
+#endif
+
 #include "lua.h"
 #include "lauxlib.h"
 
@@ -44,6 +48,7 @@
 #include "lj_cdata.c"
 #include "lj_cconv.c"
 #include "lj_ccall.c"
+#include "lj_clib.c"
 #include "lj_cparse.c"
 #include "lj_lib.c"
 #include "lj_ir.c"