texlive[43177] Build/source/texk/web2c: luatexdir: sync with the

commits+kakuto at tug.org commits+kakuto at tug.org
Thu Feb 9 23:44:03 CET 2017


Revision: 43177
          http://tug.org/svn/texlive?view=revision&revision=43177
Author:   kakuto
Date:     2017-02-09 23:44:03 +0100 (Thu, 09 Feb 2017)
Log Message:
-----------
luatexdir: sync with the upstream

Modified Paths:
--------------
    trunk/Build/source/texk/web2c/ChangeLog
    trunk/Build/source/texk/web2c/Makefile.am
    trunk/Build/source/texk/web2c/Makefile.in
    trunk/Build/source/texk/web2c/luatexdir/ChangeLog
    trunk/Build/source/texk/web2c/luatexdir/am/luamisc.am
    trunk/Build/source/texk/web2c/luatexdir/am/luatex.am
    trunk/Build/source/texk/web2c/luatexdir/font/luafont.w
    trunk/Build/source/texk/web2c/luatexdir/image/writejpg.w
    trunk/Build/source/texk/web2c/luatexdir/lua/lnodelib.c
    trunk/Build/source/texk/web2c/luatexdir/lua/luainit.w
    trunk/Build/source/texk/web2c/luatexdir/lua/luajitstuff.w
    trunk/Build/source/texk/web2c/luatexdir/lua/luastuff.w
    trunk/Build/source/texk/web2c/luatexdir/lua/luatex-api.h
    trunk/Build/source/texk/web2c/luatexdir/tex/commands.w
    trunk/Build/source/texk/web2c/luatexdir/tex/dumpdata.w
    trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.h
    trunk/Build/source/texk/web2c/luatexdir/tex/maincontrol.w
    trunk/Build/source/texk/web2c/luatexdir/tex/texmath.w
    trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.w

Added Paths:
-----------
    trunk/Build/source/texk/web2c/luatexdir/am/luaffi.am
    trunk/Build/source/texk/web2c/luatexdir/luaffi/
    trunk/Build/source/texk/web2c/luatexdir/luaffi/CONTRIBUTING.md
    trunk/Build/source/texk/web2c/luatexdir/luaffi/LICENSE
    trunk/Build/source/texk/web2c/luatexdir/luaffi/Makefile.orig
    trunk/Build/source/texk/web2c/luatexdir/luaffi/PATENTS
    trunk/Build/source/texk/web2c/luatexdir/luaffi/README
    trunk/Build/source/texk/web2c/luatexdir/luaffi/README.md
    trunk/Build/source/texk/web2c/luatexdir/luaffi/call.c
    trunk/Build/source/texk/web2c/luatexdir/luaffi/call_arm.dasc
    trunk/Build/source/texk/web2c/luatexdir/luaffi/call_arm.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x64.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x64win.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x86.dasc
    trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x86.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/ctype.c
    trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/
    trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.lua
    trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.lua
    trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_proto.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x64.lua
    trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.lua
    trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dynasm.lua
    trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.c
    trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.c.orig
    trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.h.orig
    trunk/Build/source/texk/web2c/luatexdir/luaffi/generate_call_h.bat
    trunk/Build/source/texk/web2c/luatexdir/luaffi/luaffi-scm-1.rockspec
    trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/
    trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/inttypes.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/stdbool.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/stdint.h
    trunk/Build/source/texk/web2c/luatexdir/luaffi/msvcbuild.bat
    trunk/Build/source/texk/web2c/luatexdir/luaffi/parser.c
    trunk/Build/source/texk/web2c/luatexdir/luaffi/test.c
    trunk/Build/source/texk/web2c/luatexdir/luaffi/test.lua

Modified: trunk/Build/source/texk/web2c/ChangeLog
===================================================================
--- trunk/Build/source/texk/web2c/ChangeLog	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/ChangeLog	2017-02-09 22:44:03 UTC (rev 43177)
@@ -1,3 +1,7 @@
+2017-02-09  Akira Kakuto  <kakuto at fuk.kindai.ac.jp>
+
+	* Makefile.am: Sync with the LuaTeX upstream.
+
 2017-01-28  Karl Berry  <karl at freefriends.org>
 
 	* tex.ch (texarray),

Modified: trunk/Build/source/texk/web2c/Makefile.am
===================================================================
--- trunk/Build/source/texk/web2c/Makefile.am	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/Makefile.am	2017-02-09 22:44:03 UTC (rev 43177)
@@ -227,6 +227,7 @@
 include $(srcdir)/luatexdir/am/libunilib.am
 include $(srcdir)/luatexdir/am/luafontforge.am
 include $(srcdir)/luatexdir/am/libluatex.am
+include $(srcdir)/luatexdir/am/luaffi.am
 include $(srcdir)/luatexdir/am/luatex.am
 
 ## XeTeX

Modified: trunk/Build/source/texk/web2c/Makefile.in
===================================================================
--- trunk/Build/source/texk/web2c/Makefile.in	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/Makefile.in	2017-02-09 22:44:03 UTC (rev 43177)
@@ -385,8 +385,9 @@
  configure.lineno config.status.lineno
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/w2c/c-auto.h ff-config.h
-CONFIG_CLEAN_FILES = web2c-sh tangle-sh ctangleboot-sh silent-sh \
-	synctexdir/synctex.pc callexe.c
+CONFIG_CLEAN_FILES = omegafonts/Makefile otps/Makefile \
+	otps/win32/Makefile window/Makefile web2c-sh tangle-sh \
+	ctangleboot-sh silent-sh synctexdir/synctex.pc callexe.c
 CONFIG_CLEAN_VPATH_FILES =
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
@@ -475,9 +476,17 @@
 libkanji_a_LIBADD =
 am_libkanji_a_OBJECTS = ptexdir/libkanji_a-kanji.$(OBJEXT)
 libkanji_a_OBJECTS = $(am_libkanji_a_OBJECTS)
+libluaffi_a_AR = $(AR) $(ARFLAGS)
+libluaffi_a_LIBADD =
+am__objects_1 = luatexdir/luaffi/libluaffi_a-call.$(OBJEXT) \
+	luatexdir/luaffi/libluaffi_a-ctype.$(OBJEXT) \
+	luatexdir/luaffi/libluaffi_a-ffi.$(OBJEXT) \
+	luatexdir/luaffi/libluaffi_a-parser.$(OBJEXT)
+nodist_libluaffi_a_OBJECTS = $(am__objects_1)
+libluaffi_a_OBJECTS = $(nodist_libluaffi_a_OBJECTS)
 libluajitmisc_a_AR = $(AR) $(ARFLAGS)
 libluajitmisc_a_LIBADD =
-am__objects_1 =  \
+am__objects_2 =  \
 	luatexdir/luafilesystem/src/libluajitmisc_a-lfs.$(OBJEXT) \
 	luatexdir/luamd5/libluajitmisc_a-md5.$(OBJEXT) \
 	luatexdir/luamd5/libluajitmisc_a-md5lib.$(OBJEXT) \
@@ -492,11 +501,11 @@
 	luatexdir/luazlib/libluajitmisc_a-lgzip.$(OBJEXT) \
 	luatexdir/luazlib/libluajitmisc_a-lzlib.$(OBJEXT) \
 	luatexdir/slnunicode/libluajitmisc_a-slnunico.$(OBJEXT)
-nodist_libluajitmisc_a_OBJECTS = $(am__objects_1)
+nodist_libluajitmisc_a_OBJECTS = $(am__objects_2)
 libluajitmisc_a_OBJECTS = $(nodist_libluajitmisc_a_OBJECTS)
 libluajitsocket_a_AR = $(AR) $(ARFLAGS)
 libluajitsocket_a_LIBADD =
-am__objects_2 =  \
+am__objects_3 =  \
 	luatexdir/luasocket/src/libluajitsocket_a-auxiliar.$(OBJEXT) \
 	luatexdir/luasocket/src/libluajitsocket_a-buffer.$(OBJEXT) \
 	luatexdir/luasocket/src/libluajitsocket_a-except.$(OBJEXT) \
@@ -512,13 +521,13 @@
 	luatexdir/luasocket/src/libluajitsocket_a-tcp.$(OBJEXT) \
 	luatexdir/luasocket/src/libluajitsocket_a-timeout.$(OBJEXT) \
 	luatexdir/luasocket/src/libluajitsocket_a-udp.$(OBJEXT)
-nodist_libluajitsocket_a_OBJECTS = $(am__objects_2)
+nodist_libluajitsocket_a_OBJECTS = $(am__objects_3)
 libluajitsocket_a_OBJECTS = $(nodist_libluajitsocket_a_OBJECTS)
 libluajittex_a_AR = $(AR) $(ARFLAGS)
 libluajittex_a_LIBADD =
 dist_libluajittex_a_OBJECTS =  \
 	luatexdir/lua/libluajittex_a-lstrlibextjit.$(OBJEXT)
-am__objects_3 = luatexdir/luafontloader/src/libluajittex_a-ffdummies.$(OBJEXT) \
+am__objects_4 = luatexdir/luafontloader/src/libluajittex_a-ffdummies.$(OBJEXT) \
 	luatexdir/luafontloader/src/libluajittex_a-luafflib.$(OBJEXT) \
 	luatexdir/lua/libluajittex_a-lcallbacklib.$(OBJEXT) \
 	luatexdir/lua/libluajittex_a-lfontlib.$(OBJEXT) \
@@ -539,7 +548,7 @@
 	luatexdir/lua/libluajittex_a-lnewtokenlib.$(OBJEXT) \
 	luatexdir/utils/libluajittex_a-avl.$(OBJEXT) \
 	synctexdir/libluajittex_a-synctex.$(OBJEXT)
-am__objects_4 = libluajittex_a-dvigen.$(OBJEXT) \
+am__objects_5 = libluajittex_a-dvigen.$(OBJEXT) \
 	libluajittex_a-dofont.$(OBJEXT) \
 	libluajittex_a-luafont.$(OBJEXT) \
 	libluajittex_a-mapfile.$(OBJEXT) libluajittex_a-pkin.$(OBJEXT) \
@@ -630,13 +639,13 @@
 	libluajittex_a-utils.$(OBJEXT) \
 	libluajittex_a-unistring.$(OBJEXT)
 nodist_libluajittex_a_OBJECTS = libluajittex_a-luajitstuff.$(OBJEXT) \
-	libluajittex_a-texluajitc.$(OBJEXT) $(am__objects_3) \
-	$(am__objects_4)
+	libluajittex_a-texluajitc.$(OBJEXT) $(am__objects_4) \
+	$(am__objects_5)
 libluajittex_a_OBJECTS = $(dist_libluajittex_a_OBJECTS) \
 	$(nodist_libluajittex_a_OBJECTS)
 libluamisc_a_AR = $(AR) $(ARFLAGS)
 libluamisc_a_LIBADD =
-am__objects_5 =  \
+am__objects_6 =  \
 	luatexdir/luafilesystem/src/libluamisc_a-lfs.$(OBJEXT) \
 	luatexdir/luamd5/libluamisc_a-md5.$(OBJEXT) \
 	luatexdir/luamd5/libluamisc_a-md5lib.$(OBJEXT) \
@@ -651,11 +660,11 @@
 	luatexdir/luazlib/libluamisc_a-lgzip.$(OBJEXT) \
 	luatexdir/luazlib/libluamisc_a-lzlib.$(OBJEXT) \
 	luatexdir/slnunicode/libluamisc_a-slnunico.$(OBJEXT)
-nodist_libluamisc_a_OBJECTS = $(am__objects_5)
+nodist_libluamisc_a_OBJECTS = $(am__objects_6)
 libluamisc_a_OBJECTS = $(nodist_libluamisc_a_OBJECTS)
 libluasocket_a_AR = $(AR) $(ARFLAGS)
 libluasocket_a_LIBADD =
-am__objects_6 =  \
+am__objects_7 =  \
 	luatexdir/luasocket/src/libluasocket_a-auxiliar.$(OBJEXT) \
 	luatexdir/luasocket/src/libluasocket_a-buffer.$(OBJEXT) \
 	luatexdir/luasocket/src/libluasocket_a-except.$(OBJEXT) \
@@ -671,13 +680,13 @@
 	luatexdir/luasocket/src/libluasocket_a-tcp.$(OBJEXT) \
 	luatexdir/luasocket/src/libluasocket_a-timeout.$(OBJEXT) \
 	luatexdir/luasocket/src/libluasocket_a-udp.$(OBJEXT)
-nodist_libluasocket_a_OBJECTS = $(am__objects_6)
+nodist_libluasocket_a_OBJECTS = $(am__objects_7)
 libluasocket_a_OBJECTS = $(nodist_libluasocket_a_OBJECTS)
 libluatex_a_AR = $(AR) $(ARFLAGS)
 libluatex_a_LIBADD =
 dist_libluatex_a_OBJECTS =  \
 	luatexdir/lua/libluatex_a-lstrlibext.$(OBJEXT)
-am__objects_7 =  \
+am__objects_8 =  \
 	luatexdir/luafontloader/src/libluatex_a-ffdummies.$(OBJEXT) \
 	luatexdir/luafontloader/src/libluatex_a-luafflib.$(OBJEXT) \
 	luatexdir/lua/libluatex_a-lcallbacklib.$(OBJEXT) \
@@ -699,7 +708,7 @@
 	luatexdir/lua/libluatex_a-lnewtokenlib.$(OBJEXT) \
 	luatexdir/utils/libluatex_a-avl.$(OBJEXT) \
 	synctexdir/libluatex_a-synctex.$(OBJEXT)
-am__objects_8 = libluatex_a-dvigen.$(OBJEXT) \
+am__objects_9 = libluatex_a-dvigen.$(OBJEXT) \
 	libluatex_a-dofont.$(OBJEXT) libluatex_a-luafont.$(OBJEXT) \
 	libluatex_a-mapfile.$(OBJEXT) libluatex_a-pkin.$(OBJEXT) \
 	libluatex_a-sfnt.$(OBJEXT) libluatex_a-subfont.$(OBJEXT) \
@@ -759,8 +768,8 @@
 	libluatex_a-managed-sa.$(OBJEXT) libluatex_a-utils.$(OBJEXT) \
 	libluatex_a-unistring.$(OBJEXT)
 nodist_libluatex_a_OBJECTS = libluatex_a-luastuff.$(OBJEXT) \
-	libluatex_a-texluac.$(OBJEXT) $(am__objects_7) \
-	$(am__objects_8)
+	libluatex_a-texluac.$(OBJEXT) $(am__objects_8) \
+	$(am__objects_9)
 libluatex_a_OBJECTS = $(dist_libluatex_a_OBJECTS) \
 	$(nodist_libluatex_a_OBJECTS)
 libmd5_a_AR = $(AR) $(ARFLAGS)
@@ -769,16 +778,16 @@
 libmd5_a_OBJECTS = $(am_libmd5_a_OBJECTS)
 libmf_a_AR = $(AR) $(ARFLAGS)
 libmf_a_LIBADD =
-am__objects_9 = mfini.$(OBJEXT) mf0.$(OBJEXT)
-nodist_libmf_a_OBJECTS = $(am__objects_9) mf-pool.$(OBJEXT)
+am__objects_10 = mfini.$(OBJEXT) mf0.$(OBJEXT)
+nodist_libmf_a_OBJECTS = $(am__objects_10) mf-pool.$(OBJEXT)
 libmf_a_OBJECTS = $(nodist_libmf_a_OBJECTS)
 libmflua_a_AR = $(AR) $(ARFLAGS)
 libmflua_a_LIBADD =
 dist_libmflua_a_OBJECTS = luatexdir/lua/libmflua_a-lkpselib.$(OBJEXT) \
 	mfluadir/libmflua_a-mfluac.$(OBJEXT)
-am__objects_10 = libmflua_a-mfluaini.$(OBJEXT) \
+am__objects_11 = libmflua_a-mfluaini.$(OBJEXT) \
 	libmflua_a-mflua0.$(OBJEXT)
-nodist_libmflua_a_OBJECTS = $(am__objects_10) \
+nodist_libmflua_a_OBJECTS = $(am__objects_11) \
 	libmflua_a-mflua-pool.$(OBJEXT)
 libmflua_a_OBJECTS = $(dist_libmflua_a_OBJECTS) \
 	$(nodist_libmflua_a_OBJECTS)
@@ -787,27 +796,27 @@
 dist_libmfluajit_a_OBJECTS =  \
 	luatexdir/lua/libmfluajit_a-lkpselib.$(OBJEXT) \
 	mfluadir/libmfluajit_a-mfluac.$(OBJEXT)
-am__objects_11 = libmfluajit_a-mfluajitini.$(OBJEXT) \
+am__objects_12 = libmfluajit_a-mfluajitini.$(OBJEXT) \
 	libmfluajit_a-mfluajit0.$(OBJEXT)
-nodist_libmfluajit_a_OBJECTS = $(am__objects_11) \
+nodist_libmfluajit_a_OBJECTS = $(am__objects_12) \
 	libmfluajit_a-mfluajit-pool.$(OBJEXT)
 libmfluajit_a_OBJECTS = $(dist_libmfluajit_a_OBJECTS) \
 	$(nodist_libmfluajit_a_OBJECTS)
 libmplib_a_AR = $(AR) $(ARFLAGS)
 libmplib_a_LIBADD =
-am__objects_12 = libmplib_a-mp.$(OBJEXT)
-am__objects_13 = libmplib_a-mpmath.$(OBJEXT)
-am__objects_14 = libmplib_a-mpmathbinary.$(OBJEXT)
-am__objects_15 = libmplib_a-mpmathdecimal.$(OBJEXT)
-am__objects_16 = libmplib_a-mpmathdouble.$(OBJEXT)
-am__objects_17 = libmplib_a-mpstrings.$(OBJEXT)
-am__objects_18 = libmplib_a-pngout.$(OBJEXT)
-am__objects_19 = libmplib_a-psout.$(OBJEXT)
-am__objects_20 = libmplib_a-svgout.$(OBJEXT)
+am__objects_13 = libmplib_a-mp.$(OBJEXT)
+am__objects_14 = libmplib_a-mpmath.$(OBJEXT)
+am__objects_15 = libmplib_a-mpmathbinary.$(OBJEXT)
+am__objects_16 = libmplib_a-mpmathdecimal.$(OBJEXT)
+am__objects_17 = libmplib_a-mpmathdouble.$(OBJEXT)
+am__objects_18 = libmplib_a-mpstrings.$(OBJEXT)
+am__objects_19 = libmplib_a-pngout.$(OBJEXT)
+am__objects_20 = libmplib_a-psout.$(OBJEXT)
+am__objects_21 = libmplib_a-svgout.$(OBJEXT)
 nodist_libmplib_a_OBJECTS = libmplib_a-tfmin.$(OBJEXT) \
-	$(am__objects_12) $(am__objects_13) $(am__objects_14) \
-	$(am__objects_15) $(am__objects_16) $(am__objects_17) \
-	$(am__objects_18) $(am__objects_19) $(am__objects_20)
+	$(am__objects_13) $(am__objects_14) $(am__objects_15) \
+	$(am__objects_16) $(am__objects_17) $(am__objects_18) \
+	$(am__objects_19) $(am__objects_20) $(am__objects_21)
 libmplib_a_OBJECTS = $(nodist_libmplib_a_OBJECTS)
 libmputil_a_AR = $(AR) $(ARFLAGS)
 libmputil_a_LIBADD =
@@ -829,7 +838,7 @@
 	pdftexdir/writepng.c pdftexdir/writet1.c pdftexdir/writet3.c \
 	pdftexdir/writettf.c pdftexdir/writettf.h pdftexdir/writezip.c \
 	pdftexdir/regex/regex.c pdftexdir/regex/regex.h
- at MINGW32_TRUE@am__objects_21 =  \
+ at MINGW32_TRUE@am__objects_22 =  \
 @MINGW32_TRUE@	pdftexdir/regex/libpdftex_a-regex.$(OBJEXT)
 am_libpdftex_a_OBJECTS = pdftexdir/libpdftex_a-avl.$(OBJEXT) \
 	pdftexdir/libpdftex_a-avlstuff.$(OBJEXT) \
@@ -850,13 +859,13 @@
 	pdftexdir/libpdftex_a-writet1.$(OBJEXT) \
 	pdftexdir/libpdftex_a-writet3.$(OBJEXT) \
 	pdftexdir/libpdftex_a-writettf.$(OBJEXT) \
-	pdftexdir/libpdftex_a-writezip.$(OBJEXT) $(am__objects_21)
+	pdftexdir/libpdftex_a-writezip.$(OBJEXT) $(am__objects_22)
 libpdftex_a_OBJECTS = $(am_libpdftex_a_OBJECTS)
 libsynctex_a_AR = $(AR) $(ARFLAGS)
 libsynctex_a_LIBADD =
-am__objects_22 = synctexdir/libsynctex_a-synctex_parser.$(OBJEXT) \
+am__objects_23 = synctexdir/libsynctex_a-synctex_parser.$(OBJEXT) \
 	synctexdir/libsynctex_a-synctex_parser_utils.$(OBJEXT)
-nodist_libsynctex_a_OBJECTS = $(am__objects_22)
+nodist_libsynctex_a_OBJECTS = $(am__objects_23)
 libsynctex_a_OBJECTS = $(nodist_libsynctex_a_OBJECTS)
 libukanji_a_AR = $(AR) $(ARFLAGS)
 libukanji_a_LIBADD =
@@ -897,10 +906,10 @@
 	xetexdir/XeTeXFontInst_Mac.h xetexdir/XeTeXFontMgr_Mac.mm \
 	xetexdir/XeTeXFontMgr_Mac.h xetexdir/XeTeX_mac.c \
 	xetexdir/XeTeXFontMgr_FC.cpp xetexdir/XeTeXFontMgr_FC.h
- at XETEX_MACOSX_TRUE@am__objects_23 = xetexdir/libxetex_a-XeTeXFontInst_Mac.$(OBJEXT) \
+ at XETEX_MACOSX_TRUE@am__objects_24 = xetexdir/libxetex_a-XeTeXFontInst_Mac.$(OBJEXT) \
 @XETEX_MACOSX_TRUE@	xetexdir/libxetex_a-XeTeXFontMgr_Mac.$(OBJEXT) \
 @XETEX_MACOSX_TRUE@	xetexdir/libxetex_a-XeTeX_mac.$(OBJEXT)
- at XETEX_MACOSX_FALSE@am__objects_24 = xetexdir/libxetex_a-XeTeXFontMgr_FC.$(OBJEXT)
+ at XETEX_MACOSX_FALSE@am__objects_25 = xetexdir/libxetex_a-XeTeXFontMgr_FC.$(OBJEXT)
 am_libxetex_a_OBJECTS = xetexdir/libxetex_a-XeTeXFontInst.$(OBJEXT) \
 	xetexdir/libxetex_a-XeTeXFontMgr.$(OBJEXT) \
 	xetexdir/libxetex_a-XeTeXLayoutInterface.$(OBJEXT) \
@@ -914,8 +923,8 @@
 	xetexdir/image/libxetex_a-jpegimage.$(OBJEXT) \
 	xetexdir/image/libxetex_a-mfileio.$(OBJEXT) \
 	xetexdir/image/libxetex_a-numbers.$(OBJEXT) \
-	xetexdir/image/libxetex_a-pngimage.$(OBJEXT) $(am__objects_23) \
-	$(am__objects_24)
+	xetexdir/image/libxetex_a-pngimage.$(OBJEXT) $(am__objects_24) \
+	$(am__objects_25)
 libxetex_a_OBJECTS = $(am_libxetex_a_OBJECTS)
 LTLIBRARIES = $(lib_LTLIBRARIES)
 am__DEPENDENCIES_1 =
@@ -983,8 +992,8 @@
 dist_aleph_OBJECTS = alephdir/aleph-aleph.$(OBJEXT) \
 	alephdir/aleph-alephbis.$(OBJEXT) \
 	alephdir/aleph-alephextra.$(OBJEXT)
-am__objects_25 = aleph-alephini.$(OBJEXT) aleph-aleph0.$(OBJEXT)
-nodist_aleph_OBJECTS = $(am__objects_25) aleph-aleph-pool.$(OBJEXT)
+am__objects_26 = aleph-alephini.$(OBJEXT) aleph-aleph0.$(OBJEXT)
+nodist_aleph_OBJECTS = $(am__objects_26) aleph-aleph-pool.$(OBJEXT)
 aleph_OBJECTS = $(dist_aleph_OBJECTS) $(nodist_aleph_OBJECTS)
 am__DEPENDENCIES_2 = $(proglib) $(am__DEPENDENCIES_1)
 aleph_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
@@ -1043,12 +1052,12 @@
 	eptexdir/eptexextra.h eptexdir/eptex_version.h \
 	synctexdir/synctex.c synctexdir/synctex.h \
 	synctexdir/synctex-common.h synctexdir/synctex-eptex.h
- at EPTEX_SYNCTEX_TRUE@am__objects_26 =  \
+ at EPTEX_SYNCTEX_TRUE@am__objects_27 =  \
 @EPTEX_SYNCTEX_TRUE@	synctexdir/eptex-synctex.$(OBJEXT)
 dist_eptex_OBJECTS = eptexdir/eptex-eptexextra.$(OBJEXT) \
-	$(am__objects_26)
-am__objects_27 = eptex-eptexini.$(OBJEXT) eptex-eptex0.$(OBJEXT)
-nodist_eptex_OBJECTS = $(am__objects_27) eptex-eptex-pool.$(OBJEXT)
+	$(am__objects_27)
+am__objects_28 = eptex-eptexini.$(OBJEXT) eptex-eptex0.$(OBJEXT)
+nodist_eptex_OBJECTS = $(am__objects_28) eptex-eptex-pool.$(OBJEXT)
 eptex_OBJECTS = $(dist_eptex_OBJECTS) $(nodist_eptex_OBJECTS)
 @EPTEX_SYNCTEX_TRUE at am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
 am__dist_etex_SOURCES_DIST = etexdir/etexextra.c etexdir/etexextra.h \
@@ -1055,10 +1064,10 @@
 	etexdir/etex_version.h synctexdir/synctex.c \
 	synctexdir/synctex.h synctexdir/synctex-common.h \
 	synctexdir/synctex-etex.h
- at ETEX_SYNCTEX_TRUE@am__objects_28 = synctexdir/etex-synctex.$(OBJEXT)
-dist_etex_OBJECTS = etexdir/etex-etexextra.$(OBJEXT) $(am__objects_28)
-am__objects_29 = etex-etexini.$(OBJEXT) etex-etex0.$(OBJEXT)
-nodist_etex_OBJECTS = $(am__objects_29) etex-etex-pool.$(OBJEXT)
+ at ETEX_SYNCTEX_TRUE@am__objects_29 = synctexdir/etex-synctex.$(OBJEXT)
+dist_etex_OBJECTS = etexdir/etex-etexextra.$(OBJEXT) $(am__objects_29)
+am__objects_30 = etex-etexini.$(OBJEXT) etex-etex0.$(OBJEXT)
+nodist_etex_OBJECTS = $(am__objects_30) etex-etex-pool.$(OBJEXT)
 etex_OBJECTS = $(dist_etex_OBJECTS) $(nodist_etex_OBJECTS)
 @ETEX_SYNCTEX_TRUE at am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
 etex_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
@@ -1067,12 +1076,12 @@
 	euptexdir/euptexextra.h synctexdir/synctex.c \
 	synctexdir/synctex.h synctexdir/synctex-common.h \
 	synctexdir/synctex-euptex.h
- at EUPTEX_SYNCTEX_TRUE@am__objects_30 =  \
+ at EUPTEX_SYNCTEX_TRUE@am__objects_31 =  \
 @EUPTEX_SYNCTEX_TRUE@	synctexdir/euptex-synctex.$(OBJEXT)
 dist_euptex_OBJECTS = euptexdir/euptex-euptexextra.$(OBJEXT) \
-	$(am__objects_30)
-am__objects_31 = euptex-euptexini.$(OBJEXT) euptex-euptex0.$(OBJEXT)
-nodist_euptex_OBJECTS = $(am__objects_31) euptex-euptex-pool.$(OBJEXT)
+	$(am__objects_31)
+am__objects_32 = euptex-euptexini.$(OBJEXT) euptex-euptex0.$(OBJEXT)
+nodist_euptex_OBJECTS = $(am__objects_32) euptex-euptex-pool.$(OBJEXT)
 euptex_OBJECTS = $(dist_euptex_OBJECTS) $(nodist_euptex_OBJECTS)
 @EUPTEX_SYNCTEX_TRUE at am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1)
 am_gftodvi_OBJECTS =
@@ -1091,9 +1100,9 @@
 nodist_initex_OBJECTS = initex-callexe.$(OBJEXT)
 initex_OBJECTS = $(nodist_initex_OBJECTS)
 initex_DEPENDENCIES =
-am__objects_32 = luatexdir/luajittex-luatex.$(OBJEXT) \
+am__objects_33 = luatexdir/luajittex-luatex.$(OBJEXT) \
 	mplibdir/luajittex-lmplib.$(OBJEXT)
-nodist_luajittex_OBJECTS = $(am__objects_32)
+nodist_luajittex_OBJECTS = $(am__objects_33)
 luajittex_OBJECTS = $(nodist_luajittex_OBJECTS)
 am__DEPENDENCIES_6 = libmplib.a $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@@ -1104,9 +1113,9 @@
 luajittex_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(luajittex_CXXFLAGS) \
 	$(CXXFLAGS) $(luajittex_LDFLAGS) $(LDFLAGS) -o $@
-am__objects_33 = luatexdir/luatex-luatex.$(OBJEXT) \
+am__objects_34 = luatexdir/luatex-luatex.$(OBJEXT) \
 	mplibdir/luatex-lmplib.$(OBJEXT)
-nodist_luatex_OBJECTS = $(am__objects_33)
+nodist_luatex_OBJECTS = $(am__objects_34)
 luatex_OBJECTS = $(nodist_luatex_OBJECTS)
 am__DEPENDENCIES_7 = $(am__DEPENDENCIES_1)
 luatex_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -1133,8 +1142,8 @@
 mflua_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 	$(mflua_LDFLAGS) $(LDFLAGS) -o $@
-am__objects_34 = mfluadir/mflua_nowin-mfluaextra.$(OBJEXT)
-nodist_mflua_nowin_OBJECTS = $(am__objects_34)
+am__objects_35 = mfluadir/mflua_nowin-mfluaextra.$(OBJEXT)
+nodist_mflua_nowin_OBJECTS = $(am__objects_35)
 mflua_nowin_OBJECTS = $(nodist_mflua_nowin_OBJECTS)
 mflua_nowin_DEPENDENCIES = libmflua.a $(am__DEPENDENCIES_2) \
 	$(windowlib) $(am__DEPENDENCIES_7)
@@ -1148,8 +1157,8 @@
 mfluajit_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 	$(mfluajit_LDFLAGS) $(LDFLAGS) -o $@
-am__objects_35 = mfluajitdir/mfluajit_nowin-mfluajitextra.$(OBJEXT)
-nodist_mfluajit_nowin_OBJECTS = $(am__objects_35)
+am__objects_36 = mfluajitdir/mfluajit_nowin-mfluajitextra.$(OBJEXT)
+nodist_mfluajit_nowin_OBJECTS = $(am__objects_36)
 mfluajit_nowin_OBJECTS = $(nodist_mfluajit_nowin_OBJECTS)
 mfluajit_nowin_DEPENDENCIES = libmfluajit.a $(am__DEPENDENCIES_2) \
 	$(windowlib) $(am__DEPENDENCIES_1)
@@ -1161,8 +1170,8 @@
 mft_OBJECTS = $(nodist_mft_OBJECTS)
 mft_LDADD = $(LDADD)
 mft_DEPENDENCIES = $(proglib) $(am__DEPENDENCIES_1)
-am__objects_36 = mpost-mpxout.$(OBJEXT)
-nodist_mpost_OBJECTS = mpost-mpost.$(OBJEXT) $(am__objects_36)
+am__objects_37 = mpost-mpxout.$(OBJEXT)
+nodist_mpost_OBJECTS = mpost-mpost.$(OBJEXT) $(am__objects_37)
 mpost_OBJECTS = $(nodist_mpost_OBJECTS)
 mpost_DEPENDENCIES = libmplib.a $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@@ -1194,12 +1203,12 @@
 	pdftexdir/etex_version.h synctexdir/synctex.c \
 	synctexdir/synctex.h synctexdir/synctex-common.h \
 	synctexdir/synctex-pdftex.h
- at PDFTEX_SYNCTEX_TRUE@am__objects_37 =  \
+ at PDFTEX_SYNCTEX_TRUE@am__objects_38 =  \
 @PDFTEX_SYNCTEX_TRUE@	synctexdir/pdftex-synctex.$(OBJEXT)
 dist_pdftex_OBJECTS = pdftexdir/pdftex-pdftexextra.$(OBJEXT) \
-	$(am__objects_37)
-am__objects_38 = pdftex-pdftexini.$(OBJEXT) pdftex-pdftex0.$(OBJEXT)
-nodist_pdftex_OBJECTS = $(am__objects_38) pdftex-pdftex-pool.$(OBJEXT)
+	$(am__objects_38)
+am__objects_39 = pdftex-pdftexini.$(OBJEXT) pdftex-pdftex0.$(OBJEXT)
+nodist_pdftex_OBJECTS = $(am__objects_39) pdftex-pdftex-pool.$(OBJEXT)
 pdftex_OBJECTS = $(dist_pdftex_OBJECTS) $(nodist_pdftex_OBJECTS)
 am__DEPENDENCIES_10 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) libmd5.a
@@ -1226,20 +1235,20 @@
 pltotf_OBJECTS = $(nodist_pltotf_OBJECTS)
 pltotf_LDADD = $(LDADD)
 pltotf_DEPENDENCIES = $(proglib) $(am__DEPENDENCIES_1)
-am__objects_39 = pmpost-pmp.$(OBJEXT)
-am__objects_40 = pmpost-pmpmath.$(OBJEXT)
-am__objects_41 = pmpost-pmpmathbinary.$(OBJEXT)
-am__objects_42 = pmpost-pmpmathdecimal.$(OBJEXT)
-am__objects_43 = pmpost-pmpmathdouble.$(OBJEXT)
-am__objects_44 = pmpost-pmpstrings.$(OBJEXT)
-am__objects_45 = pmpost-pmpxout.$(OBJEXT)
-am__objects_46 = pmpost-ppngout.$(OBJEXT)
-am__objects_47 = pmpost-ppsout.$(OBJEXT)
-am__objects_48 = pmpost-psvgout.$(OBJEXT)
-nodist_pmpost_OBJECTS = $(am__objects_39) $(am__objects_40) \
-	$(am__objects_41) $(am__objects_42) $(am__objects_43) \
-	pmpost-pmpost.$(OBJEXT) $(am__objects_44) $(am__objects_45) \
-	$(am__objects_46) $(am__objects_47) $(am__objects_48) \
+am__objects_40 = pmpost-pmp.$(OBJEXT)
+am__objects_41 = pmpost-pmpmath.$(OBJEXT)
+am__objects_42 = pmpost-pmpmathbinary.$(OBJEXT)
+am__objects_43 = pmpost-pmpmathdecimal.$(OBJEXT)
+am__objects_44 = pmpost-pmpmathdouble.$(OBJEXT)
+am__objects_45 = pmpost-pmpstrings.$(OBJEXT)
+am__objects_46 = pmpost-pmpxout.$(OBJEXT)
+am__objects_47 = pmpost-ppngout.$(OBJEXT)
+am__objects_48 = pmpost-ppsout.$(OBJEXT)
+am__objects_49 = pmpost-psvgout.$(OBJEXT)
+nodist_pmpost_OBJECTS = $(am__objects_40) $(am__objects_41) \
+	$(am__objects_42) $(am__objects_43) $(am__objects_44) \
+	pmpost-pmpost.$(OBJEXT) $(am__objects_45) $(am__objects_46) \
+	$(am__objects_47) $(am__objects_48) $(am__objects_49) \
 	pmpost-ptfmin.$(OBJEXT)
 pmpost_OBJECTS = $(nodist_pmpost_OBJECTS)
 pmpost_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@@ -1257,10 +1266,10 @@
 	ptexdir/ptex_version.h synctexdir/synctex.c \
 	synctexdir/synctex.h synctexdir/synctex-common.h \
 	synctexdir/synctex-ptex.h
- at PTEX_SYNCTEX_TRUE@am__objects_49 = synctexdir/ptex-synctex.$(OBJEXT)
-dist_ptex_OBJECTS = ptexdir/ptex-ptexextra.$(OBJEXT) $(am__objects_49)
-am__objects_50 = ptex-ptexini.$(OBJEXT) ptex-ptex0.$(OBJEXT)
-nodist_ptex_OBJECTS = $(am__objects_50) ptex-ptex-pool.$(OBJEXT)
+ at PTEX_SYNCTEX_TRUE@am__objects_50 = synctexdir/ptex-synctex.$(OBJEXT)
+dist_ptex_OBJECTS = ptexdir/ptex-ptexextra.$(OBJEXT) $(am__objects_50)
+am__objects_51 = ptex-ptexini.$(OBJEXT) ptex-ptex0.$(OBJEXT)
+nodist_ptex_OBJECTS = $(am__objects_51) ptex-ptex-pool.$(OBJEXT)
 ptex_OBJECTS = $(dist_ptex_OBJECTS) $(nodist_ptex_OBJECTS)
 @PTEX_SYNCTEX_TRUE at am__DEPENDENCIES_11 = $(am__DEPENDENCIES_1)
 am_ptftopl_OBJECTS =
@@ -1281,10 +1290,10 @@
 am__dist_tex_SOURCES_DIST = texextra.c synctexdir/synctex.c \
 	synctexdir/synctex.h synctexdir/synctex-common.h \
 	synctexdir/synctex-tex.h
- at TEX_SYNCTEX_TRUE@am__objects_51 = synctexdir/tex-synctex.$(OBJEXT)
-dist_tex_OBJECTS = tex-texextra.$(OBJEXT) $(am__objects_51)
-am__objects_52 = tex-texini.$(OBJEXT) tex-tex0.$(OBJEXT)
-nodist_tex_OBJECTS = $(am__objects_52) tex-tex-pool.$(OBJEXT)
+ at TEX_SYNCTEX_TRUE@am__objects_52 = synctexdir/tex-synctex.$(OBJEXT)
+dist_tex_OBJECTS = tex-texextra.$(OBJEXT) $(am__objects_52)
+am__objects_53 = tex-texini.$(OBJEXT) tex-tex0.$(OBJEXT)
+nodist_tex_OBJECTS = $(am__objects_53) tex-tex-pool.$(OBJEXT)
 tex_OBJECTS = $(dist_tex_OBJECTS) $(nodist_tex_OBJECTS)
 @TEX_SYNCTEX_TRUE at am__DEPENDENCIES_13 = $(am__DEPENDENCIES_1)
 tex_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
@@ -1309,21 +1318,21 @@
 nodist_updvitype_OBJECTS = updvitype-updvitype.$(OBJEXT)
 updvitype_OBJECTS = $(am_updvitype_OBJECTS) \
 	$(nodist_updvitype_OBJECTS)
-am__objects_53 = upmpost-pmp.$(OBJEXT)
-am__objects_54 = upmpost-pmpmath.$(OBJEXT)
-am__objects_55 = upmpost-pmpmathbinary.$(OBJEXT)
-am__objects_56 = upmpost-pmpmathdecimal.$(OBJEXT)
-am__objects_57 = upmpost-pmpmathdouble.$(OBJEXT)
-am__objects_58 = upmpost-pmpstrings.$(OBJEXT)
-am__objects_59 = upmpost-pmpxout.$(OBJEXT)
-am__objects_60 = upmpost-ppngout.$(OBJEXT)
-am__objects_61 = upmpost-ppsout.$(OBJEXT)
-am__objects_62 = upmpost-psvgout.$(OBJEXT)
-am__objects_63 = $(am__objects_53) $(am__objects_54) $(am__objects_55) \
-	$(am__objects_56) $(am__objects_57) upmpost-pmpost.$(OBJEXT) \
-	$(am__objects_58) $(am__objects_59) $(am__objects_60) \
-	$(am__objects_61) $(am__objects_62) upmpost-ptfmin.$(OBJEXT)
-nodist_upmpost_OBJECTS = $(am__objects_63)
+am__objects_54 = upmpost-pmp.$(OBJEXT)
+am__objects_55 = upmpost-pmpmath.$(OBJEXT)
+am__objects_56 = upmpost-pmpmathbinary.$(OBJEXT)
+am__objects_57 = upmpost-pmpmathdecimal.$(OBJEXT)
+am__objects_58 = upmpost-pmpmathdouble.$(OBJEXT)
+am__objects_59 = upmpost-pmpstrings.$(OBJEXT)
+am__objects_60 = upmpost-pmpxout.$(OBJEXT)
+am__objects_61 = upmpost-ppngout.$(OBJEXT)
+am__objects_62 = upmpost-ppsout.$(OBJEXT)
+am__objects_63 = upmpost-psvgout.$(OBJEXT)
+am__objects_64 = $(am__objects_54) $(am__objects_55) $(am__objects_56) \
+	$(am__objects_57) $(am__objects_58) upmpost-pmpost.$(OBJEXT) \
+	$(am__objects_59) $(am__objects_60) $(am__objects_61) \
+	$(am__objects_62) $(am__objects_63) upmpost-ptfmin.$(OBJEXT)
+nodist_upmpost_OBJECTS = $(am__objects_64)
 upmpost_OBJECTS = $(nodist_upmpost_OBJECTS)
 am__DEPENDENCIES_15 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@@ -1337,12 +1346,12 @@
 	uptexdir/uptexextra.h uptexdir/uptex_version.h \
 	synctexdir/synctex.c synctexdir/synctex.h \
 	synctexdir/synctex-common.h synctexdir/synctex-uptex.h
- at UPTEX_SYNCTEX_TRUE@am__objects_64 =  \
+ at UPTEX_SYNCTEX_TRUE@am__objects_65 =  \
 @UPTEX_SYNCTEX_TRUE@	synctexdir/uptex-synctex.$(OBJEXT)
 dist_uptex_OBJECTS = uptexdir/uptex-uptexextra.$(OBJEXT) \
-	$(am__objects_64)
-am__objects_65 = uptex-uptexini.$(OBJEXT) uptex-uptex0.$(OBJEXT)
-nodist_uptex_OBJECTS = $(am__objects_65) uptex-uptex-pool.$(OBJEXT)
+	$(am__objects_65)
+am__objects_66 = uptex-uptexini.$(OBJEXT) uptex-uptex0.$(OBJEXT)
+nodist_uptex_OBJECTS = $(am__objects_66) uptex-uptex-pool.$(OBJEXT)
 uptex_OBJECTS = $(dist_uptex_OBJECTS) $(nodist_uptex_OBJECTS)
 @UPTEX_SYNCTEX_TRUE at am__DEPENDENCIES_16 = $(am__DEPENDENCIES_1)
 am_uptftopl_OBJECTS =
@@ -1381,12 +1390,12 @@
 	xetexdir/xetex_version.h synctexdir/synctex.c \
 	synctexdir/synctex.h synctexdir/synctex-common.h \
 	synctexdir/synctex-xetex.h
- at XETEX_SYNCTEX_TRUE@am__objects_66 =  \
+ at XETEX_SYNCTEX_TRUE@am__objects_67 =  \
 @XETEX_SYNCTEX_TRUE@	synctexdir/xetex-synctex.$(OBJEXT)
 dist_xetex_OBJECTS = xetexdir/xetex-xetexextra.$(OBJEXT) \
-	$(am__objects_66)
-am__objects_67 = xetex-xetexini.$(OBJEXT) xetex-xetex0.$(OBJEXT)
-nodist_xetex_OBJECTS = $(am__objects_67) xetex-xetex-pool.$(OBJEXT)
+	$(am__objects_67)
+am__objects_68 = xetex-xetexini.$(OBJEXT) xetex-xetex0.$(OBJEXT)
+nodist_xetex_OBJECTS = $(am__objects_68) xetex-xetex-pool.$(OBJEXT)
 xetex_OBJECTS = $(dist_xetex_OBJECTS) $(nodist_xetex_OBJECTS)
 @XETEX_MACOSX_FALSE at am__DEPENDENCIES_17 = $(am__DEPENDENCIES_1)
 am__DEPENDENCIES_18 = $(libxetex) $(am__DEPENDENCIES_1) \
@@ -1469,6 +1478,7 @@
 am__v_OBJCXXLD_0 = @echo "  OBJCXXLD" $@;
 am__v_OBJCXXLD_1 = 
 SOURCES = $(libff_a_SOURCES) $(libkanji_a_SOURCES) \
+	$(nodist_libluaffi_a_SOURCES) \
 	$(nodist_libluajitmisc_a_SOURCES) \
 	$(nodist_libluajitsocket_a_SOURCES) \
 	$(dist_libluajittex_a_SOURCES) \
@@ -1793,6 +1803,7 @@
 	$(srcdir)/euptexdir/am/euptex.am $(srcdir)/libmd5/am/md5.am \
 	$(srcdir)/luatexdir/am/libluatex.am \
 	$(srcdir)/luatexdir/am/libunilib.am \
+	$(srcdir)/luatexdir/am/luaffi.am \
 	$(srcdir)/luatexdir/am/luafontforge.am \
 	$(srcdir)/luatexdir/am/luamisc.am \
 	$(srcdir)/luatexdir/am/luasocket.am \
@@ -1821,7 +1832,11 @@
 	$(top_srcdir)/../../build-aux/test-driver \
 	$(top_srcdir)/../texlive/w32_wrapper/callexe.c \
 	$(top_srcdir)/luatexdir/luafontloader/ff-config.in \
-	$(top_srcdir)/synctexdir/synctex.pc.in ../../build-aux/compile \
+	$(top_srcdir)/omegafonts/Makefile.in \
+	$(top_srcdir)/otps/Makefile.in \
+	$(top_srcdir)/otps/win32/Makefile.in \
+	$(top_srcdir)/synctexdir/synctex.pc.in \
+	$(top_srcdir)/window/Makefile.in ../../build-aux/compile \
 	../../build-aux/config.guess ../../build-aux/config.sub \
 	../../build-aux/depcomp ../../build-aux/install-sh \
 	../../build-aux/ltmain.sh ../../build-aux/missing \
@@ -2100,8 +2115,8 @@
 EXTRA_LIBRARIES = libmf.a libmflua.a libmfluajit.a libmputil.a \
 	libmplib.a libkanji.a libukanji.a libpdftex.a libluasocket.a \
 	libluajitsocket.a libluamisc.a libluajitmisc.a libunilib.a \
-	libff.a libluatex.a libluajittex.a libxetex.a libsynctex.a \
-	libmd5.a
+	libff.a libluatex.a libluajittex.a libluaffi.a libxetex.a \
+	libsynctex.a libmd5.a
 EXTRA_LTLIBRARIES = libsynctex.la
 lib_LIBRARIES = $(am__append_109)
 lib_LTLIBRARIES = $(am__append_108)
@@ -3166,7 +3181,7 @@
 	luatexdir/luasocket/src/udp.h \
 	luatexdir/luasocket/src/usocket.h
 
-libluamisc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) libluasocket.a
+libluamisc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) libluasocket.a libluaffi.a
 libluajitmisc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) libluajitsocket.a
 libluamisc_a_CPPFLAGS = $(ZLIB_INCLUDES) $(ZZIPLIB_INCLUDES) $(LUA_INCLUDES)
 libluajitmisc_a_CPPFLAGS = $(ZLIB_INCLUDES) $(ZZIPLIB_INCLUDES) \
@@ -3501,7 +3516,23 @@
 ################################################################################
 luatex_tex_ctangle = $(ctangle_silent)CWEBINPUTS=$(srcdir)/luatexdir/tex $(ctangle)
 luatex_utils_ctangle = $(ctangle_silent)CWEBINPUTS=$(srcdir)/luatexdir/utils $(ctangle)
+libluaffi_a_CPPFLAGS = \
+	-I$(top_srcdir)/luatexdir/luaffi -I$(top_srcdir)/luatexdir/luaffi/dynasm $(LUA_INCLUDES)
 
+libluaffi_a_CFLAGS = # $(WARNING_CFLAGS)
+nodist_libluaffi_a_SOURCES = $(libluaffi_sources)
+libluaffi_sources = \
+	luatexdir/luaffi/call_arm.h \
+	luatexdir/luaffi/call.c \
+	luatexdir/luaffi/call_x64.h \
+	luatexdir/luaffi/call_x64win.h \
+	luatexdir/luaffi/call_x86.h \
+	luatexdir/luaffi/ctype.c \
+	luatexdir/luaffi/ffi.c \
+	luatexdir/luaffi/ffi.h \
+	luatexdir/luaffi/parser.c
+
+
 # Force Automake to use CXXLD for linking
 nodist_EXTRA_luatex_SOURCES = dummy.cxx
 nodist_EXTRA_luajittex_SOURCES = dummy.cxx
@@ -3520,7 +3551,7 @@
 	$(PIXMAN_LIBS) $(ZZIPLIB_LIBS) $(LIBPNG_LIBS) $(ZLIB_LIBS) \
 	$(POPPLER_LIBS) $(LDADD) libmputil.a libunilib.a libmd5.a \
 	$(lua_socketlibs)
-luatex_LDADD = libluatex.a libff.a libluamisc.a libluasocket.a $(LUA_LIBS) $(luatex_postldadd)
+luatex_LDADD = libluatex.a libff.a libluamisc.a libluasocket.a libluaffi.a $(LUA_LIBS) $(luatex_postldadd)
 luajittex_LDADD = libluajittex.a libff.a libluajitmisc.a libluajitsocket.a $(LUAJIT_LIBS) $(luatex_postldadd)
 luatex_depend = $(proglib) $(KPATHSEA_DEPEND) $(LIBPNG_DEPEND) libmputil.a libmd5.a
 luatex_DEPENDENCIES = $(luatex_depend) libluatex.a
@@ -3823,7 +3854,7 @@
 .SUFFIXES: .c .cc .cin .cpp .cxx .h .hin .lo .log .mm .o .obj .p .pin .pl .pl$(EXEEXT) .test .test$(EXEEXT) .trs
 am--refresh: Makefile
 	@:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../../am/dist_hook.am $(srcdir)/am/bootstrap.am $(srcdir)/am/web.am $(srcdir)/am/cweb.am $(srcdir)/am/texmf.am $(srcdir)/mfluadir/am/mflua.am $(srcdir)/mfluajitdir/am/mfluajit.am $(srcdir)/mplibdir/am/mplib.am $(srcdir)/pmpostdir/am/pmpost.am $(srcdir)/mplibdir/am/libmputil.am $(srcdir)/mplibdir/am/libmplib.am $(srcdir)/etexdir/am/etex.am $(srcdir)/ptexdir/am/ptex.am $(srcdir)/eptexdir/am/eptex.am $(srcdir)/uptexdir/am/uptex.am $(srcdir)/euptexdir/am/euptex.am $(srcdir)/pdftexdir/am/libpdftex.am $(srcdir)/pdftexdir/am/pdftex.am $(srcdir)/pdftexdir/am/ttf2afm.am $(srcdir)/pdftexdir/am/pdftosrc.am $(srcdir)/luatexdir/am/luasocket.am $(srcdir)/luatexdir/am/luamisc.am $(srcdir)/luatexdir/am/libunilib.am $(srcdir)/luatexdir/am/luafontforge.am $(srcdir)/luatexdir/am/libluatex.am $(srcdir)/luatexdir/am/luatex.am $(srcdir)/xetexdir/am/xetex.am $(srcdir)/omegaware/am/omegaware.am $(srcdir)/alephdir/am/aleph.am $(srcdir)/synctexdir/am/synctex.am $(srcdir)/libmd5/am/md5.am $(srcdir)/../../am/bin_links.am $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../../am/dist_hook.am $(srcdir)/am/bootstrap.am $(srcdir)/am/web.am $(srcdir)/am/cweb.am $(srcdir)/am/texmf.am $(srcdir)/mfluadir/am/mflua.am $(srcdir)/mfluajitdir/am/mfluajit.am $(srcdir)/mplibdir/am/mplib.am $(srcdir)/pmpostdir/am/pmpost.am $(srcdir)/mplibdir/am/libmputil.am $(srcdir)/mplibdir/am/libmplib.am $(srcdir)/etexdir/am/etex.am $(srcdir)/ptexdir/am/ptex.am $(srcdir)/eptexdir/am/eptex.am $(srcdir)/uptexdir/am/uptex.am $(srcdir)/euptexdir/am/euptex.am $(srcdir)/pdftexdir/am/libpdftex.am $(srcdir)/pdftexdir/am/pdftex.am $(srcdir)/pdftexdir/am/ttf2afm.am $(srcdir)/pdftexdir/am/pdftosrc.am $(srcdir)/luatexdir/am/luasocket.am $(srcdir)/luatexdir/am/luamisc.am $(srcdir)/luatexdir/am/libunilib.am $(srcdir)/luatexdir/am/luafontforge.am $(srcdir)/luatexdir/am/libluatex.am $(srcdir)/luatexdir/am/luaffi.am $(srcdir)/luatexdir/am/luatex.am $(srcdir)/xetexdir/am/xetex.am $(srcdir)/omegaware/am/omegaware.am $(srcdir)/alephdir/am/aleph.am $(srcdir)/synctexdir/am/synctex.am $(srcdir)/libmd5/am/md5.am $(srcdir)/../../am/bin_links.am $(am__configure_deps)
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
 	    *$$dep*) \
@@ -3845,7 +3876,7 @@
 	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
 	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
 	esac;
-$(srcdir)/../../am/dist_hook.am $(srcdir)/am/bootstrap.am $(srcdir)/am/web.am $(srcdir)/am/cweb.am $(srcdir)/am/texmf.am $(srcdir)/mfluadir/am/mflua.am $(srcdir)/mfluajitdir/am/mfluajit.am $(srcdir)/mplibdir/am/mplib.am $(srcdir)/pmpostdir/am/pmpost.am $(srcdir)/mplibdir/am/libmputil.am $(srcdir)/mplibdir/am/libmplib.am $(srcdir)/etexdir/am/etex.am $(srcdir)/ptexdir/am/ptex.am $(srcdir)/eptexdir/am/eptex.am $(srcdir)/uptexdir/am/uptex.am $(srcdir)/euptexdir/am/euptex.am $(srcdir)/pdftexdir/am/libpdftex.am $(srcdir)/pdftexdir/am/pdftex.am $(srcdir)/pdftexdir/am/ttf2afm.am $(srcdir)/pdftexdir/am/pdftosrc.am $(srcdir)/luatexdir/am/luasocket.am $(srcdir)/luatexdir/am/luamisc.am $(srcdir)/luatexdir/am/libunilib.am $(srcdir)/luatexdir/am/luafontforge.am $(srcdir)/luatexdir/am/libluatex.am $(srcdir)/luatexdir/am/luatex.am $(srcdir)/xetexdir/am/xetex.am $(srcdir)/omegaware/am/omegaware.am $(srcdir)/alephdir/am/aleph.am $(srcdir)/synctexdir/am/synctex.am $(srcdir)/libmd5/am/md5.am $(srcdir)/../../am/bin_links.am $(am__empty):
+$(srcdir)/../../am/dist_hook.am $(srcdir)/am/bootstrap.am $(srcdir)/am/web.am $(srcdir)/am/cweb.am $(srcdir)/am/texmf.am $(srcdir)/mfluadir/am/mflua.am $(srcdir)/mfluajitdir/am/mfluajit.am $(srcdir)/mplibdir/am/mplib.am $(srcdir)/pmpostdir/am/pmpost.am $(srcdir)/mplibdir/am/libmputil.am $(srcdir)/mplibdir/am/libmplib.am $(srcdir)/etexdir/am/etex.am $(srcdir)/ptexdir/am/ptex.am $(srcdir)/eptexdir/am/eptex.am $(srcdir)/uptexdir/am/uptex.am $(srcdir)/euptexdir/am/euptex.am $(srcdir)/pdftexdir/am/libpdftex.am $(srcdir)/pdftexdir/am/pdftex.am $(srcdir)/pdftexdir/am/ttf2afm.am $(srcdir)/pdftexdir/am/pdftosrc.am $(srcdir)/luatexdir/am/luasocket.am $(srcdir)/luatexdir/am/luamisc.am $(srcdir)/luatexdir/am/libunilib.am $(srcdir)/luatexdir/am/luafontforge.am $(srcdir)/luatexdir/am/libluatex.am $(srcdir)/luatexdir/am/luaffi.am $(srcdir)/luatexdir/am/luatex.am $(srcdir)/xetexdir/am/xetex.am $(srcdir)/omegaware/am/omegaware.am $(srcdir)/alephdir/am/aleph.am $(srcdir)/synctexdir/am/synctex.am $(srcdir)/libmd5/am/md5.am $(srcdir)/../../am/bin_links.am $(am__empty):
 
 $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
 	$(SHELL) ./config.status --recheck
@@ -3878,6 +3909,14 @@
 
 distclean-hdr:
 	-rm -f w2c/c-auto.h w2c/stamp-h1 ff-config.h stamp-h2
+omegafonts/Makefile: $(top_builddir)/config.status $(top_srcdir)/omegafonts/Makefile.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+otps/Makefile: $(top_builddir)/config.status $(top_srcdir)/otps/Makefile.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+otps/win32/Makefile: $(top_builddir)/config.status $(top_srcdir)/otps/win32/Makefile.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+window/Makefile: $(top_builddir)/config.status $(top_srcdir)/window/Makefile.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
 web2c-sh: $(top_builddir)/config.status $(srcdir)/web2c-sh.in
 	cd $(top_builddir) && $(SHELL) ./config.status $@
 tangle-sh: $(top_builddir)/config.status $(srcdir)/tangle-sh.in
@@ -4075,6 +4114,29 @@
 	$(AM_V_at)-rm -f libkanji.a
 	$(AM_V_AR)$(libkanji_a_AR) libkanji.a $(libkanji_a_OBJECTS) $(libkanji_a_LIBADD)
 	$(AM_V_at)$(RANLIB) libkanji.a
+luatexdir/luaffi/$(am__dirstamp):
+	@$(MKDIR_P) luatexdir/luaffi
+	@: > luatexdir/luaffi/$(am__dirstamp)
+luatexdir/luaffi/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) luatexdir/luaffi/$(DEPDIR)
+	@: > luatexdir/luaffi/$(DEPDIR)/$(am__dirstamp)
+luatexdir/luaffi/libluaffi_a-call.$(OBJEXT):  \
+	luatexdir/luaffi/$(am__dirstamp) \
+	luatexdir/luaffi/$(DEPDIR)/$(am__dirstamp)
+luatexdir/luaffi/libluaffi_a-ctype.$(OBJEXT):  \
+	luatexdir/luaffi/$(am__dirstamp) \
+	luatexdir/luaffi/$(DEPDIR)/$(am__dirstamp)
+luatexdir/luaffi/libluaffi_a-ffi.$(OBJEXT):  \
+	luatexdir/luaffi/$(am__dirstamp) \
+	luatexdir/luaffi/$(DEPDIR)/$(am__dirstamp)
+luatexdir/luaffi/libluaffi_a-parser.$(OBJEXT):  \
+	luatexdir/luaffi/$(am__dirstamp) \
+	luatexdir/luaffi/$(DEPDIR)/$(am__dirstamp)
+
+libluaffi.a: $(libluaffi_a_OBJECTS) $(libluaffi_a_DEPENDENCIES) $(EXTRA_libluaffi_a_DEPENDENCIES) 
+	$(AM_V_at)-rm -f libluaffi.a
+	$(AM_V_AR)$(libluaffi_a_AR) libluaffi.a $(libluaffi_a_OBJECTS) $(libluaffi_a_LIBADD)
+	$(AM_V_at)$(RANLIB) libluaffi.a
 luatexdir/luafilesystem/src/$(am__dirstamp):
 	@$(MKDIR_P) luatexdir/luafilesystem/src
 	@: > luatexdir/luafilesystem/src/$(am__dirstamp)
@@ -5240,6 +5302,7 @@
 	-rm -f libmd5/*.$(OBJEXT)
 	-rm -f luatexdir/*.$(OBJEXT)
 	-rm -f luatexdir/lua/*.$(OBJEXT)
+	-rm -f luatexdir/luaffi/*.$(OBJEXT)
 	-rm -f luatexdir/luafilesystem/src/*.$(OBJEXT)
 	-rm -f luatexdir/luafontloader/fontforge/fontforge/*.$(OBJEXT)
 	-rm -f luatexdir/luafontloader/fontforge/gutils/*.$(OBJEXT)
@@ -5633,6 +5696,10 @@
 @AMDEP_TRUE@@am__include@ @am__quote at luatexdir/lua/$(DEPDIR)/libluatex_a-ltexlib.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at luatexdir/lua/$(DEPDIR)/libmflua_a-lkpselib.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at luatexdir/lua/$(DEPDIR)/libmfluajit_a-lkpselib.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at luatexdir/luaffi/$(DEPDIR)/libluaffi_a-call.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ctype.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ffi.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at luatexdir/luaffi/$(DEPDIR)/libluaffi_a-parser.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at luatexdir/luafilesystem/src/$(DEPDIR)/libluajitmisc_a-lfs.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at luatexdir/luafilesystem/src/$(DEPDIR)/libluamisc_a-lfs.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at luatexdir/luafontloader/fontforge/fontforge/$(DEPDIR)/libff_a-autohint.Po at am__quote@
@@ -6455,6 +6522,62 @@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkanji_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ptexdir/libkanji_a-kanji.obj `if test -f 'ptexdir/kanji.c'; then $(CYGPATH_W) 'ptexdir/kanji.c'; else $(CYGPATH_W) '$(srcdir)/ptexdir/kanji.c'; fi`
 
+luatexdir/luaffi/libluaffi_a-call.o: luatexdir/luaffi/call.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -MT luatexdir/luaffi/libluaffi_a-call.o -MD -MP -MF luatexdir/luaffi/$(DEPDIR)/libluaffi_a-call.Tpo -c -o luatexdir/luaffi/libluaffi_a-call.o `test -f 'luatexdir/luaffi/call.c' || echo '$(srcdir)/'`luatexdir/luaffi/call.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) luatexdir/luaffi/$(DEPDIR)/libluaffi_a-call.Tpo luatexdir/luaffi/$(DEPDIR)/libluaffi_a-call.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='luatexdir/luaffi/call.c' object='luatexdir/luaffi/libluaffi_a-call.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -c -o luatexdir/luaffi/libluaffi_a-call.o `test -f 'luatexdir/luaffi/call.c' || echo '$(srcdir)/'`luatexdir/luaffi/call.c
+
+luatexdir/luaffi/libluaffi_a-call.obj: luatexdir/luaffi/call.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -MT luatexdir/luaffi/libluaffi_a-call.obj -MD -MP -MF luatexdir/luaffi/$(DEPDIR)/libluaffi_a-call.Tpo -c -o luatexdir/luaffi/libluaffi_a-call.obj `if test -f 'luatexdir/luaffi/call.c'; then $(CYGPATH_W) 'luatexdir/luaffi/call.c'; else $(CYGPATH_W) '$(srcdir)/luatexdir/luaffi/call.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) luatexdir/luaffi/$(DEPDIR)/libluaffi_a-call.Tpo luatexdir/luaffi/$(DEPDIR)/libluaffi_a-call.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='luatexdir/luaffi/call.c' object='luatexdir/luaffi/libluaffi_a-call.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -c -o luatexdir/luaffi/libluaffi_a-call.obj `if test -f 'luatexdir/luaffi/call.c'; then $(CYGPATH_W) 'luatexdir/luaffi/call.c'; else $(CYGPATH_W) '$(srcdir)/luatexdir/luaffi/call.c'; fi`
+
+luatexdir/luaffi/libluaffi_a-ctype.o: luatexdir/luaffi/ctype.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -MT luatexdir/luaffi/libluaffi_a-ctype.o -MD -MP -MF luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ctype.Tpo -c -o luatexdir/luaffi/libluaffi_a-ctype.o `test -f 'luatexdir/luaffi/ctype.c' || echo '$(srcdir)/'`luatexdir/luaffi/ctype.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ctype.Tpo luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ctype.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='luatexdir/luaffi/ctype.c' object='luatexdir/luaffi/libluaffi_a-ctype.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -c -o luatexdir/luaffi/libluaffi_a-ctype.o `test -f 'luatexdir/luaffi/ctype.c' || echo '$(srcdir)/'`luatexdir/luaffi/ctype.c
+
+luatexdir/luaffi/libluaffi_a-ctype.obj: luatexdir/luaffi/ctype.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -MT luatexdir/luaffi/libluaffi_a-ctype.obj -MD -MP -MF luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ctype.Tpo -c -o luatexdir/luaffi/libluaffi_a-ctype.obj `if test -f 'luatexdir/luaffi/ctype.c'; then $(CYGPATH_W) 'luatexdir/luaffi/ctype.c'; else $(CYGPATH_W) '$(srcdir)/luatexdir/luaffi/ctype.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ctype.Tpo luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ctype.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='luatexdir/luaffi/ctype.c' object='luatexdir/luaffi/libluaffi_a-ctype.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -c -o luatexdir/luaffi/libluaffi_a-ctype.obj `if test -f 'luatexdir/luaffi/ctype.c'; then $(CYGPATH_W) 'luatexdir/luaffi/ctype.c'; else $(CYGPATH_W) '$(srcdir)/luatexdir/luaffi/ctype.c'; fi`
+
+luatexdir/luaffi/libluaffi_a-ffi.o: luatexdir/luaffi/ffi.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -MT luatexdir/luaffi/libluaffi_a-ffi.o -MD -MP -MF luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ffi.Tpo -c -o luatexdir/luaffi/libluaffi_a-ffi.o `test -f 'luatexdir/luaffi/ffi.c' || echo '$(srcdir)/'`luatexdir/luaffi/ffi.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ffi.Tpo luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ffi.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='luatexdir/luaffi/ffi.c' object='luatexdir/luaffi/libluaffi_a-ffi.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -c -o luatexdir/luaffi/libluaffi_a-ffi.o `test -f 'luatexdir/luaffi/ffi.c' || echo '$(srcdir)/'`luatexdir/luaffi/ffi.c
+
+luatexdir/luaffi/libluaffi_a-ffi.obj: luatexdir/luaffi/ffi.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -MT luatexdir/luaffi/libluaffi_a-ffi.obj -MD -MP -MF luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ffi.Tpo -c -o luatexdir/luaffi/libluaffi_a-ffi.obj `if test -f 'luatexdir/luaffi/ffi.c'; then $(CYGPATH_W) 'luatexdir/luaffi/ffi.c'; else $(CYGPATH_W) '$(srcdir)/luatexdir/luaffi/ffi.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ffi.Tpo luatexdir/luaffi/$(DEPDIR)/libluaffi_a-ffi.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='luatexdir/luaffi/ffi.c' object='luatexdir/luaffi/libluaffi_a-ffi.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -c -o luatexdir/luaffi/libluaffi_a-ffi.obj `if test -f 'luatexdir/luaffi/ffi.c'; then $(CYGPATH_W) 'luatexdir/luaffi/ffi.c'; else $(CYGPATH_W) '$(srcdir)/luatexdir/luaffi/ffi.c'; fi`
+
+luatexdir/luaffi/libluaffi_a-parser.o: luatexdir/luaffi/parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -MT luatexdir/luaffi/libluaffi_a-parser.o -MD -MP -MF luatexdir/luaffi/$(DEPDIR)/libluaffi_a-parser.Tpo -c -o luatexdir/luaffi/libluaffi_a-parser.o `test -f 'luatexdir/luaffi/parser.c' || echo '$(srcdir)/'`luatexdir/luaffi/parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) luatexdir/luaffi/$(DEPDIR)/libluaffi_a-parser.Tpo luatexdir/luaffi/$(DEPDIR)/libluaffi_a-parser.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='luatexdir/luaffi/parser.c' object='luatexdir/luaffi/libluaffi_a-parser.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -c -o luatexdir/luaffi/libluaffi_a-parser.o `test -f 'luatexdir/luaffi/parser.c' || echo '$(srcdir)/'`luatexdir/luaffi/parser.c
+
+luatexdir/luaffi/libluaffi_a-parser.obj: luatexdir/luaffi/parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -MT luatexdir/luaffi/libluaffi_a-parser.obj -MD -MP -MF luatexdir/luaffi/$(DEPDIR)/libluaffi_a-parser.Tpo -c -o luatexdir/luaffi/libluaffi_a-parser.obj `if test -f 'luatexdir/luaffi/parser.c'; then $(CYGPATH_W) 'luatexdir/luaffi/parser.c'; else $(CYGPATH_W) '$(srcdir)/luatexdir/luaffi/parser.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) luatexdir/luaffi/$(DEPDIR)/libluaffi_a-parser.Tpo luatexdir/luaffi/$(DEPDIR)/libluaffi_a-parser.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='luatexdir/luaffi/parser.c' object='luatexdir/luaffi/libluaffi_a-parser.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluaffi_a_CPPFLAGS) $(CPPFLAGS) $(libluaffi_a_CFLAGS) $(CFLAGS) -c -o luatexdir/luaffi/libluaffi_a-parser.obj `if test -f 'luatexdir/luaffi/parser.c'; then $(CYGPATH_W) 'luatexdir/luaffi/parser.c'; else $(CYGPATH_W) '$(srcdir)/luatexdir/luaffi/parser.c'; fi`
+
 luatexdir/luafilesystem/src/libluajitmisc_a-lfs.o: luatexdir/luafilesystem/src/lfs.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluajitmisc_a_CPPFLAGS) $(CPPFLAGS) $(libluajitmisc_a_CFLAGS) $(CFLAGS) -MT luatexdir/luafilesystem/src/libluajitmisc_a-lfs.o -MD -MP -MF luatexdir/luafilesystem/src/$(DEPDIR)/libluajitmisc_a-lfs.Tpo -c -o luatexdir/luafilesystem/src/libluajitmisc_a-lfs.o `test -f 'luatexdir/luafilesystem/src/lfs.c' || echo '$(srcdir)/'`luatexdir/luafilesystem/src/lfs.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) luatexdir/luafilesystem/src/$(DEPDIR)/libluajitmisc_a-lfs.Tpo luatexdir/luafilesystem/src/$(DEPDIR)/libluajitmisc_a-lfs.Po
@@ -13960,6 +14083,8 @@
 	-rm -f luatexdir/$(am__dirstamp)
 	-rm -f luatexdir/lua/$(DEPDIR)/$(am__dirstamp)
 	-rm -f luatexdir/lua/$(am__dirstamp)
+	-rm -f luatexdir/luaffi/$(DEPDIR)/$(am__dirstamp)
+	-rm -f luatexdir/luaffi/$(am__dirstamp)
 	-rm -f luatexdir/luafilesystem/src/$(DEPDIR)/$(am__dirstamp)
 	-rm -f luatexdir/luafilesystem/src/$(am__dirstamp)
 	-rm -f luatexdir/luafontloader/fontforge/fontforge/$(DEPDIR)/$(am__dirstamp)
@@ -14019,7 +14144,7 @@
 
 distclean: distclean-recursive
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-	-rm -rf ./$(DEPDIR) alephdir/$(DEPDIR) eptexdir/$(DEPDIR) etexdir/$(DEPDIR) euptexdir/$(DEPDIR) libmd5/$(DEPDIR) luatexdir/$(DEPDIR) luatexdir/lua/$(DEPDIR) luatexdir/luafilesystem/src/$(DEPDIR) luatexdir/luafontloader/fontforge/fontforge/$(DEPDIR) luatexdir/luafontloader/fontforge/gutils/$(DEPDIR) luatexdir/luafontloader/src/$(DEPDIR) luatexdir/luamd5/$(DEPDIR) luatexdir/luapeg/$(DEPDIR) luatexdir/luaprofiler/$(DEPDIR) luatexdir/luasocket/src/$(DEPDIR) luatexdir/luazip/src/$(DEPDIR) luatexdir/luazlib/$(DEPDIR) luatexdir/slnunicode/$(DEPDIR) luatexdir/unilib/$(DEPDIR) luatexdir/utils/$(DEPDIR) mfluadir/$(DEPDIR) mfluajitdir/$(DEPDIR) mplibdir/$(DEPDIR) pdftexdir/$(DEPDIR) pdftexdir/regex/$(DEPDIR) ptexdir/$(DEPDIR) synctexdir/$(DEPDIR) uptexdir/$(DEPDIR) xetexdir/$(DEPDIR) xetexdir/image/$(DEPDIR)
+	-rm -rf ./$(DEPDIR) alephdir/$(DEPDIR) eptexdir/$(DEPDIR) etexdir/$(DEPDIR) euptexdir/$(DEPDIR) libmd5/$(DEPDIR) luatexdir/$(DEPDIR) luatexdir/lua/$(DEPDIR) luatexdir/luaffi/$(DEPDIR) luatexdir/luafilesystem/src/$(DEPDIR) luatexdir/luafontloader/fontforge/fontforge/$(DEPDIR) luatexdir/luafontloader/fontforge/gutils/$(DEPDIR) luatexdir/luafontloader/src/$(DEPDIR) luatexdir/luamd5/$(DEPDIR) luatexdir/luapeg/$(DEPDIR) luatexdir/luaprofiler/$(DEPDIR) luatexdir/luasocket/src/$(DEPDIR) luatexdir/luazip/src/$(DEPDIR) luatexdir/luazlib/$(DEPDIR) luatexdir/slnunicode/$(DEPDIR) luatexdir/unilib/$(DEPDIR) luatexdir/utils/$(DEPDIR) mfluadir/$(DEPDIR) mfluajitdir/$(DEPDIR) mplibdir/$(DEPDIR) pdftexdir/$(DEPDIR) pdftexdir/regex/$(DEPDIR) ptexdir/$(DEPDIR) synctexdir/$(DEPDIR) uptexdir/$(DEPDIR) xetexdir/$(DEPDIR) xetexdir/image/$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-hdr distclean-libtool distclean-tags
@@ -14070,7 +14195,7 @@
 maintainer-clean: maintainer-clean-recursive
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
 	-rm -rf $(top_srcdir)/autom4te.cache
-	-rm -rf ./$(DEPDIR) alephdir/$(DEPDIR) eptexdir/$(DEPDIR) etexdir/$(DEPDIR) euptexdir/$(DEPDIR) libmd5/$(DEPDIR) luatexdir/$(DEPDIR) luatexdir/lua/$(DEPDIR) luatexdir/luafilesystem/src/$(DEPDIR) luatexdir/luafontloader/fontforge/fontforge/$(DEPDIR) luatexdir/luafontloader/fontforge/gutils/$(DEPDIR) luatexdir/luafontloader/src/$(DEPDIR) luatexdir/luamd5/$(DEPDIR) luatexdir/luapeg/$(DEPDIR) luatexdir/luaprofiler/$(DEPDIR) luatexdir/luasocket/src/$(DEPDIR) luatexdir/luazip/src/$(DEPDIR) luatexdir/luazlib/$(DEPDIR) luatexdir/slnunicode/$(DEPDIR) luatexdir/unilib/$(DEPDIR) luatexdir/utils/$(DEPDIR) mfluadir/$(DEPDIR) mfluajitdir/$(DEPDIR) mplibdir/$(DEPDIR) pdftexdir/$(DEPDIR) pdftexdir/regex/$(DEPDIR) ptexdir/$(DEPDIR) synctexdir/$(DEPDIR) uptexdir/$(DEPDIR) xetexdir/$(DEPDIR) xetexdir/image/$(DEPDIR)
+	-rm -rf ./$(DEPDIR) alephdir/$(DEPDIR) eptexdir/$(DEPDIR) etexdir/$(DEPDIR) euptexdir/$(DEPDIR) libmd5/$(DEPDIR) luatexdir/$(DEPDIR) luatexdir/lua/$(DEPDIR) luatexdir/luaffi/$(DEPDIR) luatexdir/luafilesystem/src/$(DEPDIR) luatexdir/luafontloader/fontforge/fontforge/$(DEPDIR) luatexdir/luafontloader/fontforge/gutils/$(DEPDIR) luatexdir/luafontloader/src/$(DEPDIR) luatexdir/luamd5/$(DEPDIR) luatexdir/luapeg/$(DEPDIR) luatexdir/luaprofiler/$(DEPDIR) luatexdir/luasocket/src/$(DEPDIR) luatexdir/luazip/src/$(DEPDIR) luatexdir/luazlib/$(DEPDIR) luatexdir/slnunicode/$(DEPDIR) luatexdir/unilib/$(DEPDIR) luatexdir/utils/$(DEPDIR) mfluadir/$(DEPDIR) mfluajitdir/$(DEPDIR) mplibdir/$(DEPDIR) pdftexdir/$(DEPDIR) pdftexdir/regex/$(DEPDIR) ptexdir/$(DEPDIR) synctexdir/$(DEPDIR) uptexdir/$(DEPDIR) xetexdir/$(DEPDIR) xetexdir/image/$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
@@ -15147,6 +15272,12 @@
 unistring.c: ctangle$(EXEEXT) luatexdir/utils/unistring.w
 	$(luatex_utils_ctangle) unistring.w
 
+#libluaffi_a_DEPENDENCIES = $(ZLIB_DEPEND)
+
+$(libluaffi_a_OBJECTS): $(LUA_DEPEND)
+
+#EXTRA_DIST 
+
 $(luatex_OBJECTS): libluatex.a
 $(luajittex_OBJECTS): libluajittex.a
 

Modified: trunk/Build/source/texk/web2c/luatexdir/ChangeLog
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/ChangeLog	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/ChangeLog	2017-02-09 22:44:03 UTC (rev 43177)
@@ -1,3 +1,9 @@
+2017-02-07  Luigi Scarso <luigi.scarso at gmail.com>
+
+	* luaffi/: First attempt to implement the ffi module in lua
+	compatible with the ffi module of luajit.
+
+
 2015-11-01  Akira Kakuto  <kakuto at fuk.kindai.ac.jp>
 
 	* luatex.c: Improve a little (w32 only).

Added: trunk/Build/source/texk/web2c/luatexdir/am/luaffi.am
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/am/luaffi.am	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/am/luaffi.am	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,43 @@
+## texk/web2c/luatexdir/am/luaffi.am: Makefile fragment for luaffi
+##
+## Copyright (C) 2017 Luigi Scarso <tex-live at tug.org>
+## You may freely use, modify and/or distribute this file.
+
+## luaffi
+## Only for luatex, luajittex has its own module
+
+##
+## Preliminary version
+## UNSTABLE AND UNTESTED !!!!
+##
+
+
+EXTRA_LIBRARIES += libluaffi.a 
+
+#libluaffi_a_DEPENDENCIES = $(ZLIB_DEPEND)
+
+$(libluaffi_a_OBJECTS): $(LUA_DEPEND)
+
+libluaffi_a_CPPFLAGS = \
+	-I$(top_srcdir)/luatexdir/luaffi -I$(top_srcdir)/luatexdir/luaffi/dynasm $(LUA_INCLUDES)
+
+libluaffi_a_CFLAGS = # $(WARNING_CFLAGS)
+
+nodist_libluaffi_a_SOURCES = $(libluaffi_sources)
+
+
+
+libluaffi_sources = \
+	luatexdir/luaffi/call_arm.h \
+	luatexdir/luaffi/call.c \
+	luatexdir/luaffi/call_x64.h \
+	luatexdir/luaffi/call_x64win.h \
+	luatexdir/luaffi/call_x86.h \
+	luatexdir/luaffi/ctype.c \
+	luatexdir/luaffi/ffi.c \
+	luatexdir/luaffi/ffi.h \
+	luatexdir/luaffi/parser.c
+
+## Not used
+##
+#EXTRA_DIST 

Modified: trunk/Build/source/texk/web2c/luatexdir/am/luamisc.am
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/am/luamisc.am	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/am/luamisc.am	2017-02-09 22:44:03 UTC (rev 43177)
@@ -8,7 +8,7 @@
 ## and slnunicode)
 EXTRA_LIBRARIES += libluamisc.a libluajitmisc.a
 
-libluamisc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) libluasocket.a
+libluamisc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) libluasocket.a libluaffi.a
 libluajitmisc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) libluajitsocket.a
 
 $(libluamisc_a_OBJECTS): $(libluamisc_a_DEPENDENCIES)

Modified: trunk/Build/source/texk/web2c/luatexdir/am/luatex.am
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/am/luatex.am	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/am/luatex.am	2017-02-09 22:44:03 UTC (rev 43177)
@@ -52,7 +52,7 @@
 luatex_postldadd += $(ZZIPLIB_LIBS) $(LIBPNG_LIBS) $(ZLIB_LIBS) $(POPPLER_LIBS)
 luatex_postldadd += $(LDADD) libmputil.a libunilib.a libmd5.a $(lua_socketlibs)
 
-luatex_LDADD = libluatex.a libff.a libluamisc.a libluasocket.a $(LUA_LIBS) $(luatex_postldadd)
+luatex_LDADD = libluatex.a libff.a libluamisc.a libluasocket.a libluaffi.a $(LUA_LIBS) $(luatex_postldadd)
 luajittex_LDADD = libluajittex.a libff.a libluajitmisc.a libluajitsocket.a $(LUAJIT_LIBS) $(luatex_postldadd)
 
 luatex_depend = $(proglib) $(KPATHSEA_DEPEND) $(LIBPNG_DEPEND) libmputil.a libmd5.a

Modified: trunk/Build/source/texk/web2c/luatexdir/font/luafont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/luafont.w	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/font/luafont.w	2017-02-09 22:44:03 UTC (rev 43177)
@@ -1,2195 +1,2222 @@
-% luafont.w
-%
-% Copyright 2006-2011 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-#define noVERBOSE
-
-/* todo: also keys */
-
-const char *font_type_strings[] = {
-    "unknown", "virtual", "real", NULL
-};
-
-const char *font_writingmode_strings[] = {
-    "unknown", "horizontal", "vertical", NULL
-};
-
-const char *font_identity_strings[] = {
-    "unknown", "horizontal", "vertical", NULL
-};
-
-const char *font_format_strings[] = {
-    "unknown", "type1", "type3", "truetype", "opentype", NULL
-};
-
-const char *font_embedding_strings[] = {
-    "unknown", "no", "subset", "full", NULL
-};
-
-const char *ligature_type_strings[] = {
-    "=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "", "|=:|>>", NULL
-};
-
-const char *MATH_param_names[] = {
-    "nil",
-    "ScriptPercentScaleDown",
-    "ScriptScriptPercentScaleDown",
-    "DelimitedSubFormulaMinHeight",
-    "DisplayOperatorMinHeight",
-    "MathLeading",
-    "AxisHeight",
-    "AccentBaseHeight",
-    "FlattenedAccentBaseHeight",
-    "SubscriptShiftDown",
-    "SubscriptTopMax",
-    "SubscriptBaselineDropMin",
-    "SuperscriptShiftUp",
-    "SuperscriptShiftUpCramped",
-    "SuperscriptBottomMin",
-    "SuperscriptBaselineDropMax",
-    "SubSuperscriptGapMin",
-    "SuperscriptBottomMaxWithSubscript",
-    "SpaceAfterScript",
-    "UpperLimitGapMin",
-    "UpperLimitBaselineRiseMin",
-    "LowerLimitGapMin",
-    "LowerLimitBaselineDropMin",
-    "StackTopShiftUp",
-    "StackTopDisplayStyleShiftUp",
-    "StackBottomShiftDown",
-    "StackBottomDisplayStyleShiftDown",
-    "StackGapMin",
-    "StackDisplayStyleGapMin",
-    "StretchStackTopShiftUp",
-    "StretchStackBottomShiftDown",
-    "StretchStackGapAboveMin",
-    "StretchStackGapBelowMin",
-    "FractionNumeratorShiftUp",
-    "FractionNumeratorDisplayStyleShiftUp",
-    "FractionDenominatorShiftDown",
-    "FractionDenominatorDisplayStyleShiftDown",
-    "FractionNumeratorGapMin",
-    "FractionNumeratorDisplayStyleGapMin",
-    "FractionRuleThickness",
-    "FractionDenominatorGapMin",
-    "FractionDenominatorDisplayStyleGapMin",
-    "SkewedFractionHorizontalGap",
-    "SkewedFractionVerticalGap",
-    "OverbarVerticalGap",
-    "OverbarRuleThickness",
-    "OverbarExtraAscender",
-    "UnderbarVerticalGap",
-    "UnderbarRuleThickness",
-    "UnderbarExtraDescender",
-    "RadicalVerticalGap",
-    "RadicalDisplayStyleVerticalGap",
-    "RadicalRuleThickness",
-    "RadicalExtraAscender",
-    "RadicalKernBeforeDegree",
-    "RadicalKernAfterDegree",
-    "RadicalDegreeBottomRaisePercent",
-    "MinConnectorOverlap",
-    "SubscriptShiftDownWithSuperscript",
-    "FractionDelimiterSize",
-    "FractionDelimiterDisplayStyleSize",
-    "NoLimitSubFactor",
-    "NoLimitSupFactor",
-    NULL,
-};
-
-/* here for now, may be useful elsewhere */
-
-int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]);
-
-int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) {
-    const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
-    int i;
-    for (i=0; lst[i]; i++)
-    if (strcmp(lst[i], name) == 0)
-        return i;
-    return -1;
-}
-
-#define dump_intfield(L,n,c) \
-    lua_push_string_by_name(L,n); \
-    lua_pushinteger(L, c); \
-    lua_rawset(L, -3); \
-
-#define dump_stringfield(L,n,c) \
-    lua_push_string_by_name(L,n); \
-    lua_pushstring(L, c); \
-    lua_rawset(L, -3);
-
-#define dump_booleanfield(L,n,c) \
-    lua_push_string_by_name(L,n); \
-    lua_pushboolean(L, c); \
-    lua_rawset(L, -3);
-
-static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id)
-{
-    int i;
-    for (i = 0; i < l; i++) {
-        lua_newtable(L);
-        if (id==top_left_kern) {
-            dump_intfield(L, height, co->top_left_math_kern_array[(2*i)]);
-            dump_intfield(L, kern,   co->top_left_math_kern_array[(2*i)+1]);
-        } else if (id==top_right_kern) {
-            dump_intfield(L, height, co->top_right_math_kern_array[(2*i)]);
-            dump_intfield(L, kern,   co->top_right_math_kern_array[(2*i)+1]);
-        } else if (id==bottom_right_kern) {
-            dump_intfield(L, height, co->bottom_right_math_kern_array[(2*i)]);
-            dump_intfield(L, kern,   co->bottom_right_math_kern_array[(2*i)+1]);
-        } else if (id==bottom_left_kern) {
-            dump_intfield(L, height, co->bottom_left_math_kern_array[(2*i)]);
-            dump_intfield(L, kern,   co->bottom_left_math_kern_array[(2*i)+1]);
-        }
-        lua_rawseti(L, -2, (i + 1));
-    }
-}
-
-static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co)
-{
-    liginfo *l;
-    kerninfo *ki;
-
-    lua_createtable(L, 0, 10);
-
-    dump_intfield(L,width,get_charinfo_width(co));
-    dump_intfield(L,height,get_charinfo_height(co));
-    dump_intfield(L,depth,get_charinfo_depth(co));
-
-    if (get_charinfo_italic(co) != 0) {
-       dump_intfield(L,italic,get_charinfo_italic(co));
-    }
-    if (get_charinfo_vert_italic(co) != 0) {
-       dump_intfield(L,vert_italic,get_charinfo_vert_italic(co));
-    }
-    if (get_charinfo_top_accent(co) !=0 && get_charinfo_top_accent(co) != INT_MIN) {
-       dump_intfield(L,top_accent,get_charinfo_top_accent(co));
-    }
-    if (get_charinfo_bot_accent(co) != 0 && get_charinfo_bot_accent(co) != INT_MIN) {
-       dump_intfield(L,bot_accent,get_charinfo_bot_accent(co));
-    }
-    if (get_charinfo_ef(co) != 1000) {
-        dump_intfield(L,expansion_factor,get_charinfo_ef(co));
-    }
-    if (get_charinfo_lp(co) != 0) {
-        dump_intfield(L,left_protruding,get_charinfo_lp(co));
-    }
-    if (get_charinfo_rp(co) != 0) {
-        dump_intfield(L,right_protruding,get_charinfo_rp(co));
-    }
-    if (font_encodingbytes(f) == 2) {
-        dump_intfield(L,index,get_charinfo_index(co));
-    }
-    if (get_charinfo_name(co) != NULL) {
-        dump_stringfield(L,name,get_charinfo_name(co));
-    }
-    if (get_charinfo_tounicode(co) != NULL) {
-        dump_stringfield(L,tounicode,get_charinfo_tounicode(co));
-    }
-    if (get_charinfo_tag(co) == list_tag) {
-        dump_intfield(L,next,get_charinfo_remainder(co));
-    }
-    if (get_charinfo_used(co)) {
-        dump_booleanfield(L,used,(get_charinfo_used(co) ? true : false));
-    }
-    if (get_charinfo_tag(co) == ext_tag) {
-        extinfo *h;
-        h = get_charinfo_hor_variants(co);
-        if (h != NULL) {
-            int i = 1;
-            lua_push_string_by_name(L,horiz_variants);
-            lua_newtable(L);
-            while (h != NULL) {
-                lua_createtable(L, 0, 5);
-                dump_intfield(L, glyph, h->glyph);
-                dump_intfield(L, extender, h->extender);
-                dump_intfield(L, start, h->start_overlap);
-                dump_intfield(L, end, h->end_overlap);
-                dump_intfield(L, advance, h->advance);
-                lua_rawseti(L, -2, i);
-                i++;
-                h = h->next;
-            }
-            lua_rawset(L, -3);
-        }
-        h = get_charinfo_vert_variants(co);
-        if (h != NULL) {
-            int i = 1;
-            lua_push_string_by_name(L,vert_variants);
-            lua_newtable(L);
-            while (h != NULL) {
-                lua_createtable(L, 0, 5);
-                dump_intfield(L, glyph, h->glyph);
-                dump_intfield(L, extender, h->extender);
-                dump_intfield(L, start, h->start_overlap);
-                dump_intfield(L, end, h->end_overlap);
-                dump_intfield(L, advance, h->advance);
-                lua_rawseti(L, -2, i);
-                i++;
-                h = h->next;
-            }
-            lua_rawset(L, -3);
-        }
-    }
-    ki = get_charinfo_kerns(co);
-    if (ki != NULL) {
-        int i;
-        lua_push_string_by_name(L,kerns);
-        lua_createtable(L, 10, 1);
-        for (i = 0; !kern_end(ki[i]); i++) {
-            if (kern_disabled(ki[i])) {
-                /* skip like in lookup */
-            } else {
-                lua_rawgeti(L, -1, kern_char(ki[i]));
-                if (lua_type(L,-1) == LUA_TNIL) {
-                    lua_pop(L,1);
-                    if (kern_char(ki[i]) == right_boundarychar) {
-                        lua_push_string_by_name(L,right_boundary);
-                    } else {
-                        lua_pushinteger(L, kern_char(ki[i]));
-                    }
-                    lua_pushinteger(L, kern_kern(ki[i]));
-                    lua_rawset(L, -3);
-                } else {
-                    /* first one wins */
-                    lua_pop(L,1);
-                }
-            }
-        }
-        lua_rawset(L, -3);
-    }
-    l = get_charinfo_ligatures(co);
-    if (l != NULL) {
-        int i;
-        lua_push_string_by_name(L,ligatures);
-        lua_createtable(L, 10, 1);
-        for (i = 0; !lig_end(l[i]); i++) {
-            if (lig_char(l[i]) == right_boundarychar) {
-                lua_push_string_by_name(L,right_boundary);
-            } else {
-                lua_pushinteger(L, lig_char(l[i]));
-            }
-            lua_createtable(L, 0, 2);
-            lua_push_string_by_name(L,type);
-            lua_pushinteger(L, lig_type(l[i]));
-            lua_rawset(L, -3);
-            lua_push_string_by_name(L,char);
-            lua_pushinteger(L, lig_replacement(l[i]));
-            lua_rawset(L, -3);
-            lua_rawset(L, -3);
-        }
-        lua_rawset(L, -3);
-    }
-
-    lua_push_string_by_name(L,mathkern);
-    lua_newtable(L);
-    {
-    int i, j;
-    i = get_charinfo_math_kerns(co, top_right_kern);
-    j = 0;
-    if (i > 0) {
-        j++;
-        lua_push_string_by_name(L,top_right);
-        lua_newtable(L);
-        dump_math_kerns(L, co, i, top_right_kern);
-        lua_rawset(L, -3);
-    }
-    i = get_charinfo_math_kerns(co, top_left_kern);
-    if (i > 0) {
-        j++;
-        lua_push_string_by_name(L,top_left);
-        lua_newtable(L);
-        dump_math_kerns(L, co, i, top_left_kern);
-        lua_rawset(L, -3);
-    }
-    i = get_charinfo_math_kerns(co, bottom_right_kern);
-    if (i > 0) {
-        j++;
-        lua_push_string_by_name(L,bottom_right);
-        lua_newtable(L);
-        dump_math_kerns(L, co, i, bottom_right_kern);
-        lua_rawset(L, -3);
-    }
-    i = get_charinfo_math_kerns(co, bottom_left_kern);
-    if (i > 0) {
-        j++;
-        lua_push_string_by_name(L,bottom_left);
-        lua_newtable(L);
-        dump_math_kerns(L, co, i, bottom_left_kern);
-        lua_rawset(L, -3);
-    }
-    if (j > 0)
-        lua_rawset(L, -3);
-    else
-        lua_pop(L, 2);
-    }
-}
-
-static void write_lua_parameters(lua_State * L, int f)
-{
-    int k;
-    lua_push_string_by_name(L,parameters);
-    lua_newtable(L);
-    for (k = 1; k <= font_params(f); k++) {
-        switch (k) {
-            case slant_code:
-                dump_intfield(L,slant,font_param(f, k));
-                break;
-            case space_code:
-                dump_intfield(L,space,font_param(f, k));
-                break;
-            case space_stretch_code:
-                dump_intfield(L,space_stretch,font_param(f, k));
-                break;
-            case space_shrink_code:
-                dump_intfield(L,space_shrink,font_param(f, k));
-                break;
-            case x_height_code:
-                dump_intfield(L,x_height,font_param(f, k));
-                break;
-            case quad_code:
-                dump_intfield(L,quad,font_param(f, k));
-                break;
-            case extra_space_code:
-                dump_intfield(L,extra_space,font_param(f, k));
-                break;
-            default:
-                lua_pushinteger(L, font_param(f, k));
-                lua_rawseti(L, -2, k);
-        }
-    }
-    lua_rawset(L, -3);
-}
-
-@ @c
-static void write_lua_math_parameters(lua_State * L, int f)
-{
-    int k;
-    lua_push_string_by_name(L,MathConstants);
-    lua_newtable(L);
-    for (k = 1; k <= font_math_params(f); k++) {
-        lua_pushinteger(L, font_math_param(f, k));
-        if (k <= MATH_param_max) {
-            lua_setfield(L, -2, MATH_param_names[k]);
-        } else {
-            lua_rawseti(L, -2, k);
-        }
-    }
-    lua_rawset(L, -3);
-}
-
-int font_to_lua(lua_State * L, int f)
-{
-    int k;
-    charinfo *co;
-    if (font_cache_id(f) > 0) {
-        /* fetch the table from the registry if it was
-           saved there by |font_from_lua()| */
-        lua_rawgeti(L, LUA_REGISTRYINDEX, font_cache_id(f));
-        /* fontdimens can be changed from tex code */
-        write_lua_parameters(L, f);
-        return 1;
-    }
-
-    lua_newtable(L);
-    lua_push_string_by_name(L,name);
-    lua_pushstring(L, font_name(f));
-    lua_rawset(L, -3);
-    if (font_area(f) != NULL) {
-        dump_stringfield(L,area,font_area(f));
-    }
-    if (font_filename(f) != NULL) {
-        dump_stringfield(L,filename,font_filename(f));
-    }
-    if (font_fullname(f) != NULL) {
-        dump_stringfield(L,fullname,font_fullname(f));
-    }
-    if (font_psname(f) != NULL) {
-        dump_stringfield(L,psname,font_psname(f));
-    }
-    if (font_encodingname(f) != NULL) {
-        dump_stringfield(L,encodingname,font_encodingname(f));
-    }
-
-    dump_booleanfield(L,used,(font_used(f) ? true : false));
-    dump_stringfield(L,type,font_type_strings[font_type(f)]);
-    dump_stringfield(L,format,font_format_strings[font_format(f)]);
-    dump_stringfield(L,writingmode,font_writingmode_strings[font_writingmode(f)]);
-    dump_stringfield(L,identity,font_identity_strings[font_identity(f)]);
-    dump_stringfield(L,embedding,font_embedding_strings[font_embedding(f)]);
-
-    dump_intfield(L,units_per_em,font_units_per_em(f));
-    dump_intfield(L,size,font_size(f));
-    dump_intfield(L,designsize,font_dsize(f));
-    dump_intfield(L,checksum,font_checksum(f));
-    dump_intfield(L,slant,font_slant(f));
-    dump_intfield(L,extend,font_extend(f));
-    dump_intfield(L,direction,font_natural_dir(f));
-    dump_intfield(L,encodingbytes,font_encodingbytes(f));
-    dump_booleanfield(L,oldmath,font_oldmath(f));
-    dump_intfield(L,tounicode,font_tounicode(f));
-
-    /* the next one is read only */
-    if (font_max_shrink(f) != 0) {
-        dump_intfield(L,shrink,font_max_shrink(f));
-    }
-    if (font_max_stretch(f) != 0) {
-        dump_intfield(L,stretch,font_max_stretch(f));
-    }
-    if (font_step(f) != 0) {
-        dump_intfield(L,step,font_step(f));
-    }
-    if (font_auto_expand(f) != 0) {
-        dump_booleanfield(L,auto_expand,font_auto_expand(f));
-    }
-    if (pdf_font_attr(f) != 0) {
-        char *s = makecstring(pdf_font_attr(f));
-        dump_stringfield(L,attributes,s);
-        free(s);
-    }
-
-    /* params */
-    write_lua_parameters(L, f);
-    write_lua_math_parameters(L, f);
-
-    /* chars */
-    lua_push_string_by_name(L,characters);
-    lua_createtable(L, font_tables[f]->charinfo_size, 0);       /* all characters */
-    if (has_left_boundary(f)) {
-        co = get_charinfo(f, left_boundarychar);
-        lua_push_string_by_name(L,left_boundary);
-        font_char_to_lua(L, f, co);
-        lua_rawset(L, -3);
-    }
-    if (has_right_boundary(f)) {
-        co = get_charinfo(f, right_boundarychar);
-        lua_push_string_by_name(L,right_boundary);
-        font_char_to_lua(L, f, co);
-        lua_rawset(L, -3);
-    }
-    for (k = font_bc(f); k <= font_ec(f); k++) {
-        if (quick_char_exists(f, k)) {
-            lua_pushinteger(L, k);
-            co = get_charinfo(f, k);
-            font_char_to_lua(L, f, co);
-            lua_rawset(L, -3);
-        }
-    }
-    lua_rawset(L, -3);
-
-    if (font_cache_id(f) == 0) {        /* renew */
-        int r;
-        lua_pushvalue(L, -1);
-        r = luaL_ref(L, LUA_REGISTRYINDEX);     /* pops the table */
-        set_font_cache_id(f, r);
-    }
-    return 1;
-}
-
-#define count_hash_items(L,name,n) \
-    n = 0; \
-    lua_key_rawgeti(name); \
-    if (lua_type(L, -1) == LUA_TTABLE) { \
-        lua_pushnil(L); \
-        while (lua_next(L, -2) != 0) { \
-            n++; \
-            lua_pop(L, 1); \
-        } \
-    } \
-    if (n) { \
-        /* keep table on stack */ \
-    } else{ \
-        lua_pop(L, 1); \
-    }
-
-@ @c
-#define streq(a,b) (strcmp(a,b)==0)
-
-#define append_packet(k) { *(cp++) = (eight_bits) (k); }
-
-#define do_store_four(l) {                 \
-    append_packet((l & 0xFF000000) >> 24); \
-    append_packet((l & 0x00FF0000) >> 16); \
-    append_packet((l & 0x0000FF00) >> 8);  \
-    append_packet((l & 0x000000FF));       \
-}
-
-@ @c
-static void append_float(eight_bits ** cpp, float a)
-{
-    unsigned int i;
-    eight_bits *cp = *cpp;
-    union U {
-        float a;
-        eight_bits b[sizeof(float)];
-    } u;
-    u.a = a;
-    for (i = 0; i < sizeof(float); i++)
-        append_packet(u.b[i]);
-    *cpp = cp;
-}
-
-static int n_enum_field(lua_State * L, int name_index, int dflt, const char **values)
-{
-    int k, t;
-    const char *s;
-    int i = dflt;
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    t = lua_type(L,-1);
-    if (t == LUA_TNUMBER) {
-        i = (int) lua_tointeger(L, -1);
-    } else if (t == LUA_TSTRING) {
-        s = lua_tostring(L, -1);
-        k = 0;
-        while (values[k] != NULL) {
-            if (strcmp(values[k], s) == 0) {
-                i = k;
-                break;
-            }
-            k++;
-        }
-    }
-    lua_pop(L, 1);
-    return i;
-}
-
-static int n_boolean_field(lua_State * L, int name_index, int dflt)
-{
-    int i = dflt;
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    if (lua_isboolean(L, -1)) {
-        i = lua_toboolean(L, -1);
-    }
-    lua_pop(L, 1);
-    return i;
-}
-
-static char *n_string_field_copy(lua_State * L, int name_index, const char *dflt)
-{
-    char *i;
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    if (lua_type(L,-1) == LUA_TSTRING) {
-        i = xstrdup(lua_tostring(L, -1));
-    } else if (dflt == NULL) {
-        i = NULL;
-    } else {
-        i = xstrdup(dflt);
-    }
-    lua_pop(L, 1);
-    return i;
-}
-
-static const char *n_string_field(lua_State * L, int name_index)
-{
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    return lua_tostring(L,-1);
-}
-
-static int n_some_field(lua_State * L, int name_index)
-{
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    return lua_type(L,-1);
-}
-
-/*static void init_font_string_pointers(lua_State * L){}*/
-
-static int count_char_packet_bytes(lua_State * L)
-{
-    register int i;
-    register int l = 0;
-    int ff = 0;
-    for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
-        lua_rawgeti(L, -1, i);
-        if (lua_istable(L, -1)) {
-            lua_rawgeti(L, -1, 1);
-            if (lua_type(L,-1) == LUA_TSTRING) {
-                const char *s = lua_tostring(L, -1);
-                if (lua_key_eq(s, font)) {
-                    l += 5;
-                    ff = 1;
-                } else if (lua_key_eq(s, char)) {
-                    if (ff == 0) {
-                        l += 5;
-                    }
-                    l += 5;
-                    ff = 1;
-                } else if (lua_key_eq(s, slot)) {
-                    l += 10;
-                    ff = 1;
-                } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
-                    ;
-                } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) {
-                    l++;
-                } else if (lua_key_eq(s, rule)) {
-                    l += 9;
-                } else if (lua_key_eq(s, right) || lua_key_eq(s, node)
-                           || lua_key_eq(s, down) || lua_key_eq(s, image)) {
-                    l += 5;
-                } else if (lua_key_eq(s, scale)) {
-                    l += sizeof(float) + 1;
-                } else if (lua_key_eq(s, special) || lua_key_eq(s, lua)) {
-                    size_t len;
-                    lua_rawgeti(L, -2, 2);
-                    if (lua_type(L,-1) == LUA_TSTRING) {
-                        (void) lua_tolstring(L, -1, &len);
-                        lua_pop(L, 1);
-                        if (len > 0) {
-                            l = (int) (l + 5 + (int) len);
-                        }
-                    } else {
-                        lua_pop(L, 1);
-                        normal_error("vf command","invalid packet special");
-                        /* fprintf(stdout, "invalid packet special!\n"); */
-                    }
-                } else {
-                    normal_error("vf command","unknown packet command");
-                    /* fprintf(stdout, "unknown packet command %s!\n", s); */
-                }
-            } else {
-                normal_error("vf command","no packet command");
-             /* fprintf(stdout, "no packet command!\n"); */
-            }
-            lua_pop(L, 1);      /* command name */
-        }
-        lua_pop(L, 1);          /* item */
-    }
-    return l;
-}
-
-static scaled sp_to_dvi(halfword sp, halfword atsize)
-{
-    double result, mult;
-    mult = (double) (atsize / 65536.0);
-    result = (double) (sp * 16.0);
-    return floor(result / mult);
-}
-
-@ @c
-static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, internal_font_number f, int atsize)
-{
-    int i, n, m;
-    size_t l;
-    int cmd;
-    const char *s;
-    eight_bits *cpackets, *cp;
-    int ff = 0;
-    int max_f = 0;
-    int pc = count_char_packet_bytes(L);
-    if (pc <= 0)
-        return;
-    while (l_fonts[(max_f + 1)] != 0)
-        max_f++;
-    cp = cpackets = xmalloc((unsigned) (pc + 1));
-    for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
-        lua_rawgeti(L, -1, i);
-        if (lua_istable(L, -1)) {
-            /* fetch the command code */
-            lua_rawgeti(L, -1, 1);
-            if (lua_type(L,-1) == LUA_TSTRING) {
-                s = lua_tostring(L, -1);
-                cmd = 0;
-                if (lua_key_eq(s, font)) {
-                    cmd = packet_font_code;
-                } else if (lua_key_eq(s, char)) {
-                    cmd = packet_char_code;
-                    if (ff == 0) {
-                        append_packet(packet_font_code);
-                        ff = l_fonts[1];
-                        do_store_four(ff);
-                    }
-                } else if (lua_key_eq(s, slot)) {
-                    cmd = packet_nop_code;
-                    lua_rawgeti(L, -2, 2);
-                    n = (int) luaL_checkinteger(L, -1);
-                    if (n ==0) {
-                        ff = f;
-                    } else {
-                        ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
-                    }
-                    lua_rawgeti(L, -3, 3);
-                    n = (int) luaL_checkinteger(L, -1);
-                    lua_pop(L, 2);
-                    append_packet(packet_font_code);
-                    do_store_four(ff);
-                    append_packet(packet_char_code);
-                    do_store_four(n);
-                } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
-                    cmd = packet_nop_code;
-                } else if (lua_key_eq(s, node)) {
-                    cmd = packet_node_code;
-                } else if (lua_key_eq(s, push)) {
-                    cmd = packet_push_code;
-                } else if (lua_key_eq(s, pop)) {
-                    cmd = packet_pop_code;
-                } else if (lua_key_eq(s, rule)) {
-                    cmd = packet_rule_code;
-                } else if (lua_key_eq(s, right)) {
-                    cmd = packet_right_code;
-                } else if (lua_key_eq(s, down)) {
-                    cmd = packet_down_code;
-                } else if (lua_key_eq(s, special)) {
-                    cmd = packet_special_code;
-                } else if (lua_key_eq(s, image)) {
-                    cmd = packet_image_code;
-                } else if (lua_key_eq(s, scale)) {
-                    cmd = packet_scale_code;
-                } else if (lua_key_eq(s, lua)) {
-                    cmd = packet_lua_code;
-                }
-                switch (cmd) {
-                    case packet_push_code:
-                    case packet_pop_code:
-                        append_packet(cmd);
-                        break;
-                    case packet_font_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        n = (int) luaL_checkinteger(L, -1);
-                        if (n == 0) {
-                            ff = n;
-                        } else {
-                            ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
-                        }
-                        do_store_four(ff);
-                        lua_pop(L, 1);
-                        break;
-                    case packet_node_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        n = copy_node_list(nodelist_from_lua(L));
-                        do_store_four(n);
-                        lua_pop(L, 1);
-                        break;
-                    case packet_char_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        n = (int) luaL_checkinteger(L, -1);
-                        do_store_four(n);
-                        lua_pop(L, 1);
-                        break;
-                    case packet_right_code:
-                    case packet_down_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        n = (int) luaL_checkinteger(L, -1);
-                        do_store_four(sp_to_dvi(n, atsize));
-                        lua_pop(L, 1);
-                        break;
-                    case packet_rule_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        n = (int) luaL_checkinteger(L, -1);
-                        do_store_four(sp_to_dvi(n, atsize));
-                        lua_rawgeti(L, -3, 3);
-                        n = (int) luaL_checkinteger(L, -1);
-                        do_store_four(sp_to_dvi(n, atsize));
-                        lua_pop(L, 2);
-                        break;
-                    case packet_special_code:
-                    case packet_lua_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        s = luaL_checklstring(L, -1, &l);
-                        if (l > 0) {
-                            do_store_four(l);
-                            m = (int) l;
-                            while (m > 0) {
-                                n = *s++;
-                                m--;
-                                append_packet(n);
-                            }
-                        }
-                        lua_pop(L, 1);
-                        break;
-                    case packet_image_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);      /* img/imgtable? ... */
-                        if (lua_istable(L, -1)) {   /* imgtable ... */
-                            lua_getglobal(L, "img");        /* imglib imgtable ... */
-                            lua_pushstring(L, "new");       /* `new' imglib imgtable ... */
-                            lua_gettable(L, -2);    /* f imglib imgtable ... */
-                            lua_insert(L, -3);      /* imglib imgtable f ... */
-                            lua_pop(L, 1);  /* imgtable f ... */
-                            lua_call(L, 1, 1);
-                        }           /* img ... */
-                        luaL_checkudata(L, -1, TYPE_IMG);   /* img ... --- just typecheck */
-                        n = luaL_ref(L, LUA_REGISTRYINDEX);  /* ... */
-                        do_store_four(n);
-                        break;
-                    case packet_nop_code:
-                        break;
-                    case packet_scale_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        append_float(&cp, (float) luaL_checknumber(L, -1));
-                        lua_pop(L, 1);
-                        break;
-                    default:
-                        normal_error("vf command","invalid packet code");
-                        /* fprintf(stdout, "Unknown char packet code %s\n", s); */
-                }
-            }
-            lua_pop(L, 1);      /* command code */
-        } else {
-            normal_error("vf command","commands has to be a tbale");
-            /* fprintf(stdout, "Found a `commands' item that is not a table\n"); */
-        }
-        lua_pop(L, 1);          /* command table */
-    }
-    append_packet(packet_end_code);
-    set_charinfo_packets(co, cpackets);
-    return;
-}
-
-@ @c
-static void read_lua_cidinfo(lua_State * L, int f)
-{
-    int i;
-    char *s;
-    /*lua_getfield(L, -1, "cidinfo");*/
-    lua_key_rawgeti(cidinfo);
-    if (lua_istable(L, -1)) {
-        i = lua_numeric_field_by_index(L,lua_key_index(version), 0);
-        set_font_cidversion(f, i);
-        i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0);
-        set_font_cidsupplement(f, i);
-        s = n_string_field_copy(L, lua_key_index(registry), "Adobe");       /* Adobe-Identity-0 */
-        set_font_cidregistry(f, s);
-        s = n_string_field_copy(L, lua_key_index(ordering), "Identity");
-        set_font_cidordering(f, s);
-    }
-    lua_pop(L, 1);
-}
-
-
-@ @c
-static void read_lua_parameters(lua_State * L, int f)
-{
-    int i, n, t;
-    const char *s;
-    /*lua_getfield(L, -1, "parameters");*/
-    lua_key_rawgeti(parameters);
-    if (lua_istable(L, -1)) {
-        /* the number of parameters is the max(IntegerKeys(L)),7) */
-        n = 7;
-        lua_pushnil(L);         /* first key */
-        while (lua_next(L, -2) != 0) {
-            if (lua_type(L, -2) == LUA_TNUMBER) {
-                i = (int) lua_tointeger(L, -2);
-                if (i > n)
-                    n = i;
-            }
-            lua_pop(L, 1);      /* pop value */
-        }
-        if (n > 7)
-            set_font_params(f, n);
-        /* sometimes it is handy to have all integer keys */
-        for (i = 1; i <= 7; i++) {
-            lua_rawgeti(L, -1, i);
-            if (lua_type(L, -1) == LUA_TNUMBER) {
-                n = lua_roundnumber(L, -1); /* round ? */
-                set_font_param(f, i, n);
-            }
-            lua_pop(L, 1);
-        }
-        lua_pushnil(L);         /* first key */
-        while (lua_next(L, -2) != 0) {
-            t = lua_type(L,-2);
-            if (t == LUA_TNUMBER) {
-                i = (int) lua_tointeger(L, -2);
-                if (i >= 8) {
-                    if (lua_type(L,-1) == LUA_TNUMBER) {
-                        n = lua_roundnumber(L, -1);
-                    } else {
-                        n = 0;
-                    }
-                    set_font_param(f, i, n);
-                }
-            } else if (t == LUA_TSTRING) {
-                s = lua_tostring(L, -2);
-                if (lua_type(L,-1) == LUA_TNUMBER) {
-                    n = lua_roundnumber(L, -1);
-                } else {
-                    n = 0;
-                }
-                if (lua_key_eq(s, slant)) {
-                    set_font_param(f, slant_code, n);
-                } else if (lua_key_eq(s, space)) {
-                    set_font_param(f, space_code, n);
-                } else if (lua_key_eq(s, space_stretch)) {
-                    set_font_param(f, space_stretch_code, n);
-                } else if (lua_key_eq(s, space_shrink)) {
-                    set_font_param(f, space_shrink_code, n);
-                } else if (lua_key_eq(s, x_height)) {
-                    set_font_param(f, x_height_code, n);
-                } else if (lua_key_eq(s, quad)) {
-                    set_font_param(f, quad_code, n);
-                } else if (lua_key_eq(s, extra_space)) {
-                    set_font_param(f, extra_space_code, n);
-                }
-            }
-            lua_pop(L, 1);
-        }
-    }
-    lua_pop(L, 1);
-
-}
-
-@ @c
-static void read_lua_math_parameters(lua_State * L, int f)
-{
-    int i = 0, n = 0, t;
-    /*lua_getfield(L, -1, "MathConstants");*/
-    lua_key_rawgeti(MathConstants);
-    if (lua_istable(L, -1)) {
-        lua_pushnil(L);
-        while (lua_next(L, -2) != 0) {
-            t = lua_type(L,-2);
-            if (t == LUA_TNUMBER) {
-                i = (int) lua_tointeger(L, -2);
-            } else if (t == LUA_TSTRING) {
-                i = ff_checkoption(L, -2, NULL, MATH_param_names);
-            }
-            n = (int) lua_roundnumber(L, -1);
-            if (i > 0) {
-                set_font_math_param(f, i, n);
-            }
-            lua_pop(L, 1);      /* pop value */
-        }
-        set_font_oldmath(f,false);
-    } else {
-        set_font_oldmath(f,true);
-    }
-    lua_pop(L, 1);
-}
-
-@ @c
-#define MIN_INF -0x7FFFFFFF
-
-static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
-{
-    int l, k;
-    scaled ht, krn;
-    lua_key_direct_rawgeti(index);
-    if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) {
-        for (l = 0; l < k; l++) {
-            lua_rawgeti(L, -1, (l + 1));
-            if (lua_istable(L, -1)) {
-                ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF);
-                krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF);
-                if (krn > MIN_INF && ht > MIN_INF)
-                    add_charinfo_math_kern(co, id, ht, krn);
-            }
-            lua_pop(L, 1);
-        }
-    }
-    lua_pop(L, 1);
-}
-
-@ @c
-static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int *l_fonts, boolean has_math)
-{
-    int k, r, t, lt, u, n;
-    charinfo *co;
-    kerninfo *ckerns;
-    liginfo *cligs;
-    scaled j;
-    const char *s;
-    int nl = 0;                 /* number of ligature table items */
-    int nk = 0;                 /* number of kern table items */
-    int ctr = 0;
-    int atsize = font_size(f);
-    if (lua_istable(L, -1)) {
-        co = get_charinfo(f, i);
-        set_charinfo_tag(co, 0);
-        j = lua_numeric_field_by_index(L, lua_key_index(width), 0);
-        set_charinfo_width(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(height), 0);
-        set_charinfo_height(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(depth), 0);
-        set_charinfo_depth(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(italic), 0);
-        set_charinfo_italic(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(vert_italic), 0);
-        set_charinfo_vert_italic(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(index), 0);
-        set_charinfo_index(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 1000);
-        set_charinfo_ef(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0);
-        set_charinfo_lp(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0);
-        set_charinfo_rp(co, j);
-        k = n_boolean_field(L, lua_key_index(used), 0);
-        set_charinfo_used(co, k);
-        s = n_string_field(L, lua_key_index(name));
-        if (s != NULL)
-            set_charinfo_name(co, xstrdup(s));
-        else
-            set_charinfo_name(co, NULL);
-        /* n_string_field leaves a value on stack*/
-        lua_pop(L,1);
-        u = n_some_field(L,lua_key_index(tounicode));
-        if (u == LUA_TNUMBER) {
-            u = lua_tointeger(L,-1);
-            if (u < 0) {
-                set_charinfo_tounicode(co, NULL);
-            } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
-                char *s = malloc(5);
-                sprintf(s,"%04X",(unsigned int) u);
-                set_charinfo_tounicode(co,s);
-            } else {
-                char *s = malloc(9);
-                u = u - 0x10000;
-                sprintf(s,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
-                set_charinfo_tounicode(co,s);
-            }
-        } else if (u == LUA_TTABLE) {
-            n = lua_rawlen(L,-1);
-            u = 0;
-            for (k = 1; k <= n; k++) {
-                lua_rawgeti(L, -1, k);
-                if (lua_type(L,-1) == LUA_TNUMBER) {
-                    u = lua_tointeger(L,-1);
-                } else {
-                    lua_pop(L, 1);
-                    break;
-                }
-                if (u < 0) {
-                    u = -1;
-                    lua_pop(L, 1);
-                    break;
-                } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
-                    u = u + 4;
-                } else {
-                    u = u + 8;
-                }
-                lua_pop(L, 1);
-            }
-            if (u>0) {
-                char *s = malloc(u+1);
-                char *t = s ;
-                for (k = 1; k <= n; k++) {
-                    lua_rawgeti(L, -1, k);
-                    u = lua_tointeger(L,-1);
-                    if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
-                        sprintf(t,"%04X",(unsigned int) u);
-                        t += 4;
-                    } else {
-                        u = u - 0x10000;
-                        sprintf(t,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
-                        t += 8;
-                    }
-                    lua_pop(L, 1);
-                }
-                set_charinfo_tounicode(co,s);
-            } else {
-                set_charinfo_tounicode(co, NULL);
-            }
-        } else if (u == LUA_TSTRING) {
-            s = lua_tostring(L,-1);
-            set_charinfo_tounicode(co, xstrdup(s));
-        } else {
-            set_charinfo_tounicode(co, NULL);
-        }
-        /* ... leaves a value on stack*/
-        lua_pop(L,1);
-
-        if (has_math) {
-            j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN);
-            set_charinfo_top_accent(co, j);
-            j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN);
-            set_charinfo_bot_accent(co, j);
-            k = lua_numeric_field_by_index(L, lua_key_index(next), -1);
-            if (k >= 0) {
-                set_charinfo_tag(co, list_tag);
-                set_charinfo_remainder(co, k);
-            }
-
-            lua_key_rawgeti(extensible);
-            if (lua_istable(L, -1)) {
-                int top, bot, mid, rep;
-                top = lua_numeric_field_by_index(L, lua_key_index(top), 0);
-                bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0);
-                mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0);
-                rep = lua_numeric_field_by_index(L, lua_key_index(rep), 0);
-                if (top != 0 || bot != 0 || mid != 0 || rep != 0) {
-                    set_charinfo_tag(co, ext_tag);
-                    set_charinfo_extensible(co, top, bot, mid, rep);
-                } else {
-                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid extensible field",
-                        font_name(f), (int) i);
-                }
-            }
-            lua_pop(L, 1);
-
-            lua_key_rawgeti(horiz_variants);
-            if (lua_istable(L, -1)) {
-                int glyph, startconnect, endconnect, advance, extender;
-                extinfo *h;
-                set_charinfo_tag(co, ext_tag);
-                set_charinfo_hor_variants(co, NULL);
-                for (k = 1;; k++) {
-                    lua_rawgeti(L, -1, k);
-                    if (lua_istable(L, -1)) {
-                        glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
-                        extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
-                        startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
-                        endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
-                        advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
-                        h = new_variant(glyph, startconnect, endconnect, advance, extender);
-                        add_charinfo_hor_variant(co, h);
-                        lua_pop(L, 1);
-                    } else {
-                        lua_pop(L, 1);
-                        break;
-                    }
-                }
-            }
-            lua_pop(L, 1);
-
-            lua_key_rawgeti(vert_variants);
-            if (lua_istable(L, -1)) {
-                int glyph, startconnect, endconnect, advance, extender;
-                extinfo *h;
-                set_charinfo_tag(co, ext_tag);
-                set_charinfo_vert_variants(co, NULL);
-                for (k = 1;; k++) {
-                    lua_rawgeti(L, -1, k);
-                    if (lua_istable(L, -1)) {
-                        glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
-                        extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
-                        startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
-                        endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
-                        advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
-                        h = new_variant(glyph, startconnect, endconnect, advance, extender);
-                        add_charinfo_vert_variant(co, h);
-                        lua_pop(L, 1);
-                    } else {
-                        lua_pop(L, 1);
-                        break;
-                    }
-                }
-            }
-            lua_pop(L, 1);
-
-            /*
-                Here is a complete example:
-
-                |mathkern = {|
-                    | bottom_left  = { { height = 420, kern = 80  }, { height = 520, kern = 4   } },|
-                    | bottom_right = { { height = 0,   kern = 48  } },|
-                    | top_left     = { { height = 620, kern = 0   }, { height = 720, kern = -80 } },|
-                    | top_right    = { { height = 676, kern = 115 }, { height = 776, kern = 45  } },|
-                |}|
-
-            */
-
-            lua_key_rawgeti(mathkern);
-            if (lua_istable(L, -1)) {
-                store_math_kerns(L,lua_key_index(top_left), co, top_left_kern);
-                store_math_kerns(L,lua_key_index(top_right), co, top_right_kern);
-                store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern);
-                store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern);
-            }
-            lua_pop(L, 1);
-        }
-        /* end of |has_math| */
-        count_hash_items(L, kerns, nk);
-        if (nk > 0) {
-            /* kerns table still on stack */
-            ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo));
-            ctr = 0;
-            lua_pushnil(L); /* traverse hash */
-            while (lua_next(L, -2) != 0) {
-                k = non_boundarychar;
-                lt = lua_type(L,-2);
-                if (lt == LUA_TNUMBER) {
-                    k = (int) lua_tointeger(L, -2); /* adjacent char */
-                    if (k < 0)
-                        k = non_boundarychar;
-                } else if (lt == LUA_TSTRING) {
-                    s = lua_tostring(L, -2);
-                    if (lua_key_eq(s, right_boundary)) {
-                        k = right_boundarychar;
-                        if (!has_right_boundary(f))
-                            set_right_boundary(f, get_charinfo(f, right_boundarychar));
-                    }
-                }
-                j = lua_roundnumber(L, -1); /* movement */
-                if (k != non_boundarychar) {
-                    set_kern_item(ckerns[ctr], k, j);
-                    ctr++;
-                } else {
-                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kern field",
-                        font_name(f), (int) i);
-                }
-                lua_pop(L, 1);
-            }
-            /* guard against empty tables */
-            if (ctr > 0) {
-                set_kern_item(ckerns[ctr], end_kern, 0);
-                set_charinfo_kerns(co, ckerns);
-            } else {
-                formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kerns field",
-                    font_name(f), (int) i);
-            }
-            lua_pop(L, 1);
-        }
-
-        /* packet commands */
-        lua_key_rawgeti(commands);
-        if (lua_istable(L, -1)) {
-            lua_pushnil(L);     /* first key */
-            if (lua_next(L, -2) != 0) {
-                lua_pop(L, 2);
-                read_char_packets(L, (int *) l_fonts, co, f, atsize);
-            }
-        }
-        lua_pop(L, 1);
-
-        /* ligatures */
-        count_hash_items(L, ligatures, nl);
-        if (nl > 0) {
-            /* ligatures table still on stack */
-            cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo));
-            ctr = 0;
-            lua_pushnil(L); /* traverse hash */
-            while (lua_next(L, -2) != 0) {
-                k = non_boundarychar;
-                lt = lua_type(L,-2);
-                if (lt == LUA_TNUMBER) {
-                    k = (int) lua_tointeger(L, -2); /* adjacent char */
-                    if (k < 0) {
-                        k = non_boundarychar;
-                    }
-                } else if (lt == LUA_TSTRING) {
-                    s = lua_tostring(L, -2);
-                    if (lua_key_eq(s, right_boundary)) {
-                        k = right_boundarychar;
-                        if (!has_right_boundary(f))
-                            set_right_boundary(f, get_charinfo(f, right_boundarychar));
-                    }
-                }
-                r = -1;
-                if (lua_istable(L, -1)) {
-                    r = lua_numeric_field_by_index(L, lua_key_index(char), -1);    /* ligature */
-                }
-                if (r != -1 && k != non_boundarychar) {
-                    t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings);
-                    set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, r);
-                    ctr++;
-                } else {
-                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligature field",
-                        font_name(f), (int) i);
-                }
-                lua_pop(L, 1);      /* iterator value */
-            }
-            /* guard against empty tables */
-            if (ctr > 0) {
-                set_ligature_item(cligs[ctr], 0, end_ligature, 0);
-                set_charinfo_ligatures(co, cligs);
-            } else {
-                formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligatures field",
-                    font_name(f), (int) i);
-            }
-            lua_pop(L, 1);      /* ligatures table */
-        }
-    }
-}
-
-@ The caller has to fix the state of the lua stack when there is an error!
-
- at c
-int font_from_lua(lua_State * L, int f)
-{
-    int i, n, r, t, lt;
-    int s_top;                  /* lua stack top */
-    int bc;                     /* first char index */
-    int ec;                     /* last char index */
-    char *s;
-    const char *ss;
-    int *l_fonts = NULL;
-    int save_ref ;
-    boolean no_math = false;
-
-    /* will we save a cache of the luat table? */
-
-    save_ref = 1; /* we start with  ss = "yes" */
-    ss = NULL;
-    ss = n_string_field(L, lua_key_index(cache));
-    if (lua_key_eq(ss, no))
-        save_ref = -1;
-    else if (lua_key_eq(ss, renew))
-        save_ref = 0;
-    /* n_string_field leaves a value on stack*/
-    lua_pop(L,1);
-
-    /* the table is at stack index -1 */
-
-    s = n_string_field_copy(L,lua_key_index(area), "");
-    set_font_area(f, s);
-    s = n_string_field_copy(L, lua_key_index(filename), NULL);
-    set_font_filename(f, s);
-    s = n_string_field_copy(L, lua_key_index(encodingname), NULL);
-    set_font_encodingname(f, s);
-
-    s = n_string_field_copy(L, lua_key_index(name), NULL);
-    set_font_name(f, s);
-    s = n_string_field_copy(L, lua_key_index(fullname), font_name(f));
-    set_font_fullname(f, s);
-
-    if (s == NULL) {
-        formatted_error("font","lua-loaded font '%d' has no name!", f);
-        return false;
-    }
-    s = n_string_field_copy(L, lua_key_index(psname), NULL);
-    set_font_psname(f, s);
-
-    i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0);
-    set_font_units_per_em(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360);
-    set_font_dsize(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f));
-    set_font_size(f, i);
-    set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ;
-    i = lua_numeric_field_by_index(L,lua_key_index(direction), 0);
-    set_font_natural_dir(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0);
-    set_font_encodingbytes(f, (char) i);
-    i = n_boolean_field(L,lua_key_index(oldmath), 0);
-    set_font_oldmath(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0);
-    set_font_tounicode(f, (char) i);
-
-    i = lua_numeric_field_by_index(L,lua_key_index(extend), 1000);
-    if (i < FONT_EXTEND_MIN)
-        i = FONT_EXTEND_MIN;
-    if (i > FONT_EXTEND_MAX)
-        i = FONT_EXTEND_MAX;
-    set_font_extend(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(slant), 0);
-    if (i < FONT_SLANT_MIN)
-        i = FONT_SLANT_MIN;
-    if (i > FONT_SLANT_MAX)
-        i = FONT_SLANT_MAX;
-    set_font_slant(f, i);
-
-    i = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), default_hyphen_char_par);
-    set_hyphen_char(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(skewchar), default_skew_char_par);
-    set_skew_char(f, i);
-    i = n_boolean_field(L, lua_key_index(used), 0);
-    set_font_used(f, (char) i);
-
-    s = n_string_field_copy(L, lua_key_index(attributes), NULL);
-    if (s != NULL && strlen(s) > 0) {
-        i = maketexstring(s);
-        set_pdf_font_attr(f, i);
-    }
-    free(s);
-
-    i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings);
-    set_font_type(f, i);
-    i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings);
-    set_font_format(f, i);
-    i = n_enum_field(L, lua_key_index(writingmode), unknown_writingmode, font_writingmode_strings);
-    set_font_writingmode(f, i);
-    i = n_enum_field(L, lua_key_index(identity), unknown_identity, font_identity_strings);
-    set_font_identity(f, i);
-    i = n_enum_field(L, lua_key_index(embedding), unknown_embedding, font_embedding_strings);
-    set_font_embedding(f, i);
-    if (font_encodingbytes(f) == 0 && (font_format(f) == opentype_format || font_format(f) == truetype_format)) {
-        set_font_encodingbytes(f, 2);
-    }
-
-    /* now fetch the base fonts, if needed */
-    count_hash_items(L, fonts, n);
-    if (n > 0) {
-        /* font table still on stack */
-        l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
-        memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
-        for (i = 1; i <= n; i++) {
-            lua_rawgeti(L, -1, i);
-            if (lua_istable(L, -1)) {
-                lua_key_rawgeti(id);
-                if (lua_isnumber(L, -1)) {
-                    l_fonts[i] = (int) lua_tointeger(L, -1);
-                    if (l_fonts[i] == 0) {
-                        l_fonts[i] = (int) f;
-                    }
-                    lua_pop(L, 2); /* pop id and entry */
-                    continue;
-                }
-                lua_pop(L, 1); /* pop id */
-            };
-            ss = NULL;
-            if (lua_istable(L, -1)) {
-                ss = n_string_field(L, lua_key_index(name));
-                /* string is anchored */
-                lua_pop(L,1);
-            }
-            if (ss != NULL) {
-                t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
-                /* TODO: the stack is messed up, otherwise this explicit resizing would not be needed */
-                s_top = lua_gettop(L);
-                if (strcmp(font_name(f), ss) == 0)
-                    l_fonts[i] = f;
-                else
-                    l_fonts[i] = find_font_id(ss, t);
-                lua_settop(L, s_top);
-            } else {
-                formatted_error("font","invalid local font in lua-loaded font '%s'", font_name(f));
-            }
-            lua_pop(L, 1); /* pop list entry */
-        }
-        lua_pop(L, 1); /* pop font table */
-    } else if (font_type(f) == virtual_font_type) {
-        formatted_error("font","invalid local fonts in lua-loaded font '%s'", font_name(f));
-    } else {
-        l_fonts = xmalloc(3 * sizeof(int));
-        l_fonts[0] = 0;
-        l_fonts[1] = f;
-        l_fonts[2] = 0;
-    }
-
-    /* parameters */
-    no_math = n_boolean_field(L, lua_key_index(nomath), 0);
-    read_lua_parameters(L, f);
-    if (!no_math) {
-        read_lua_math_parameters(L, f);
-        if (n_boolean_field(L, lua_key_index(oldmath), 0)) {
-            set_font_oldmath(f,true);
-        }
-
-    } else {
-        set_font_oldmath(f,true);
-    }
-    read_lua_cidinfo(L, f);
-
-    /* characters */
-    lua_key_rawgeti(characters);
-    if (lua_istable(L, -1)) {
-        /* find the array size values */
-        int num = 0;            /* number of charinfo's to add */
-        ec = 0;
-        bc = -1;
-        lua_pushnil(L);         /* first key */
-        while (lua_next(L, -2) != 0) {
-            if (lua_isnumber(L, -2)) {
-                i = (int) lua_tointeger(L, -2);
-                if (i >= 0) {
-                    if (lua_istable(L, -1)) {
-                        num++;
-                        if (i > ec)
-                            ec = i;
-                        if (bc < 0)
-                            bc = i;
-                        if (bc >= 0 && i < bc)
-                            bc = i;
-                    }
-                }
-            }
-            lua_pop(L, 1);
-        }
-        if (bc != -1) {
-            font_malloc_charinfo(f, num);
-            set_font_bc(f, bc);
-            set_font_ec(f, ec);
-            lua_pushnil(L);     /* first key */
-            while (lua_next(L, -2) != 0) {
-                lt = lua_type(L,-2);
-                if (lt == LUA_TNUMBER) {
-                    i = (int) lua_tointeger(L, -2);
-                    if (i >= 0) {
-                        font_char_from_lua(L, f, i, l_fonts, !no_math);
-                    }
-                } else if (lt == LUA_TSTRING) {
-                    const char *ss1 = lua_tostring(L, -2);
-                    if (lua_key_eq(ss1, left_boundary)) {
-                        font_char_from_lua(L, f, left_boundarychar, l_fonts,
-                                           !no_math);
-                    } else if (lua_key_eq(ss1, right_boundary)) {
-                        font_char_from_lua(L, f, right_boundarychar, l_fonts,
-                                           !no_math);
-                    }
-                }
-                lua_pop(L, 1);
-            }
-            lua_pop(L, 1);
-
-            /*
-                Handle font expansion last: the |copy_font| routine is called eventually,
-                and that needs to know |bc| and |ec|.
-            */
-
-            if (font_type(f) != virtual_font_type) {
-                int fstep = lua_numeric_field_by_index(L, lua_key_index(step), 0);
-                if (fstep < 0)
-                    fstep = 0;
-                if (fstep > 100)
-                    fstep = 100;
-                if (fstep != 0) {
-                    int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0);
-                    int fstretch =lua_numeric_field_by_index(L, lua_key_index(stretch), 0);
-                    int fexpand = n_boolean_field(L, lua_key_index(auto_expand), 0);
-                    if (fshrink < 0)
-                        fshrink = 0;
-                    if (fshrink > 500)
-                        fshrink = 500;
-                    fshrink -= (fshrink % fstep);
-                    if (fshrink < 0)
-                        fshrink = 0;
-                    if (fstretch < 0)
-                        fstretch = 0;
-                    if (fstretch > 1000)
-                        fstretch = 1000;
-                    fstretch -= (fstretch % fstep);
-                    if (fstretch < 0)
-                        fstretch = 0;
-                    set_expand_params(f, fexpand, fstretch, fshrink, fstep);
-                }
-            }
-
-        } else {
-            /* jikes, no characters */
-            formatted_warning("font","lua-loaded font '%d' with name '%s' has no characters", f, font_name(f));
-        }
-
-        if (save_ref > 0) {
-            r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */
-            set_font_cache_id(f, r);
-        } else {
-            lua_pop(L, 1);
-            set_font_cache_id(f, save_ref);
-        }
-    } else {
-        /* jikes, no characters */
-        formatted_warning("font","lua-loaded font '%d' with name '%s' has no character table", f, font_name(f));
-    }
-    if (l_fonts != NULL)
-        free(l_fonts);
-    return true;
-}
-
-@* Ligaturing.
-
- at c
-static void nesting_append(halfword nest1, halfword newn)
-{
-    halfword tail = tlink(nest1);
-    if (tail == null) {
-        couple_nodes(nest1, newn);
-    } else {
-        couple_nodes(tail, newn);
-    }
-    tlink(nest1) = newn;
-}
-
-static void nesting_prepend(halfword nest1, halfword newn)
-{
-    halfword head = vlink(nest1);
-    couple_nodes(nest1, newn);
-    if (head == null) {
-        tlink(nest1) = newn;
-    } else {
-        couple_nodes(newn, head);
-    }
-}
-
-static void nesting_prepend_list(halfword nest1, halfword newn)
-{
-    halfword head = vlink(nest1);
-    couple_nodes(nest1, newn);
-    if (head == null) {
-        tlink(nest1) = tail_of_list(newn);
-    } else {
-        halfword tail = tail_of_list(newn);
-        couple_nodes(tail, head);
-    }
-}
-
-static int test_ligature(liginfo * lig, halfword left, halfword right)
-{
-    if (type(left) != glyph_node)
-        return 0;
-    if (font(left) != font(right))
-        return 0;
-    if (is_ghost(left) || is_ghost(right))
-        return 0;
-    *lig = get_ligature(font(left), character(left), character(right));
-    if (is_valid_ligature(*lig)) {
-        return 1;
-    }
-    return 0;
-}
-
-static int try_ligature(halfword * frst, halfword fwd)
-{
-    halfword cur = *frst;
-    liginfo lig;
-    if (test_ligature(&lig, cur, fwd)) {
-        int move_after = (lig_type(lig) & 0x0C) >> 2;
-        int keep_right = ((lig_type(lig) & 0x01) != 0);
-        int keep_left = ((lig_type(lig) & 0x02) != 0);
-        halfword newgl = raw_glyph_node();
-        font(newgl) = font(cur);
-        character(newgl) = lig_replacement(lig);
-        set_is_ligature(newgl);
-        /*
-            below might not be correct in contrived border case.
-            but we use it only for debugging, so ...
-        */
-        if (character(cur) < 0) {
-            set_is_leftboundary(newgl);
-        }
-        if (character(fwd) < 0) {
-            set_is_rightboundary(newgl);
-        }
-        if (character(cur) < 0) {
-            if (character(fwd) < 0) {
-                build_attribute_list(newgl);
-            } else {
-                add_node_attr_ref(node_attr(fwd));
-                node_attr(newgl) = node_attr(fwd);
-            }
-        } else {
-            add_node_attr_ref(node_attr(cur));
-            node_attr(newgl) = node_attr(cur);
-        }
-
-        /*
-            TODO/FIXME if this ligature is consists of another ligature
-            we should add it's |lig_ptr| to the new glyphs |lig_ptr| (and
-            cleanup the no longer needed node) LOW PRIORITY
-        */
-        /* left side */
-        if (keep_left) {
-            halfword new_first = copy_node(cur);
-            lig_ptr(newgl) = new_first;
-            couple_nodes(cur, newgl);
-            if (move_after) {
-                move_after--;
-                cur = newgl;
-            }
-        } else {
-            halfword prev = alink(cur);
-            uncouple_node(cur);
-            lig_ptr(newgl) = cur;
-            couple_nodes(prev, newgl);
-            cur = newgl;        /* as cur has disappeared */
-        }
-        /* right side */
-        if (keep_right) {
-            halfword new_second = copy_node(fwd);
-            /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
-            couple_nodes(lig_ptr(newgl), new_second);
-            couple_nodes(newgl, fwd);
-            if (move_after) {
-                move_after--;
-                cur = fwd;
-            }
-        } else {
-            halfword next = vlink(fwd);
-            uncouple_node(fwd);
-            /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
-            couple_nodes(lig_ptr(newgl), fwd);
-            if (next != null) {
-                couple_nodes(newgl, next);
-            }
-        }
-        /* check and return */
-        *frst = cur;
-        return 1;
-    }
-    return 0;
-}
-
-@ there shouldn't be any ligatures here - we only add them at the end of
- |xxx_break| in a \.{DISC-1 - DISC-2} situation and we stop processing \.{DISC-1}
- (we continue with \.{DISC-1}'s |post_| and |no_break|.
-
- at c
-static halfword handle_lig_nest(halfword root, halfword cur)
-{
-    if (cur == null)
-        return root;
-    while (vlink(cur) != null) {
-        halfword fwd = vlink(cur);
-        if (type(cur) == glyph_node && type(fwd) == glyph_node &&
-                font(cur) == font(fwd) && try_ligature(&cur, fwd)) {
-            continue;
-        }
-        cur = vlink(cur);
-    }
-    tlink(root) = cur;
-    return root;
-}
-
-static halfword handle_lig_word(halfword cur)
-{
-    halfword right = null;
-    if (type(cur) == boundary_node) {
-        halfword prev = alink(cur);
-        halfword fwd = vlink(cur);
-        /* no need to uncouple |cur|, it is freed */
-        flush_node(cur);
-        if (fwd == null) {
-            vlink(prev) = fwd;
-            return prev;
-        }
-        couple_nodes(prev, fwd);
-        if (type(fwd) != glyph_node)
-            return prev;
-        cur = fwd;
-    } else if (has_left_boundary(font(cur))) {
-        halfword prev = alink(cur);
-        halfword p = new_glyph(font(cur), left_boundarychar);
-        couple_nodes(prev, p);
-        couple_nodes(p, cur);
-        cur = p;
-    }
-    if (has_right_boundary(font(cur))) {
-        right = new_glyph(font(cur), right_boundarychar);
-    }
-    while (1) {
-        /* A glyph followed by ... */
-        if (type(cur) == glyph_node) {
-            halfword fwd = vlink(cur);
-            if (fwd == null) {  /* last character of paragraph */
-                if (right == null)
-                    break;
-                /* \.{--\\par} prohibits use of |couple_nodes| here */
-                try_couple_nodes(cur, right);
-                right = null;
-                continue;
-            }
-            if (type(fwd) == glyph_node) {      /* |GLYPH - GLYPH| */
-                if (font(cur) != font(fwd))
-                    break;
-                if (try_ligature(&cur, fwd))
-                    continue;
-            } else if (type(fwd) == disc_node) {        /* |GLYPH - DISC| */
-
-                /* if  \.{a{bx}{}{y}} and \.{a+b=>B} convert to \.{{Bx}{}{ay}} */
-                halfword pre = vlink_pre_break(fwd);
-                halfword nob = vlink_no_break(fwd);
-                halfword next, tail;
-                liginfo lig;
-                /* Check on: a{b?}{?}{?} and a+b=>B : {B?}{?}{a?} */
-                /* Check on: a{?}{?}{b?} and a+b=>B : {a?}{?}{B?} */
-                if ((pre != null && type(pre) == glyph_node
-                     && test_ligature(&lig, cur, pre))
-                    || (nob != null && type(nob) == glyph_node
-                        && test_ligature(&lig, cur, nob))) {
-                    /* move cur from before disc, to skipped part */
-                    halfword prev = alink(cur);
-                    uncouple_node(cur);
-                    couple_nodes(prev, fwd);
-                    nesting_prepend(no_break(fwd), cur);
-                    /* now ligature the |pre_break| */
-                    nesting_prepend(pre_break(fwd), copy_node(cur));
-                    /* As we have removed cur, we need to start again ... */
-                    cur = prev;
-                }
-                /* Check on: a{?}{?}{}b and a+b=>B : {a?}{?b}{B} */
-                next = vlink(fwd);
-                if (nob == null && next != null && type(next) == glyph_node
-                    && test_ligature(&lig, cur, next)) {
-                    /* move |cur| from before |disc| to |no_break| part */
-                    halfword prev = alink(cur);
-                    uncouple_node(cur);
-                    couple_nodes(prev, fwd);
-                    couple_nodes(no_break(fwd), cur);   /* we {\it know\/} it's empty */
-                    /* now copy cur the |pre_break| */
-                    nesting_prepend(pre_break(fwd), copy_node(cur));
-                    /* move next from after disc to |no_break| part */
-                    tail = vlink(next);
-                    uncouple_node(next);
-                    try_couple_nodes(fwd, tail);
-                    couple_nodes(cur, next);    /* we {\it know\/} this works */
-                    tlink(no_break(fwd)) = next;        /* and make sure the list is correct */
-                    /* now copy next to the |post_break| */
-                    nesting_append(post_break(fwd), copy_node(next));
-                    /* As we have removed cur, we need to start again ... */
-                    cur = prev;
-                }
-                /* we are finished with the |pre_break| */
-                handle_lig_nest(pre_break(fwd), vlink_pre_break(fwd));
-            } else if (type(fwd) == boundary_node) {
-                halfword next = vlink(fwd);
-                try_couple_nodes(cur, next);
-                flush_node(fwd);
-                if (right != null) {
-                    flush_node(right);  /* Shame, didn't need it */
-                    /* no need to reset |right|, we're going to leave the loop anyway */
-                }
-                break;
-            } else {
-                /* fwd is something unknown */
-                if (right == null)
-                    break;
-                couple_nodes(cur, right);
-                couple_nodes(right, fwd);
-                right = null;
-                continue;
-            }
-            /* A discretionary followed by ... */
-        } else if (type(cur) == disc_node) {
-            /* If \.{{?}{x}{?}} or \.{{?}{?}{y}} then ... */
-            if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) {
-                halfword prev = 0;
-                halfword fwd;
-                liginfo lig;
-                if (subtype(cur) == select_disc) {
-                    prev = alink(cur);
-                    if (vlink_post_break(cur) != null)
-                        handle_lig_nest(post_break(prev), vlink_post_break(prev));
-                    if (vlink_no_break(cur) != null)
-                        handle_lig_nest(no_break(prev), vlink_no_break(prev));
-                }
-                if (vlink_post_break(cur) != null)
-                    handle_lig_nest(post_break(cur), vlink_post_break(cur));
-                if (vlink_no_break(cur) != null)
-                    handle_lig_nest(no_break(cur), vlink_no_break(cur));
-                while ((fwd = vlink(cur)) != null) {
-                    halfword nob, pst, next;
-                    if (type(fwd) != glyph_node)
-                        break;
-                    if (subtype(cur) != select_disc) {
-                        nob = tlink_no_break(cur);
-                        pst = tlink_post_break(cur);
-                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
-                            (pst == null || !test_ligature(&lig, pst, fwd)))
-                            break;
-                        nesting_append(no_break(cur), copy_node(fwd));
-                        handle_lig_nest(no_break(cur), nob);
-                    } else {
-                        int dobreak = 0;
-                        nob = tlink_no_break(prev);
-                        pst = tlink_post_break(prev);
-                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
-                            (pst == null || !test_ligature(&lig, pst, fwd)))
-                            dobreak = 1;
-                        if (!dobreak) {
-                            nesting_append(no_break(prev), copy_node(fwd));
-                            handle_lig_nest(no_break(prev), nob);
-                            nesting_append(post_break(prev), copy_node(fwd));
-                            handle_lig_nest(post_break(prev), pst);
-                        }
-                        dobreak = 0;
-                        nob = tlink_no_break(cur);
-                        pst = tlink_post_break(cur);
-                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
-                            (pst == null || !test_ligature(&lig, pst, fwd)))
-                            dobreak = 1;
-                        if (!dobreak) {
-                            nesting_append(no_break(cur), copy_node(fwd));
-                            handle_lig_nest(no_break(cur), nob);
-                        }
-                        if (dobreak)
-                            break;
-                    }
-                    next = vlink(fwd);
-                    uncouple_node(fwd);
-                    try_couple_nodes(cur, next);
-                    nesting_append(post_break(cur), fwd);
-                    handle_lig_nest(post_break(cur), pst);
-                }
-                if (fwd != null && type(fwd) == disc_node) {
-                        halfword next = vlink(fwd);
-                        if (vlink_no_break(fwd) == null
-                        && vlink_post_break(fwd) == null
-                        && next != null
-                        && type(next) == glyph_node
-                        && ((tlink_post_break(cur) != null && test_ligature(&lig, tlink_post_break(cur), next)) ||
-                            (tlink_no_break  (cur) != null && test_ligature(&lig, tlink_no_break  (cur), next)))) {
-                        /* Building an |init_disc| followed by a |select_disc|
-                          \.{{a-}{b}{AB} {-}{}{}} 'c'
-                         */
-                        /* is it tail necessary ? */
-                        halfword last1 = vlink(next), tail ;
-                        uncouple_node(next);
-                        try_couple_nodes(fwd, last1);
-                        /* \.{{a-}{b}{AB} {-}{c}{}} */
-                        nesting_append(post_break(fwd), copy_node(next));
-                        /* \.{{a-}{b}{AB} {-}{c}{-}} */
-                        if (vlink_no_break(cur) != null) {
-                            nesting_prepend(no_break(fwd), copy_node(vlink_pre_break(fwd)));
-                        }
-                        /* \.{{a-}{b}{AB} {b-}{c}{-}} */
-                        if (vlink_post_break(cur) != null)
-                            nesting_prepend_list(pre_break(fwd), copy_node_list(vlink_post_break(cur)));
-                        /* \.{{a-}{b}{AB} {b-}{c}{AB-}} */
-                        if (vlink_no_break(cur) != null) {
-                            nesting_prepend_list(no_break(fwd), copy_node_list(vlink_no_break(cur)));
-                        }
-                        /* \.{{a-}{b}{ABC} {b-}{c}{AB-}} */
-                        tail = tlink_no_break(cur);
-                        nesting_append(no_break(cur), copy_node(next));
-                        handle_lig_nest(no_break(cur), tail);
-                        /* \.{{a-}{BC}{ABC} {b-}{c}{AB-}} */
-                        tail = tlink_post_break(cur);
-                        nesting_append(post_break(cur), next);
-                        handle_lig_nest(post_break(cur), tail);
-                        /* and set the subtypes */
-                        subtype(cur) = init_disc;
-                        subtype(fwd) = select_disc;
-                    }
-                }
-            }
-
-        } else {
-            /* NO GLYPH NOR DISC */
-            return cur;
-        }
-        /* step-to-next-node */
-        /* \.{--\\par} allows |vlink(cur)| to be null */
-        cur = vlink(cur);
-    }
-
-    return cur;
-}
-
-@ Return value is the new tail, head should be a dummy
-
- at c
-halfword handle_ligaturing(halfword head, halfword tail)
-{
-    halfword save_tail1; /* trick to allow explicit |node==null| tests */
-    halfword cur, prev;
-
-    if (vlink(head) == null)
-        return tail;
-    save_tail1 = vlink(tail);
-    vlink(tail) = null;
-
-    /* |if (fix_node_lists)| */
-    fix_node_list(head);
-
-    prev = head;
-    cur = vlink(prev);
-
-    while (cur != null) {
-        if (type(cur) == glyph_node || (type(cur) == boundary_node)) {
-            cur = handle_lig_word(cur);
-        }
-        prev = cur;
-        cur = vlink(cur);
-    }
-    if (prev == null)
-        prev = tail;
-
-    if (valid_node(save_tail1)) {
-        try_couple_nodes(prev, save_tail1);
-    }
-    return prev;
-}
-
-
-@* Kerning.
-
- at c
-static void add_kern_before(halfword left, halfword right)
-{
-    if ((!is_rightghost(right)) &&
-        font(left) == font(right) && has_kern(font(left), character(left))) {
-        int k = raw_get_kern(font(left), character(left), character(right));
-        if (k != 0) {
-            halfword kern = new_kern(k);
-            halfword prev = alink(right);
-            couple_nodes(prev, kern);
-            couple_nodes(kern, right);
-            /* update the attribute list (inherit from left) */
-            delete_attribute_ref(node_attr(kern));
-            add_node_attr_ref(node_attr(left));
-            node_attr(kern) = node_attr(left);
-        }
-    }
-}
-
-static void add_kern_after(halfword left, halfword right, halfword aft)
-{
-    if ((!is_rightghost(right)) &&
-        font(left) == font(right) && has_kern(font(left), character(left))) {
-        int k = raw_get_kern(font(left), character(left), character(right));
-        if (k != 0) {
-            halfword kern = new_kern(k);
-            halfword next = vlink(aft);
-            couple_nodes(aft, kern);
-            try_couple_nodes(kern, next);
-            /* update the attribute list (inherit from left == aft) */
-            delete_attribute_ref(node_attr(kern));
-            add_node_attr_ref(node_attr(aft));
-            node_attr(kern) = node_attr(aft);
-        }
-    }
-}
-
-static void do_handle_kerning(halfword root, halfword init_left, halfword init_right)
-{
-    halfword cur = vlink(root);
-    halfword left = null;
-    if (cur == null) {
-        if (init_left != null && init_right != null) {
-            add_kern_after(init_left, init_right, root);
-            tlink(root) = vlink(root);
-        }
-        return;
-    }
-    if (type(cur) == glyph_node) {
-        set_is_glyph(cur);
-        if (init_left != null)
-            add_kern_before(init_left, cur);
-        left = cur;
-    }
-    while ((cur = vlink(cur)) != null) {
-        if (type(cur) == glyph_node) {
-            set_is_glyph(cur);
-            if (left != null) {
-                add_kern_before(left, cur);
-                if (character(left) < 0 || is_ghost(left)) {
-                    halfword prev = alink(left);
-                    couple_nodes(prev, cur);
-                    flush_node(left);
-                }
-            }
-            left = cur;
-        } else {
-            if (type(cur) == disc_node) {
-                halfword right = type(vlink(cur)) == glyph_node ? vlink(cur) : null;
-                do_handle_kerning(pre_break(cur), left, null);
-                do_handle_kerning(post_break(cur), null, right);
-                if (vlink_post_break(cur) != null)
-                    tlink_post_break(cur) = tail_of_list(vlink_post_break(cur));
-                do_handle_kerning(no_break(cur), left, right);
-                if (vlink_no_break(cur) != null)
-                    tlink_no_break(cur) = tail_of_list(vlink_no_break(cur));    /* needed? */
-            }
-            if (left != null) {
-                if (character(left) < 0 || is_ghost(left)) {
-                    halfword prev = alink(left);
-                    couple_nodes(prev, cur);
-                    flush_node(left);
-                }
-                left = null;
-            }
-        }
-    }
-    if (left != null) {
-        if (init_right != null)
-            add_kern_after(left, init_right, left);
-        if (character(left) < 0 || is_ghost(left)) {
-            halfword prev = alink(left);
-            halfword next = vlink(left);
-            if (next != null) {
-                couple_nodes(prev, next);
-                tlink(root) = next;
-            } else if (prev != root) {
-                vlink(prev) = null;
-                tlink(root) = prev;
-            } else {
-                vlink(root) = null;
-                tlink(root) = null;
-            }
-            flush_node(left);
-        }
-    }
-}
-
-halfword handle_kerning(halfword head, halfword tail)
-{
-    halfword save_link;
-    save_link = vlink(tail);
-    vlink(tail) = null;
-    tlink(head) = tail;
-    do_handle_kerning(head, null, null);
-    tail = tlink(head);
-    if (valid_node(save_link)) {
-        try_couple_nodes(tail, save_link);
-    }
-    return tail;
-}
-
-@* ligaturing and kerning : lua-interface.
-
- at c
-static halfword run_lua_ligkern_callback(halfword head, halfword tail, int callback_id)
-{
-    int i;
-    int top = lua_gettop(Luas);
-    if (!get_callback(Luas, callback_id)) {
-        lua_pop(Luas, 2);
-        return tail;
-    }
-    nodelist_to_lua(Luas, head);
-    nodelist_to_lua(Luas, tail);
-    if ((i=lua_pcall(Luas, 2, 0, 0)) != 0) {
-        luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
-        return tail;
-    }
-    fix_node_list(head);
-    lua_settop(Luas, top);
-    return tail;
-}
-
-halfword new_ligkern(halfword head, halfword tail)
-{
-    int callback_id = 0;
-    if (vlink(head) == null)
-        return tail;
-    callback_id = callback_defined(ligaturing_callback);
-    if (callback_id > 0) {
-        tail = run_lua_ligkern_callback(head, tail, callback_id);
-        if (tail == null)
-            tail = tail_of_list(head);
-    } else if (callback_id == 0) {
-        tail = handle_ligaturing(head, tail);
-    }
-    callback_id = callback_defined(kerning_callback);
-    if (callback_id > 0) {
-        tail = run_lua_ligkern_callback(head, tail, callback_id);
-        if (tail == null) {
-            tail = tail_of_list(head);
-        }
-    } else if (callback_id == 0) {
-        halfword nest1 = new_node(nesting_node, 1);
-        halfword cur = vlink(head);
-        halfword aft = vlink(tail);
-        couple_nodes(nest1, cur);
-        tlink(nest1) = tail;
-        vlink(tail) = null;
-        do_handle_kerning(nest1, null, null);
-        couple_nodes(head, vlink(nest1));
-        tail = tlink(nest1);
-        try_couple_nodes(tail, aft);
-        flush_node(nest1);
-    }
-    return tail;
-}
+% luafont.w
+%
+% Copyright 2006-2011 Taco Hoekwater <taco@@luatex.org>
+%
+% This file is part of LuaTeX.
+%
+% LuaTeX is free software; you can redistribute it and/or modify it under
+% the terms of the GNU General Public License as published by the Free
+% Software Foundation; either version 2 of the License, or (at your
+% option) any later version.
+%
+% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+% License for more details.
+%
+% You should have received a copy of the GNU General Public License along
+% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+@ @c
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+#define noVERBOSE
+
+/* todo: also keys */
+
+const char *font_type_strings[] = {
+    "unknown", "virtual", "real", NULL
+};
+
+const char *font_writingmode_strings[] = {
+    "unknown", "horizontal", "vertical", NULL
+};
+
+const char *font_identity_strings[] = {
+    "unknown", "horizontal", "vertical", NULL
+};
+
+const char *font_format_strings[] = {
+    "unknown", "type1", "type3", "truetype", "opentype", NULL
+};
+
+const char *font_embedding_strings[] = {
+    "unknown", "no", "subset", "full", NULL
+};
+
+const char *ligature_type_strings[] = {
+    "=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "", "|=:|>>", NULL
+};
+
+const char *MATH_param_names[] = {
+    "nil",
+    "ScriptPercentScaleDown",
+    "ScriptScriptPercentScaleDown",
+    "DelimitedSubFormulaMinHeight",
+    "DisplayOperatorMinHeight",
+    "MathLeading",
+    "AxisHeight",
+    "AccentBaseHeight",
+    "FlattenedAccentBaseHeight",
+    "SubscriptShiftDown",
+    "SubscriptTopMax",
+    "SubscriptBaselineDropMin",
+    "SuperscriptShiftUp",
+    "SuperscriptShiftUpCramped",
+    "SuperscriptBottomMin",
+    "SuperscriptBaselineDropMax",
+    "SubSuperscriptGapMin",
+    "SuperscriptBottomMaxWithSubscript",
+    "SpaceAfterScript",
+    "UpperLimitGapMin",
+    "UpperLimitBaselineRiseMin",
+    "LowerLimitGapMin",
+    "LowerLimitBaselineDropMin",
+    "StackTopShiftUp",
+    "StackTopDisplayStyleShiftUp",
+    "StackBottomShiftDown",
+    "StackBottomDisplayStyleShiftDown",
+    "StackGapMin",
+    "StackDisplayStyleGapMin",
+    "StretchStackTopShiftUp",
+    "StretchStackBottomShiftDown",
+    "StretchStackGapAboveMin",
+    "StretchStackGapBelowMin",
+    "FractionNumeratorShiftUp",
+    "FractionNumeratorDisplayStyleShiftUp",
+    "FractionDenominatorShiftDown",
+    "FractionDenominatorDisplayStyleShiftDown",
+    "FractionNumeratorGapMin",
+    "FractionNumeratorDisplayStyleGapMin",
+    "FractionRuleThickness",
+    "FractionDenominatorGapMin",
+    "FractionDenominatorDisplayStyleGapMin",
+    "SkewedFractionHorizontalGap",
+    "SkewedFractionVerticalGap",
+    "OverbarVerticalGap",
+    "OverbarRuleThickness",
+    "OverbarExtraAscender",
+    "UnderbarVerticalGap",
+    "UnderbarRuleThickness",
+    "UnderbarExtraDescender",
+    "RadicalVerticalGap",
+    "RadicalDisplayStyleVerticalGap",
+    "RadicalRuleThickness",
+    "RadicalExtraAscender",
+    "RadicalKernBeforeDegree",
+    "RadicalKernAfterDegree",
+    "RadicalDegreeBottomRaisePercent",
+    "MinConnectorOverlap",
+    "SubscriptShiftDownWithSuperscript",
+    "FractionDelimiterSize",
+    "FractionDelimiterDisplayStyleSize",
+    "NoLimitSubFactor",
+    "NoLimitSupFactor",
+    NULL,
+};
+
+/* here for now, may be useful elsewhere */
+
+int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]);
+
+int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) {
+    const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
+    int i;
+    for (i=0; lst[i]; i++)
+    if (strcmp(lst[i], name) == 0)
+        return i;
+    return -1;
+}
+
+#define dump_intfield(L,n,c) \
+    lua_push_string_by_name(L,n); \
+    lua_pushinteger(L, c); \
+    lua_rawset(L, -3); \
+
+#define dump_stringfield(L,n,c) \
+    lua_push_string_by_name(L,n); \
+    lua_pushstring(L, c); \
+    lua_rawset(L, -3);
+
+#define dump_booleanfield(L,n,c) \
+    lua_push_string_by_name(L,n); \
+    lua_pushboolean(L, c); \
+    lua_rawset(L, -3);
+
+static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id)
+{
+    int i;
+    for (i = 0; i < l; i++) {
+        lua_newtable(L);
+        if (id==top_left_kern) {
+            dump_intfield(L, height, co->top_left_math_kern_array[(2*i)]);
+            dump_intfield(L, kern,   co->top_left_math_kern_array[(2*i)+1]);
+        } else if (id==top_right_kern) {
+            dump_intfield(L, height, co->top_right_math_kern_array[(2*i)]);
+            dump_intfield(L, kern,   co->top_right_math_kern_array[(2*i)+1]);
+        } else if (id==bottom_right_kern) {
+            dump_intfield(L, height, co->bottom_right_math_kern_array[(2*i)]);
+            dump_intfield(L, kern,   co->bottom_right_math_kern_array[(2*i)+1]);
+        } else if (id==bottom_left_kern) {
+            dump_intfield(L, height, co->bottom_left_math_kern_array[(2*i)]);
+            dump_intfield(L, kern,   co->bottom_left_math_kern_array[(2*i)+1]);
+        }
+        lua_rawseti(L, -2, (i + 1));
+    }
+}
+
+static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co)
+{
+    liginfo *l;
+    kerninfo *ki;
+
+    lua_createtable(L, 0, 10);
+
+    dump_intfield(L,width,get_charinfo_width(co));
+    dump_intfield(L,height,get_charinfo_height(co));
+    dump_intfield(L,depth,get_charinfo_depth(co));
+
+    if (get_charinfo_italic(co) != 0) {
+       dump_intfield(L,italic,get_charinfo_italic(co));
+    }
+    if (get_charinfo_vert_italic(co) != 0) {
+       dump_intfield(L,vert_italic,get_charinfo_vert_italic(co));
+    }
+    if (get_charinfo_top_accent(co) !=0 && get_charinfo_top_accent(co) != INT_MIN) {
+       dump_intfield(L,top_accent,get_charinfo_top_accent(co));
+    }
+    if (get_charinfo_bot_accent(co) != 0 && get_charinfo_bot_accent(co) != INT_MIN) {
+       dump_intfield(L,bot_accent,get_charinfo_bot_accent(co));
+    }
+    if (get_charinfo_ef(co) != 1000) {
+        dump_intfield(L,expansion_factor,get_charinfo_ef(co));
+    }
+    if (get_charinfo_lp(co) != 0) {
+        dump_intfield(L,left_protruding,get_charinfo_lp(co));
+    }
+    if (get_charinfo_rp(co) != 0) {
+        dump_intfield(L,right_protruding,get_charinfo_rp(co));
+    }
+    if (font_encodingbytes(f) == 2) {
+        dump_intfield(L,index,get_charinfo_index(co));
+    }
+    if (get_charinfo_name(co) != NULL) {
+        dump_stringfield(L,name,get_charinfo_name(co));
+    }
+    if (get_charinfo_tounicode(co) != NULL) {
+        dump_stringfield(L,tounicode,get_charinfo_tounicode(co));
+    }
+    if (get_charinfo_tag(co) == list_tag) {
+        dump_intfield(L,next,get_charinfo_remainder(co));
+    }
+    if (get_charinfo_used(co)) {
+        dump_booleanfield(L,used,(get_charinfo_used(co) ? true : false));
+    }
+    if (get_charinfo_tag(co) == ext_tag) {
+        extinfo *h;
+        h = get_charinfo_hor_variants(co);
+        if (h != NULL) {
+            int i = 1;
+            lua_push_string_by_name(L,horiz_variants);
+            lua_newtable(L);
+            while (h != NULL) {
+                lua_createtable(L, 0, 5);
+                dump_intfield(L, glyph, h->glyph);
+                dump_intfield(L, extender, h->extender);
+                dump_intfield(L, start, h->start_overlap);
+                dump_intfield(L, end, h->end_overlap);
+                dump_intfield(L, advance, h->advance);
+                lua_rawseti(L, -2, i);
+                i++;
+                h = h->next;
+            }
+            lua_rawset(L, -3);
+        }
+        h = get_charinfo_vert_variants(co);
+        if (h != NULL) {
+            int i = 1;
+            lua_push_string_by_name(L,vert_variants);
+            lua_newtable(L);
+            while (h != NULL) {
+                lua_createtable(L, 0, 5);
+                dump_intfield(L, glyph, h->glyph);
+                dump_intfield(L, extender, h->extender);
+                dump_intfield(L, start, h->start_overlap);
+                dump_intfield(L, end, h->end_overlap);
+                dump_intfield(L, advance, h->advance);
+                lua_rawseti(L, -2, i);
+                i++;
+                h = h->next;
+            }
+            lua_rawset(L, -3);
+        }
+    }
+    ki = get_charinfo_kerns(co);
+    if (ki != NULL) {
+        int i;
+        lua_push_string_by_name(L,kerns);
+        lua_createtable(L, 10, 1);
+        for (i = 0; !kern_end(ki[i]); i++) {
+            if (kern_disabled(ki[i])) {
+                /* skip like in lookup */
+            } else {
+                lua_rawgeti(L, -1, kern_char(ki[i]));
+                if (lua_type(L,-1) == LUA_TNIL) {
+                    lua_pop(L,1);
+                    if (kern_char(ki[i]) == right_boundarychar) {
+                        lua_push_string_by_name(L,right_boundary);
+                    } else {
+                        lua_pushinteger(L, kern_char(ki[i]));
+                    }
+                    lua_pushinteger(L, kern_kern(ki[i]));
+                    lua_rawset(L, -3);
+                } else {
+                    /* first one wins */
+                    lua_pop(L,1);
+                }
+            }
+        }
+        lua_rawset(L, -3);
+    }
+    l = get_charinfo_ligatures(co);
+    if (l != NULL) {
+        int i;
+        lua_push_string_by_name(L,ligatures);
+        lua_createtable(L, 10, 1);
+        for (i = 0; !lig_end(l[i]); i++) {
+            if (lig_char(l[i]) == right_boundarychar) {
+                lua_push_string_by_name(L,right_boundary);
+            } else {
+                lua_pushinteger(L, lig_char(l[i]));
+            }
+            lua_createtable(L, 0, 2);
+            lua_push_string_by_name(L,type);
+            lua_pushinteger(L, lig_type(l[i]));
+            lua_rawset(L, -3);
+            lua_push_string_by_name(L,char);
+            lua_pushinteger(L, lig_replacement(l[i]));
+            lua_rawset(L, -3);
+            lua_rawset(L, -3);
+        }
+        lua_rawset(L, -3);
+    }
+
+    lua_push_string_by_name(L,mathkern);
+    lua_newtable(L);
+    {
+    int i, j;
+    i = get_charinfo_math_kerns(co, top_right_kern);
+    j = 0;
+    if (i > 0) {
+        j++;
+        lua_push_string_by_name(L,top_right);
+        lua_newtable(L);
+        dump_math_kerns(L, co, i, top_right_kern);
+        lua_rawset(L, -3);
+    }
+    i = get_charinfo_math_kerns(co, top_left_kern);
+    if (i > 0) {
+        j++;
+        lua_push_string_by_name(L,top_left);
+        lua_newtable(L);
+        dump_math_kerns(L, co, i, top_left_kern);
+        lua_rawset(L, -3);
+    }
+    i = get_charinfo_math_kerns(co, bottom_right_kern);
+    if (i > 0) {
+        j++;
+        lua_push_string_by_name(L,bottom_right);
+        lua_newtable(L);
+        dump_math_kerns(L, co, i, bottom_right_kern);
+        lua_rawset(L, -3);
+    }
+    i = get_charinfo_math_kerns(co, bottom_left_kern);
+    if (i > 0) {
+        j++;
+        lua_push_string_by_name(L,bottom_left);
+        lua_newtable(L);
+        dump_math_kerns(L, co, i, bottom_left_kern);
+        lua_rawset(L, -3);
+    }
+    if (j > 0)
+        lua_rawset(L, -3);
+    else
+        lua_pop(L, 2);
+    }
+}
+
+static void write_lua_parameters(lua_State * L, int f)
+{
+    int k;
+    lua_push_string_by_name(L,parameters);
+    lua_newtable(L);
+    for (k = 1; k <= font_params(f); k++) {
+        switch (k) {
+            case slant_code:
+                dump_intfield(L,slant,font_param(f, k));
+                break;
+            case space_code:
+                dump_intfield(L,space,font_param(f, k));
+                break;
+            case space_stretch_code:
+                dump_intfield(L,space_stretch,font_param(f, k));
+                break;
+            case space_shrink_code:
+                dump_intfield(L,space_shrink,font_param(f, k));
+                break;
+            case x_height_code:
+                dump_intfield(L,x_height,font_param(f, k));
+                break;
+            case quad_code:
+                dump_intfield(L,quad,font_param(f, k));
+                break;
+            case extra_space_code:
+                dump_intfield(L,extra_space,font_param(f, k));
+                break;
+            default:
+                lua_pushinteger(L, font_param(f, k));
+                lua_rawseti(L, -2, k);
+        }
+    }
+    lua_rawset(L, -3);
+}
+
+@ @c
+static void write_lua_math_parameters(lua_State * L, int f)
+{
+    int k;
+    lua_push_string_by_name(L,MathConstants);
+    lua_newtable(L);
+    for (k = 1; k <= font_math_params(f); k++) {
+        lua_pushinteger(L, font_math_param(f, k));
+        if (k <= MATH_param_max) {
+            lua_setfield(L, -2, MATH_param_names[k]);
+        } else {
+            lua_rawseti(L, -2, k);
+        }
+    }
+    lua_rawset(L, -3);
+}
+
+int font_to_lua(lua_State * L, int f)
+{
+    int k;
+    charinfo *co;
+    if (font_cache_id(f) > 0) {
+        /* fetch the table from the registry if it was
+           saved there by |font_from_lua()| */
+        lua_rawgeti(L, LUA_REGISTRYINDEX, font_cache_id(f));
+        /* fontdimens can be changed from tex code */
+        write_lua_parameters(L, f);
+        return 1;
+    }
+
+    lua_newtable(L);
+    lua_push_string_by_name(L,name);
+    lua_pushstring(L, font_name(f));
+    lua_rawset(L, -3);
+    if (font_area(f) != NULL) {
+        dump_stringfield(L,area,font_area(f));
+    }
+    if (font_filename(f) != NULL) {
+        dump_stringfield(L,filename,font_filename(f));
+    }
+    if (font_fullname(f) != NULL) {
+        dump_stringfield(L,fullname,font_fullname(f));
+    }
+    if (font_psname(f) != NULL) {
+        dump_stringfield(L,psname,font_psname(f));
+    }
+    if (font_encodingname(f) != NULL) {
+        dump_stringfield(L,encodingname,font_encodingname(f));
+    }
+
+    dump_booleanfield(L,used,(font_used(f) ? true : false));
+    dump_stringfield(L,type,font_type_strings[font_type(f)]);
+    dump_stringfield(L,format,font_format_strings[font_format(f)]);
+    dump_stringfield(L,writingmode,font_writingmode_strings[font_writingmode(f)]);
+    dump_stringfield(L,identity,font_identity_strings[font_identity(f)]);
+    dump_stringfield(L,embedding,font_embedding_strings[font_embedding(f)]);
+
+    dump_intfield(L,units_per_em,font_units_per_em(f));
+    dump_intfield(L,size,font_size(f));
+    dump_intfield(L,designsize,font_dsize(f));
+    dump_intfield(L,checksum,font_checksum(f));
+    dump_intfield(L,slant,font_slant(f));
+    dump_intfield(L,extend,font_extend(f));
+    dump_intfield(L,direction,font_natural_dir(f));
+    dump_intfield(L,encodingbytes,font_encodingbytes(f));
+    dump_booleanfield(L,oldmath,font_oldmath(f));
+    dump_intfield(L,tounicode,font_tounicode(f));
+
+    /* the next one is read only */
+    if (font_max_shrink(f) != 0) {
+        dump_intfield(L,shrink,font_max_shrink(f));
+    }
+    if (font_max_stretch(f) != 0) {
+        dump_intfield(L,stretch,font_max_stretch(f));
+    }
+    if (font_step(f) != 0) {
+        dump_intfield(L,step,font_step(f));
+    }
+    if (font_auto_expand(f) != 0) {
+        dump_booleanfield(L,auto_expand,font_auto_expand(f));
+    }
+    if (pdf_font_attr(f) != 0) {
+        char *s = makecstring(pdf_font_attr(f));
+        dump_stringfield(L,attributes,s);
+        free(s);
+    }
+
+    /* params */
+    write_lua_parameters(L, f);
+    write_lua_math_parameters(L, f);
+
+    /* chars */
+    lua_push_string_by_name(L,characters);
+    lua_createtable(L, font_tables[f]->charinfo_size, 0);       /* all characters */
+    if (has_left_boundary(f)) {
+        co = get_charinfo(f, left_boundarychar);
+        lua_push_string_by_name(L,left_boundary);
+        font_char_to_lua(L, f, co);
+        lua_rawset(L, -3);
+    }
+    if (has_right_boundary(f)) {
+        co = get_charinfo(f, right_boundarychar);
+        lua_push_string_by_name(L,right_boundary);
+        font_char_to_lua(L, f, co);
+        lua_rawset(L, -3);
+    }
+    for (k = font_bc(f); k <= font_ec(f); k++) {
+        if (quick_char_exists(f, k)) {
+            lua_pushinteger(L, k);
+            co = get_charinfo(f, k);
+            font_char_to_lua(L, f, co);
+            lua_rawset(L, -3);
+        }
+    }
+    lua_rawset(L, -3);
+
+    if (font_cache_id(f) == 0) {        /* renew */
+        int r;
+        lua_pushvalue(L, -1);
+        r = luaL_ref(L, LUA_REGISTRYINDEX);     /* pops the table */
+        set_font_cache_id(f, r);
+    }
+    return 1;
+}
+
+#define count_hash_items(L,name,n) \
+    n = 0; \
+    lua_key_rawgeti(name); \
+    if (lua_type(L, -1) == LUA_TTABLE) { \
+        lua_pushnil(L); \
+        while (lua_next(L, -2) != 0) { \
+            n++; \
+            lua_pop(L, 1); \
+        } \
+    } \
+    if (n) { \
+        /* keep table on stack */ \
+    } else{ \
+        lua_pop(L, 1); \
+    }
+
+@ @c
+#define streq(a,b) (strcmp(a,b)==0)
+
+#define append_packet(k) { *(cp++) = (eight_bits) (k); }
+
+#define do_store_four(l) {                 \
+    append_packet((l & 0xFF000000) >> 24); \
+    append_packet((l & 0x00FF0000) >> 16); \
+    append_packet((l & 0x0000FF00) >> 8);  \
+    append_packet((l & 0x000000FF));       \
+}
+
+@ @c
+static void append_float(eight_bits ** cpp, float a)
+{
+    unsigned int i;
+    eight_bits *cp = *cpp;
+    union U {
+        float a;
+        eight_bits b[sizeof(float)];
+    } u;
+    u.a = a;
+    for (i = 0; i < sizeof(float); i++)
+        append_packet(u.b[i]);
+    *cpp = cp;
+}
+
+static int n_enum_field(lua_State * L, int name_index, int dflt, const char **values)
+{
+    int k, t;
+    const char *s;
+    int i = dflt;
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
+    lua_rawget(L, -2);
+    t = lua_type(L,-1);
+    if (t == LUA_TNUMBER) {
+        i = (int) lua_tointeger(L, -1);
+    } else if (t == LUA_TSTRING) {
+        s = lua_tostring(L, -1);
+        k = 0;
+        while (values[k] != NULL) {
+            if (strcmp(values[k], s) == 0) {
+                i = k;
+                break;
+            }
+            k++;
+        }
+    }
+    lua_pop(L, 1);
+    return i;
+}
+
+static int n_boolean_field(lua_State * L, int name_index, int dflt)
+{
+    int i = dflt;
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
+    lua_rawget(L, -2);
+    if (lua_isboolean(L, -1)) {
+        i = lua_toboolean(L, -1);
+    }
+    lua_pop(L, 1);
+    return i;
+}
+
+static char *n_string_field_copy(lua_State * L, int name_index, const char *dflt)
+{
+    char *i;
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
+    lua_rawget(L, -2);
+    if (lua_type(L,-1) == LUA_TSTRING) {
+        i = xstrdup(lua_tostring(L, -1));
+    } else if (dflt == NULL) {
+        i = NULL;
+    } else {
+        i = xstrdup(dflt);
+    }
+    lua_pop(L, 1);
+    return i;
+}
+
+static const char *n_string_field(lua_State * L, int name_index)
+{
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
+    lua_rawget(L, -2);
+    return lua_tostring(L,-1);
+}
+
+static int n_some_field(lua_State * L, int name_index)
+{
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
+    lua_rawget(L, -2);
+    return lua_type(L,-1);
+}
+
+/*static void init_font_string_pointers(lua_State * L){}*/
+
+static int count_char_packet_bytes(lua_State * L)
+{
+    register int i;
+    register int l = 0;
+    int ff = 0;
+    for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
+        lua_rawgeti(L, -1, i);
+        if (lua_istable(L, -1)) {
+            lua_rawgeti(L, -1, 1);
+            if (lua_type(L,-1) == LUA_TSTRING) {
+                const char *s = lua_tostring(L, -1);
+                if (lua_key_eq(s, font)) {
+                    l += 5;
+                    ff = 1;
+                } else if (lua_key_eq(s, char)) {
+                    if (ff == 0) {
+                        l += 5;
+                    }
+                    l += 5;
+                    ff = 1;
+                } else if (lua_key_eq(s, slot)) {
+                    l += 10;
+                    ff = 1;
+                } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
+                    ;
+                } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) {
+                    l++;
+                } else if (lua_key_eq(s, rule)) {
+                    l += 9;
+                } else if (lua_key_eq(s, right) || lua_key_eq(s, node)
+                           || lua_key_eq(s, down) || lua_key_eq(s, image)) {
+                    l += 5;
+                } else if (lua_key_eq(s, scale)) {
+                    l += sizeof(float) + 1;
+                } else if (lua_key_eq(s, special) || lua_key_eq(s, lua)) {
+                    size_t len;
+                    lua_rawgeti(L, -2, 2);
+                    if (lua_type(L,-1) == LUA_TSTRING) {
+                        (void) lua_tolstring(L, -1, &len);
+                        lua_pop(L, 1);
+                        if (len > 0) {
+                            l = (int) (l + 5 + (int) len);
+                        }
+                    } else {
+                        lua_pop(L, 1);
+                        normal_error("vf command","invalid packet special");
+                        /* fprintf(stdout, "invalid packet special!\n"); */
+                    }
+                } else {
+                    normal_error("vf command","unknown packet command");
+                    /* fprintf(stdout, "unknown packet command %s!\n", s); */
+                }
+            } else {
+                normal_error("vf command","no packet command");
+             /* fprintf(stdout, "no packet command!\n"); */
+            }
+            lua_pop(L, 1);      /* command name */
+        }
+        lua_pop(L, 1);          /* item */
+    }
+    return l;
+}
+
+static scaled sp_to_dvi(halfword sp, halfword atsize)
+{
+    double result, mult;
+    mult = (double) (atsize / 65536.0);
+    result = (double) (sp * 16.0);
+    return floor(result / mult);
+}
+
+@ @c
+static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, internal_font_number f, int atsize)
+{
+    int i, n, m;
+    size_t l;
+    int cmd;
+    const char *s;
+    eight_bits *cpackets, *cp;
+    int ff = 0;
+    int max_f = 0;
+    int pc = count_char_packet_bytes(L);
+    if (pc <= 0)
+        return;
+    while (l_fonts[(max_f + 1)] != 0)
+        max_f++;
+    cp = cpackets = xmalloc((unsigned) (pc + 1));
+    for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
+        lua_rawgeti(L, -1, i);
+        if (lua_istable(L, -1)) {
+            /* fetch the command code */
+            lua_rawgeti(L, -1, 1);
+            if (lua_type(L,-1) == LUA_TSTRING) {
+                s = lua_tostring(L, -1);
+                cmd = 0;
+                if (lua_key_eq(s, font)) {
+                    cmd = packet_font_code;
+                } else if (lua_key_eq(s, char)) {
+                    cmd = packet_char_code;
+                    if (ff == 0) {
+                        append_packet(packet_font_code);
+                        ff = l_fonts[1];
+                        do_store_four(ff);
+                    }
+                } else if (lua_key_eq(s, slot)) {
+                    cmd = packet_nop_code;
+                    lua_rawgeti(L, -2, 2);
+                    n = (int) luaL_checkinteger(L, -1);
+                    if (n ==0) {
+                        ff = f;
+                    } else {
+                        ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
+                    }
+                    lua_rawgeti(L, -3, 3);
+                    n = (int) luaL_checkinteger(L, -1);
+                    lua_pop(L, 2);
+                    append_packet(packet_font_code);
+                    do_store_four(ff);
+                    append_packet(packet_char_code);
+                    do_store_four(n);
+                } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
+                    cmd = packet_nop_code;
+                } else if (lua_key_eq(s, node)) {
+                    cmd = packet_node_code;
+                } else if (lua_key_eq(s, push)) {
+                    cmd = packet_push_code;
+                } else if (lua_key_eq(s, pop)) {
+                    cmd = packet_pop_code;
+                } else if (lua_key_eq(s, rule)) {
+                    cmd = packet_rule_code;
+                } else if (lua_key_eq(s, right)) {
+                    cmd = packet_right_code;
+                } else if (lua_key_eq(s, down)) {
+                    cmd = packet_down_code;
+                } else if (lua_key_eq(s, special)) {
+                    cmd = packet_special_code;
+                } else if (lua_key_eq(s, image)) {
+                    cmd = packet_image_code;
+                } else if (lua_key_eq(s, scale)) {
+                    cmd = packet_scale_code;
+                } else if (lua_key_eq(s, lua)) {
+                    cmd = packet_lua_code;
+                }
+                switch (cmd) {
+                    case packet_push_code:
+                    case packet_pop_code:
+                        append_packet(cmd);
+                        break;
+                    case packet_font_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = (int) luaL_checkinteger(L, -1);
+                        if (n == 0) {
+                            ff = n;
+                        } else {
+                            ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
+                        }
+                        do_store_four(ff);
+                        lua_pop(L, 1);
+                        break;
+                    case packet_node_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = copy_node_list(nodelist_from_lua(L));
+                        do_store_four(n);
+                        lua_pop(L, 1);
+                        break;
+                    case packet_char_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = (int) luaL_checkinteger(L, -1);
+                        do_store_four(n);
+                        lua_pop(L, 1);
+                        break;
+                    case packet_right_code:
+                    case packet_down_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = (int) luaL_checkinteger(L, -1);
+                        do_store_four(sp_to_dvi(n, atsize));
+                        lua_pop(L, 1);
+                        break;
+                    case packet_rule_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = (int) luaL_checkinteger(L, -1);
+                        do_store_four(sp_to_dvi(n, atsize));
+                        lua_rawgeti(L, -3, 3);
+                        n = (int) luaL_checkinteger(L, -1);
+                        do_store_four(sp_to_dvi(n, atsize));
+                        lua_pop(L, 2);
+                        break;
+                    case packet_special_code:
+                    case packet_lua_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        s = luaL_checklstring(L, -1, &l);
+                        if (l > 0) {
+                            do_store_four(l);
+                            m = (int) l;
+                            while (m > 0) {
+                                n = *s++;
+                                m--;
+                                append_packet(n);
+                            }
+                        }
+                        lua_pop(L, 1);
+                        break;
+                    case packet_image_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);      /* img/imgtable? ... */
+                        if (lua_istable(L, -1)) {   /* imgtable ... */
+                            lua_getglobal(L, "img");        /* imglib imgtable ... */
+                            lua_pushstring(L, "new");       /* `new' imglib imgtable ... */
+                            lua_gettable(L, -2);    /* f imglib imgtable ... */
+                            lua_insert(L, -3);      /* imglib imgtable f ... */
+                            lua_pop(L, 1);  /* imgtable f ... */
+                            lua_call(L, 1, 1);
+                        }           /* img ... */
+                        luaL_checkudata(L, -1, TYPE_IMG);   /* img ... --- just typecheck */
+                        n = luaL_ref(L, LUA_REGISTRYINDEX);  /* ... */
+                        do_store_four(n);
+                        break;
+                    case packet_nop_code:
+                        break;
+                    case packet_scale_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        append_float(&cp, (float) luaL_checknumber(L, -1));
+                        lua_pop(L, 1);
+                        break;
+                    default:
+                        normal_error("vf command","invalid packet code");
+                        /* fprintf(stdout, "Unknown char packet code %s\n", s); */
+                }
+            }
+            lua_pop(L, 1);      /* command code */
+        } else {
+            normal_error("vf command","commands has to be a tbale");
+            /* fprintf(stdout, "Found a `commands' item that is not a table\n"); */
+        }
+        lua_pop(L, 1);          /* command table */
+    }
+    append_packet(packet_end_code);
+    set_charinfo_packets(co, cpackets);
+    return;
+}
+
+@ @c
+static void read_lua_cidinfo(lua_State * L, int f)
+{
+    int i;
+    char *s;
+    /*lua_getfield(L, -1, "cidinfo");*/
+    lua_key_rawgeti(cidinfo);
+    if (lua_istable(L, -1)) {
+        i = lua_numeric_field_by_index(L,lua_key_index(version), 0);
+        set_font_cidversion(f, i);
+        i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0);
+        set_font_cidsupplement(f, i);
+        s = n_string_field_copy(L, lua_key_index(registry), "Adobe");       /* Adobe-Identity-0 */
+        set_font_cidregistry(f, s);
+        s = n_string_field_copy(L, lua_key_index(ordering), "Identity");
+        set_font_cidordering(f, s);
+    }
+    lua_pop(L, 1);
+}
+
+
+@ @c
+static void read_lua_parameters(lua_State * L, int f)
+{
+    int i, n, t;
+    const char *s;
+    /*lua_getfield(L, -1, "parameters");*/
+    lua_key_rawgeti(parameters);
+    if (lua_istable(L, -1)) {
+        /* the number of parameters is the max(IntegerKeys(L)),7) */
+        n = 7;
+        lua_pushnil(L);         /* first key */
+        while (lua_next(L, -2) != 0) {
+            if (lua_type(L, -2) == LUA_TNUMBER) {
+                i = (int) lua_tointeger(L, -2);
+                if (i > n)
+                    n = i;
+            }
+            lua_pop(L, 1);      /* pop value */
+        }
+        if (n > 7)
+            set_font_params(f, n);
+        /* sometimes it is handy to have all integer keys */
+        for (i = 1; i <= 7; i++) {
+            lua_rawgeti(L, -1, i);
+            if (lua_type(L, -1) == LUA_TNUMBER) {
+                n = lua_roundnumber(L, -1); /* round ? */
+                set_font_param(f, i, n);
+            }
+            lua_pop(L, 1);
+        }
+        lua_pushnil(L);         /* first key */
+        while (lua_next(L, -2) != 0) {
+            t = lua_type(L,-2);
+            if (t == LUA_TNUMBER) {
+                i = (int) lua_tointeger(L, -2);
+                if (i >= 8) {
+                    if (lua_type(L,-1) == LUA_TNUMBER) {
+                        n = lua_roundnumber(L, -1);
+                    } else {
+                        n = 0;
+                    }
+                    set_font_param(f, i, n);
+                }
+            } else if (t == LUA_TSTRING) {
+                s = lua_tostring(L, -2);
+                if (lua_type(L,-1) == LUA_TNUMBER) {
+                    n = lua_roundnumber(L, -1);
+                } else {
+                    n = 0;
+                }
+                if (lua_key_eq(s, slant)) {
+                    set_font_param(f, slant_code, n);
+                } else if (lua_key_eq(s, space)) {
+                    set_font_param(f, space_code, n);
+                } else if (lua_key_eq(s, space_stretch)) {
+                    set_font_param(f, space_stretch_code, n);
+                } else if (lua_key_eq(s, space_shrink)) {
+                    set_font_param(f, space_shrink_code, n);
+                } else if (lua_key_eq(s, x_height)) {
+                    set_font_param(f, x_height_code, n);
+                } else if (lua_key_eq(s, quad)) {
+                    set_font_param(f, quad_code, n);
+                } else if (lua_key_eq(s, extra_space)) {
+                    set_font_param(f, extra_space_code, n);
+                }
+            }
+            lua_pop(L, 1);
+        }
+    }
+    lua_pop(L, 1);
+
+}
+
+@ @c
+static void read_lua_math_parameters(lua_State * L, int f)
+{
+    int i = 0, n = 0, t;
+    /*lua_getfield(L, -1, "MathConstants");*/
+    lua_key_rawgeti(MathConstants);
+    if (lua_istable(L, -1)) {
+        lua_pushnil(L);
+        while (lua_next(L, -2) != 0) {
+            t = lua_type(L,-2);
+            if (t == LUA_TNUMBER) {
+                i = (int) lua_tointeger(L, -2);
+            } else if (t == LUA_TSTRING) {
+                i = ff_checkoption(L, -2, NULL, MATH_param_names);
+            }
+            n = (int) lua_roundnumber(L, -1);
+            if (i > 0) {
+                set_font_math_param(f, i, n);
+            }
+            lua_pop(L, 1);      /* pop value */
+        }
+        set_font_oldmath(f,false);
+    } else {
+        set_font_oldmath(f,true);
+    }
+    lua_pop(L, 1);
+}
+
+@ @c
+#define MIN_INF -0x7FFFFFFF
+
+static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
+{
+    int l, k;
+    scaled ht, krn;
+    lua_key_direct_rawgeti(index);
+    if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) {
+        for (l = 0; l < k; l++) {
+            lua_rawgeti(L, -1, (l + 1));
+            if (lua_istable(L, -1)) {
+                ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF);
+                krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF);
+                if (krn > MIN_INF && ht > MIN_INF)
+                    add_charinfo_math_kern(co, id, ht, krn);
+            }
+            lua_pop(L, 1);
+        }
+    }
+    lua_pop(L, 1);
+}
+
+@ @c
+static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int *l_fonts, boolean has_math)
+{
+    int k, r, t, lt, u, n;
+    charinfo *co;
+    kerninfo *ckerns;
+    liginfo *cligs;
+    scaled j;
+    const char *s;
+    int nl = 0;                 /* number of ligature table items */
+    int nk = 0;                 /* number of kern table items */
+    int ctr = 0;
+    int atsize = font_size(f);
+    if (lua_istable(L, -1)) {
+        co = get_charinfo(f, i);
+        set_charinfo_tag(co, 0);
+        j = lua_numeric_field_by_index(L, lua_key_index(width), 0);
+        set_charinfo_width(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(height), 0);
+        set_charinfo_height(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(depth), 0);
+        set_charinfo_depth(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(italic), 0);
+        set_charinfo_italic(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(vert_italic), 0);
+        set_charinfo_vert_italic(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(index), 0);
+        set_charinfo_index(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 1000);
+        set_charinfo_ef(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0);
+        set_charinfo_lp(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0);
+        set_charinfo_rp(co, j);
+        k = n_boolean_field(L, lua_key_index(used), 0);
+        set_charinfo_used(co, k);
+        s = n_string_field(L, lua_key_index(name));
+        if (s != NULL)
+            set_charinfo_name(co, xstrdup(s));
+        else
+            set_charinfo_name(co, NULL);
+        /* n_string_field leaves a value on stack*/
+        lua_pop(L,1);
+        u = n_some_field(L,lua_key_index(tounicode));
+        if (u == LUA_TNUMBER) {
+            u = lua_tointeger(L,-1);
+            if (u < 0) {
+                set_charinfo_tounicode(co, NULL);
+            } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
+                char *s = malloc(5);
+                sprintf(s,"%04X",(unsigned int) u);
+                set_charinfo_tounicode(co,s);
+            } else {
+                char *s = malloc(9);
+                u = u - 0x10000;
+                sprintf(s,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
+                set_charinfo_tounicode(co,s);
+            }
+        } else if (u == LUA_TTABLE) {
+            n = lua_rawlen(L,-1);
+            u = 0;
+            for (k = 1; k <= n; k++) {
+                lua_rawgeti(L, -1, k);
+                if (lua_type(L,-1) == LUA_TNUMBER) {
+                    u = lua_tointeger(L,-1);
+                } else {
+                    lua_pop(L, 1);
+                    break;
+                }
+                if (u < 0) {
+                    u = -1;
+                    lua_pop(L, 1);
+                    break;
+                } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
+                    u = u + 4;
+                } else {
+                    u = u + 8;
+                }
+                lua_pop(L, 1);
+            }
+            if (u>0) {
+                char *s = malloc(u+1);
+                char *t = s ;
+                for (k = 1; k <= n; k++) {
+                    lua_rawgeti(L, -1, k);
+                    u = lua_tointeger(L,-1);
+                    if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
+                        sprintf(t,"%04X",(unsigned int) u);
+                        t += 4;
+                    } else {
+                        u = u - 0x10000;
+                        sprintf(t,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
+                        t += 8;
+                    }
+                    lua_pop(L, 1);
+                }
+                set_charinfo_tounicode(co,s);
+            } else {
+                set_charinfo_tounicode(co, NULL);
+            }
+        } else if (u == LUA_TSTRING) {
+            s = lua_tostring(L,-1);
+            set_charinfo_tounicode(co, xstrdup(s));
+        } else {
+            set_charinfo_tounicode(co, NULL);
+        }
+        /* ... leaves a value on stack*/
+        lua_pop(L,1);
+
+        if (has_math) {
+            j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN);
+            set_charinfo_top_accent(co, j);
+            j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN);
+            set_charinfo_bot_accent(co, j);
+            k = lua_numeric_field_by_index(L, lua_key_index(next), -1);
+            if (k >= 0) {
+                set_charinfo_tag(co, list_tag);
+                set_charinfo_remainder(co, k);
+            }
+
+            lua_key_rawgeti(extensible);
+            if (lua_istable(L, -1)) {
+                int top, bot, mid, rep;
+                top = lua_numeric_field_by_index(L, lua_key_index(top), 0);
+                bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0);
+                mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0);
+                rep = lua_numeric_field_by_index(L, lua_key_index(rep), 0);
+                if (top != 0 || bot != 0 || mid != 0 || rep != 0) {
+                    set_charinfo_tag(co, ext_tag);
+                    set_charinfo_extensible(co, top, bot, mid, rep);
+                } else {
+                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid extensible field",
+                        font_name(f), (int) i);
+                }
+            }
+            lua_pop(L, 1);
+
+            lua_key_rawgeti(horiz_variants);
+            if (lua_istable(L, -1)) {
+                int glyph, startconnect, endconnect, advance, extender;
+                extinfo *h;
+                set_charinfo_tag(co, ext_tag);
+                set_charinfo_hor_variants(co, NULL);
+                for (k = 1;; k++) {
+                    lua_rawgeti(L, -1, k);
+                    if (lua_istable(L, -1)) {
+                        glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
+                        extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
+                        startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
+                        endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
+                        advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
+                        h = new_variant(glyph, startconnect, endconnect, advance, extender);
+                        add_charinfo_hor_variant(co, h);
+                        lua_pop(L, 1);
+                    } else {
+                        lua_pop(L, 1);
+                        break;
+                    }
+                }
+            }
+            lua_pop(L, 1);
+
+            lua_key_rawgeti(vert_variants);
+            if (lua_istable(L, -1)) {
+                int glyph, startconnect, endconnect, advance, extender;
+                extinfo *h;
+                set_charinfo_tag(co, ext_tag);
+                set_charinfo_vert_variants(co, NULL);
+                for (k = 1;; k++) {
+                    lua_rawgeti(L, -1, k);
+                    if (lua_istable(L, -1)) {
+                        glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
+                        extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
+                        startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
+                        endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
+                        advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
+                        h = new_variant(glyph, startconnect, endconnect, advance, extender);
+                        add_charinfo_vert_variant(co, h);
+                        lua_pop(L, 1);
+                    } else {
+                        lua_pop(L, 1);
+                        break;
+                    }
+                }
+            }
+            lua_pop(L, 1);
+
+            /*
+                Here is a complete example:
+
+                |mathkern = {|
+                    | bottom_left  = { { height = 420, kern = 80  }, { height = 520, kern = 4   } },|
+                    | bottom_right = { { height = 0,   kern = 48  } },|
+                    | top_left     = { { height = 620, kern = 0   }, { height = 720, kern = -80 } },|
+                    | top_right    = { { height = 676, kern = 115 }, { height = 776, kern = 45  } },|
+                |}|
+
+            */
+
+            lua_key_rawgeti(mathkern);
+            if (lua_istable(L, -1)) {
+                store_math_kerns(L,lua_key_index(top_left), co, top_left_kern);
+                store_math_kerns(L,lua_key_index(top_right), co, top_right_kern);
+                store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern);
+                store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern);
+            }
+            lua_pop(L, 1);
+        }
+        /* end of |has_math| */
+        count_hash_items(L, kerns, nk);
+        if (nk > 0) {
+            /* kerns table still on stack */
+            ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo));
+            ctr = 0;
+            lua_pushnil(L); /* traverse hash */
+            while (lua_next(L, -2) != 0) {
+                k = non_boundarychar;
+                lt = lua_type(L,-2);
+                if (lt == LUA_TNUMBER) {
+                    k = (int) lua_tointeger(L, -2); /* adjacent char */
+                    if (k < 0)
+                        k = non_boundarychar;
+                } else if (lt == LUA_TSTRING) {
+                    s = lua_tostring(L, -2);
+                    if (lua_key_eq(s, right_boundary)) {
+                        k = right_boundarychar;
+                        if (!has_right_boundary(f))
+                            set_right_boundary(f, get_charinfo(f, right_boundarychar));
+                    }
+                }
+                j = lua_roundnumber(L, -1); /* movement */
+                if (k != non_boundarychar) {
+                    set_kern_item(ckerns[ctr], k, j);
+                    ctr++;
+                } else {
+                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kern field",
+                        font_name(f), (int) i);
+                }
+                lua_pop(L, 1);
+            }
+            /* guard against empty tables */
+            if (ctr > 0) {
+                set_kern_item(ckerns[ctr], end_kern, 0);
+                set_charinfo_kerns(co, ckerns);
+            } else {
+                formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kerns field",
+                    font_name(f), (int) i);
+            }
+            lua_pop(L, 1);
+        }
+
+        /* packet commands */
+        lua_key_rawgeti(commands);
+        if (lua_istable(L, -1)) {
+            lua_pushnil(L);     /* first key */
+            if (lua_next(L, -2) != 0) {
+                lua_pop(L, 2);
+                read_char_packets(L, (int *) l_fonts, co, f, atsize);
+            }
+        }
+        lua_pop(L, 1);
+
+        /* ligatures */
+        count_hash_items(L, ligatures, nl);
+        if (nl > 0) {
+            /* ligatures table still on stack */
+            cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo));
+            ctr = 0;
+            lua_pushnil(L); /* traverse hash */
+            while (lua_next(L, -2) != 0) {
+                k = non_boundarychar;
+                lt = lua_type(L,-2);
+                if (lt == LUA_TNUMBER) {
+                    k = (int) lua_tointeger(L, -2); /* adjacent char */
+                    if (k < 0) {
+                        k = non_boundarychar;
+                    }
+                } else if (lt == LUA_TSTRING) {
+                    s = lua_tostring(L, -2);
+                    if (lua_key_eq(s, right_boundary)) {
+                        k = right_boundarychar;
+                        if (!has_right_boundary(f))
+                            set_right_boundary(f, get_charinfo(f, right_boundarychar));
+                    }
+                }
+                r = -1;
+                if (lua_istable(L, -1)) {
+                    r = lua_numeric_field_by_index(L, lua_key_index(char), -1);    /* ligature */
+                }
+                if (r != -1 && k != non_boundarychar) {
+                    t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings);
+                    set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, r);
+                    ctr++;
+                } else {
+                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligature field",
+                        font_name(f), (int) i);
+                }
+                lua_pop(L, 1);      /* iterator value */
+            }
+            /* guard against empty tables */
+            if (ctr > 0) {
+                set_ligature_item(cligs[ctr], 0, end_ligature, 0);
+                set_charinfo_ligatures(co, cligs);
+            } else {
+                formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligatures field",
+                    font_name(f), (int) i);
+            }
+            lua_pop(L, 1);      /* ligatures table */
+        }
+    }
+}
+
+@ The caller has to fix the state of the lua stack when there is an error!
+
+ at c
+int font_from_lua(lua_State * L, int f)
+{
+    int i, n, r, t, lt;
+    int s_top;                  /* lua stack top */
+    int bc;                     /* first char index */
+    int ec;                     /* last char index */
+    char *s;
+    const char *ss;
+    int *l_fonts = NULL;
+    int save_ref ;
+    boolean no_math = false;
+
+    /* will we save a cache of the luat table? */
+
+    save_ref = 1; /* we start with  ss = "yes" */
+    ss = NULL;
+    ss = n_string_field(L, lua_key_index(cache));
+    if (lua_key_eq(ss, no))
+        save_ref = -1;
+    else if (lua_key_eq(ss, renew))
+        save_ref = 0;
+    /* n_string_field leaves a value on stack*/
+    lua_pop(L,1);
+
+    /* the table is at stack index -1 */
+
+    s = n_string_field_copy(L,lua_key_index(area), "");
+    set_font_area(f, s);
+    s = n_string_field_copy(L, lua_key_index(filename), NULL);
+    set_font_filename(f, s);
+    s = n_string_field_copy(L, lua_key_index(encodingname), NULL);
+    set_font_encodingname(f, s);
+
+    s = n_string_field_copy(L, lua_key_index(name), NULL);
+    set_font_name(f, s);
+    s = n_string_field_copy(L, lua_key_index(fullname), font_name(f));
+    set_font_fullname(f, s);
+
+    if (s == NULL) {
+        formatted_error("font","lua-loaded font '%d' has no name!", f);
+        return false;
+    }
+    s = n_string_field_copy(L, lua_key_index(psname), NULL);
+    set_font_psname(f, s);
+
+    i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0);
+    set_font_units_per_em(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360);
+    set_font_dsize(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f));
+    set_font_size(f, i);
+    set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ;
+    i = lua_numeric_field_by_index(L,lua_key_index(direction), 0);
+    set_font_natural_dir(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0);
+    set_font_encodingbytes(f, (char) i);
+    i = n_boolean_field(L,lua_key_index(oldmath), 0);
+    set_font_oldmath(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0);
+    set_font_tounicode(f, (char) i);
+
+    i = lua_numeric_field_by_index(L,lua_key_index(extend), 1000);
+    if (i < FONT_EXTEND_MIN)
+        i = FONT_EXTEND_MIN;
+    if (i > FONT_EXTEND_MAX)
+        i = FONT_EXTEND_MAX;
+    set_font_extend(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(slant), 0);
+    if (i < FONT_SLANT_MIN)
+        i = FONT_SLANT_MIN;
+    if (i > FONT_SLANT_MAX)
+        i = FONT_SLANT_MAX;
+    set_font_slant(f, i);
+
+    i = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), default_hyphen_char_par);
+    set_hyphen_char(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(skewchar), default_skew_char_par);
+    set_skew_char(f, i);
+    i = n_boolean_field(L, lua_key_index(used), 0);
+    set_font_used(f, (char) i);
+
+    s = n_string_field_copy(L, lua_key_index(attributes), NULL);
+    if (s != NULL && strlen(s) > 0) {
+        i = maketexstring(s);
+        set_pdf_font_attr(f, i);
+    }
+    free(s);
+
+    i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings);
+    set_font_type(f, i);
+    i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings);
+    set_font_format(f, i);
+    i = n_enum_field(L, lua_key_index(writingmode), unknown_writingmode, font_writingmode_strings);
+    set_font_writingmode(f, i);
+    i = n_enum_field(L, lua_key_index(identity), unknown_identity, font_identity_strings);
+    set_font_identity(f, i);
+    i = n_enum_field(L, lua_key_index(embedding), unknown_embedding, font_embedding_strings);
+    set_font_embedding(f, i);
+    if (font_encodingbytes(f) == 0 && (font_format(f) == opentype_format || font_format(f) == truetype_format)) {
+        set_font_encodingbytes(f, 2);
+    }
+
+    /* now fetch the base fonts, if needed */
+    count_hash_items(L, fonts, n);
+    if (n > 0) {
+        /* font table still on stack */
+        l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
+        memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
+        for (i = 1; i <= n; i++) {
+            lua_rawgeti(L, -1, i);
+            if (lua_istable(L, -1)) {
+                lua_key_rawgeti(id);
+                if (lua_isnumber(L, -1)) {
+                    l_fonts[i] = (int) lua_tointeger(L, -1);
+                    if (l_fonts[i] == 0) {
+                        l_fonts[i] = (int) f;
+                    }
+                    lua_pop(L, 2); /* pop id and entry */
+                    continue;
+                }
+                lua_pop(L, 1); /* pop id */
+            };
+            ss = NULL;
+            if (lua_istable(L, -1)) {
+                ss = n_string_field(L, lua_key_index(name));
+                /* string is anchored */
+                lua_pop(L,1);
+            }
+            if (ss != NULL) {
+                t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
+                /* TODO: the stack is messed up, otherwise this explicit resizing would not be needed */
+                s_top = lua_gettop(L);
+                if (strcmp(font_name(f), ss) == 0)
+                    l_fonts[i] = f;
+                else
+                    l_fonts[i] = find_font_id(ss, t);
+                lua_settop(L, s_top);
+            } else {
+                formatted_error("font","invalid local font in lua-loaded font '%s'", font_name(f));
+            }
+            lua_pop(L, 1); /* pop list entry */
+        }
+        lua_pop(L, 1); /* pop font table */
+    } else if (font_type(f) == virtual_font_type) {
+        formatted_error("font","invalid local fonts in lua-loaded font '%s'", font_name(f));
+    } else {
+        l_fonts = xmalloc(3 * sizeof(int));
+        l_fonts[0] = 0;
+        l_fonts[1] = f;
+        l_fonts[2] = 0;
+    }
+
+    /* parameters */
+    no_math = n_boolean_field(L, lua_key_index(nomath), 0);
+    read_lua_parameters(L, f);
+    if (!no_math) {
+        read_lua_math_parameters(L, f);
+        if (n_boolean_field(L, lua_key_index(oldmath), 0)) {
+            set_font_oldmath(f,true);
+        }
+
+    } else {
+        set_font_oldmath(f,true);
+    }
+    read_lua_cidinfo(L, f);
+
+    /* characters */
+    lua_key_rawgeti(characters);
+    if (lua_istable(L, -1)) {
+        /* find the array size values */
+        int num = 0;            /* number of charinfo's to add */
+        ec = 0;
+        bc = -1;
+        lua_pushnil(L);         /* first key */
+        while (lua_next(L, -2) != 0) {
+            if (lua_isnumber(L, -2)) {
+                i = (int) lua_tointeger(L, -2);
+                if (i >= 0) {
+                    if (lua_istable(L, -1)) {
+                        num++;
+                        if (i > ec)
+                            ec = i;
+                        if (bc < 0)
+                            bc = i;
+                        if (bc >= 0 && i < bc)
+                            bc = i;
+                    }
+                }
+            }
+            lua_pop(L, 1);
+        }
+        if (bc != -1) {
+            font_malloc_charinfo(f, num);
+            set_font_bc(f, bc);
+            set_font_ec(f, ec);
+            lua_pushnil(L);     /* first key */
+            while (lua_next(L, -2) != 0) {
+                lt = lua_type(L,-2);
+                if (lt == LUA_TNUMBER) {
+                    i = (int) lua_tointeger(L, -2);
+                    if (i >= 0) {
+                        font_char_from_lua(L, f, i, l_fonts, !no_math);
+                    }
+                } else if (lt == LUA_TSTRING) {
+                    const char *ss1 = lua_tostring(L, -2);
+                    if (lua_key_eq(ss1, left_boundary)) {
+                        font_char_from_lua(L, f, left_boundarychar, l_fonts,
+                                           !no_math);
+                    } else if (lua_key_eq(ss1, right_boundary)) {
+                        font_char_from_lua(L, f, right_boundarychar, l_fonts,
+                                           !no_math);
+                    }
+                }
+                lua_pop(L, 1);
+            }
+            lua_pop(L, 1);
+
+            /*
+                Handle font expansion last: the |copy_font| routine is called eventually,
+                and that needs to know |bc| and |ec|.
+            */
+
+            if (font_type(f) != virtual_font_type) {
+                int fstep = lua_numeric_field_by_index(L, lua_key_index(step), 0);
+                if (fstep < 0)
+                    fstep = 0;
+                if (fstep > 100)
+                    fstep = 100;
+                if (fstep != 0) {
+                    int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0);
+                    int fstretch =lua_numeric_field_by_index(L, lua_key_index(stretch), 0);
+                    int fexpand = n_boolean_field(L, lua_key_index(auto_expand), 0);
+                    if (fshrink < 0)
+                        fshrink = 0;
+                    if (fshrink > 500)
+                        fshrink = 500;
+                    fshrink -= (fshrink % fstep);
+                    if (fshrink < 0)
+                        fshrink = 0;
+                    if (fstretch < 0)
+                        fstretch = 0;
+                    if (fstretch > 1000)
+                        fstretch = 1000;
+                    fstretch -= (fstretch % fstep);
+                    if (fstretch < 0)
+                        fstretch = 0;
+                    set_expand_params(f, fexpand, fstretch, fshrink, fstep);
+                }
+            }
+
+        } else {
+            /* jikes, no characters */
+            formatted_warning("font","lua-loaded font '%d' with name '%s' has no characters", f, font_name(f));
+        }
+
+        if (save_ref > 0) {
+            r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */
+            set_font_cache_id(f, r);
+        } else {
+            lua_pop(L, 1);
+            set_font_cache_id(f, save_ref);
+        }
+    } else {
+        /* jikes, no characters */
+        formatted_warning("font","lua-loaded font '%d' with name '%s' has no character table", f, font_name(f));
+    }
+    if (l_fonts != NULL)
+        free(l_fonts);
+    return true;
+}
+
+@* Ligaturing.
+
+ at c
+static void nesting_append(halfword nest1, halfword newn)
+{
+    halfword tail = tlink(nest1);
+    if (tail == null) {
+        couple_nodes(nest1, newn);
+    } else {
+        couple_nodes(tail, newn);
+    }
+    tlink(nest1) = newn;
+}
+
+static void nesting_prepend(halfword nest1, halfword newn)
+{
+    halfword head = vlink(nest1);
+    couple_nodes(nest1, newn);
+    if (head == null) {
+        tlink(nest1) = newn;
+    } else {
+        couple_nodes(newn, head);
+    }
+}
+
+static void nesting_prepend_list(halfword nest1, halfword newn)
+{
+    halfword head = vlink(nest1);
+    couple_nodes(nest1, newn);
+    if (head == null) {
+        tlink(nest1) = tail_of_list(newn);
+    } else {
+        halfword tail = tail_of_list(newn);
+        couple_nodes(tail, head);
+    }
+}
+
+static int test_ligature(liginfo * lig, halfword left, halfword right)
+{
+    if (type(left) != glyph_node)
+        return 0;
+    if (font(left) != font(right))
+        return 0;
+    if (is_ghost(left) || is_ghost(right))
+        return 0;
+    *lig = get_ligature(font(left), character(left), character(right));
+    if (is_valid_ligature(*lig)) {
+        return 1;
+    }
+    return 0;
+}
+
+static int try_ligature(halfword * frst, halfword fwd)
+{
+    halfword cur = *frst;
+    liginfo lig;
+    if (test_ligature(&lig, cur, fwd)) {
+        int move_after = (lig_type(lig) & 0x0C) >> 2;
+        int keep_right = ((lig_type(lig) & 0x01) != 0);
+        int keep_left = ((lig_type(lig) & 0x02) != 0);
+        halfword newgl = raw_glyph_node();
+        font(newgl) = font(cur);
+        character(newgl) = lig_replacement(lig);
+        set_is_ligature(newgl);
+        /*
+            below might not be correct in contrived border case.
+            but we use it only for debugging, so ...
+        */
+        if (character(cur) < 0) {
+            set_is_leftboundary(newgl);
+        }
+        if (character(fwd) < 0) {
+            set_is_rightboundary(newgl);
+        }
+        if (character(cur) < 0) {
+            if (character(fwd) < 0) {
+                build_attribute_list(newgl);
+            } else {
+                add_node_attr_ref(node_attr(fwd));
+                node_attr(newgl) = node_attr(fwd);
+            }
+        } else {
+            add_node_attr_ref(node_attr(cur));
+            node_attr(newgl) = node_attr(cur);
+        }
+
+        /*
+            TODO/FIXME if this ligature is consists of another ligature
+            we should add it's |lig_ptr| to the new glyphs |lig_ptr| (and
+            cleanup the no longer needed node) LOW PRIORITY
+        */
+        /* left side */
+        if (keep_left) {
+            halfword new_first = copy_node(cur);
+            lig_ptr(newgl) = new_first;
+            couple_nodes(cur, newgl);
+            if (move_after) {
+                move_after--;
+                cur = newgl;
+            }
+        } else {
+            halfword prev = alink(cur);
+            uncouple_node(cur);
+            lig_ptr(newgl) = cur;
+            couple_nodes(prev, newgl);
+            cur = newgl;        /* as cur has disappeared */
+        }
+        /* right side */
+        if (keep_right) {
+            halfword new_second = copy_node(fwd);
+            /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
+            couple_nodes(lig_ptr(newgl), new_second);
+            couple_nodes(newgl, fwd);
+            if (move_after) {
+                move_after--;
+                cur = fwd;
+            }
+        } else {
+            halfword next = vlink(fwd);
+            uncouple_node(fwd);
+            /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
+            couple_nodes(lig_ptr(newgl), fwd);
+            if (next != null) {
+                couple_nodes(newgl, next);
+            }
+        }
+        /* check and return */
+        *frst = cur;
+        return 1;
+    }
+    return 0;
+}
+
+@ there shouldn't be any ligatures here - we only add them at the end of
+ |xxx_break| in a \.{DISC-1 - DISC-2} situation and we stop processing \.{DISC-1}
+ (we continue with \.{DISC-1}'s |post_| and |no_break|.
+
+ at c
+static halfword handle_lig_nest(halfword root, halfword cur)
+{
+    if (cur == null)
+        return root;
+    while (vlink(cur) != null) {
+        halfword fwd = vlink(cur);
+        if (type(cur) == glyph_node && type(fwd) == glyph_node &&
+                font(cur) == font(fwd) && try_ligature(&cur, fwd)) {
+            continue;
+        }
+        cur = vlink(cur);
+    }
+    tlink(root) = cur;
+    return root;
+}
+
+static halfword handle_lig_word(halfword cur)
+{
+    halfword right = null;
+    if (type(cur) == boundary_node) {
+        halfword prev = alink(cur);
+        halfword fwd = vlink(cur);
+        /* no need to uncouple |cur|, it is freed */
+        flush_node(cur);
+        if (fwd == null) {
+            vlink(prev) = fwd;
+            return prev;
+        }
+        couple_nodes(prev, fwd);
+        if (type(fwd) != glyph_node)
+            return prev;
+        cur = fwd;
+    } else if (has_left_boundary(font(cur))) {
+        halfword prev = alink(cur);
+        halfword p = new_glyph(font(cur), left_boundarychar);
+        couple_nodes(prev, p);
+        couple_nodes(p, cur);
+        cur = p;
+    }
+    if (has_right_boundary(font(cur))) {
+        right = new_glyph(font(cur), right_boundarychar);
+    }
+    while (1) {
+        /* A glyph followed by ... */
+        if (type(cur) == glyph_node) {
+            halfword fwd = vlink(cur);
+            if (fwd == null) {  /* last character of paragraph */
+                if (right == null)
+                    break;
+                /* \.{--\\par} prohibits use of |couple_nodes| here */
+                try_couple_nodes(cur, right);
+                right = null;
+                continue;
+            }
+            if (type(fwd) == glyph_node) {      /* |GLYPH - GLYPH| */
+                if (font(cur) != font(fwd))
+                    break;
+                if (try_ligature(&cur, fwd))
+                    continue;
+            } else if (type(fwd) == disc_node) {        /* |GLYPH - DISC| */
+
+                /* if  \.{a{bx}{}{y}} and \.{a+b=>B} convert to \.{{Bx}{}{ay}} */
+                halfword pre = vlink_pre_break(fwd);
+                halfword nob = vlink_no_break(fwd);
+                halfword next, tail;
+                liginfo lig;
+                /* Check on: a{b?}{?}{?} and a+b=>B : {B?}{?}{a?} */
+                /* Check on: a{?}{?}{b?} and a+b=>B : {a?}{?}{B?} */
+                if ((pre != null && type(pre) == glyph_node
+                     && test_ligature(&lig, cur, pre))
+                    || (nob != null && type(nob) == glyph_node
+                        && test_ligature(&lig, cur, nob))) {
+                    /* move cur from before disc, to skipped part */
+                    halfword prev = alink(cur);
+                    uncouple_node(cur);
+                    couple_nodes(prev, fwd);
+                    nesting_prepend(no_break(fwd), cur);
+                    /* now ligature the |pre_break| */
+                    nesting_prepend(pre_break(fwd), copy_node(cur));
+                    /* As we have removed cur, we need to start again ... */
+                    cur = prev;
+                }
+                /* Check on: a{?}{?}{}b and a+b=>B : {a?}{?b}{B} */
+                next = vlink(fwd);
+                if (nob == null && next != null && type(next) == glyph_node
+                    && test_ligature(&lig, cur, next)) {
+                    /* move |cur| from before |disc| to |no_break| part */
+                    halfword prev = alink(cur);
+                    uncouple_node(cur);
+                    couple_nodes(prev, fwd);
+                    couple_nodes(no_break(fwd), cur);   /* we {\it know\/} it's empty */
+                    /* now copy cur the |pre_break| */
+                    nesting_prepend(pre_break(fwd), copy_node(cur));
+                    /* move next from after disc to |no_break| part */
+                    tail = vlink(next);
+                    uncouple_node(next);
+                    try_couple_nodes(fwd, tail);
+                    couple_nodes(cur, next);    /* we {\it know\/} this works */
+                    tlink(no_break(fwd)) = next;        /* and make sure the list is correct */
+                    /* now copy next to the |post_break| */
+                    nesting_append(post_break(fwd), copy_node(next));
+                    /* As we have removed cur, we need to start again ... */
+                    cur = prev;
+                }
+                /* we are finished with the |pre_break| */
+                handle_lig_nest(pre_break(fwd), vlink_pre_break(fwd));
+            } else if (type(fwd) == boundary_node) {
+                halfword next = vlink(fwd);
+                try_couple_nodes(cur, next);
+                flush_node(fwd);
+                if (right != null) {
+                    flush_node(right);  /* Shame, didn't need it */
+                    /* no need to reset |right|, we're going to leave the loop anyway */
+                }
+                break;
+            } else {
+                /* fwd is something unknown */
+                if (right == null)
+                    break;
+                couple_nodes(cur, right);
+                couple_nodes(right, fwd);
+                right = null;
+                continue;
+            }
+            /* A discretionary followed by ... */
+        } else if (type(cur) == disc_node) {
+            /* If \.{{?}{x}{?}} or \.{{?}{?}{y}} then ... */
+            if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) {
+                halfword prev = 0;
+                halfword fwd;
+                liginfo lig;
+                if (subtype(cur) == select_disc) {
+                    prev = alink(cur);
+                    if (vlink_post_break(cur) != null)
+                        handle_lig_nest(post_break(prev), vlink_post_break(prev));
+                    if (vlink_no_break(cur) != null)
+                        handle_lig_nest(no_break(prev), vlink_no_break(prev));
+                }
+                if (vlink_post_break(cur) != null)
+                    handle_lig_nest(post_break(cur), vlink_post_break(cur));
+                if (vlink_no_break(cur) != null)
+                    handle_lig_nest(no_break(cur), vlink_no_break(cur));
+                while ((fwd = vlink(cur)) != null) {
+                    halfword nob, pst, next;
+                    if (type(fwd) != glyph_node)
+                        break;
+                    if (subtype(cur) != select_disc) {
+                        nob = tlink_no_break(cur);
+                        pst = tlink_post_break(cur);
+                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
+                            (pst == null || !test_ligature(&lig, pst, fwd)))
+                            break;
+                        nesting_append(no_break(cur), copy_node(fwd));
+                        handle_lig_nest(no_break(cur), nob);
+                    } else {
+                        int dobreak = 0;
+                        nob = tlink_no_break(prev);
+                        pst = tlink_post_break(prev);
+                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
+                            (pst == null || !test_ligature(&lig, pst, fwd)))
+                            dobreak = 1;
+                        if (!dobreak) {
+                            nesting_append(no_break(prev), copy_node(fwd));
+                            handle_lig_nest(no_break(prev), nob);
+                            nesting_append(post_break(prev), copy_node(fwd));
+                            handle_lig_nest(post_break(prev), pst);
+                        }
+                        dobreak = 0;
+                        nob = tlink_no_break(cur);
+                        pst = tlink_post_break(cur);
+                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
+                            (pst == null || !test_ligature(&lig, pst, fwd)))
+                            dobreak = 1;
+                        if (!dobreak) {
+                            nesting_append(no_break(cur), copy_node(fwd));
+                            handle_lig_nest(no_break(cur), nob);
+                        }
+                        if (dobreak)
+                            break;
+                    }
+                    next = vlink(fwd);
+                    uncouple_node(fwd);
+                    try_couple_nodes(cur, next);
+                    nesting_append(post_break(cur), fwd);
+                    handle_lig_nest(post_break(cur), pst);
+                }
+                if (fwd != null && type(fwd) == disc_node) {
+                        halfword next = vlink(fwd);
+                        if (vlink_no_break(fwd) == null
+                        && vlink_post_break(fwd) == null
+                        && next != null
+                        && type(next) == glyph_node
+                        && ((tlink_post_break(cur) != null && test_ligature(&lig, tlink_post_break(cur), next)) ||
+                            (tlink_no_break  (cur) != null && test_ligature(&lig, tlink_no_break  (cur), next)))) {
+                        /* Building an |init_disc| followed by a |select_disc|
+                          \.{{a-}{b}{AB} {-}{}{}} 'c'
+                         */
+                        /* is it tail necessary ? */
+                        halfword last1 = vlink(next), tail ;
+                        uncouple_node(next);
+                        try_couple_nodes(fwd, last1);
+                        /* \.{{a-}{b}{AB} {-}{c}{}} */
+                        nesting_append(post_break(fwd), copy_node(next));
+                        /* \.{{a-}{b}{AB} {-}{c}{-}} */
+                        if (vlink_no_break(cur) != null) {
+                            nesting_prepend(no_break(fwd), copy_node(vlink_pre_break(fwd)));
+                        }
+                        /* \.{{a-}{b}{AB} {b-}{c}{-}} */
+                        if (vlink_post_break(cur) != null)
+                            nesting_prepend_list(pre_break(fwd), copy_node_list(vlink_post_break(cur)));
+                        /* \.{{a-}{b}{AB} {b-}{c}{AB-}} */
+                        if (vlink_no_break(cur) != null) {
+                            nesting_prepend_list(no_break(fwd), copy_node_list(vlink_no_break(cur)));
+                        }
+                        /* \.{{a-}{b}{ABC} {b-}{c}{AB-}} */
+                        tail = tlink_no_break(cur);
+                        nesting_append(no_break(cur), copy_node(next));
+                        handle_lig_nest(no_break(cur), tail);
+                        /* \.{{a-}{BC}{ABC} {b-}{c}{AB-}} */
+                        tail = tlink_post_break(cur);
+                        nesting_append(post_break(cur), next);
+                        handle_lig_nest(post_break(cur), tail);
+                        /* and set the subtypes */
+                        subtype(cur) = init_disc;
+                        subtype(fwd) = select_disc;
+                    }
+                }
+            }
+
+        } else {
+            /* NO GLYPH NOR DISC */
+            return cur;
+        }
+        /* step-to-next-node */
+        /* \.{--\\par} allows |vlink(cur)| to be null */
+        cur = vlink(cur);
+    }
+
+    return cur;
+}
+
+@ Return value is the new tail, head should be a dummy
+
+ at c
+halfword handle_ligaturing(halfword head, halfword tail)
+{
+    halfword save_tail1 = null; /* trick to allow explicit |node==null| tests */
+    halfword cur, prev;
+
+    if (vlink(head) == null)
+        return tail;
+    if (tail != null) {
+        save_tail1 = vlink(tail);
+        vlink(tail) = null;
+    }
+
+    /* |if (fix_node_lists)| */
+    fix_node_list(head);
+
+    prev = head;
+    cur = vlink(prev);
+
+    while (cur != null) {
+        if (type(cur) == glyph_node || (type(cur) == boundary_node)) {
+            cur = handle_lig_word(cur);
+        }
+        prev = cur;
+        cur = vlink(cur);
+    }
+    if (prev == null) {
+        /* hh: looks bad to me */
+        prev = tail;
+    }
+
+    if (tail != null) {
+        try_couple_nodes(prev, save_tail1);
+    }
+    return prev;
+}
+
+
+@* Kerning.
+
+ at c
+static void add_kern_before(halfword left, halfword right)
+{
+    if ((!is_rightghost(right)) &&
+        font(left) == font(right) && has_kern(font(left), character(left))) {
+        int k = raw_get_kern(font(left), character(left), character(right));
+        if (k != 0) {
+            halfword kern = new_kern(k);
+            halfword prev = alink(right);
+            couple_nodes(prev, kern);
+            couple_nodes(kern, right);
+            /* update the attribute list (inherit from left) */
+            delete_attribute_ref(node_attr(kern));
+            add_node_attr_ref(node_attr(left));
+            node_attr(kern) = node_attr(left);
+        }
+    }
+}
+
+static void add_kern_after(halfword left, halfword right, halfword aft)
+{
+    if ((!is_rightghost(right)) &&
+        font(left) == font(right) && has_kern(font(left), character(left))) {
+        int k = raw_get_kern(font(left), character(left), character(right));
+        if (k != 0) {
+            halfword kern = new_kern(k);
+            halfword next = vlink(aft);
+            couple_nodes(aft, kern);
+            try_couple_nodes(kern, next);
+            /* update the attribute list (inherit from left == aft) */
+            delete_attribute_ref(node_attr(kern));
+            add_node_attr_ref(node_attr(aft));
+            node_attr(kern) = node_attr(aft);
+        }
+    }
+}
+
+static void do_handle_kerning(halfword root, halfword init_left, halfword init_right)
+{
+    halfword cur = vlink(root);
+    halfword left = null;
+    if (cur == null) {
+        if (init_left != null && init_right != null) {
+            add_kern_after(init_left, init_right, root);
+            tlink(root) = vlink(root);
+        }
+        return;
+    }
+    if (type(cur) == glyph_node) {
+        set_is_glyph(cur);
+        if (init_left != null)
+            add_kern_before(init_left, cur);
+        left = cur;
+    }
+    while ((cur = vlink(cur)) != null) {
+        if (type(cur) == glyph_node) {
+            set_is_glyph(cur);
+            if (left != null) {
+                add_kern_before(left, cur);
+                if (character(left) < 0 || is_ghost(left)) {
+                    halfword prev = alink(left);
+                    couple_nodes(prev, cur);
+                    flush_node(left);
+                }
+            }
+            left = cur;
+        } else {
+            if (type(cur) == disc_node) {
+                halfword right = type(vlink(cur)) == glyph_node ? vlink(cur) : null;
+                do_handle_kerning(pre_break(cur), left, null);
+                if (vlink_pre_break(cur) != null)
+                    tlink_pre_break(cur) = tail_of_list(vlink_pre_break(cur));
+                do_handle_kerning(post_break(cur), null, right);
+                if (vlink_post_break(cur) != null)
+                    tlink_post_break(cur) = tail_of_list(vlink_post_break(cur));
+                do_handle_kerning(no_break(cur), left, right);
+                if (vlink_no_break(cur) != null)
+                    tlink_no_break(cur) = tail_of_list(vlink_no_break(cur));    /* needed? */
+            }
+            if (left != null) {
+                if (character(left) < 0 || is_ghost(left)) {
+                    halfword prev = alink(left);
+                    couple_nodes(prev, cur);
+                    flush_node(left);
+                }
+                left = null;
+            }
+        }
+    }
+    if (left != null) {
+        if (init_right != null)
+            add_kern_after(left, init_right, left);
+        if (character(left) < 0 || is_ghost(left)) {
+            halfword prev = alink(left);
+            halfword next = vlink(left);
+            if (next != null) {
+                couple_nodes(prev, next);
+                tlink(root) = next;
+            } else if (prev != root) {
+                vlink(prev) = null;
+                tlink(root) = prev;
+            } else {
+                vlink(root) = null;
+                tlink(root) = null;
+            }
+            flush_node(left);
+        }
+    }
+}
+
+/*
+halfword handle_kerning(halfword head, halfword tail)
+{
+    halfword save_link;
+    save_link = vlink(tail);
+    vlink(tail) = null;
+    tlink(head) = tail;
+    do_handle_kerning(head, null, null);
+    tail = tlink(head);
+    if (valid_node(save_link)) {
+        try_couple_nodes(tail, save_link);
+    }
+    return tail;
+}
+*/
+
+halfword handle_kerning(halfword head, halfword tail)
+{
+    halfword save_link = null;
+    if (tail == null) {
+        tlink(head) = null;
+        do_handle_kerning(head, null, null);
+    } else {
+        save_link = vlink(tail);
+        vlink(tail) = null;
+        tlink(head) = tail;
+        do_handle_kerning(head, null, null);
+        tail = tlink(head);
+        if (valid_node(save_link)) {
+            try_couple_nodes(tail, save_link);
+        }
+    }
+    return tail;
+}
+
+@* ligaturing and kerning : lua-interface.
+
+ at c
+static halfword run_lua_ligkern_callback(halfword head, halfword tail, int callback_id)
+{
+    int i;
+    int top = lua_gettop(Luas);
+    if (!get_callback(Luas, callback_id)) {
+        lua_pop(Luas, 2);
+        return tail;
+    }
+    nodelist_to_lua(Luas, head);
+    nodelist_to_lua(Luas, tail);
+    if ((i=lua_pcall(Luas, 2, 0, 0)) != 0) {
+        luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+        return tail;
+    }
+    fix_node_list(head);
+    lua_settop(Luas, top);
+    return tail;
+}
+
+halfword new_ligkern(halfword head, halfword tail)
+{
+    int callback_id = 0;
+    if (vlink(head) == null)
+        return tail;
+    callback_id = callback_defined(ligaturing_callback);
+    if (callback_id > 0) {
+        tail = run_lua_ligkern_callback(head, tail, callback_id);
+        if (tail == null)
+            tail = tail_of_list(head);
+    } else if (callback_id == 0) {
+        tail = handle_ligaturing(head, tail);
+    }
+    callback_id = callback_defined(kerning_callback);
+    if (callback_id > 0) {
+        tail = run_lua_ligkern_callback(head, tail, callback_id);
+        if (tail == null) {
+            tail = tail_of_list(head);
+        }
+    } else if (callback_id == 0) {
+        halfword nest1 = new_node(nesting_node, 1);
+        halfword cur = vlink(head);
+        halfword aft = vlink(tail);
+        couple_nodes(nest1, cur);
+        tlink(nest1) = tail;
+        vlink(tail) = null;
+        do_handle_kerning(nest1, null, null);
+        couple_nodes(head, vlink(nest1));
+        tail = tlink(nest1);
+        try_couple_nodes(tail, aft);
+        flush_node(nest1);
+    }
+    return tail;
+}

Modified: trunk/Build/source/texk/web2c/luatexdir/image/writejpg.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/image/writejpg.w	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/image/writejpg.w	2017-02-09 22:44:03 UTC (rev 43177)
@@ -281,7 +281,7 @@
     }
     if (found_res) {
       if (tempx>0 && tempy>0) {
-       if (tempx!=(*xx) || tempy!=(*yy) && (*xx!=0 && (*yy!=0) )  ) {
+       if ((tempx!=(*xx) || tempy!=(*yy)) && (*xx!=0 && (*yy!=0) )  ) {
         formatted_warning("readjpg","Exif resolution  %ddpi x %ddpi differs from the input resolution %ddpi x %ddpi",tempx,tempy,*xx,*yy);
        }
        if (tempx==1 || tempy==1) {

Modified: trunk/Build/source/texk/web2c/luatexdir/lua/lnodelib.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/lua/lnodelib.c	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/lua/lnodelib.c	2017-02-09 22:44:03 UTC (rev 43177)
@@ -569,6 +569,107 @@
     return 1;
 }
 
+static int lua_nodelib_direct_getcomponents(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n == null) {
+        lua_pushnil(L);
+    } else if (type(n) == glyph_node) {
+        lua_pushinteger(L, lig_ptr(n));
+    } else {
+        lua_pushnil(L);
+    }
+    return 1;
+}
+
+static int lua_nodelib_direct_getlang(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n == null) {
+        lua_pushnil(L);
+    } else if (type(n) == glyph_node) {
+        lua_pushinteger(L, char_lang(n));
+    } else {
+        lua_pushnil(L);
+    }
+    return 1;
+}
+
+static int lua_nodelib_direct_getattributelist(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if ((n) && nodetype_has_attributes(type(n))) {
+        lua_pushinteger(L, node_attr(n));
+    } else {
+        lua_pushnil(L);
+    }
+    return 1;
+}
+
+static int lua_nodelib_direct_getpenalty(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n == null) {
+        lua_pushnil(L);
+    } else if (type(n) == penalty_node) {
+        lua_pushinteger(L, penalty(n));
+    } else if (type(n) == disc_node) {
+        lua_pushinteger(L, disc_penalty(n));
+    } else {
+        lua_pushnil(L);
+    }
+    return 1;
+}
+
+static int lua_nodelib_direct_getkern(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n == null) {
+        lua_pushnil(L);
+    } else if (type(n) == kern_node || type(n) == margin_kern_node) {
+        lua_pushinteger(L, width(n));
+    } else if (type(n) == math_node) {
+        lua_pushinteger(L, surround(n));
+    } else {
+        lua_pushnil(L);
+    }
+    return 1;
+}
+
+static int lua_nodelib_direct_getdir(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n == null) {
+        lua_pushnil(L);
+    } else if (type(n) == dir_node) {
+        lua_push_dir_text(L, dir_dir(n));
+    } else if (type(n) == hlist_node || type(n) == vlist_node) {
+        lua_push_dir_par(L, box_dir(n));
+    } else if (type(n) == rule_node) {
+        lua_push_dir_par(L, rule_dir(n));
+    } else if (type(n) == local_par_node) {
+        lua_push_dir_par(L, local_par_dir(n));
+    } else {
+        lua_pushnil(L);
+    }
+    return 1;
+}
+
+static int lua_nodelib_direct_getoffsets(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n == null) {
+        lua_pushnil(L);
+    } else if (type(n) == glyph_node) {
+        lua_pushinteger(L, x_displace(n));
+        lua_pushinteger(L, y_displace(n));
+        return 2;
+    } else {
+        lua_pushnil(L);
+    }
+    return 1;
+}
+
 /* node.getdisc */
 
 static int lua_nodelib_direct_getdiscretionary(lua_State * L)
@@ -696,22 +797,25 @@
         if ((t == hlist_node) || (t == vlist_node) || (t == rule_node) || (t == unset_node)) {
             int t = lua_gettop(L) ;
             if (t > 1) {
-                width(n) = (halfword) lua_roundnumber(L, 2);
+                if ((lua_type(L, 2) == LUA_TNUMBER)) {
+                    width(n) = (halfword) lua_roundnumber(L, 2);
+                } else {
+                    /* leave as is */
+                }
                 if (t > 2) {
-                    height(n) = (halfword) lua_roundnumber(L, 3);
-                    if (t > 3) {
-                        depth(n) = (halfword) lua_roundnumber(L, 4);
+                    if ((lua_type(L, 3) == LUA_TNUMBER)) {
+                        height(n) = (halfword) lua_roundnumber(L, 3);
                     } else {
-                        depth(n) = 0;
+                        /* leave as is */
                     }
-                } else {
-                    height(n) = 0;
-                    depth(n) = 0;
+                    if (t > 3) {
+                        if ((lua_type(L, 4) == LUA_TNUMBER)) {
+                            depth(n) = (halfword) lua_roundnumber(L, 4);
+                        } else {
+                            /* leave as is */
+                        }
+                    }
                 }
-            } else {
-                width(n) = 0;
-                height(n) = 0;
-                depth(n) = 0;
             }
         }
     }
@@ -728,6 +832,8 @@
         lua_pushnil(L);
     } else if ((type(*n) == hlist_node) || (type(*n) == vlist_node)) {
         fast_metatable_or_nil_alink(list_ptr(*n));
+    } else if ((type(*n) == sub_box_node) || (type(*n) == sub_mlist_node)) {
+        fast_metatable_or_nil_alink(math_list(*n));
     } else {
         lua_pushnil(L);
     }
@@ -739,13 +845,21 @@
 static int lua_nodelib_setlist(lua_State * L)
 {
     halfword *n = lua_touserdata(L, 1);
-    if ((n != null) && ((type(n) == hlist_node) || (type(n) == vlist_node))) {
-        if (lua_type(L,2) == LUA_TNIL) {
-            list_ptr(n) = null;
+    if (n != null) {
+        if ((type(*n) == hlist_node) || (type(*n) == vlist_node)) {
+            if (lua_type(L,2) == LUA_TNIL) {
+                list_ptr(n) = null;
+            } else {
+                halfword *l = lua_touserdata(L, 2);
+                list_ptr(n) = l;
+            }
         } else {
-            halfword *l = lua_touserdata(L, 2);
-            list_ptr(n) = l;
-        }
+            if (lua_type(L,2) == LUA_TNIL) {
+                math_list(n) = null;
+            } else {
+                halfword *l = lua_touserdata(L, 2);
+                math_list(n) = l;
+            }
     }
     return 0;
 }
@@ -759,10 +873,17 @@
     halfword n = lua_tointeger(L, 1);
     if (n == null) {
         lua_pushnil(L);
-    } else if ((type(n) == hlist_node) || (type(n) == vlist_node)) {
-        nodelib_pushdirect_or_nil_alink(list_ptr(n));
     } else {
-        lua_pushnil(L);
+        halfword t = type(n) ;
+        if ((t == hlist_node) || (t == vlist_node)) {
+            nodelib_pushdirect_or_nil_alink(list_ptr(n));
+        } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
+            nodelib_pushdirect_or_nil_alink(math_list(n));
+        } else if (t == adjust_node) {
+            nodelib_pushdirect_or_nil_alink(adjust_ptr(n));
+        } else {
+            lua_pushnil(L);
+        }
     }
     return 1;
 }
@@ -770,11 +891,26 @@
 static int lua_nodelib_direct_setlist(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if ((n != null) && ((type(n) == hlist_node) || (type(n) == vlist_node))) {
-        if (lua_type(L,2) == LUA_TNUMBER) {
-            list_ptr(n) = (halfword) lua_tointeger(L, 2);
-        } else {
-            list_ptr(n) = null;
+    if (n != null) {
+        halfword t = type(n) ;
+        if ((t == hlist_node) || (t == vlist_node)) {
+            if (lua_type(L,2) == LUA_TNUMBER) {
+                list_ptr(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                list_ptr(n) = null;
+            }
+        } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
+            if (lua_type(L,2) == LUA_TNUMBER) {
+                math_list(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                math_list(n) = null;
+            }
+        } else if (t == adjust_node) {
+            if (lua_type(L,2) == LUA_TNUMBER) {
+                adjust_ptr(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                adjust_ptr(n) = null;
+            }
         }
     }
     return 0;
@@ -874,6 +1010,14 @@
     halfword p = lua_tointeger(L, 1);
     if (p == null) {
         lua_pushnil(L);
+    } else if ((lua_type(L, 2) == LUA_TNUMBER)) {
+        /* experiment */
+        int n = lua_tointeger(L,2);
+        while (p != null && n > 0) {
+            p = vlink(p);
+            n -= 1;
+        }
+        nodelib_pushdirect_or_nil(p);
     } else {
         nodelib_pushdirect_or_nil(vlink(p));
     }
@@ -889,6 +1033,7 @@
     if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
         lua_pushnil(L);
     } else {
+        /* experiment */
         lua_get_metatablelua(luatex_node);
         if (!lua_rawequal(L, -1, -2)) {
             lua_pushnil(L);
@@ -947,6 +1092,13 @@
     halfword p = lua_tointeger(L, 1);
     if (p == null) {
         lua_pushnil(L);
+    } else if ((lua_type(L, 2) == LUA_TNUMBER)) {
+        int n = lua_tointeger(L,2);
+        while (p != null && n > 0) {
+            p = alink(p);
+            n -= 1;
+        }
+        nodelib_pushdirect_or_nil(p);
     } else {
         nodelib_pushdirect_or_nil(alink(p));
     }
@@ -1351,7 +1503,7 @@
             set_t_to_prev(head, current);
         couple_nodes(t, n);
     }
-    couple_nodes(n, current);
+    couple_nodes(n, current); /*  nice but incompatible: couple_nodes(tail_of_list(n),current) */
     if (head == current) {
         lua_pushinteger(L, n);
     } else {
@@ -1427,7 +1579,7 @@
         while (vlink(current) != null)
             current = vlink(current);
     }
-    try_couple_nodes(n, vlink(current));
+    try_couple_nodes(n, vlink(current)); /* nice but incompatible: try_couple_nodes(tail_of_list(n), vlink(current)); */
     couple_nodes(current, n);
     lua_pop(L, 2);
     lua_pushinteger(L, n);
@@ -4678,7 +4830,11 @@
     }
     alink(vlink(tmp_head)) = p ;
     lua_pushinteger(L, vlink(tmp_head));
-    lua_pushinteger(L, t);
+    if (t == null) {
+        lua_pushnil(L);
+    } else {
+        lua_pushinteger(L, t);
+    }
     lua_pushboolean(L, 1);
     flush_node(tmp_head);
     return 3;
@@ -6092,6 +6248,143 @@
     return 0;
 }
 
+static int lua_nodelib_direct_setfont(lua_State * L) /* family_font is not yet in manual, what does arg 2 do */
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n != null) {
+        halfword t = type(n);
+        /* mandate font */
+        if (t == glyph_node) {
+            font(n) = (halfword) lua_tointeger(L,2);
+            /* optional char */
+            if ((lua_type(L, 3) == LUA_TNUMBER)) {
+                character(n) = (halfword) lua_tointeger(L, 3);
+            }
+        }
+    }
+    return 0;
+}
+
+
+static int lua_nodelib_direct_setcomponents(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
+        if (type(n) == glyph_node) {
+            lig_ptr(n) = (halfword) lua_tointeger(L, 2);
+        }
+    }
+    return 0;
+}
+
+static int lua_nodelib_direct_setattributelist(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if ((n) && nodetype_has_attributes(type(n))) {
+        if (lua_type(L, 2) == LUA_TNUMBER) {
+            halfword a =lua_tointeger(L, 2);
+            if (type(a) == attribute_list_node) {
+                reassign_attribute(n,a);
+            } else if (nodetype_has_attributes(type(a))) {
+                reassign_attribute(n,node_attr(a));
+            } else {
+                reassign_attribute(n,null);
+            }
+        } else {
+            reassign_attribute(n,null);
+        }
+        return 0;
+    }
+    return 0;
+}
+
+static int lua_nodelib_direct_setlang(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
+        if (type(n) == glyph_node) {
+            set_char_lang(n,lua_tointeger(L, 2));
+        }
+    }
+    return 0;
+}
+
+static int lua_nodelib_direct_setpenalty(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n == null) {
+        if (type(n) == penalty_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                penalty(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                penalty(n) = 0;
+            }
+        } else if (type(n) == disc_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                disc_penalty(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                penalty(n) = 0;
+            }
+        }
+    }
+    return 0;
+}
+
+static int lua_nodelib_direct_setkern(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n != null) {
+        if (type(n) == kern_node || type(n) == margin_kern_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                width(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                width(n) = 0;
+            }
+            if (lua_type(L, 3) == LUA_TNUMBER) {
+                subtype(n) = (halfword) lua_tointeger(L, 3);
+            }
+        } else if (type(n) == math_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                surround(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                surround(n) = 0;
+            }
+        }
+    }
+    return 0;
+}
+
+static int lua_nodelib_direct_setdir(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n != null) {
+        if (type(n) == dir_node) {
+            dir_dir(n) = nodelib_getdir(L, 2, 0);
+        } else if (type(n) == hlist_node || type(n) == vlist_node) {
+            box_dir(n) = nodelib_getdir(L, 2, 1);
+        } else if (type(n) == rule_node) {
+            rule_dir(n) = nodelib_getdir(L, 2, 1);
+        } else if (type(n) == local_par_node) {
+            local_par_dir(n) = nodelib_getdir(L, 3, 1);
+        }
+    }
+    return 0;
+}
+
+static int lua_nodelib_direct_setoffsets(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if ((n) && (type(n) == glyph_node)) {
+        if ((lua_type(L, 2) == LUA_TNUMBER)) {
+            x_displace(n) = (halfword) lua_tointeger(L, 2);
+        }
+        if ((lua_type(L, 3) == LUA_TNUMBER)) {
+            y_displace(n) = (halfword) lua_tointeger(L, 3);
+        }
+    }
+    return 0;
+}
+
 static int lua_nodelib_direct_setnext(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
@@ -6136,6 +6429,7 @@
     return 0;
 }
 
+/*
 static int lua_nodelib_direct_setlink(lua_State * L)
 {
     if (lua_type(L, 1) == LUA_TNUMBER) {
@@ -6153,7 +6447,60 @@
     }
     return 0;
 }
+*/
 
+/*
+    a b b nil c d         : prev-a-b-c-next
+    nil a b b nil c d nil : nil-a-b-c-nil
+*/
+
+static int lua_nodelib_direct_setlink(lua_State * L)
+{
+    int n = lua_gettop(L);
+    int i;
+    halfword h = null; /* head node */
+    halfword t = null; /* tail node */
+    halfword c = null; /* current node */
+    for (i=1;i<=n;i++) {
+        /*
+            we don't go for the tail of the current node because we can inject
+            between existing nodes and the nodes themselves can have old values
+            for prev and next, so ... only single nodes are looked at!
+        */
+        if (lua_type(L, i) == LUA_TNUMBER) {
+            c = lua_tointeger(L, i);
+            if (c != t) {
+                if (t != null) {
+                    vlink(t) = c;
+                    alink(c) = t;
+                } else if (i > 1) {
+                    /* we assume that the first node is a kind of head */
+                    alink(c) = null;
+                }
+                t = c;
+                if (h == null) {
+                    h = t;
+                }
+            } else {
+                /* we ignore duplicate nodes which can be tails or the previous */
+            }
+        } else if (t == null) {
+            /* we just ignore nil nodes and have no tail yet */
+        } else {
+            /* safeguard: a nil in the list can be meant as end so we nil the next of tail */
+            vlink(t) = null;
+        }
+    }
+    if (h == null) {
+        /* no head */
+        lua_pushnil(L);
+    } else {
+        /* first valid head */
+        lua_pushinteger(L,h);
+    }
+    return 1;
+}
+
 static int lua_nodelib_direct_is_char(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
@@ -7158,6 +7505,12 @@
     {"free", lua_nodelib_direct_free},
     {"getbox", lua_nodelib_direct_getbox},
     {"getchar", lua_nodelib_direct_getcharacter},
+    {"getcomponents", lua_nodelib_direct_getcomponents},
+    {"getlang", lua_nodelib_direct_getlang},
+    {"getkern", lua_nodelib_direct_getkern},
+    {"getpenalty", lua_nodelib_direct_getpenalty},
+    {"getdir", lua_nodelib_direct_getdir},
+    {"getoffsets", lua_nodelib_direct_getoffsets},
     {"getdisc", lua_nodelib_direct_getdiscretionary},
     {"getwhd", lua_nodelib_direct_getwhd},
     {"getfield", lua_nodelib_direct_getfield},
@@ -7169,6 +7522,7 @@
     {"getlist", lua_nodelib_direct_getlist},
     {"getleader", lua_nodelib_direct_getleader},
     {"getsubtype", lua_nodelib_direct_getsubtype},
+    {"getattributelist", lua_nodelib_direct_getattributelist},
     {"has_glyph", lua_nodelib_direct_has_glyph},
     {"has_attribute", lua_nodelib_direct_has_attribute},
     {"get_attribute", lua_nodelib_direct_get_attribute},
@@ -7197,6 +7551,13 @@
     {"setbox", lua_nodelib_direct_setbox},
     {"setfield", lua_nodelib_direct_setfield},
     {"setchar", lua_nodelib_direct_setcharacter},
+    {"setfont", lua_nodelib_direct_setfont},
+    {"setcomponents", lua_nodelib_direct_setcomponents},
+    {"setlang", lua_nodelib_direct_setlang},
+    {"setkern", lua_nodelib_direct_setkern},
+    {"setpenalty", lua_nodelib_direct_setpenalty},
+    {"setdir", lua_nodelib_direct_setdir},
+    {"setoffsets", lua_nodelib_direct_setoffsets},
     {"setdisc", lua_nodelib_direct_setdiscretionary},
     {"setwhd", lua_nodelib_direct_setwhd},
     {"setnext", lua_nodelib_direct_setnext},
@@ -7206,6 +7567,7 @@
     {"setlist", lua_nodelib_direct_setlist},
     {"setleader", lua_nodelib_direct_setleader},
     {"setsubtype", lua_nodelib_direct_setsubtype},
+    {"setattributelist", lua_nodelib_direct_setattributelist},
     {"slide", lua_nodelib_direct_slide},
  /* {"subtype", lua_nodelib_subtype}, */ /* no node argument */
     {"tail", lua_nodelib_direct_tail},

Modified: trunk/Build/source/texk/web2c/luatexdir/lua/luainit.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/lua/luainit.w	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/lua/luainit.w	2017-02-09 22:44:03 UTC (rev 43177)
@@ -1,1091 +1,1091 @@
-% luainit.w
-%
-% Copyright 2006-2016 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-#include "ptexlib.h"
-
-#include <kpathsea/c-stat.h>
-
-#include "lua/luatex-api.h"
-
-/* internalized strings: see luatex-api.h */
-set_make_keys;
-
-@
-This file is getting a bit messy, but it is not simple to fix unilaterally.
-
-Better to wait until Karl has some time (after texlive 2008) so we can
-synchronize with kpathsea. One problem, for instance, is that I would
-like to resolve the full executable path.  |kpse_set_program_name()| does
-that, indirectly (by setting SELFAUTOLOC in the environment), but it
-does much more, making it hard to use for our purpose.
-
-In fact, it sets three C variables:
-
-  |kpse_invocation_name|  |kpse_invocation_short_name|  |kpse->program_name|
-
-and five environment variables:
-
-  SELFAUTOLOC  SELFAUTODIR  SELFAUTOPARENT  SELFAUTOGRANDPARENT  progname
-
- at c
-const_string LUATEX_IHELP[] = {
-    "Usage: " my_name " --lua=FILE [OPTION]... [TEXNAME[.tex]] [COMMANDS]",
-    "   or: " my_name " --lua=FILE [OPTION]... \\FIRST-LINE",
-    "   or: " my_name " --lua=FILE [OPTION]... &FMT ARGS",
-    "  Run " MyName " on TEXNAME, usually creating TEXNAME.pdf.",
-    "  Any remaining COMMANDS are processed as luatex input, after TEXNAME is read.",
-    "",
-    "  Alternatively, if the first non-option argument begins with a backslash,",
-    "  " my_name " interprets all non-option arguments as an input line.",
-    "",
-    "  Alternatively, if the first non-option argument begins with a &, the",
-    "  next word is taken as the FMT to read, overriding all else.  Any",
-    "  remaining arguments are processed as above.",
-    "",
-    "  If no arguments or options are specified, prompt for input.",
-    "",
-    "  The following regular options are understood: ",
-    "",
-    "   --credits                     display credits and exit",
-    "   --debug-format                enable format debugging",
-    "   --draftmode                   switch on draft mode (generates no output PDF)",
-    "   --[no-]file-line-error        disable/enable file:line:error style messages",
-    "   --[no-]file-line-error-style  aliases of --[no-]file-line-error",
-    "   --fmt=FORMAT                  load the format file FORMAT",
-    "   --halt-on-error               stop processing at the first error",
-    "   --help                        display help and exit",
-    "   --ini                         be ini" my_name ", for dumping formats",
-    "   --interaction=STRING          set interaction mode (STRING=batchmode/nonstopmode/scrollmode/errorstopmode)",
-    "   --jobname=STRING              set the job name to STRING",
-    "   --kpathsea-debug=NUMBER       set path searching debugging flags according to the bits of NUMBER",
-    "   --lua=FILE                    load and execute a lua initialization script",
-    "   --[no-]mktex=FMT              disable/enable mktexFMT generation (FMT=tex/tfm)",
-    "   --nosocket                    disable the lua socket library",
-    "   --output-comment=STRING       use STRING for DVI file comment instead of date (no effect for PDF)",
-    "   --output-directory=DIR        use existing DIR as the directory to write files in",
-    "   --output-format=FORMAT        use FORMAT for job output; FORMAT is 'dvi' or 'pdf'",
-    "   --progname=STRING             set the program name to STRING",
-    "   --recorder                    enable filename recorder",
-    "   --safer                       disable easily exploitable lua commands",
-    "   --[no-]shell-escape           disable/enable system commands",
-    "   --shell-restricted            restrict system commands to a list of commands given in texmf.cnf",
-    "   --synctex=NUMBER              enable synctex",
-    "   --utc                         init time to UTC",
-    "   --version                     display version and exit",
-    "",
-    "Alternate behaviour models can be obtained by special switches",
-    "",
-    "  --luaonly                      run a lua file, then exit",
-    "  --luaconly                     byte-compile a lua file, then exit",
-    "  --luahashchars                 the bits used by current Lua interpreter for strings hashing",
-#ifdef LuajitTeX
-    "  --jiton                        turns the JIT compiler on (default off)",
-    "  --jithash=STRING               choose the hash function for the lua strings (lua51|luajit20: default lua51)",
-#endif
-    "",
-    "See the reference manual for more information about the startup process.",
-    NULL
-};
-
-/*
-    "   --8bit                        ignored, input is assumed to be in UTF-8 encoding",
-    "   --default-translate-file=FILE ignored, input is assumed to be in UTF-8 encoding",
-    "   --etex                        ignored, the etex extensions are always active",
-    "   --disable-write18             disable \\write18{SHELL COMMAND}",
-    "   --enable-write18              enable \\write18{SHELL COMMAND}",
-    "   --[no-]parse-first-line       ignored",
-    "   --translate-file=FILE         ignored, input is assumed to be in UTF-8 encoding",
-*/
-
-@ The return value will be the directory of the executable, e.g.: \.{c:/TeX/bin}
- at c
-static char *ex_selfdir(char *argv0)
-{
-#if defined(WIN32)
-#if defined(__MINGW32__)
-    char path[PATH_MAX], *fp;
-
-    /* SearchPath() always gives back an absolute directory */
-    if (SearchPath(NULL, argv0, ".exe", PATH_MAX, path, NULL) == 0)
-        FATAL1("Can't determine where the executable %s is.\n", argv0);
-    /* slashify the dirname */
-    for (fp = path; fp && *fp; fp++)
-        if (IS_DIR_SEP(*fp))
-            *fp = DIR_SEP;
-#else /* __MINGW32__ */
-#define PATH_MAX 512
-    char short_path[PATH_MAX], path[PATH_MAX], *fp;
-
-    /* SearchPath() always gives back an absolute directory */
-    if (SearchPath(NULL, argv0, ".exe", PATH_MAX, short_path, &fp) == 0)
-        FATAL1("Can't determine where the executable %s is.\n", argv0);
-    if (getlongpath(path, short_path, sizeof(path)) == 0) {
-        FATAL1("This path points to an invalid file : %s\n", short_path);
-    }
-#endif /* __MINGW32__ */
-   return xdirname(path);
-#else /* WIN32 */
-    return kpse_selfdir(argv0);
-#endif
-}
-
-@ @c
-static void prepare_cmdline(lua_State * L, char **av, int ac, int zero_offset)
-{
-    int i;
-    char *s;
-    luaL_checkstack(L, ac + 3, "too many arguments to script");
-    lua_createtable(L, 0, 0);
-    for (i = 0; i < ac; i++) {
-        lua_pushstring(L, av[i]);
-        lua_rawseti(L, -2, (i - zero_offset));
-    }
-    lua_setglobal(L, "arg");
-    lua_getglobal(L, "os");
-    s = ex_selfdir(argv[0]);
-    lua_pushstring(L, s);
-    xfree(s);
-    lua_setfield(L, -2, "selfdir");
-    return;
-}
-
-
-@ @c
-int kpse_init = -1;
-
-@ @c
-string input_name = NULL;
-
-static string user_progname = NULL;
-
-char *startup_filename = NULL;
-int lua_only = 0;
-int lua_offset = 0;
-unsigned char show_luahashchars = 0;
-
-#ifdef LuajitTeX
-int luajiton   = 0;
-char *jithash_hashname = NULL;
-#endif
-
-int safer_option = 0;
-int nosocket_option = 0;
-int utc_option = 0;
-
-@ Reading the options.
-
-@ Test whether getopt found an option ``A''.
-Assumes the option index is in the variable |option_index|, and the
-option table in a variable |long_options|.
-
- at c
-#define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
-
-/*
-    SunOS cc can't initialize automatic structs, so make this static.
-*/
-
-/*
-    Nota Bene: we still intercept some options that other engines handle
-    so that existing scripted usage will not fail.
-*/
-
-static struct option long_options[] = {
-    {"fmt", 1, 0, 0},
-    {"lua", 1, 0, 0},
-    {"luaonly", 0, 0, 0},
-    {"luahashchars", 0, 0, 0},
-#ifdef LuajitTeX
-    {"jiton", 0, 0, 0},
-    {"jithash", 1, 0, 0},
-#endif
-    {"safer", 0, &safer_option, 1},
-    {"utc", 0, &utc_option, 1},
-    {"nosocket", 0, &nosocket_option, 1},
-    {"help", 0, 0, 0},
-    {"ini", 0, &ini_version, 1},
-    {"interaction", 1, 0, 0},
-    {"halt-on-error", 0, &haltonerrorp, 1},
-    {"kpathsea-debug", 1, 0, 0},
-    {"progname", 1, 0, 0},
-    {"version", 0, 0, 0},
-    {"credits", 0, 0, 0},
-    {"recorder", 0, 0, 0},
-    {"etex", 0, 0, 0},
-    {"output-comment", 1, 0, 0},
-    {"output-directory", 1, 0, 0},
-    {"draftmode", 0, 0, 0},
-    {"output-format", 1, 0, 0},
-    {"shell-escape", 0, &shellenabledp, 1},
-    {"no-shell-escape", 0, &shellenabledp, -1},
-    {"enable-write18", 0, &shellenabledp, 1},
-    {"disable-write18", 0, &shellenabledp, -1},
-    {"shell-restricted", 0, 0, 0},
-    {"debug-format", 0, &debug_format_file, 1},
-    {"file-line-error-style", 0, &filelineerrorstylep, 1},
-    {"no-file-line-error-style", 0, &filelineerrorstylep, -1},
-
-    /* Shorter option names for the above. */
-
-    {"file-line-error", 0, &filelineerrorstylep, 1},
-    {"no-file-line-error", 0, &filelineerrorstylep, -1},
-    {"jobname", 1, 0, 0},
-    {"parse-first-line", 0, &parsefirstlinep, 1},
-    {"no-parse-first-line", 0, &parsefirstlinep, -1},
-    {"translate-file", 1, 0, 0},
-    {"default-translate-file", 1, 0, 0},
-    {"8bit", 0, 0, 0},
-    {"mktex", 1, 0, 0},
-    {"no-mktex", 1, 0, 0},
-
-    /* Synchronization: just like "interaction" above */
-
-    {"synctex", 1, 0, 0},
-    {0, 0, 0, 0}
-};
-
-@ @c
-int lua_numeric_field_by_index(lua_State * L, int name_index, int dflt)
-{
-    register int i = dflt;
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    if (lua_type(L, -1) == LUA_TNUMBER) {
-        i = lua_roundnumber(L, -1);
-    }
-    lua_pop(L, 1);
-    return i;
-}
-
-@ @c
-unsigned int lua_unsigned_numeric_field_by_index(lua_State * L, int name_index, int dflt)
-{
-    register unsigned int i = dflt;
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    if (lua_type(L, -1) == LUA_TNUMBER) {
-        i = lua_uroundnumber(L, -1);
-    }
-    lua_pop(L, 1);
-    return i;
-}
-
-@ @c
-static int recorderoption = 0;
-
-static void parse_options(int ac, char **av)
-{
-#ifdef WIN32
-/* save argc and argv */
-    int sargc = argc;
-    char **sargv = argv;
-#endif
-    int g;                      /* `getopt' return code.  */
-    int option_index;
-    char *firstfile = NULL;
-    opterr = 0;                 /* dont whine */
-#ifdef LuajitTeX
-    if ((strstr(argv[0], "luajittexlua") != NULL) ||
-        (strstr(argv[0], "texluajit") != NULL)) {
-#else
-    if ((strstr(argv[0], "luatexlua") != NULL) ||
-        (strstr(argv[0], "texlua") != NULL)) {
-#endif
-        lua_only = 1;
-        luainit = 1;
-    }
-    for (;;) {
-        g = getopt_long_only(ac, av, "+", long_options, &option_index);
-
-        if (g == -1)            /* End of arguments, exit the loop.  */
-            break;
-        if (g == '?')  {         /* Unknown option.  */
-          if (!luainit)
-            fprintf(stderr,"%s: unrecognized option '%s'\n", argv[0], argv[optind-1]);
-          continue;
-        }
-
-        assert(g == 0);         /* We have no short option names.  */
-
-        if (ARGUMENT_IS("luaonly")) {
-            lua_only = 1;
-            lua_offset = optind;
-            luainit = 1;
-        } else if (ARGUMENT_IS("lua")) {
-            startup_filename = optarg;
-            lua_offset = (optind - 1);
-            luainit = 1;
-#ifdef LuajitTeX
-        } else if (ARGUMENT_IS("jiton")) {
-            luajiton = 1;
-        } else if (ARGUMENT_IS("jithash")) {
-        size_t len = strlen(optarg);
-        if (len<16) {
-            jithash_hashname = optarg;
-        } else {
-            WARNING2("hash name truncated to 15 characters from %d. (%s)", (int) len, optarg);
-            jithash_hashname = (string) xmalloc(16);
-            strncpy(jithash_hashname, optarg, 15);
-            jithash_hashname[15] = 0;
-      }
-#endif
-        } else if (ARGUMENT_IS("luahashchars")) {
-            show_luahashchars = 1;
-        } else if (ARGUMENT_IS("kpathsea-debug")) {
-            kpathsea_debug |= atoi(optarg);
-        } else if (ARGUMENT_IS("progname")) {
-            user_progname = optarg;
-        } else if (ARGUMENT_IS("jobname")) {
-            c_job_name = optarg;
-        } else if (ARGUMENT_IS("fmt")) {
-            dump_name = optarg;
-        } else if (ARGUMENT_IS("output-directory")) {
-            output_directory = optarg;
-        } else if (ARGUMENT_IS("output-comment")) {
-            size_t len = strlen(optarg);
-            if (len < 256) {
-                output_comment = optarg;
-            } else {
-                WARNING2("Comment truncated to 255 characters from %d. (%s)", (int) len, optarg);
-                output_comment = (string) xmalloc(256);
-                strncpy(output_comment, optarg, 255);
-                output_comment[255] = 0;
-            }
-        } else if (ARGUMENT_IS("shell-restricted")) {
-            shellenabledp = 1;
-            restrictedshell = 1;
-        } else if (ARGUMENT_IS("output-format")) {
-            output_mode_option = 1;
-            if (strcmp(optarg, "dvi") == 0) {
-                output_mode_value = 0;
-            } else if (strcmp(optarg, "pdf") == 0) {
-                output_mode_value = 1;
-            } else {
-                WARNING1("Ignoring unknown value `%s' for --output-format",optarg);
-                output_mode_option = 0;
-            }
-        } else if (ARGUMENT_IS("draftmode")) {
-            draft_mode_option = 1;
-            draft_mode_value = 1;
-        } else if (ARGUMENT_IS("mktex")) {
-            kpse_maketex_option(optarg, true);
-        } else if (ARGUMENT_IS("no-mktex")) {
-            kpse_maketex_option(optarg, false);
-        } else if (ARGUMENT_IS("interaction")) {
-            /* These numbers match CPP defines */
-            if (STREQ(optarg, "batchmode")) {
-                interactionoption = 0;
-            } else if (STREQ(optarg, "nonstopmode")) {
-                interactionoption = 1;
-            } else if (STREQ(optarg, "scrollmode")) {
-                interactionoption = 2;
-            } else if (STREQ(optarg, "errorstopmode")) {
-                interactionoption = 3;
-            } else {
-                WARNING1("Ignoring unknown argument `%s' to --interaction", optarg);
-            }
-        } else if (ARGUMENT_IS("synctex")) {
-            /* Synchronize TeXnology: catching the command line option as a long  */
-            synctexoption = (int) strtol(optarg, NULL, 0);
-        } else if (ARGUMENT_IS("recorder")) {
-            recorderoption = 1 ;
-        } else if (ARGUMENT_IS("help")) {
-            usagehelp(LUATEX_IHELP, BUG_ADDRESS);
-        } else if (ARGUMENT_IS("version")) {
-            print_version_banner();
-            /* *INDENT-OFF* */
-            puts("\n\nExecute  '" my_name " --credits'  for credits and version details.\n\n"
-                 "There is NO warranty. Redistribution of this software is covered by\n"
-                 "the terms of the GNU General Public License, version 2 or (at your option)\n"
-                 "any later version. For more information about these matters, see the file\n"
-                 "named COPYING and the LuaTeX source.\n\n"
-                 "LuaTeX is Copyright 2016 Taco Hoekwater and the LuaTeX Team.\n");
-            /* *INDENT-ON* */
-            uexit(0);
-        } else if (ARGUMENT_IS("credits")) {
-            char *versions;
-            initversionstring(&versions);
-            print_version_banner();
-            /* *INDENT-OFF* */
-            puts("\n\nThe LuaTeX team is Hans Hagen, Hartmut Henkel, Taco Hoekwater, Luigi Scarso.\n\n"
-                 MyName " merges and builds upon (parts of) the code from these projects:\n\n"
-                 "tex       : Donald Knuth\n"
-                 "etex      : Peter Breitenlohner, Phil Taylor and friends\n"
-                 "omega     : John Plaice and Yannis Haralambous\n"
-                 "aleph     : Giuseppe Bilotta\n"
-                 "pdftex    : Han The Thanh and friends\n"
-                 "kpathsea  : Karl Berry, Olaf Weber and others\n"
-                 "lua       : Roberto Ierusalimschy, Waldemar Celes and Luiz Henrique de Figueiredo\n"
-                 "metapost  : John Hobby, Taco Hoekwater and friends\n"
-                 "poppler   : Derek Noonburg, Kristian H\\ogsberg (partial)\n"
-                 "fontforge : George Williams (partial)\n"
-                 "luajit    : Mike Pall (used in LuajitTeX)\n");
-            /* *INDENT-ON* */
-            puts(versions);
-            uexit(0);
-        }
-    }
-    /* attempt to find |input_name| / |dump_name| */
-    if (lua_only) {
-        if (argv[optind]) {
-            startup_filename = xstrdup(argv[optind]);
-            lua_offset = optind;
-        }
-    } else if (argv[optind] && argv[optind][0] == '&') {
-        dump_name = xstrdup(argv[optind] + 1);
-    } else if (argv[optind] && argv[optind][0] != '\\') {
-        if (argv[optind][0] == '*') {
-            input_name = xstrdup(argv[optind] + 1);
-        } else {
-            firstfile = xstrdup(argv[optind]);
-            if ((strstr(firstfile, ".lua") ==
-                 firstfile + strlen(firstfile) - 4)
-                || (strstr(firstfile, ".luc") ==
-                    firstfile + strlen(firstfile) - 4)
-                || (strstr(firstfile, ".LUA") ==
-                    firstfile + strlen(firstfile) - 4)
-                || (strstr(firstfile, ".LUC") ==
-                    firstfile + strlen(firstfile) - 4)) {
-                if (startup_filename == NULL) {
-                    startup_filename = firstfile;
-                    lua_offset = optind;
-                    lua_only = 1;
-                    luainit = 1;
-                }
-            } else {
-                input_name = firstfile;
-            }
-        }
-#ifdef WIN32
-    } else if (sargc > 1 && sargv[sargc-1] && sargv[sargc-1][0] != '-' &&
-               sargv[sargc-1][0] != '\\') {
-        if (sargv[sargc-1][0] == '&')
-            dump_name = xstrdup(sargv[sargc-1] + 1);
-        else  {
-            if (sargv[sargc-1][0] == '*')
-                input_name = xstrdup(sargv[sargc-1] + 1);
-            else
-                input_name = xstrdup(sargv[sargc-1]);
-            sargv[sargc-1] = normalize_quotes(input_name, "argument");
-        }
-        if (safer_option)      /* --safer implies --nosocket */
-            nosocket_option = 1;
-        return;
-#endif
-    }
-    if (safer_option)           /* --safer implies --nosocket */
-        nosocket_option = 1;
-    /* Finalize the input filename. */
-    if (input_name != NULL) {
-        argv[optind] = normalize_quotes(input_name, "argument");
-    }
-}
-
-@ test for readability
- at c
-#define is_readable(a) (stat(a,&finfo)==0) && S_ISREG(finfo.st_mode) &&  \
-  (f=fopen(a,"r")) != NULL && !fclose(f)
-
-@ @c
-static char *find_filename(char *name, const char *envkey)
-{
-    struct stat finfo;
-    char *dirname = NULL;
-    char *filename = NULL;
-    FILE *f;
-    if (is_readable(name)) {
-        return name;
-    } else {
-        dirname = getenv(envkey);
-        if ((dirname != NULL) && strlen(dirname)) {
-            dirname = xstrdup(getenv(envkey));
-            if (*(dirname + strlen(dirname) - 1) == '/') {
-                *(dirname + strlen(dirname) - 1) = 0;
-            }
-            filename = xmalloc((unsigned) (strlen(dirname) + strlen(name) + 2));
-            filename = concat3(dirname, "/", name);
-            xfree(dirname);
-            if (is_readable(filename)) {
-                return filename;
-            }
-            xfree(filename);
-        }
-    }
-    return NULL;
-}
-
-@ @c
-
-static void init_kpse(void)
-{
-    if (!user_progname) {
-        user_progname = dump_name;
-    } else if (!dump_name) {
-        dump_name = user_progname;
-    }
-    if (!user_progname) {
-        if (ini_version) {
-            if (input_name) {
-                char *p = input_name + strlen(input_name) - 1;
-                while (p >= input_name) {
-                    if (IS_DIR_SEP (*p)) {
-                        p++;
-                        input_name = p;
-                        break;
-                    }
-                    p--;
-                }
-                user_progname = remove_suffix (input_name);
-            }
-            if (!user_progname) {
-                user_progname = kpse_program_basename(argv[0]);
-            }
-        } else {
-            if (!dump_name) {
-                dump_name = kpse_program_basename(argv[0]);
-            }
-            user_progname = dump_name;
-        }
-    }
-    kpse_set_program_enabled(kpse_fmt_format, MAKE_TEX_FMT_BY_DEFAULT,
-                             kpse_src_compile);
-
-    kpse_set_program_name(argv[0], user_progname);
-    init_shell_escape();        /* set up 'restrictedshell' */
-    init_start_time();
-    program_name_set = 1 ;
-    if (recorderoption) {
-        recorder_enabled = 1;
-    }
-}
-
-@ @c
-static void fix_dumpname(void)
-{
-    int dist;
-    if (dump_name) {
-        /* adjust array for Pascal and provide extension, if needed */
-        dist = (int) (strlen(dump_name) - strlen(DUMP_EXT));
-        if (strstr(dump_name, DUMP_EXT) == dump_name + dist)
-            TEX_format_default = dump_name;
-        else
-            TEX_format_default = concat(dump_name, DUMP_EXT);
-    } else {
-        /* For |dump_name| to be NULL is a bug.  */
-        if (!ini_version) {
-          fprintf(stdout, "no format given, quitting\n");
-          exit(1);
-        }
-    }
-}
-
-@ lua require patch
-
-@ Auxiliary function for kpse search
-
- at c
-static const char *luatex_kpse_find_aux(lua_State *L, const char *name,
-        kpse_file_format_type format, const char *errname)
-{
-    const char *filename;
-    const char *altname;
-    altname = luaL_gsub(L, name, ".", "/"); /* Lua convention */
-    filename = kpse_find_file(altname, format, false);
-    if (filename == NULL) {
-        filename = kpse_find_file(name, format, false);
-    }
-    if (filename == NULL) {
-        lua_pushfstring(L, "\n\t[kpse %s searcher] file not found: " LUA_QS, errname, name);
-    }
-    return filename;
-}
-
-@ The lua search function.
-
-When kpathsea is not initialized, then it runs the
-normal lua function that is saved in the registry, otherwise
-it uses kpathsea.
-
-two registry ref variables are needed: one for the actual lua
-function, the other for its environment .
-
- at c
-static int lua_loader_function = 0;
-
-static int luatex_kpse_lua_find(lua_State * L)
-{
-    const char *filename;
-    const char *name;
-    name = luaL_checkstring(L, 1);
-    if (program_name_set == 0) {
-        lua_rawgeti(L, LUA_REGISTRYINDEX, lua_loader_function);
-        lua_pushvalue(L, -2);
-        lua_call(L, 1, 1);
-        return 1;
-    }
-    filename = luatex_kpse_find_aux(L, name, kpse_lua_format, "lua");
-    if (filename == NULL)
-        return 1;               /* library not found in this path */
-    if (luaL_loadfile(L, filename) != 0) {
-        luaL_error(L, "error loading module %s from file %s:\n\t%s",
-                   lua_tostring(L, 1), filename, lua_tostring(L, -1));
-    }
-    return 1;                   /* library loaded successfully */
-}
-
-@ @c
-static int clua_loader_function = 0;
-extern int searcher_C_luatex (lua_State *L, const char *name, const char *filename);
-
-static int luatex_kpse_clua_find(lua_State * L)
-{
-    const char *filename;
-    const char *name;
-    if (safer_option) {
-        lua_pushliteral(L, "\n\t[C searcher disabled in safer mode]");
-        return 1;               /* library not found in this path */
-    }
-    name = luaL_checkstring(L, 1);
-    if (program_name_set == 0) {
-        lua_rawgeti(L, LUA_REGISTRYINDEX, clua_loader_function);
-        lua_pushvalue(L, -2);
-        lua_call(L, 1, 1);
-        return 1;
-    } else {
-        const char *path_saved;
-        char *prefix, *postfix, *p, *total;
-        char *extensionless;
-        char *temp_name;
-        int j;
-        filename = luatex_kpse_find_aux(L, name, kpse_clua_format, "C");
-        if (filename == NULL)
-           return 1;               /* library not found in this path */
-        extensionless = strdup(filename);
-        if (!extensionless)
-            return 1;  /* allocation failure */
-        /* Fix Issue 850: replace '.' with LUA_DIRSEP */
-        temp_name = strdup(name);
-        for(j=0; ; j++){
-          if ((unsigned char)temp_name[j]=='\0') {
-            break;
-          }
-          if ((unsigned char)temp_name[j]=='.'){
-            temp_name[j]=LUA_DIRSEP[0];
-          }
-        }
-        p = strstr(extensionless, temp_name);
-        if (!p) return 1;  /* this would be exceedingly weird */
-        *p = '\0';
-        prefix = strdup(extensionless);
-        if (!prefix) return 1;  /* allocation failure */
-        postfix = strdup(p+strlen(name));
-        if (!postfix) return 1;  /* allocation failure */
-        total = malloc(strlen(prefix)+strlen(postfix)+2);
-        if (!total) return 1;  /* allocation failure */
-        snprintf(total,strlen(prefix)+strlen(postfix)+2, "%s?%s", prefix, postfix);
-        /* save package.path */
-        lua_getglobal(L,"package");
-        lua_getfield(L,-1,"cpath");
-        path_saved = lua_tostring(L,-1);
-        lua_pop(L,1);
-        /* set package.path = "?" */
-        lua_pushstring(L,total);
-        lua_setfield(L,-2,"cpath");
-        lua_pop(L,1); /* pop "package" */
-        /* run function */
-        lua_rawgeti(L, LUA_REGISTRYINDEX, clua_loader_function);
-        lua_pushstring(L, name);
-        lua_call(L, 1, 1);
-        /* restore package.path */
-        lua_getglobal(L,"package");
-        lua_pushstring(L,path_saved);
-        lua_setfield(L,-2,"cpath");
-        lua_pop(L,1); /* pop "package" */
-        free(extensionless);
-        free(total);
-        free(temp_name);
-        return 1;
-    }
-}
-
-@ Setting up the new search functions.
-
-This replaces package.searchers[2] and package.searchers[3] with the
-functions defined above.
-
- at c
-static void setup_lua_path(lua_State * L)
-{
-    lua_getglobal(L, "package");
-#ifdef LuajitTeX
-    lua_getfield(L, -1, "loaders");
-#else
-    lua_getfield(L, -1, "searchers");
-#endif
-    lua_rawgeti(L, -1, 2);      /* package.searchers[2] */
-    lua_loader_function = luaL_ref(L, LUA_REGISTRYINDEX);
-    lua_pushcfunction(L, luatex_kpse_lua_find);
-    lua_rawseti(L, -2, 2);      /* replace the normal lua loader */
-
-    lua_rawgeti(L, -1, 3);      /* package.searchers[3] */
-    clua_loader_function = luaL_ref(L, LUA_REGISTRYINDEX);
-    lua_pushcfunction(L, luatex_kpse_clua_find);
-    lua_rawseti(L, -2, 3);      /* replace the normal lua lib loader */
-
-    lua_pop(L, 2);              /* pop the array and table */
-}
-
-@ helper variables for the safe keeping of table ids
-
- at c
-int tex_table_id;
-int pdf_table_id;
-int token_table_id;
-int node_table_id;
-
-@ @c
-int l_pack_type_index       [PACK_TYPE_SIZE] ;
-int l_group_code_index      [GROUP_CODE_SIZE];
-int l_local_par_index       [LOCAL_PAR_SIZE];
-int l_math_style_name_index [MATH_STYLE_NAME_SIZE];
-int l_dir_par_index         [DIR_PAR_SIZE];
-int l_dir_text_index        [DIR_TEXT_SIZE];
-
-int img_parms               [img_parms_max];
-int img_pageboxes           [img_pageboxes_max];
-
-int lua_show_valid_list(lua_State *L, const char **list, int max)
-{
-    int i;
-    lua_newtable(L);
-    for (i = 0; i < max; i++) {
-        lua_pushinteger(L,i+1);
-        lua_pushstring(L, list[i]);
-        lua_settable(L, -3);
-    }
-    return 1;
-}
-
-int lua_show_valid_keys(lua_State *L, int *list, int max)
-{
-    int i;
-    lua_newtable(L);
-    for (i = 0; i < max; i++) {
-        lua_pushinteger(L,i+1);
-        lua_rawgeti(L, LUA_REGISTRYINDEX, list[i]);
-        lua_settable(L, -3);
-    }
-    return 1;
-}
-
-#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
-char **suffixlist;
-
-#  define EXE_SUFFIXES ".com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh;.ws;.tcl;.py;.pyw"
-
-@ @c
-static void mk_suffixlist(void)
-{
-    char **p;
-    char *q, *r, *v;
-    int n;
-
-#  if defined(__CYGWIN__)
-    v = xstrdup(EXE_SUFFIXES);
-#  else
-    v = (char *) getenv("PATHEXT");
-    if (v)                      /* strlwr() exists also in MingW */
-        v = (char *) strlwr(xstrdup(v));
-    else
-        v = xstrdup(EXE_SUFFIXES);
-#  endif
-
-    q = v;
-    n = 0;
-
-    while ((r = strchr(q, ';')) != NULL) {
-        n++;
-        r++;
-        q = r;
-    }
-    if (*q)
-        n++;
-    suffixlist = (char **) xmalloc((n + 2) * sizeof(char *));
-    p = suffixlist;
-    *p = xstrdup(".dll");
-    p++;
-    q = v;
-    while ((r = strchr(q, ';')) != NULL) {
-        *r = '\0';
-        *p = xstrdup(q);
-        p++;
-        r++;
-        q = r;
-    }
-    if (*q) {
-        *p = xstrdup(q);
-        p++;
-    }
-    *p = NULL;
-    free(v);
-}
-#endif
-
-@ @c
-void lua_initialize(int ac, char **av)
-{
-    char *given_file = NULL;
-    char *banner;
-    /*int kpse_init;*/
-    size_t len;
-    int starttime;
-    int utc;
-    static char LC_CTYPE_C[] = "LC_CTYPE=C";
-    static char LC_COLLATE_C[] = "LC_COLLATE=C";
-    static char LC_NUMERIC_C[] = "LC_NUMERIC=C";
-    static char engine_luatex[] = "engine=" my_name;
-    /* Save to pass along to topenin.  */
-    const char *fmt = "This is " MyName ", Version %s" WEB2CVERSION;
-    argc = ac;
-    argv = av;
-    len = strlen(fmt) + strlen(luatex_version_string) ;
-    banner = xmalloc(len);
-    sprintf(banner, fmt, luatex_version_string);
-    luatex_banner = banner;
-    kpse_invocation_name = kpse_program_basename(argv[0]);
-
-    /* be 'luac' */
-    if (argc >1) {
-#ifdef LuajitTeX
-        if (FILESTRCASEEQ(kpse_invocation_name, "texluajitc"))
-            exit(luac_main(ac, av));
-        if (STREQ(argv[1], "--luaconly") || STREQ(argv[1], "--luac")) {
-            char *argv1 = xmalloc (strlen ("luajittex") + 1);
-            av[1] = argv1;
-            strcpy (av[1], "luajittex");
-            exit(luac_main(--ac, ++av));
-        }
-#else
-        if (FILESTRCASEEQ(kpse_invocation_name, "texluac"))
-            exit(luac_main(ac, av));
-        if (STREQ(argv[1], "--luaconly") || STREQ(argv[1], "--luac")) {
-            strcpy(av[1], "luatex");
-            exit(luac_main(--ac, ++av));
-        }
-#endif
-    }
-#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
-    mk_suffixlist();
-#endif
-
-    /* Must be initialized before options are parsed.  */
-    interactionoption = 4;
-    dump_name = NULL;
-
-    /* 0 means "disable Synchronize TeXnology".
-     synctexoption is a *.web variable.
-     We initialize it to a weird value to catch the -synctex command line flag
-     At runtime, if synctexoption is not |INT_MAX|, then it contains the command line option provided,
-     otherwise no such option was given by the user. */
-#define SYNCTEX_NO_OPTION INT_MAX
-    synctexoption = SYNCTEX_NO_OPTION;
-
-    /* parse commandline */
-    parse_options(ac, av);
-    if (lua_only)
-        shellenabledp = true;
-
-    /* make sure that the locale is 'sane' (for lua) */
-
-    putenv(LC_CTYPE_C);
-    putenv(LC_COLLATE_C);
-    putenv(LC_NUMERIC_C);
-
-    /* this is sometimes needed */
-    putenv(engine_luatex);
-
-    luainterpreter();
-
-    /* init internalized strings */
-    set_init_keys;
-
-    lua_pushstring(Luas,"lua.functions");
-    lua_newtable(Luas);
-    lua_settable(Luas,LUA_REGISTRYINDEX);
-
-    /* here start the key definitions */
-    set_l_pack_type_index;
-    set_l_group_code_index;
-    set_l_local_par_index;
-    set_l_math_style_name_index;
-    set_l_dir_par_index;
-    set_l_dir_text_index;
-
-    set_l_img_keys_index;
-    set_l_img_pageboxes_index;
-
-    prepare_cmdline(Luas, argv, argc, lua_offset);      /* collect arguments */
-    setup_lua_path(Luas);
-
-    if (startup_filename != NULL) {
-        given_file = xstrdup(startup_filename);
-        if (lua_only) {
-          xfree(startup_filename);
-        }
-        startup_filename = find_filename(given_file, "LUATEXDIR");
-    }
-    /* now run the file */
-    if (startup_filename != NULL) {
-        char *v1;
-        /* hide the 'tex' and 'pdf' table */
-        tex_table_id = hide_lua_table(Luas, "tex");
-        token_table_id = hide_lua_table(Luas, "token");
-        node_table_id = hide_lua_table(Luas, "node");
-        pdf_table_id = hide_lua_table(Luas, "pdf");
-
-        if (luaL_loadfile(Luas, startup_filename)) {
-            fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
-            exit(1);
-        }
-        /* */
-        init_tex_table(Luas);
-        if (lua_pcall(Luas, 0, 0, 0)) {
-            fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
-        lua_traceback(Luas);
-            exit(1);
-        }
-        /* no filename? quit now! */
-        if (!input_name) {
-            get_lua_string("texconfig", "jobname", &input_name);
-        }
-        if (!dump_name) {
-            get_lua_string("texconfig", "formatname", &dump_name);
-        }
-        if (lua_only) {
-            if (given_file)
-                free(given_file);
-            /* this is not strictly needed but it pleases valgrind */
-            lua_close(Luas);
-            exit(0);
-        }
-        /* unhide the 'tex' and 'pdf' table */
-        unhide_lua_table(Luas, "tex", tex_table_id);
-        unhide_lua_table(Luas, "pdf", pdf_table_id);
-        unhide_lua_table(Luas, "token", token_table_id);
-        unhide_lua_table(Luas, "node", node_table_id);
-
-        /* |kpse_init| */
-        kpse_init = -1;
-        get_lua_boolean("texconfig", "kpse_init", &kpse_init);
-
-        if (kpse_init != 0) {
-            luainit = 0;        /* re-enable loading of texmf.cnf values, see luatex.ch */
-            init_kpse();
-        }
-        /* |prohibit_file_trace| (boolean) */
-        tracefilenames = 1;
-        get_lua_boolean("texconfig", "trace_file_names", &tracefilenames);
-
-        /* |file_line_error| */
-        filelineerrorstylep = false;
-        get_lua_boolean("texconfig", "file_line_error", &filelineerrorstylep);
-
-        /* |halt_on_error| */
-        haltonerrorp = false;
-        get_lua_boolean("texconfig", "halt_on_error", &haltonerrorp);
-
-        /* |restrictedshell| */
-        v1 = NULL;
-        get_lua_string("texconfig", "shell_escape", &v1);
-        if (v1) {
-            if (*v1 == 't' || *v1 == 'y' || *v1 == '1') {
-                shellenabledp = 1;
-            } else if (*v1 == 'p') {
-                shellenabledp = 1;
-                restrictedshell = 1;
-            }
-            free(v1);
-        }
-        /* If shell escapes are restricted, get allowed cmds from cnf.  */
-        if (shellenabledp && restrictedshell == 1) {
-            v1 = NULL;
-            get_lua_string("texconfig", "shell_escape_commands", &v1);
-            if (v1) {
-                mk_shellcmdlist(v1);
-            free(v1);
-            }
-        }
-
-        starttime = -1 ;
-        get_lua_number("texconfig", "start_time", &starttime);
-        if (starttime < 0) {
-            /*
-                We provide this one for compatibility reasons and therefore also in
-                uppercase.
-            */
-            get_lua_number("texconfig", "SOURCE_DATE_EPOCH", &starttime);
-        }
-        if (starttime >= 0) {
-            set_start_time(starttime);
-        }
-
-        utc = -1 ;
-        get_lua_boolean("texconfig", "use_utc_time", &utc);
-        if (utc >= 0 && utc <= 1) {
-            utc_option = utc;
-        }
-
-        fix_dumpname();
-    } else {
-        if (luainit) {
-            if (given_file) {
-                fprintf(stdout, "%s file %s not found\n", (lua_only ? "Script" : "Configuration"), given_file);
-                free(given_file);
-            } else {
-                fprintf(stdout, "No %s file given\n", (lua_only ? "script" : "configuration"));
-            }
-            exit(1);
-        } else {
-            /* init */
-            init_kpse();
-            fix_dumpname();
-        }
-    }
-}
-
-@ @c
-void check_texconfig_init(void)
-{
-    if (Luas != NULL) {
-        lua_getglobal(Luas, "texconfig");
-        if (lua_istable(Luas, -1)) {
-            lua_getfield(Luas, -1, "init");
-            if (lua_isfunction(Luas, -1)) {
-                int i = lua_pcall(Luas, 0, 0, 0);
-                if (i != 0) {
-                    /* Can't be more precise here, called before TeX initialization  */
-                    fprintf(stderr, "This went wrong: %s\n", lua_tostring(Luas, -1));
-                    error();
-                }
-            }
-        }
-    }
-}
+% luainit.w
+%
+% Copyright 2006-2017 Taco Hoekwater <taco@@luatex.org>
+%
+% This file is part of LuaTeX.
+%
+% LuaTeX is free software; you can redistribute it and/or modify it under
+% the terms of the GNU General Public License as published by the Free
+% Software Foundation; either version 2 of the License, or (at your
+% option) any later version.
+%
+% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+% License for more details.
+%
+% You should have received a copy of the GNU General Public License along
+% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+@ @c
+
+#include "ptexlib.h"
+
+#include <kpathsea/c-stat.h>
+
+#include "lua/luatex-api.h"
+
+/* internalized strings: see luatex-api.h */
+set_make_keys;
+
+@
+This file is getting a bit messy, but it is not simple to fix unilaterally.
+
+Better to wait until Karl has some time (after texlive 2008) so we can
+synchronize with kpathsea. One problem, for instance, is that I would
+like to resolve the full executable path.  |kpse_set_program_name()| does
+that, indirectly (by setting SELFAUTOLOC in the environment), but it
+does much more, making it hard to use for our purpose.
+
+In fact, it sets three C variables:
+
+  |kpse_invocation_name|  |kpse_invocation_short_name|  |kpse->program_name|
+
+and five environment variables:
+
+  SELFAUTOLOC  SELFAUTODIR  SELFAUTOPARENT  SELFAUTOGRANDPARENT  progname
+
+ at c
+const_string LUATEX_IHELP[] = {
+    "Usage: " my_name " --lua=FILE [OPTION]... [TEXNAME[.tex]] [COMMANDS]",
+    "   or: " my_name " --lua=FILE [OPTION]... \\FIRST-LINE",
+    "   or: " my_name " --lua=FILE [OPTION]... &FMT ARGS",
+    "  Run " MyName " on TEXNAME, usually creating TEXNAME.pdf.",
+    "  Any remaining COMMANDS are processed as luatex input, after TEXNAME is read.",
+    "",
+    "  Alternatively, if the first non-option argument begins with a backslash,",
+    "  " my_name " interprets all non-option arguments as an input line.",
+    "",
+    "  Alternatively, if the first non-option argument begins with a &, the",
+    "  next word is taken as the FMT to read, overriding all else.  Any",
+    "  remaining arguments are processed as above.",
+    "",
+    "  If no arguments or options are specified, prompt for input.",
+    "",
+    "  The following regular options are understood: ",
+    "",
+    "   --credits                     display credits and exit",
+    "   --debug-format                enable format debugging",
+    "   --draftmode                   switch on draft mode (generates no output PDF)",
+    "   --[no-]file-line-error        disable/enable file:line:error style messages",
+    "   --[no-]file-line-error-style  aliases of --[no-]file-line-error",
+    "   --fmt=FORMAT                  load the format file FORMAT",
+    "   --halt-on-error               stop processing at the first error",
+    "   --help                        display help and exit",
+    "   --ini                         be ini" my_name ", for dumping formats",
+    "   --interaction=STRING          set interaction mode (STRING=batchmode/nonstopmode/scrollmode/errorstopmode)",
+    "   --jobname=STRING              set the job name to STRING",
+    "   --kpathsea-debug=NUMBER       set path searching debugging flags according to the bits of NUMBER",
+    "   --lua=FILE                    load and execute a lua initialization script",
+    "   --[no-]mktex=FMT              disable/enable mktexFMT generation (FMT=tex/tfm)",
+    "   --nosocket                    disable the lua socket library",
+    "   --output-comment=STRING       use STRING for DVI file comment instead of date (no effect for PDF)",
+    "   --output-directory=DIR        use existing DIR as the directory to write files in",
+    "   --output-format=FORMAT        use FORMAT for job output; FORMAT is 'dvi' or 'pdf'",
+    "   --progname=STRING             set the program name to STRING",
+    "   --recorder                    enable filename recorder",
+    "   --safer                       disable easily exploitable lua commands",
+    "   --[no-]shell-escape           disable/enable system commands",
+    "   --shell-restricted            restrict system commands to a list of commands given in texmf.cnf",
+    "   --synctex=NUMBER              enable synctex",
+    "   --utc                         init time to UTC",
+    "   --version                     display version and exit",
+    "",
+    "Alternate behaviour models can be obtained by special switches",
+    "",
+    "  --luaonly                      run a lua file, then exit",
+    "  --luaconly                     byte-compile a lua file, then exit",
+    "  --luahashchars                 the bits used by current Lua interpreter for strings hashing",
+#ifdef LuajitTeX
+    "  --jiton                        turns the JIT compiler on (default off)",
+    "  --jithash=STRING               choose the hash function for the lua strings (lua51|luajit20: default lua51)",
+#endif
+    "",
+    "See the reference manual for more information about the startup process.",
+    NULL
+};
+
+/*
+    "   --8bit                        ignored, input is assumed to be in UTF-8 encoding",
+    "   --default-translate-file=FILE ignored, input is assumed to be in UTF-8 encoding",
+    "   --etex                        ignored, the etex extensions are always active",
+    "   --disable-write18             disable \\write18{SHELL COMMAND}",
+    "   --enable-write18              enable \\write18{SHELL COMMAND}",
+    "   --[no-]parse-first-line       ignored",
+    "   --translate-file=FILE         ignored, input is assumed to be in UTF-8 encoding",
+*/
+
+@ The return value will be the directory of the executable, e.g.: \.{c:/TeX/bin}
+ at c
+static char *ex_selfdir(char *argv0)
+{
+#if defined(WIN32)
+#if defined(__MINGW32__)
+    char path[PATH_MAX], *fp;
+
+    /* SearchPath() always gives back an absolute directory */
+    if (SearchPath(NULL, argv0, ".exe", PATH_MAX, path, NULL) == 0)
+        FATAL1("Can't determine where the executable %s is.\n", argv0);
+    /* slashify the dirname */
+    for (fp = path; fp && *fp; fp++)
+        if (IS_DIR_SEP(*fp))
+            *fp = DIR_SEP;
+#else /* __MINGW32__ */
+#define PATH_MAX 512
+    char short_path[PATH_MAX], path[PATH_MAX], *fp;
+
+    /* SearchPath() always gives back an absolute directory */
+    if (SearchPath(NULL, argv0, ".exe", PATH_MAX, short_path, &fp) == 0)
+        FATAL1("Can't determine where the executable %s is.\n", argv0);
+    if (getlongpath(path, short_path, sizeof(path)) == 0) {
+        FATAL1("This path points to an invalid file : %s\n", short_path);
+    }
+#endif /* __MINGW32__ */
+   return xdirname(path);
+#else /* WIN32 */
+    return kpse_selfdir(argv0);
+#endif
+}
+
+@ @c
+static void prepare_cmdline(lua_State * L, char **av, int ac, int zero_offset)
+{
+    int i;
+    char *s;
+    luaL_checkstack(L, ac + 3, "too many arguments to script");
+    lua_createtable(L, 0, 0);
+    for (i = 0; i < ac; i++) {
+        lua_pushstring(L, av[i]);
+        lua_rawseti(L, -2, (i - zero_offset));
+    }
+    lua_setglobal(L, "arg");
+    lua_getglobal(L, "os");
+    s = ex_selfdir(argv[0]);
+    lua_pushstring(L, s);
+    xfree(s);
+    lua_setfield(L, -2, "selfdir");
+    return;
+}
+
+
+@ @c
+int kpse_init = -1;
+
+@ @c
+string input_name = NULL;
+
+static string user_progname = NULL;
+
+char *startup_filename = NULL;
+int lua_only = 0;
+int lua_offset = 0;
+unsigned char show_luahashchars = 0;
+
+#ifdef LuajitTeX
+int luajiton   = 0;
+char *jithash_hashname = NULL;
+#endif
+
+int safer_option = 0;
+int nosocket_option = 0;
+int utc_option = 0;
+
+@ Reading the options.
+
+@ Test whether getopt found an option ``A''.
+Assumes the option index is in the variable |option_index|, and the
+option table in a variable |long_options|.
+
+ at c
+#define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
+
+/*
+    SunOS cc can't initialize automatic structs, so make this static.
+*/
+
+/*
+    Nota Bene: we still intercept some options that other engines handle
+    so that existing scripted usage will not fail.
+*/
+
+static struct option long_options[] = {
+    {"fmt", 1, 0, 0},
+    {"lua", 1, 0, 0},
+    {"luaonly", 0, 0, 0},
+    {"luahashchars", 0, 0, 0},
+#ifdef LuajitTeX
+    {"jiton", 0, 0, 0},
+    {"jithash", 1, 0, 0},
+#endif
+    {"safer", 0, &safer_option, 1},
+    {"utc", 0, &utc_option, 1},
+    {"nosocket", 0, &nosocket_option, 1},
+    {"help", 0, 0, 0},
+    {"ini", 0, &ini_version, 1},
+    {"interaction", 1, 0, 0},
+    {"halt-on-error", 0, &haltonerrorp, 1},
+    {"kpathsea-debug", 1, 0, 0},
+    {"progname", 1, 0, 0},
+    {"version", 0, 0, 0},
+    {"credits", 0, 0, 0},
+    {"recorder", 0, 0, 0},
+    {"etex", 0, 0, 0},
+    {"output-comment", 1, 0, 0},
+    {"output-directory", 1, 0, 0},
+    {"draftmode", 0, 0, 0},
+    {"output-format", 1, 0, 0},
+    {"shell-escape", 0, &shellenabledp, 1},
+    {"no-shell-escape", 0, &shellenabledp, -1},
+    {"enable-write18", 0, &shellenabledp, 1},
+    {"disable-write18", 0, &shellenabledp, -1},
+    {"shell-restricted", 0, 0, 0},
+    {"debug-format", 0, &debug_format_file, 1},
+    {"file-line-error-style", 0, &filelineerrorstylep, 1},
+    {"no-file-line-error-style", 0, &filelineerrorstylep, -1},
+
+    /* Shorter option names for the above. */
+
+    {"file-line-error", 0, &filelineerrorstylep, 1},
+    {"no-file-line-error", 0, &filelineerrorstylep, -1},
+    {"jobname", 1, 0, 0},
+    {"parse-first-line", 0, &parsefirstlinep, 1},
+    {"no-parse-first-line", 0, &parsefirstlinep, -1},
+    {"translate-file", 1, 0, 0},
+    {"default-translate-file", 1, 0, 0},
+    {"8bit", 0, 0, 0},
+    {"mktex", 1, 0, 0},
+    {"no-mktex", 1, 0, 0},
+
+    /* Synchronization: just like "interaction" above */
+
+    {"synctex", 1, 0, 0},
+    {0, 0, 0, 0}
+};
+
+@ @c
+int lua_numeric_field_by_index(lua_State * L, int name_index, int dflt)
+{
+    register int i = dflt;
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
+    lua_rawget(L, -2);
+    if (lua_type(L, -1) == LUA_TNUMBER) {
+        i = lua_roundnumber(L, -1);
+    }
+    lua_pop(L, 1);
+    return i;
+}
+
+@ @c
+unsigned int lua_unsigned_numeric_field_by_index(lua_State * L, int name_index, int dflt)
+{
+    register unsigned int i = dflt;
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
+    lua_rawget(L, -2);
+    if (lua_type(L, -1) == LUA_TNUMBER) {
+        i = lua_uroundnumber(L, -1);
+    }
+    lua_pop(L, 1);
+    return i;
+}
+
+@ @c
+static int recorderoption = 0;
+
+static void parse_options(int ac, char **av)
+{
+#ifdef WIN32
+/* save argc and argv */
+    int sargc = argc;
+    char **sargv = argv;
+#endif
+    int g;                      /* `getopt' return code.  */
+    int option_index;
+    char *firstfile = NULL;
+    opterr = 0;                 /* dont whine */
+#ifdef LuajitTeX
+    if ((strstr(argv[0], "luajittexlua") != NULL) ||
+        (strstr(argv[0], "texluajit") != NULL)) {
+#else
+    if ((strstr(argv[0], "luatexlua") != NULL) ||
+        (strstr(argv[0], "texlua") != NULL)) {
+#endif
+        lua_only = 1;
+        luainit = 1;
+    }
+    for (;;) {
+        g = getopt_long_only(ac, av, "+", long_options, &option_index);
+
+        if (g == -1)            /* End of arguments, exit the loop.  */
+            break;
+        if (g == '?')  {         /* Unknown option.  */
+          if (!luainit)
+            fprintf(stderr,"%s: unrecognized option '%s'\n", argv[0], argv[optind-1]);
+          continue;
+        }
+
+        assert(g == 0);         /* We have no short option names.  */
+
+        if (ARGUMENT_IS("luaonly")) {
+            lua_only = 1;
+            lua_offset = optind;
+            luainit = 1;
+        } else if (ARGUMENT_IS("lua")) {
+            startup_filename = optarg;
+            lua_offset = (optind - 1);
+            luainit = 1;
+#ifdef LuajitTeX
+        } else if (ARGUMENT_IS("jiton")) {
+            luajiton = 1;
+        } else if (ARGUMENT_IS("jithash")) {
+        size_t len = strlen(optarg);
+        if (len<16) {
+            jithash_hashname = optarg;
+        } else {
+            WARNING2("hash name truncated to 15 characters from %d. (%s)", (int) len, optarg);
+            jithash_hashname = (string) xmalloc(16);
+            strncpy(jithash_hashname, optarg, 15);
+            jithash_hashname[15] = 0;
+      }
+#endif
+        } else if (ARGUMENT_IS("luahashchars")) {
+            show_luahashchars = 1;
+        } else if (ARGUMENT_IS("kpathsea-debug")) {
+            kpathsea_debug |= atoi(optarg);
+        } else if (ARGUMENT_IS("progname")) {
+            user_progname = optarg;
+        } else if (ARGUMENT_IS("jobname")) {
+            c_job_name = optarg;
+        } else if (ARGUMENT_IS("fmt")) {
+            dump_name = optarg;
+        } else if (ARGUMENT_IS("output-directory")) {
+            output_directory = optarg;
+        } else if (ARGUMENT_IS("output-comment")) {
+            size_t len = strlen(optarg);
+            if (len < 256) {
+                output_comment = optarg;
+            } else {
+                WARNING2("Comment truncated to 255 characters from %d. (%s)", (int) len, optarg);
+                output_comment = (string) xmalloc(256);
+                strncpy(output_comment, optarg, 255);
+                output_comment[255] = 0;
+            }
+        } else if (ARGUMENT_IS("shell-restricted")) {
+            shellenabledp = 1;
+            restrictedshell = 1;
+        } else if (ARGUMENT_IS("output-format")) {
+            output_mode_option = 1;
+            if (strcmp(optarg, "dvi") == 0) {
+                output_mode_value = 0;
+            } else if (strcmp(optarg, "pdf") == 0) {
+                output_mode_value = 1;
+            } else {
+                WARNING1("Ignoring unknown value `%s' for --output-format",optarg);
+                output_mode_option = 0;
+            }
+        } else if (ARGUMENT_IS("draftmode")) {
+            draft_mode_option = 1;
+            draft_mode_value = 1;
+        } else if (ARGUMENT_IS("mktex")) {
+            kpse_maketex_option(optarg, true);
+        } else if (ARGUMENT_IS("no-mktex")) {
+            kpse_maketex_option(optarg, false);
+        } else if (ARGUMENT_IS("interaction")) {
+            /* These numbers match CPP defines */
+            if (STREQ(optarg, "batchmode")) {
+                interactionoption = 0;
+            } else if (STREQ(optarg, "nonstopmode")) {
+                interactionoption = 1;
+            } else if (STREQ(optarg, "scrollmode")) {
+                interactionoption = 2;
+            } else if (STREQ(optarg, "errorstopmode")) {
+                interactionoption = 3;
+            } else {
+                WARNING1("Ignoring unknown argument `%s' to --interaction", optarg);
+            }
+        } else if (ARGUMENT_IS("synctex")) {
+            /* Synchronize TeXnology: catching the command line option as a long  */
+            synctexoption = (int) strtol(optarg, NULL, 0);
+        } else if (ARGUMENT_IS("recorder")) {
+            recorderoption = 1 ;
+        } else if (ARGUMENT_IS("help")) {
+            usagehelp(LUATEX_IHELP, BUG_ADDRESS);
+        } else if (ARGUMENT_IS("version")) {
+            print_version_banner();
+            /* *INDENT-OFF* */
+            puts("\n\nExecute  '" my_name " --credits'  for credits and version details.\n\n"
+                 "There is NO warranty. Redistribution of this software is covered by\n"
+                 "the terms of the GNU General Public License, version 2 or (at your option)\n"
+                 "any later version. For more information about these matters, see the file\n"
+                 "named COPYING and the LuaTeX source.\n\n"
+                 "LuaTeX is Copyright 2017 Taco Hoekwater and the LuaTeX Team.\n");
+            /* *INDENT-ON* */
+            uexit(0);
+        } else if (ARGUMENT_IS("credits")) {
+            char *versions;
+            initversionstring(&versions);
+            print_version_banner();
+            /* *INDENT-OFF* */
+            puts("\n\nThe LuaTeX team is Hans Hagen, Hartmut Henkel, Taco Hoekwater, Luigi Scarso.\n\n"
+                 MyName " merges and builds upon (parts of) the code from these projects:\n\n"
+                 "tex       : Donald Knuth\n"
+                 "etex      : Peter Breitenlohner, Phil Taylor and friends\n"
+                 "omega     : John Plaice and Yannis Haralambous\n"
+                 "aleph     : Giuseppe Bilotta\n"
+                 "pdftex    : Han The Thanh and friends\n"
+                 "kpathsea  : Karl Berry, Olaf Weber and others\n"
+                 "lua       : Roberto Ierusalimschy, Waldemar Celes and Luiz Henrique de Figueiredo\n"
+                 "metapost  : John Hobby, Taco Hoekwater and friends\n"
+                 "poppler   : Derek Noonburg, Kristian H\\ogsberg (partial)\n"
+                 "fontforge : George Williams (partial)\n"
+                 "luajit    : Mike Pall (used in LuajitTeX)\n");
+            /* *INDENT-ON* */
+            puts(versions);
+            uexit(0);
+        }
+    }
+    /* attempt to find |input_name| / |dump_name| */
+    if (lua_only) {
+        if (argv[optind]) {
+            startup_filename = xstrdup(argv[optind]);
+            lua_offset = optind;
+        }
+    } else if (argv[optind] && argv[optind][0] == '&') {
+        dump_name = xstrdup(argv[optind] + 1);
+    } else if (argv[optind] && argv[optind][0] != '\\') {
+        if (argv[optind][0] == '*') {
+            input_name = xstrdup(argv[optind] + 1);
+        } else {
+            firstfile = xstrdup(argv[optind]);
+            if ((strstr(firstfile, ".lua") ==
+                 firstfile + strlen(firstfile) - 4)
+                || (strstr(firstfile, ".luc") ==
+                    firstfile + strlen(firstfile) - 4)
+                || (strstr(firstfile, ".LUA") ==
+                    firstfile + strlen(firstfile) - 4)
+                || (strstr(firstfile, ".LUC") ==
+                    firstfile + strlen(firstfile) - 4)) {
+                if (startup_filename == NULL) {
+                    startup_filename = firstfile;
+                    lua_offset = optind;
+                    lua_only = 1;
+                    luainit = 1;
+                }
+            } else {
+                input_name = firstfile;
+            }
+        }
+#ifdef WIN32
+    } else if (sargc > 1 && sargv[sargc-1] && sargv[sargc-1][0] != '-' &&
+               sargv[sargc-1][0] != '\\') {
+        if (sargv[sargc-1][0] == '&')
+            dump_name = xstrdup(sargv[sargc-1] + 1);
+        else  {
+            if (sargv[sargc-1][0] == '*')
+                input_name = xstrdup(sargv[sargc-1] + 1);
+            else
+                input_name = xstrdup(sargv[sargc-1]);
+            sargv[sargc-1] = normalize_quotes(input_name, "argument");
+        }
+        if (safer_option)      /* --safer implies --nosocket */
+            nosocket_option = 1;
+        return;
+#endif
+    }
+    if (safer_option)           /* --safer implies --nosocket */
+        nosocket_option = 1;
+    /* Finalize the input filename. */
+    if (input_name != NULL) {
+        argv[optind] = normalize_quotes(input_name, "argument");
+    }
+}
+
+@ test for readability
+ at c
+#define is_readable(a) (stat(a,&finfo)==0) && S_ISREG(finfo.st_mode) &&  \
+  (f=fopen(a,"r")) != NULL && !fclose(f)
+
+@ @c
+static char *find_filename(char *name, const char *envkey)
+{
+    struct stat finfo;
+    char *dirname = NULL;
+    char *filename = NULL;
+    FILE *f;
+    if (is_readable(name)) {
+        return name;
+    } else {
+        dirname = getenv(envkey);
+        if ((dirname != NULL) && strlen(dirname)) {
+            dirname = xstrdup(getenv(envkey));
+            if (*(dirname + strlen(dirname) - 1) == '/') {
+                *(dirname + strlen(dirname) - 1) = 0;
+            }
+            filename = xmalloc((unsigned) (strlen(dirname) + strlen(name) + 2));
+            filename = concat3(dirname, "/", name);
+            xfree(dirname);
+            if (is_readable(filename)) {
+                return filename;
+            }
+            xfree(filename);
+        }
+    }
+    return NULL;
+}
+
+@ @c
+
+static void init_kpse(void)
+{
+    if (!user_progname) {
+        user_progname = dump_name;
+    } else if (!dump_name) {
+        dump_name = user_progname;
+    }
+    if (!user_progname) {
+        if (ini_version) {
+            if (input_name) {
+                char *p = input_name + strlen(input_name) - 1;
+                while (p >= input_name) {
+                    if (IS_DIR_SEP (*p)) {
+                        p++;
+                        input_name = p;
+                        break;
+                    }
+                    p--;
+                }
+                user_progname = remove_suffix (input_name);
+            }
+            if (!user_progname) {
+                user_progname = kpse_program_basename(argv[0]);
+            }
+        } else {
+            if (!dump_name) {
+                dump_name = kpse_program_basename(argv[0]);
+            }
+            user_progname = dump_name;
+        }
+    }
+    kpse_set_program_enabled(kpse_fmt_format, MAKE_TEX_FMT_BY_DEFAULT,
+                             kpse_src_compile);
+
+    kpse_set_program_name(argv[0], user_progname);
+    init_shell_escape();        /* set up 'restrictedshell' */
+    init_start_time();
+    program_name_set = 1 ;
+    if (recorderoption) {
+        recorder_enabled = 1;
+    }
+}
+
+@ @c
+static void fix_dumpname(void)
+{
+    int dist;
+    if (dump_name) {
+        /* adjust array for Pascal and provide extension, if needed */
+        dist = (int) (strlen(dump_name) - strlen(DUMP_EXT));
+        if (strstr(dump_name, DUMP_EXT) == dump_name + dist)
+            TEX_format_default = dump_name;
+        else
+            TEX_format_default = concat(dump_name, DUMP_EXT);
+    } else {
+        /* For |dump_name| to be NULL is a bug.  */
+        if (!ini_version) {
+          fprintf(stdout, "no format given, quitting\n");
+          exit(1);
+        }
+    }
+}
+
+@ lua require patch
+
+@ Auxiliary function for kpse search
+
+ at c
+static const char *luatex_kpse_find_aux(lua_State *L, const char *name,
+        kpse_file_format_type format, const char *errname)
+{
+    const char *filename;
+    const char *altname;
+    altname = luaL_gsub(L, name, ".", "/"); /* Lua convention */
+    filename = kpse_find_file(altname, format, false);
+    if (filename == NULL) {
+        filename = kpse_find_file(name, format, false);
+    }
+    if (filename == NULL) {
+        lua_pushfstring(L, "\n\t[kpse %s searcher] file not found: " LUA_QS, errname, name);
+    }
+    return filename;
+}
+
+@ The lua search function.
+
+When kpathsea is not initialized, then it runs the
+normal lua function that is saved in the registry, otherwise
+it uses kpathsea.
+
+two registry ref variables are needed: one for the actual lua
+function, the other for its environment .
+
+ at c
+static int lua_loader_function = 0;
+
+static int luatex_kpse_lua_find(lua_State * L)
+{
+    const char *filename;
+    const char *name;
+    name = luaL_checkstring(L, 1);
+    if (program_name_set == 0) {
+        lua_rawgeti(L, LUA_REGISTRYINDEX, lua_loader_function);
+        lua_pushvalue(L, -2);
+        lua_call(L, 1, 1);
+        return 1;
+    }
+    filename = luatex_kpse_find_aux(L, name, kpse_lua_format, "lua");
+    if (filename == NULL)
+        return 1;               /* library not found in this path */
+    if (luaL_loadfile(L, filename) != 0) {
+        luaL_error(L, "error loading module %s from file %s:\n\t%s",
+                   lua_tostring(L, 1), filename, lua_tostring(L, -1));
+    }
+    return 1;                   /* library loaded successfully */
+}
+
+@ @c
+static int clua_loader_function = 0;
+extern int searcher_C_luatex (lua_State *L, const char *name, const char *filename);
+
+static int luatex_kpse_clua_find(lua_State * L)
+{
+    const char *filename;
+    const char *name;
+    if (safer_option) {
+        lua_pushliteral(L, "\n\t[C searcher disabled in safer mode]");
+        return 1;               /* library not found in this path */
+    }
+    name = luaL_checkstring(L, 1);
+    if (program_name_set == 0) {
+        lua_rawgeti(L, LUA_REGISTRYINDEX, clua_loader_function);
+        lua_pushvalue(L, -2);
+        lua_call(L, 1, 1);
+        return 1;
+    } else {
+        const char *path_saved;
+        char *prefix, *postfix, *p, *total;
+        char *extensionless;
+        char *temp_name;
+        int j;
+        filename = luatex_kpse_find_aux(L, name, kpse_clua_format, "C");
+        if (filename == NULL)
+           return 1;               /* library not found in this path */
+        extensionless = strdup(filename);
+        if (!extensionless)
+            return 1;  /* allocation failure */
+        /* Fix Issue 850: replace '.' with LUA_DIRSEP */
+        temp_name = strdup(name);
+        for(j=0; ; j++){
+          if ((unsigned char)temp_name[j]=='\0') {
+            break;
+          }
+          if ((unsigned char)temp_name[j]=='.'){
+            temp_name[j]=LUA_DIRSEP[0];
+          }
+        }
+        p = strstr(extensionless, temp_name);
+        if (!p) return 1;  /* this would be exceedingly weird */
+        *p = '\0';
+        prefix = strdup(extensionless);
+        if (!prefix) return 1;  /* allocation failure */
+        postfix = strdup(p+strlen(name));
+        if (!postfix) return 1;  /* allocation failure */
+        total = malloc(strlen(prefix)+strlen(postfix)+2);
+        if (!total) return 1;  /* allocation failure */
+        snprintf(total,strlen(prefix)+strlen(postfix)+2, "%s?%s", prefix, postfix);
+        /* save package.path */
+        lua_getglobal(L,"package");
+        lua_getfield(L,-1,"cpath");
+        path_saved = lua_tostring(L,-1);
+        lua_pop(L,1);
+        /* set package.path = "?" */
+        lua_pushstring(L,total);
+        lua_setfield(L,-2,"cpath");
+        lua_pop(L,1); /* pop "package" */
+        /* run function */
+        lua_rawgeti(L, LUA_REGISTRYINDEX, clua_loader_function);
+        lua_pushstring(L, name);
+        lua_call(L, 1, 1);
+        /* restore package.path */
+        lua_getglobal(L,"package");
+        lua_pushstring(L,path_saved);
+        lua_setfield(L,-2,"cpath");
+        lua_pop(L,1); /* pop "package" */
+        free(extensionless);
+        free(total);
+        free(temp_name);
+        return 1;
+    }
+}
+
+@ Setting up the new search functions.
+
+This replaces package.searchers[2] and package.searchers[3] with the
+functions defined above.
+
+ at c
+static void setup_lua_path(lua_State * L)
+{
+    lua_getglobal(L, "package");
+#ifdef LuajitTeX
+    lua_getfield(L, -1, "loaders");
+#else
+    lua_getfield(L, -1, "searchers");
+#endif
+    lua_rawgeti(L, -1, 2);      /* package.searchers[2] */
+    lua_loader_function = luaL_ref(L, LUA_REGISTRYINDEX);
+    lua_pushcfunction(L, luatex_kpse_lua_find);
+    lua_rawseti(L, -2, 2);      /* replace the normal lua loader */
+
+    lua_rawgeti(L, -1, 3);      /* package.searchers[3] */
+    clua_loader_function = luaL_ref(L, LUA_REGISTRYINDEX);
+    lua_pushcfunction(L, luatex_kpse_clua_find);
+    lua_rawseti(L, -2, 3);      /* replace the normal lua lib loader */
+
+    lua_pop(L, 2);              /* pop the array and table */
+}
+
+@ helper variables for the safe keeping of table ids
+
+ at c
+int tex_table_id;
+int pdf_table_id;
+int token_table_id;
+int node_table_id;
+
+@ @c
+int l_pack_type_index       [PACK_TYPE_SIZE] ;
+int l_group_code_index      [GROUP_CODE_SIZE];
+int l_local_par_index       [LOCAL_PAR_SIZE];
+int l_math_style_name_index [MATH_STYLE_NAME_SIZE];
+int l_dir_par_index         [DIR_PAR_SIZE];
+int l_dir_text_index        [DIR_TEXT_SIZE];
+
+int img_parms               [img_parms_max];
+int img_pageboxes           [img_pageboxes_max];
+
+int lua_show_valid_list(lua_State *L, const char **list, int max)
+{
+    int i;
+    lua_newtable(L);
+    for (i = 0; i < max; i++) {
+        lua_pushinteger(L,i+1);
+        lua_pushstring(L, list[i]);
+        lua_settable(L, -3);
+    }
+    return 1;
+}
+
+int lua_show_valid_keys(lua_State *L, int *list, int max)
+{
+    int i;
+    lua_newtable(L);
+    for (i = 0; i < max; i++) {
+        lua_pushinteger(L,i+1);
+        lua_rawgeti(L, LUA_REGISTRYINDEX, list[i]);
+        lua_settable(L, -3);
+    }
+    return 1;
+}
+
+#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
+char **suffixlist;
+
+#  define EXE_SUFFIXES ".com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh;.ws;.tcl;.py;.pyw"
+
+@ @c
+static void mk_suffixlist(void)
+{
+    char **p;
+    char *q, *r, *v;
+    int n;
+
+#  if defined(__CYGWIN__)
+    v = xstrdup(EXE_SUFFIXES);
+#  else
+    v = (char *) getenv("PATHEXT");
+    if (v)                      /* strlwr() exists also in MingW */
+        v = (char *) strlwr(xstrdup(v));
+    else
+        v = xstrdup(EXE_SUFFIXES);
+#  endif
+
+    q = v;
+    n = 0;
+
+    while ((r = strchr(q, ';')) != NULL) {
+        n++;
+        r++;
+        q = r;
+    }
+    if (*q)
+        n++;
+    suffixlist = (char **) xmalloc((n + 2) * sizeof(char *));
+    p = suffixlist;
+    *p = xstrdup(".dll");
+    p++;
+    q = v;
+    while ((r = strchr(q, ';')) != NULL) {
+        *r = '\0';
+        *p = xstrdup(q);
+        p++;
+        r++;
+        q = r;
+    }
+    if (*q) {
+        *p = xstrdup(q);
+        p++;
+    }
+    *p = NULL;
+    free(v);
+}
+#endif
+
+@ @c
+void lua_initialize(int ac, char **av)
+{
+    char *given_file = NULL;
+    char *banner;
+    /*int kpse_init;*/
+    size_t len;
+    int starttime;
+    int utc;
+    static char LC_CTYPE_C[] = "LC_CTYPE=C";
+    static char LC_COLLATE_C[] = "LC_COLLATE=C";
+    static char LC_NUMERIC_C[] = "LC_NUMERIC=C";
+    static char engine_luatex[] = "engine=" my_name;
+    /* Save to pass along to topenin.  */
+    const char *fmt = "This is " MyName ", Version %s" WEB2CVERSION;
+    argc = ac;
+    argv = av;
+    len = strlen(fmt) + strlen(luatex_version_string) ;
+    banner = xmalloc(len);
+    sprintf(banner, fmt, luatex_version_string);
+    luatex_banner = banner;
+    kpse_invocation_name = kpse_program_basename(argv[0]);
+
+    /* be 'luac' */
+    if (argc >1) {
+#ifdef LuajitTeX
+        if (FILESTRCASEEQ(kpse_invocation_name, "texluajitc"))
+            exit(luac_main(ac, av));
+        if (STREQ(argv[1], "--luaconly") || STREQ(argv[1], "--luac")) {
+            char *argv1 = xmalloc (strlen ("luajittex") + 1);
+            av[1] = argv1;
+            strcpy (av[1], "luajittex");
+            exit(luac_main(--ac, ++av));
+        }
+#else
+        if (FILESTRCASEEQ(kpse_invocation_name, "texluac"))
+            exit(luac_main(ac, av));
+        if (STREQ(argv[1], "--luaconly") || STREQ(argv[1], "--luac")) {
+            strcpy(av[1], "luatex");
+            exit(luac_main(--ac, ++av));
+        }
+#endif
+    }
+#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
+    mk_suffixlist();
+#endif
+
+    /* Must be initialized before options are parsed.  */
+    interactionoption = 4;
+    dump_name = NULL;
+
+    /* 0 means "disable Synchronize TeXnology".
+     synctexoption is a *.web variable.
+     We initialize it to a weird value to catch the -synctex command line flag
+     At runtime, if synctexoption is not |INT_MAX|, then it contains the command line option provided,
+     otherwise no such option was given by the user. */
+#define SYNCTEX_NO_OPTION INT_MAX
+    synctexoption = SYNCTEX_NO_OPTION;
+
+    /* parse commandline */
+    parse_options(ac, av);
+    if (lua_only)
+        shellenabledp = true;
+
+    /* make sure that the locale is 'sane' (for lua) */
+
+    putenv(LC_CTYPE_C);
+    putenv(LC_COLLATE_C);
+    putenv(LC_NUMERIC_C);
+
+    /* this is sometimes needed */
+    putenv(engine_luatex);
+
+    luainterpreter();
+
+    /* init internalized strings */
+    set_init_keys;
+
+    lua_pushstring(Luas,"lua.functions");
+    lua_newtable(Luas);
+    lua_settable(Luas,LUA_REGISTRYINDEX);
+
+    /* here start the key definitions */
+    set_l_pack_type_index;
+    set_l_group_code_index;
+    set_l_local_par_index;
+    set_l_math_style_name_index;
+    set_l_dir_par_index;
+    set_l_dir_text_index;
+
+    set_l_img_keys_index;
+    set_l_img_pageboxes_index;
+
+    prepare_cmdline(Luas, argv, argc, lua_offset);      /* collect arguments */
+    setup_lua_path(Luas);
+
+    if (startup_filename != NULL) {
+        given_file = xstrdup(startup_filename);
+        if (lua_only) {
+          xfree(startup_filename);
+        }
+        startup_filename = find_filename(given_file, "LUATEXDIR");
+    }
+    /* now run the file */
+    if (startup_filename != NULL) {
+        char *v1;
+        /* hide the 'tex' and 'pdf' table */
+        tex_table_id = hide_lua_table(Luas, "tex");
+        token_table_id = hide_lua_table(Luas, "token");
+        node_table_id = hide_lua_table(Luas, "node");
+        pdf_table_id = hide_lua_table(Luas, "pdf");
+
+        if (luaL_loadfile(Luas, startup_filename)) {
+            fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
+            exit(1);
+        }
+        /* */
+        init_tex_table(Luas);
+        if (lua_pcall(Luas, 0, 0, 0)) {
+            fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
+        lua_traceback(Luas);
+            exit(1);
+        }
+        /* no filename? quit now! */
+        if (!input_name) {
+            get_lua_string("texconfig", "jobname", &input_name);
+        }
+        if (!dump_name) {
+            get_lua_string("texconfig", "formatname", &dump_name);
+        }
+        if (lua_only) {
+            if (given_file)
+                free(given_file);
+            /* this is not strictly needed but it pleases valgrind */
+            lua_close(Luas);
+            exit(0);
+        }
+        /* unhide the 'tex' and 'pdf' table */
+        unhide_lua_table(Luas, "tex", tex_table_id);
+        unhide_lua_table(Luas, "pdf", pdf_table_id);
+        unhide_lua_table(Luas, "token", token_table_id);
+        unhide_lua_table(Luas, "node", node_table_id);
+
+        /* |kpse_init| */
+        kpse_init = -1;
+        get_lua_boolean("texconfig", "kpse_init", &kpse_init);
+
+        if (kpse_init != 0) {
+            luainit = 0;        /* re-enable loading of texmf.cnf values, see luatex.ch */
+            init_kpse();
+        }
+        /* |prohibit_file_trace| (boolean) */
+        tracefilenames = 1;
+        get_lua_boolean("texconfig", "trace_file_names", &tracefilenames);
+
+        /* |file_line_error| */
+        filelineerrorstylep = false;
+        get_lua_boolean("texconfig", "file_line_error", &filelineerrorstylep);
+
+        /* |halt_on_error| */
+        haltonerrorp = false;
+        get_lua_boolean("texconfig", "halt_on_error", &haltonerrorp);
+
+        /* |restrictedshell| */
+        v1 = NULL;
+        get_lua_string("texconfig", "shell_escape", &v1);
+        if (v1) {
+            if (*v1 == 't' || *v1 == 'y' || *v1 == '1') {
+                shellenabledp = 1;
+            } else if (*v1 == 'p') {
+                shellenabledp = 1;
+                restrictedshell = 1;
+            }
+            free(v1);
+        }
+        /* If shell escapes are restricted, get allowed cmds from cnf.  */
+        if (shellenabledp && restrictedshell == 1) {
+            v1 = NULL;
+            get_lua_string("texconfig", "shell_escape_commands", &v1);
+            if (v1) {
+                mk_shellcmdlist(v1);
+            free(v1);
+            }
+        }
+
+        starttime = -1 ;
+        get_lua_number("texconfig", "start_time", &starttime);
+        if (starttime < 0) {
+            /*
+                We provide this one for compatibility reasons and therefore also in
+                uppercase.
+            */
+            get_lua_number("texconfig", "SOURCE_DATE_EPOCH", &starttime);
+        }
+        if (starttime >= 0) {
+            set_start_time(starttime);
+        }
+
+        utc = -1 ;
+        get_lua_boolean("texconfig", "use_utc_time", &utc);
+        if (utc >= 0 && utc <= 1) {
+            utc_option = utc;
+        }
+
+        fix_dumpname();
+    } else {
+        if (luainit) {
+            if (given_file) {
+                fprintf(stdout, "%s file %s not found\n", (lua_only ? "Script" : "Configuration"), given_file);
+                free(given_file);
+            } else {
+                fprintf(stdout, "No %s file given\n", (lua_only ? "script" : "configuration"));
+            }
+            exit(1);
+        } else {
+            /* init */
+            init_kpse();
+            fix_dumpname();
+        }
+    }
+}
+
+@ @c
+void check_texconfig_init(void)
+{
+    if (Luas != NULL) {
+        lua_getglobal(Luas, "texconfig");
+        if (lua_istable(Luas, -1)) {
+            lua_getfield(Luas, -1, "init");
+            if (lua_isfunction(Luas, -1)) {
+                int i = lua_pcall(Luas, 0, 0, 0);
+                if (i != 0) {
+                    /* Can't be more precise here, called before TeX initialization  */
+                    fprintf(stderr, "This went wrong: %s\n", lua_tostring(Luas, -1));
+                    error();
+                }
+            }
+        }
+    }
+}

Modified: trunk/Build/source/texk/web2c/luatexdir/lua/luajitstuff.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/lua/luajitstuff.w	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/lua/luajitstuff.w	2017-02-09 22:44:03 UTC (rev 43177)
@@ -349,6 +349,10 @@
         (void) hide_lua_value(L, "lfs", "rmdir");
         (void) hide_lua_value(L, "lfs", "mkdir");
     }
+    /* Maybe we can extend this way to the others tables, using luac. */
+    if ( safer_option || ((shellenabledp == 0) || (shellenabledp == 1 && restrictedshell == 1)) ) {
+       (void)   luaL_dostring(L,"ffi=require[[ffi]]; for k,_ in pairs(ffi) do if k~='gc' then ffi[k]=nil end ;end; ffi=nil;");
+    }  
     /* fprintf(stdout, "\nLuajitTeX default hash function type:%s\n", */
     /* 		                                jithash_hashname); */
     Luas = L;

Modified: trunk/Build/source/texk/web2c/luatexdir/lua/luastuff.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/lua/luastuff.w	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/lua/luastuff.w	2017-02-09 22:44:03 UTC (rev 43177)
@@ -1,561 +1,567 @@
-% luastuff.w
-%
-% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-@ @c
-lua_State *Luas = NULL;
-
-int luastate_bytes = 0;
-int lua_active = 0;
-
-@ @c
-void make_table(lua_State * L, const char *tab, const char *mttab, const char *getfunc,
-                const char *setfunc)
-{
-    /* make the table *//* |[{<tex>}]| */
-    lua_pushstring(L, tab);     /* |[{<tex>},"dimen"]| */
-    lua_newtable(L);            /* |[{<tex>},"dimen",{}]| */
-    lua_settable(L, -3);        /* |[{<tex>}]| */
-    /* fetch it back */
-    lua_pushstring(L, tab);     /* |[{<tex>},"dimen"]| */
-    lua_gettable(L, -2);        /* |[{<tex>},{<dimen>}]| */
-    /* make the meta entries */
-    luaL_newmetatable(L, mttab);  /* |[{<tex>},{<dimen>},{<dimen_m>}]| */
-    lua_pushstring(L, "__index");       /* |[{<tex>},{<dimen>},{<dimen_m>},"__index"]| */
-    lua_pushstring(L, getfunc); /* |[{<tex>},{<dimen>},{<dimen_m>},"__index","getdimen"]| */
-    lua_gettable(L, -5);        /* |[{<tex>},{<dimen>},{<dimen_m>},"__index",<tex.getdimen>]| */
-    lua_settable(L, -3);        /* |[{<tex>},{<dimen>},{<dimen_m>}]|  */
-    lua_pushstring(L, "__newindex");    /* |[{<tex>},{<dimen>},{<dimen_m>},"__newindex"]| */
-    lua_pushstring(L, setfunc); /* |[{<tex>},{<dimen>},{<dimen_m>},"__newindex","setdimen"]| */
-    lua_gettable(L, -5);        /* |[{<tex>},{<dimen>},{<dimen_m>},"__newindex",<tex.setdimen>]| */
-    lua_settable(L, -3);        /* |[{<tex>},{<dimen>},{<dimen_m>}]| */
-    lua_setmetatable(L, -2);    /* |[{<tex>},{<dimen>}]| : assign the metatable */
-    lua_pop(L, 1);              /* |[{<tex>}]| : clean the stack */
-}
-
-@ @c
-static const char *getS(lua_State * L, void *ud, size_t * size)
-{
-    LoadS *ls = (LoadS *) ud;
-    (void) L;
-    if (ls->size == 0)
-        return NULL;
-    *size = ls->size;
-    ls->size = 0;
-    return ls->s;
-}
-
-@ @c
-static void *my_luaalloc(void *ud, void *ptr, size_t osize, size_t nsize)
-{
-    void *ret = NULL;
-    (void) ud;                  /* for -Wunused */
-    if (nsize == 0)
-        free(ptr);
-    else
-        ret = realloc(ptr, nsize);
-    luastate_bytes += (int) (nsize - osize);
-    return ret;
-}
-
-@ @c
-static int my_luapanic(lua_State * L)
-{
-    (void) L;                   /* to avoid warnings */
-    fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1));
-    return 0;
-}
-
-@ @c
-void luafunctioncall(int slot)
-{
-    int i ;
-    int stacktop = lua_gettop(Luas);
-    lua_active++;
-    lua_rawgeti(Luas, LUA_REGISTRYINDEX, lua_key_index(lua_functions));
-    lua_gettable(Luas, LUA_REGISTRYINDEX);
-    lua_rawgeti(Luas, -1,slot);
-    if (lua_isfunction(Luas,-1)) {
-        int base = lua_gettop(Luas); /* function index */
-        lua_pushinteger(Luas, slot);
-        lua_pushcfunction(Luas, lua_traceback); /* push traceback function */
-        lua_insert(Luas, base); /* put it under chunk  */
-        i = lua_pcall(Luas, 1, 0, base);
-        lua_remove(Luas, base); /* remove traceback function */
-        if (i != 0) {
-            lua_gc(Luas, LUA_GCCOLLECT, 0);
-            Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
-        }
-    }
-    lua_settop(Luas,stacktop);
-    lua_active--;
-}
-
-@ @c
-static const luaL_Reg lualibs[] = {
-    {"", luaopen_base},
-    {"package", luaopen_package},
-    {"coroutine", luaopen_coroutine},
-    {"table", luaopen_table},
-    {"io", open_iolibext},
-    {"os", luaopen_os},
-    {"string", luaopen_string},
-    {"math", luaopen_math},
-    {"debug", luaopen_debug},
-    {"unicode", luaopen_unicode},
-    {"zip", luaopen_zip},
-    {"bit32", luaopen_bit32},
-    {"md5", luaopen_md5},
-    {"lfs", luaopen_lfs},
-    {"profiler", luaopen_profiler},
-    {"lpeg", luaopen_lpeg},
-    {NULL, NULL}
-};
-
-@ @c
-static void do_openlibs(lua_State * L)
-{
-    const luaL_Reg *lib;
-    for (lib = lualibs; lib->func; lib++) {
-        luaL_requiref(L, lib->name, lib->func, 1);
-    	lua_pop(L, 1);  /* remove lib */
-    }
-}
-
-@ @c
-static int load_aux (lua_State *L, int status) {
-  if (status == 0)  /* OK? */
-    return 1;
-  else {
-    lua_pushnil(L);
-    lua_insert(L, -2);  /* put before error message */
-    return 2;  /* return nil plus error message */
-  }
-}
-
-@ @c
-static int luatex_loadfile (lua_State *L) {
-  int status = 0;
-  const char *fname = luaL_optstring(L, 1, NULL);
-  const char *mode = luaL_optstring(L, 2, NULL);
-  int env = !lua_isnone(L, 3);  /* 'env' parameter? */
-  if (!lua_only && !fname && interaction == batch_mode) {
-     lua_pushnil(L);
-     lua_pushstring(L, "reading from stdin is disabled in batch mode");
-     return 2;  /* return nil plus error message */
-  }
-  status = luaL_loadfilex(L, fname, mode);
-  if (status == LUA_OK) {
-    recorder_record_input(fname);
-    if (env) {  /* 'env' parameter? */
-      lua_pushvalue(L, 3);
-      lua_setupvalue(L, -2, 1);  /* set it as 1st upvalue of loaded chunk */
-    }
-  }
-  return load_aux(L, status);
-}
-
-@ @c
-static int luatex_dofile (lua_State *L) {
-  const char *fname = luaL_optstring(L, 1, NULL);
-  int n = lua_gettop(L);
-  if (!lua_only && !fname) {
-      if (interaction == batch_mode) {
-	  lua_pushnil(L);
-	  lua_pushstring(L, "reading from stdin is disabled in batch mode");
-	  return 2;  /* return nil plus error message */
-      } else {
-	  tprint_nl("lua> ");
-      }
-  }
-  if (luaL_loadfile(L, fname) != 0) lua_error(L);
-  recorder_record_input(fname);
-  lua_call(L, 0, LUA_MULTRET);
-  return lua_gettop(L) - n;
-}
-
-@ @c
-void luainterpreter(void)
-{
-    lua_State *L;
-    L = lua_newstate(my_luaalloc, NULL);
-    if (L == NULL) {
-        fprintf(stderr, "Can't create the Lua state.\n");
-        return;
-    }
-    lua_atpanic(L, &my_luapanic);
-
-    do_openlibs(L);             /* does all the 'simple' libraries */
-
-    lua_pushcfunction(L,luatex_dofile);
-    lua_setglobal(L, "dofile");
-    lua_pushcfunction(L,luatex_loadfile);
-    lua_setglobal(L, "loadfile");
-
-    luatex_md5_lua_open(L);
-
-    open_oslibext(L, safer_option);
-/*
-    open_iolibext(L);
-*/
-    open_strlibext(L);
-    open_lfslibext(L);
-
-    /* luasockets */
-    /* socket and mime are a bit tricky to open because
-     they use a load-time  dependency that has to be
-     worked around for luatex, where the C module is
-     loaded way before the lua module.
-     */
-    if (!nosocket_option) {
-        lua_getglobal(L, "package");
-        lua_getfield(L, -1, "loaded");
-        if (!lua_istable(L, -1)) {
-            lua_newtable(L);
-            lua_setfield(L, -2, "loaded");
-            lua_getfield(L, -1, "loaded");
-        }
-        luaopen_socket_core(L);
-        lua_setfield(L, -2, "socket.core");
-        lua_pushnil(L);
-        lua_setfield(L, -2, "socket");  /* package.loaded.socket = nil */
-
-        luaopen_mime_core(L);
-        lua_setfield(L, -2, "mime.core");
-        lua_pushnil(L);
-        lua_setfield(L, -2, "mime");    /* package.loaded.mime = nil */
-        lua_pop(L, 2);          /* pop the tables */
-
-        luatex_socketlua_open(L);       /* preload the pure lua modules */
-    }
-    /* zlib. slightly odd calling convention */
-    luaopen_zlib(L);
-    lua_setglobal(L, "zlib");
-    luaopen_gzip(L);
-
-    /* our own libraries */
-    luaopen_ff(L);
-    luaopen_tex(L);
-    luaopen_token(L);
-    luaopen_node(L);
-    luaopen_texio(L);
-    luaopen_kpse(L);
-    luaopen_callback(L);
-    luaopen_lua(L, startup_filename);
-    luaopen_stats(L);
-    luaopen_font(L);
-    luaopen_lang(L);
-    luaopen_mplib(L);
-    luaopen_vf(L);
-
-    /* |luaopen_pdf(L);| */
-    /* environment table at |LUA_ENVIRONINDEX| needs to load this way: */
-    lua_pushcfunction(L, luaopen_pdf);
-    lua_pushstring(L, "pdf");
-    lua_call(L, 1, 0);
-
-    if (!lua_only) {
-        luaL_requiref(L, "img", luaopen_img, 1);
-        lua_pop(L, 1);
-    }
-
-    luaL_requiref(L, "epdf", luaopen_epdf, 1);
-    lua_pop(L, 1);
-
-    /* |luaopen_pdfscanner(L);| */
-    lua_pushcfunction(L, luaopen_pdfscanner);
-    lua_pushstring(L, "pdfscanner");
-    lua_call(L, 1, 0);
-
-    lua_createtable(L, 0, 0);
-    lua_setglobal(L, "texconfig");
-
-    if (safer_option) {
-        /* disable some stuff if --safer */
-        (void) hide_lua_value(L, "os", "execute");
-        (void) hide_lua_value(L, "os", "rename");
-        (void) hide_lua_value(L, "os", "remove");
-        (void) hide_lua_value(L, "io", "popen");
-        /* make io.open only read files */
-        luaL_checkstack(L, 2, "out of stack space");
-        lua_getglobal(L, "io");
-        lua_getfield(L, -1, "open_ro");
-        lua_setfield(L, -2, "open");
-        (void) hide_lua_value(L, "io", "tmpfile");
-        (void) hide_lua_value(L, "io", "output");
-        (void) hide_lua_value(L, "lfs", "chdir");
-        (void) hide_lua_value(L, "lfs", "lock");
-        (void) hide_lua_value(L, "lfs", "touch");
-        (void) hide_lua_value(L, "lfs", "rmdir");
-        (void) hide_lua_value(L, "lfs", "mkdir");
-    }
-    Luas = L;
-}
-
-@ @c
-int hide_lua_table(lua_State * L, const char *name)
-{
-    int r = 0;
-    lua_getglobal(L, name);
-    if (lua_istable(L, -1)) {
-        r = luaL_ref(L, LUA_REGISTRYINDEX);
-        lua_pushnil(L);
-        lua_setglobal(L, name);
-    }
-    return r;
-}
-
-@ @c
-void unhide_lua_table(lua_State * L, const char *name, int r)
-{
-    lua_rawgeti(L, LUA_REGISTRYINDEX, r);
-    lua_setglobal(L, name);
-    luaL_unref(L, LUA_REGISTRYINDEX, r);
-}
-
-@ @c
-int hide_lua_value(lua_State * L, const char *name, const char *item)
-{
-    int r = 0;
-    lua_getglobal(L, name);
-    if (lua_istable(L, -1)) {
-        lua_getfield(L, -1, item);
-        r = luaL_ref(L, LUA_REGISTRYINDEX);
-        lua_pushnil(L);
-        lua_setfield(L, -2, item);
-    }
-    return r;
-}
-
-@ @c
-void unhide_lua_value(lua_State * L, const char *name, const char *item, int r)
-{
-    lua_getglobal(L, name);
-    if (lua_istable(L, -1)) {
-        lua_rawgeti(L, LUA_REGISTRYINDEX, r);
-        lua_setfield(L, -2, item);
-        luaL_unref(L, LUA_REGISTRYINDEX, r);
-    }
-}
-
-@ @c
-int lua_traceback(lua_State * L)
-{
-    lua_getglobal(L, "debug");
-    if (!lua_istable(L, -1)) {
-        lua_pop(L, 1);
-        return 1;
-    }
-    lua_getfield(L, -1, "traceback");
-    if (!lua_isfunction(L, -1)) {
-        lua_pop(L, 2);
-        return 1;
-    }
-    lua_pushvalue(L, 1);        /* pass error message */
-    lua_pushinteger(L, 2);      /* skip this function and traceback */
-    lua_call(L, 2, 1);          /* call debug.traceback */
-    return 1;
-}
-
-@ @c
-static void luacall(int p, int nameptr, boolean is_string) /* hh-ls: optimized lua_id resolving */
-{
-    LoadS ls;
-    int i;
-    size_t ll = 0;
-    char *lua_id;
-    char *s = NULL;
-
-    if (Luas == NULL) {
-        luainterpreter();
-    }
-    lua_active++;
-    if (is_string) {
-        const char *ss = NULL;
-        lua_rawgeti(Luas, LUA_REGISTRYINDEX, p);
-        if (lua_isfunction(Luas,-1)) {
-            int base = lua_gettop(Luas);        /* function index */
-            lua_checkstack(Luas, 1);
-            lua_pushcfunction(Luas, lua_traceback);     /* push traceback function */
-            lua_insert(Luas, base);     /* put it under chunk  */
-            i = lua_pcall(Luas, 0, 0, base);
-            lua_remove(Luas, base);     /* remove traceback function */
-            if (i != 0) {
-                lua_gc(Luas, LUA_GCCOLLECT, 0);
-                Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
-            }
-            lua_active--;
-            return ;
-        }
-        ss = lua_tolstring(Luas, -1, &ll);
-        s = xmalloc(ll+1);
-        memcpy(s,ss,ll+1);
-        lua_pop(Luas,1);
-    } else {
-        int l = 0;
-        s = tokenlist_to_cstring(p, 1, &l);
-        ll = (size_t)l;
-    }
-    ls.s = s;
-    ls.size = ll;
-    if (ls.size > 0) {
-        if (nameptr > 0) {
-            int l = 0; /* not used */
-            lua_id = tokenlist_to_cstring(nameptr, 1, &l);
-            i = lua_load(Luas, getS, &ls, lua_id, NULL);
-            xfree(lua_id);
-        } else if (nameptr < 0) {
-            lua_id = get_lua_name((nameptr + 65536));
-            if (lua_id != NULL) {
-                i = lua_load(Luas, getS, &ls, lua_id, NULL);
-            } else {
-                i = lua_load(Luas, getS, &ls, "=[\\latelua]", NULL);
-            }
-        } else {
-            i = lua_load(Luas, getS, &ls, "=[\\latelua]", NULL);
-        }
-        if (i != 0) {
-            Luas = luatex_error(Luas, (i == LUA_ERRSYNTAX ? 0 : 1));
-        } else {
-            int base = lua_gettop(Luas);        /* function index */
-            lua_checkstack(Luas, 1);
-            lua_pushcfunction(Luas, lua_traceback);     /* push traceback function */
-            lua_insert(Luas, base);     /* put it under chunk  */
-            i = lua_pcall(Luas, 0, 0, base);
-            lua_remove(Luas, base);     /* remove traceback function */
-            if (i != 0) {
-                lua_gc(Luas, LUA_GCCOLLECT, 0);
-                Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
-            }
-        }
-        xfree(ls.s);
-    }
-    lua_active--;
-}
-
-@ @c
-void late_lua(PDF pdf, halfword p)
-{
-    (void) pdf;
-    if (late_lua_type(p)==normal) {
-        expand_macros_in_tokenlist(p);      /* sets |def_ref| */
-        luacall(def_ref, late_lua_name(p), false);
-        flush_list(def_ref);
-    } else {
-        luacall(late_lua_data(p), late_lua_name(p), true);
-    }
-}
-
-@ @c
-void luatokencall(int p, int nameptr) /* hh-ls: optimized lua_id resolving */
-{
-    LoadS ls;
-    int i, l;
-    char *s = NULL;
-    char *lua_id;
-    assert(Luas);
-    l = 0;
-    lua_active++;
-    s = tokenlist_to_cstring(p, 1, &l);
-    ls.s = s;
-    ls.size = (size_t) l;
-    if (ls.size > 0) {
-        if (nameptr > 0) {
-            lua_id = tokenlist_to_cstring(nameptr, 1, &l);
-            i = lua_load(Luas, getS, &ls, lua_id, NULL);
-	    xfree(lua_id);
-        } else if (nameptr < 0) {
-            lua_id = get_lua_name((nameptr + 65536));
-            if (lua_id != NULL) {
-                i = lua_load(Luas, getS, &ls, lua_id, NULL);
-            } else {
-                i = lua_load(Luas, getS, &ls, "=[\\directlua]", NULL);
-            }
-        } else {
-            i = lua_load(Luas, getS, &ls, "=[\\directlua]", NULL);
-        }
-        xfree(s);
-        if (i != 0) {
-            Luas = luatex_error(Luas, (i == LUA_ERRSYNTAX ? 0 : 1));
-        } else {
-            int base = lua_gettop(Luas);        /* function index */
-            lua_checkstack(Luas, 1);
-            lua_pushcfunction(Luas, lua_traceback);     /* push traceback function */
-            lua_insert(Luas, base);     /* put it under chunk  */
-            i = lua_pcall(Luas, 0, 0, base);
-            lua_remove(Luas, base);     /* remove traceback function */
-            if (i != 0) {
-                lua_gc(Luas, LUA_GCCOLLECT, 0);
-                Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
-            }
-        }
-    }
-    lua_active--;
-}
-
-@ @c
-lua_State *luatex_error(lua_State * L, int is_fatal)
-{
-
-    const_lstring luaerr;
-    char *err = NULL;
-    if (lua_type(L, -1) == LUA_TSTRING) {
-        luaerr.s = lua_tolstring(L, -1, &luaerr.l);
-        /* free last one ? */
-        err = (char *) xmalloc((unsigned) (luaerr.l + 1));
-        snprintf(err, (luaerr.l + 1), "%s", luaerr.s);
-        last_lua_error = err; /* hm, what if we have several .. not freed */
-    }
-    if (is_fatal > 0) {
-        /* Normally a memory error from lua.
-           The pool may overflow during the |maketexlstring()|, but we
-           are crashing anyway so we may as well abort on the pool size */
-        normal_error("lua",err);
-        /* never reached */
-        lua_close(L);
-        return (lua_State *) NULL;
-    } else {
-        normal_warning("lua",err);
-        return L;
-    }
-}
-
-@ @c
-void preset_environment(lua_State * L, const parm_struct * p, const char *s)
-{
-    int i;
-    assert(L != NULL);
-    /* double call with same s gives assert(0) */
-    lua_pushstring(L, s);       /* s */
-    lua_gettable(L, LUA_REGISTRYINDEX); /* t */
-    assert(lua_isnil(L, -1));
-    lua_pop(L, 1);              /* - */
-    lua_pushstring(L, s);       /* s */
-    lua_newtable(L);            /* t s */
-    for (i = 1, ++p; p->name != NULL; i++, p++) {
-        assert(i == p->idx);
-        lua_pushstring(L, p->name);     /* k t s */
-        lua_pushinteger(L, p->idx);     /* v k t s */
-        lua_settable(L, -3);    /* t s */
-    }
-    lua_settable(L, LUA_REGISTRYINDEX); /* - */
-}
+% luastuff.w
+%
+% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
+%
+% This file is part of LuaTeX.
+%
+% LuaTeX is free software; you can redistribute it and/or modify it under
+% the terms of the GNU General Public License as published by the Free
+% Software Foundation; either version 2 of the License, or (at your
+% option) any later version.
+%
+% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+% License for more details.
+%
+% You should have received a copy of the GNU General Public License along
+% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+@ @c
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+@ @c
+lua_State *Luas = NULL;
+
+int luastate_bytes = 0;
+int lua_active = 0;
+
+@ @c
+void make_table(lua_State * L, const char *tab, const char *mttab, const char *getfunc,
+                const char *setfunc)
+{
+    /* make the table *//* |[{<tex>}]| */
+    lua_pushstring(L, tab);     /* |[{<tex>},"dimen"]| */
+    lua_newtable(L);            /* |[{<tex>},"dimen",{}]| */
+    lua_settable(L, -3);        /* |[{<tex>}]| */
+    /* fetch it back */
+    lua_pushstring(L, tab);     /* |[{<tex>},"dimen"]| */
+    lua_gettable(L, -2);        /* |[{<tex>},{<dimen>}]| */
+    /* make the meta entries */
+    luaL_newmetatable(L, mttab);  /* |[{<tex>},{<dimen>},{<dimen_m>}]| */
+    lua_pushstring(L, "__index");       /* |[{<tex>},{<dimen>},{<dimen_m>},"__index"]| */
+    lua_pushstring(L, getfunc); /* |[{<tex>},{<dimen>},{<dimen_m>},"__index","getdimen"]| */
+    lua_gettable(L, -5);        /* |[{<tex>},{<dimen>},{<dimen_m>},"__index",<tex.getdimen>]| */
+    lua_settable(L, -3);        /* |[{<tex>},{<dimen>},{<dimen_m>}]|  */
+    lua_pushstring(L, "__newindex");    /* |[{<tex>},{<dimen>},{<dimen_m>},"__newindex"]| */
+    lua_pushstring(L, setfunc); /* |[{<tex>},{<dimen>},{<dimen_m>},"__newindex","setdimen"]| */
+    lua_gettable(L, -5);        /* |[{<tex>},{<dimen>},{<dimen_m>},"__newindex",<tex.setdimen>]| */
+    lua_settable(L, -3);        /* |[{<tex>},{<dimen>},{<dimen_m>}]| */
+    lua_setmetatable(L, -2);    /* |[{<tex>},{<dimen>}]| : assign the metatable */
+    lua_pop(L, 1);              /* |[{<tex>}]| : clean the stack */
+}
+
+@ @c
+static const char *getS(lua_State * L, void *ud, size_t * size)
+{
+    LoadS *ls = (LoadS *) ud;
+    (void) L;
+    if (ls->size == 0)
+        return NULL;
+    *size = ls->size;
+    ls->size = 0;
+    return ls->s;
+}
+
+@ @c
+static void *my_luaalloc(void *ud, void *ptr, size_t osize, size_t nsize)
+{
+    void *ret = NULL;
+    (void) ud;                  /* for -Wunused */
+    if (nsize == 0)
+        free(ptr);
+    else
+        ret = realloc(ptr, nsize);
+    luastate_bytes += (int) (nsize - osize);
+    return ret;
+}
+
+@ @c
+static int my_luapanic(lua_State * L)
+{
+    (void) L;                   /* to avoid warnings */
+    fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1));
+    return 0;
+}
+
+@ @c
+void luafunctioncall(int slot)
+{
+    int i ;
+    int stacktop = lua_gettop(Luas);
+    lua_active++;
+    lua_rawgeti(Luas, LUA_REGISTRYINDEX, lua_key_index(lua_functions));
+    lua_gettable(Luas, LUA_REGISTRYINDEX);
+    lua_rawgeti(Luas, -1,slot);
+    if (lua_isfunction(Luas,-1)) {
+        int base = lua_gettop(Luas); /* function index */
+        lua_pushinteger(Luas, slot);
+        lua_pushcfunction(Luas, lua_traceback); /* push traceback function */
+        lua_insert(Luas, base); /* put it under chunk  */
+        i = lua_pcall(Luas, 1, 0, base);
+        lua_remove(Luas, base); /* remove traceback function */
+        if (i != 0) {
+            lua_gc(Luas, LUA_GCCOLLECT, 0);
+            Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+        }
+    }
+    lua_settop(Luas,stacktop);
+    lua_active--;
+}
+
+@ @c
+static const luaL_Reg lualibs[] = {
+    {"", luaopen_base},
+    {"package", luaopen_package},
+    {"coroutine", luaopen_coroutine},
+    {"table", luaopen_table},
+    {"io", open_iolibext},
+    {"os", luaopen_os},
+    {"string", luaopen_string},
+    {"math", luaopen_math},
+    {"debug", luaopen_debug},
+    {"unicode", luaopen_unicode},
+    {"zip", luaopen_zip},
+    {"bit32", luaopen_bit32},
+    {"md5", luaopen_md5},
+    {"ffi", luaopen_ffi},
+    {"lfs", luaopen_lfs},
+    {"profiler", luaopen_profiler},
+    {"lpeg", luaopen_lpeg},
+    {NULL, NULL}
+};
+
+@ @c
+static void do_openlibs(lua_State * L)
+{
+    const luaL_Reg *lib;
+    for (lib = lualibs; lib->func; lib++) {
+        luaL_requiref(L, lib->name, lib->func, 1);
+    	lua_pop(L, 1);  /* remove lib */
+    }
+}
+
+@ @c
+static int load_aux (lua_State *L, int status) {
+  if (status == 0)  /* OK? */
+    return 1;
+  else {
+    lua_pushnil(L);
+    lua_insert(L, -2);  /* put before error message */
+    return 2;  /* return nil plus error message */
+  }
+}
+
+@ @c
+static int luatex_loadfile (lua_State *L) {
+  int status = 0;
+  const char *fname = luaL_optstring(L, 1, NULL);
+  const char *mode = luaL_optstring(L, 2, NULL);
+  int env = !lua_isnone(L, 3);  /* 'env' parameter? */
+  if (!lua_only && !fname && interaction == batch_mode) {
+     lua_pushnil(L);
+     lua_pushstring(L, "reading from stdin is disabled in batch mode");
+     return 2;  /* return nil plus error message */
+  }
+  status = luaL_loadfilex(L, fname, mode);
+  if (status == LUA_OK) {
+    recorder_record_input(fname);
+    if (env) {  /* 'env' parameter? */
+      lua_pushvalue(L, 3);
+      lua_setupvalue(L, -2, 1);  /* set it as 1st upvalue of loaded chunk */
+    }
+  }
+  return load_aux(L, status);
+}
+
+@ @c
+static int luatex_dofile (lua_State *L) {
+  const char *fname = luaL_optstring(L, 1, NULL);
+  int n = lua_gettop(L);
+  if (!lua_only && !fname) {
+      if (interaction == batch_mode) {
+	  lua_pushnil(L);
+	  lua_pushstring(L, "reading from stdin is disabled in batch mode");
+	  return 2;  /* return nil plus error message */
+      } else {
+	  tprint_nl("lua> ");
+      }
+  }
+  if (luaL_loadfile(L, fname) != 0) lua_error(L);
+  recorder_record_input(fname);
+  lua_call(L, 0, LUA_MULTRET);
+  return lua_gettop(L) - n;
+}
+
+@ @c
+void luainterpreter(void)
+{
+    lua_State *L;
+    L = lua_newstate(my_luaalloc, NULL);
+    if (L == NULL) {
+        fprintf(stderr, "Can't create the Lua state.\n");
+        return;
+    }
+    lua_atpanic(L, &my_luapanic);
+
+    do_openlibs(L);             /* does all the 'simple' libraries */
+
+    lua_pushcfunction(L,luatex_dofile);
+    lua_setglobal(L, "dofile");
+    lua_pushcfunction(L,luatex_loadfile);
+    lua_setglobal(L, "loadfile");
+
+    luatex_md5_lua_open(L);
+
+    open_oslibext(L, safer_option);
+/*
+    open_iolibext(L);
+*/
+    open_strlibext(L);
+    open_lfslibext(L);
+
+
+    /* luasockets */
+    /* socket and mime are a bit tricky to open because
+     they use a load-time  dependency that has to be
+     worked around for luatex, where the C module is
+     loaded way before the lua module.
+     */
+    if (!nosocket_option) {
+        lua_getglobal(L, "package");
+        lua_getfield(L, -1, "loaded");
+        if (!lua_istable(L, -1)) {
+            lua_newtable(L);
+            lua_setfield(L, -2, "loaded");
+            lua_getfield(L, -1, "loaded");
+        }
+        luaopen_socket_core(L);
+        lua_setfield(L, -2, "socket.core");
+        lua_pushnil(L);
+        lua_setfield(L, -2, "socket");  /* package.loaded.socket = nil */
+
+        luaopen_mime_core(L);
+        lua_setfield(L, -2, "mime.core");
+        lua_pushnil(L);
+        lua_setfield(L, -2, "mime");    /* package.loaded.mime = nil */
+        lua_pop(L, 2);          /* pop the tables */
+
+        luatex_socketlua_open(L);       /* preload the pure lua modules */
+    }
+    /* zlib. slightly odd calling convention */
+    luaopen_zlib(L);
+    lua_setglobal(L, "zlib");
+    luaopen_gzip(L);
+
+    /* our own libraries */
+    luaopen_ff(L);
+    luaopen_tex(L);
+    luaopen_token(L);
+    luaopen_node(L);
+    luaopen_texio(L);
+    luaopen_kpse(L);
+    luaopen_callback(L);
+    luaopen_lua(L, startup_filename);
+    luaopen_stats(L);
+    luaopen_font(L);
+    luaopen_lang(L);
+    luaopen_mplib(L);
+    luaopen_vf(L);
+
+    /* |luaopen_pdf(L);| */
+    /* environment table at |LUA_ENVIRONINDEX| needs to load this way: */
+    lua_pushcfunction(L, luaopen_pdf);
+    lua_pushstring(L, "pdf");
+    lua_call(L, 1, 0);
+
+    if (!lua_only) {
+        luaL_requiref(L, "img", luaopen_img, 1);
+        lua_pop(L, 1);
+    }
+
+    luaL_requiref(L, "epdf", luaopen_epdf, 1);
+    lua_pop(L, 1);
+
+    /* |luaopen_pdfscanner(L);| */
+    lua_pushcfunction(L, luaopen_pdfscanner);
+    lua_pushstring(L, "pdfscanner");
+    lua_call(L, 1, 0);
+
+    lua_createtable(L, 0, 0);
+    lua_setglobal(L, "texconfig");
+
+    if (safer_option) {
+        /* disable some stuff if --safer */
+        (void) hide_lua_value(L, "os", "execute");
+        (void) hide_lua_value(L, "os", "rename");
+        (void) hide_lua_value(L, "os", "remove");
+        (void) hide_lua_value(L, "io", "popen");
+        /* make io.open only read files */
+        luaL_checkstack(L, 2, "out of stack space");
+        lua_getglobal(L, "io");
+        lua_getfield(L, -1, "open_ro");
+        lua_setfield(L, -2, "open");
+        (void) hide_lua_value(L, "io", "tmpfile");
+        (void) hide_lua_value(L, "io", "output");
+        (void) hide_lua_value(L, "lfs", "chdir");
+        (void) hide_lua_value(L, "lfs", "lock");
+        (void) hide_lua_value(L, "lfs", "touch");
+        (void) hide_lua_value(L, "lfs", "rmdir");
+        (void) hide_lua_value(L, "lfs", "mkdir");
+    }
+    /* Maybe we can extend this way to the others tables, using luac. */
+    if ( safer_option || ((shellenabledp == 0) || (shellenabledp == 1 && restrictedshell == 1)) ) {
+       (void)   luaL_dostring(L,"ffi=require[[ffi]]; for k,_ in pairs(ffi) do if k~='gc' then ffi[k]=nil end; end; ffi=nil;");
+    }  
+    Luas = L;
+}
+
+@ @c
+int hide_lua_table(lua_State * L, const char *name)
+{
+    int r = 0;
+    lua_getglobal(L, name);
+    if (lua_istable(L, -1)) {
+        r = luaL_ref(L, LUA_REGISTRYINDEX);
+        lua_pushnil(L);
+        lua_setglobal(L, name);
+    }
+    return r;
+}
+
+@ @c
+void unhide_lua_table(lua_State * L, const char *name, int r)
+{
+    lua_rawgeti(L, LUA_REGISTRYINDEX, r);
+    lua_setglobal(L, name);
+    luaL_unref(L, LUA_REGISTRYINDEX, r);
+}
+
+@ @c
+int hide_lua_value(lua_State * L, const char *name, const char *item)
+{
+    int r = 0;
+    lua_getglobal(L, name);
+    if (lua_istable(L, -1)) {
+        lua_getfield(L, -1, item);
+        r = luaL_ref(L, LUA_REGISTRYINDEX);
+        lua_pushnil(L);
+        lua_setfield(L, -2, item);
+    }
+    return r;
+}
+
+@ @c
+void unhide_lua_value(lua_State * L, const char *name, const char *item, int r)
+{
+    lua_getglobal(L, name);
+    if (lua_istable(L, -1)) {
+        lua_rawgeti(L, LUA_REGISTRYINDEX, r);
+        lua_setfield(L, -2, item);
+        luaL_unref(L, LUA_REGISTRYINDEX, r);
+    }
+}
+
+@ @c
+int lua_traceback(lua_State * L)
+{
+    lua_getglobal(L, "debug");
+    if (!lua_istable(L, -1)) {
+        lua_pop(L, 1);
+        return 1;
+    }
+    lua_getfield(L, -1, "traceback");
+    if (!lua_isfunction(L, -1)) {
+        lua_pop(L, 2);
+        return 1;
+    }
+    lua_pushvalue(L, 1);        /* pass error message */
+    lua_pushinteger(L, 2);      /* skip this function and traceback */
+    lua_call(L, 2, 1);          /* call debug.traceback */
+    return 1;
+}
+
+@ @c
+static void luacall(int p, int nameptr, boolean is_string) /* hh-ls: optimized lua_id resolving */
+{
+    LoadS ls;
+    int i;
+    size_t ll = 0;
+    char *lua_id;
+    char *s = NULL;
+
+    if (Luas == NULL) {
+        luainterpreter();
+    }
+    lua_active++;
+    if (is_string) {
+        const char *ss = NULL;
+        lua_rawgeti(Luas, LUA_REGISTRYINDEX, p);
+        if (lua_isfunction(Luas,-1)) {
+            int base = lua_gettop(Luas);        /* function index */
+            lua_checkstack(Luas, 1);
+            lua_pushcfunction(Luas, lua_traceback);     /* push traceback function */
+            lua_insert(Luas, base);     /* put it under chunk  */
+            i = lua_pcall(Luas, 0, 0, base);
+            lua_remove(Luas, base);     /* remove traceback function */
+            if (i != 0) {
+                lua_gc(Luas, LUA_GCCOLLECT, 0);
+                Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+            }
+            lua_active--;
+            return ;
+        }
+        ss = lua_tolstring(Luas, -1, &ll);
+        s = xmalloc(ll+1);
+        memcpy(s,ss,ll+1);
+        lua_pop(Luas,1);
+    } else {
+        int l = 0;
+        s = tokenlist_to_cstring(p, 1, &l);
+        ll = (size_t)l;
+    }
+    ls.s = s;
+    ls.size = ll;
+    if (ls.size > 0) {
+        if (nameptr > 0) {
+            int l = 0; /* not used */
+            lua_id = tokenlist_to_cstring(nameptr, 1, &l);
+            i = lua_load(Luas, getS, &ls, lua_id, NULL);
+            xfree(lua_id);
+        } else if (nameptr < 0) {
+            lua_id = get_lua_name((nameptr + 65536));
+            if (lua_id != NULL) {
+                i = lua_load(Luas, getS, &ls, lua_id, NULL);
+            } else {
+                i = lua_load(Luas, getS, &ls, "=[\\latelua]", NULL);
+            }
+        } else {
+            i = lua_load(Luas, getS, &ls, "=[\\latelua]", NULL);
+        }
+        if (i != 0) {
+            Luas = luatex_error(Luas, (i == LUA_ERRSYNTAX ? 0 : 1));
+        } else {
+            int base = lua_gettop(Luas);        /* function index */
+            lua_checkstack(Luas, 1);
+            lua_pushcfunction(Luas, lua_traceback);     /* push traceback function */
+            lua_insert(Luas, base);     /* put it under chunk  */
+            i = lua_pcall(Luas, 0, 0, base);
+            lua_remove(Luas, base);     /* remove traceback function */
+            if (i != 0) {
+                lua_gc(Luas, LUA_GCCOLLECT, 0);
+                Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+            }
+        }
+        xfree(ls.s);
+    }
+    lua_active--;
+}
+
+@ @c
+void late_lua(PDF pdf, halfword p)
+{
+    (void) pdf;
+    if (late_lua_type(p)==normal) {
+        expand_macros_in_tokenlist(p);      /* sets |def_ref| */
+        luacall(def_ref, late_lua_name(p), false);
+        flush_list(def_ref);
+    } else {
+        luacall(late_lua_data(p), late_lua_name(p), true);
+    }
+}
+
+@ @c
+void luatokencall(int p, int nameptr) /* hh-ls: optimized lua_id resolving */
+{
+    LoadS ls;
+    int i, l;
+    char *s = NULL;
+    char *lua_id;
+    assert(Luas);
+    l = 0;
+    lua_active++;
+    s = tokenlist_to_cstring(p, 1, &l);
+    ls.s = s;
+    ls.size = (size_t) l;
+    if (ls.size > 0) {
+        if (nameptr > 0) {
+            lua_id = tokenlist_to_cstring(nameptr, 1, &l);
+            i = lua_load(Luas, getS, &ls, lua_id, NULL);
+	    xfree(lua_id);
+        } else if (nameptr < 0) {
+            lua_id = get_lua_name((nameptr + 65536));
+            if (lua_id != NULL) {
+                i = lua_load(Luas, getS, &ls, lua_id, NULL);
+            } else {
+                i = lua_load(Luas, getS, &ls, "=[\\directlua]", NULL);
+            }
+        } else {
+            i = lua_load(Luas, getS, &ls, "=[\\directlua]", NULL);
+        }
+        xfree(s);
+        if (i != 0) {
+            Luas = luatex_error(Luas, (i == LUA_ERRSYNTAX ? 0 : 1));
+        } else {
+            int base = lua_gettop(Luas);        /* function index */
+            lua_checkstack(Luas, 1);
+            lua_pushcfunction(Luas, lua_traceback);     /* push traceback function */
+            lua_insert(Luas, base);     /* put it under chunk  */
+            i = lua_pcall(Luas, 0, 0, base);
+            lua_remove(Luas, base);     /* remove traceback function */
+            if (i != 0) {
+                lua_gc(Luas, LUA_GCCOLLECT, 0);
+                Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+            }
+        }
+    }
+    lua_active--;
+}
+
+@ @c
+lua_State *luatex_error(lua_State * L, int is_fatal)
+{
+
+    const_lstring luaerr;
+    char *err = NULL;
+    if (lua_type(L, -1) == LUA_TSTRING) {
+        luaerr.s = lua_tolstring(L, -1, &luaerr.l);
+        /* free last one ? */
+        err = (char *) xmalloc((unsigned) (luaerr.l + 1));
+        snprintf(err, (luaerr.l + 1), "%s", luaerr.s);
+        last_lua_error = err; /* hm, what if we have several .. not freed */
+    }
+    if (is_fatal > 0) {
+        /* Normally a memory error from lua.
+           The pool may overflow during the |maketexlstring()|, but we
+           are crashing anyway so we may as well abort on the pool size */
+        normal_error("lua",err);
+        /* never reached */
+        lua_close(L);
+        return (lua_State *) NULL;
+    } else {
+        normal_warning("lua",err);
+        return L;
+    }
+}
+
+@ @c
+void preset_environment(lua_State * L, const parm_struct * p, const char *s)
+{
+    int i;
+    assert(L != NULL);
+    /* double call with same s gives assert(0) */
+    lua_pushstring(L, s);       /* s */
+    lua_gettable(L, LUA_REGISTRYINDEX); /* t */
+    assert(lua_isnil(L, -1));
+    lua_pop(L, 1);              /* - */
+    lua_pushstring(L, s);       /* s */
+    lua_newtable(L);            /* t s */
+    for (i = 1, ++p; p->name != NULL; i++, p++) {
+        assert(i == p->idx);
+        lua_pushstring(L, p->name);     /* k t s */
+        lua_pushinteger(L, p->idx);     /* v k t s */
+        lua_settable(L, -3);    /* t s */
+    }
+    lua_settable(L, LUA_REGISTRYINDEX); /* - */
+}

Modified: trunk/Build/source/texk/web2c/luatexdir/lua/luatex-api.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/lua/luatex-api.h	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/lua/luatex-api.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -87,6 +87,10 @@
 extern int luaopen_md5(lua_State * L);
 extern int luatex_md5_lua_open(lua_State * L);
 
+#ifndef LuajitTeX
+ extern int luaopen_ffi(lua_State * L);
+#endif
+
 extern int luaopen_zlib(lua_State * L);
 extern int luaopen_gzip(lua_State * L);
 extern int luaopen_ff(lua_State * L);

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/CONTRIBUTING.md
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/CONTRIBUTING.md	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/CONTRIBUTING.md	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,30 @@
+# Contributing to luaffifb
+We want to make contributing to this project as easy and transparent as
+possible.
+
+## Our Development Process
+... (in particular how this is synced with internal changes to the project)
+
+## Pull Requests
+We actively welcome your pull requests.
+1. Fork the repo and create your branch from `master`.
+2. If you've added code that should be tested, add tests
+3. If you haven't already, complete the Contributor License Agreement ("CLA").
+
+## Contributor License Agreement ("CLA")
+In order to accept your pull request, we need you to submit a CLA. You only need
+to do this once to work on any of Facebook's open source projects.
+
+Complete your CLA here: <https://code.facebook.com/cla>
+
+## Issues
+We use GitHub issues to track public bugs. Please ensure your description is
+clear and has sufficient instructions to be able to reproduce the issue.
+
+## Coding Style
+* Use four spaces for indentation rather than tabs
+* 80 character line length
+
+## License
+By contributing to luaffifb, you agree that your contributions will be licensed
+under its BSD license.

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/LICENSE
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/LICENSE	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/LICENSE	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,58 @@
+BSD License
+
+For luaffifb software
+
+Copyright (c) 2015, Facebook, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------
+
+This product contains portions of third party software provided under this license:
+
+luaffi software
+
+Copyright (c) 2011 James R. McKaskill
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+Facebook provides this code under the BSD License above.

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/Makefile.orig
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/Makefile.orig	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/Makefile.orig	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,32 @@
+#
+# Use luarocks to install LuaFFI:
+# > git clone https://github.com/facebook/luaffifb
+# > cd luaffifb && luarocks make
+#
+# To rebuild the call_* headers:
+# > rm call_*.h && make headers
+#
+
+.PHONY: build clean headers
+LUA=lua
+
+build:
+	luarocks make
+
+clean:
+	rm -f *.o *.so *.dylib
+
+headers:
+	$(MAKE) call_x86.h call_x64.h call_x64win.h call_arm.h
+
+call_x86.h: call_x86.dasc dynasm/*.lua
+	$(LUA) dynasm/dynasm.lua -LN -o $@ $<
+
+call_x64.h: call_x86.dasc dynasm/*.lua
+	$(LUA) dynasm/dynasm.lua -D X64 -LN -o $@ $<
+
+call_x64win.h: call_x86.dasc dynasm/*.lua
+	$(LUA) dynasm/dynasm.lua -D X64 -D X64WIN -LN -o $@ $<
+
+call_arm.h: call_arm.dasc dynasm/*.lua
+	$(LUA) dynasm/dynasm.lua -LNE -o $@ $<

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/PATENTS
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/PATENTS	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/PATENTS	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the luaffifb software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook’s rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/README
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/README	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/README	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,78 @@
+This is luaffifb from https://github.com/facebook/luaffifb
+patched to compile for TeXLive..
+
+It should compile even where the ffi is not defined,
+because there is a ffi stub that does nothing:
+
+local info = [[
+The ffi module is available for:
+ 
+    archictures       : ARCH_X86 and ARCH_X64,
+    operating systems : OS_CE, OS_WIN, OS_LINUX, OS BD and OS_POSIX
+
+The ARM processor is currently not supported. There are subtle
+differences between this module and the one in luajitTeX 
+and we hope to be in sync around TeXLive 2018.
+Different OS can have different interfaces,
+for instance OS_WIN has not 'complex.h'. If you want portable
+code, stick to the most common concepts.
+]]
+
+local function stub()
+    texio.write_nl(info)
+end
+
+ffi = {
+    fill      = stub,
+    cast      = stub,
+    offsetof  = stub,
+    copy      = stub,
+    string    = stub,
+    abi       = stub,
+    cdef      = stub,
+    typeof    = stub,
+    sizeof    = stub,
+    type      = stub,
+    number    = stub,
+    gc        = stub,
+    metatype  = stub,
+    errno     = stub,
+    debug     = stub,
+    os        = ''  ,
+    arch      = ''  ,
+    NULL      = nil ,
+    alignof   = stub,
+    new       = stub,
+    u64       = stub,
+    i64       = stub,
+    istype    = stub,
+    load      = stub,
+    C         = nil ,
+}
+
+
+So the following chunk of code can be used as an 
+example of how to check the ffi:
+
+ if ffi then 
+   if (ffi.os=='' and ffi.arch=='') then
+   -- ffi is the stub
+   -- or it's not a sane ffi
+   -- This should print something on terminal
+      print(ffi.cdef(''))
+   else
+   -- ffi looks ok
+   end
+ else
+   -- no ffi at all: perhaps an old luatex ?
+ end
+
+The ARCH enabled ARCH_X86 and ARCH_X64, 
+the OS enabled are OS_CE, OS_WIN, OS_LINUX, OS BD and OS_POSIX.
+Currently ARM is not supported.
+
+The module is not aligned with  luajit-2.1.0.beta2
+(the plan is to be in sync for TeXLive 2018) and 
+test.lua can fail. Be careful that different OS have different 
+interfaces (i.e. OS_WIN has not complex.h, for example)
+so extra care must be take to ensure code portability.

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/README.md
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/README.md	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/README.md	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,86 @@
+[![Build Status](https://travis-ci.org/facebook/luaffifb.svg?branch=master)](https://travis-ci.org/facebook/luaffifb)
+
+About
+-----
+This is a library for calling C function and manipulating C types from lua. It
+is designed to be interface compatible with the FFI library in LuaJIT (see
+http://luajit.org/ext_ffi.html). It can parse C function declarations and
+struct definitions that have been directly copied out of C header files and
+into lua source as a string.
+
+This is a fork of https://github.com/jmckaskill/luaffi
+
+Source
+------
+https://github.com/facebook/luaffifb
+
+Platforms
+---------
+Currently supported:
+- Linux x86/x64
+- OS X x86/x64
+
+Runs with Lua 5.1, 5.2, and 5.3
+
+Build
+-----
+In a terminal:
+
+```bash
+git clone https://github.com/facebook/luaffifb
+cd luaffifb
+luarocks make
+```
+
+Documentation
+-------------
+This library is designed to be source compatible with LuaJIT's FFI extension. The documentation at http://luajit.org/ext_ffi.html describes the API and semantics.
+
+Pointer Comparison
+------------
+Use `ffi.NULL` instead of `nil` when checking for `NULL` pointers.
+```lua
+  ffi.new('void *', 0) == ffi.NULL -- true
+```
+
+Known Issues
+------------
+- Comparing a ctype pointer to `nil` doesn't work the same as in LuaJIT (see above).
+  This is unfixable with the current metamethod semantics.
+- Constant expressions can't handle non integer intermediate values (eg
+  offsetof won't work because it manipulates pointers)
+- Not all metamethods work with Lua 5.1 (eg char* + number). This is due to
+  the way metamethods are looked up with mixed types in Lua 5.1. If you need
+this upgrade to Lua 5.2 or use boxed numbers (uint64_t and uintptr_t).
+- All bitfields are treated as unsigned (does anyone even use signed
+  bitfields?). Note that "int s:8" is unsigned on unix x86/x64, but signed on
+windows.
+
+
+How it works
+------------
+Types are represented by a struct ctype structure and an associated user value
+table. The table is shared between all related types for structs, unions, and
+functions. It's members have the types of struct members, function argument
+types, etc. The struct ctype structure then contains the modifications from
+the base type (eg number of pointers, array size, etc).
+
+Types are pushed into lua as a userdata containing the struct ctype with a
+user value (or fenv in 5.1) set to the shared type table.
+
+Boxed cdata types are pushed into lua as a userdata containing the struct
+cdata structure (which contains the struct ctype of the data as its header)
+followed by the boxed data.
+
+The functions in `ffi.C` provide the `cdata` and `ctype` metatables and ffi.*
+functions which manipulate these two types.
+
+C functions (and function pointers) are pushed into lua as a lua c function
+with the function pointer cdata as the first upvalue. The actual code is JITed
+using dynasm (see call_x86.dasc). The JITed code does the following in order:
+
+1. Calls the needed unpack functions in `ffi.C` placing each argument on the HW stack
+2. Updates `errno`
+3. Performs the C call
+4. Retrieves `errno`
+5. Pushes the result back into lua from the HW register or stack

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/call.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/call.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/call.c	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,275 @@
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+#include "ffi.h"
+
+static cfunction compile(Dst_DECL, lua_State* L, cfunction func, int ref);
+
+static void* reserve_code(struct jit* jit, lua_State* L, size_t sz);
+static void commit_code(struct jit* jit, void* p, size_t sz);
+
+static void push_int(lua_State* L, int val)
+{ lua_pushinteger(L, val); }
+
+static void push_uint(lua_State* L, unsigned int val)
+{ lua_pushinteger(L, val); }
+
+static void push_float(lua_State* L, float val)
+{ lua_pushnumber(L, val); }
+
+#ifndef _WIN32
+static int GetLastError(void)
+{ return errno; }
+static void SetLastError(int err)
+{ errno = err; }
+#endif
+
+#ifdef NDEBUG
+#define shred(a,b,c)
+#else
+#define shred(p,s,e) memset((uint8_t*)(p)+(s),0xCC,(e)-(s))
+#endif
+
+
+#ifdef _WIN64
+#include "dynasm/dasm_x86.h"
+#include "call_x64win.h"
+#elif defined __amd64__
+#include "dynasm/dasm_x86.h"
+#include "call_x64.h"
+#elif defined __arm__ || defined __arm || defined __ARM__ || defined __ARM || defined ARM || defined _ARM_ || defined ARMV4I || defined _M_ARM
+#include "dynasm/dasm_arm.h"
+#include "call_arm.h"
+#else
+#include "dynasm/dasm_x86.h"
+#include "call_x86.h"
+#endif
+
+struct jit_head {
+    size_t size;
+    int ref;
+    uint8_t jump[JUMP_SIZE];
+};
+
+#define LINKTABLE_MAX_SIZE (sizeof(extnames) / sizeof(extnames[0]) * (JUMP_SIZE))
+
+static cfunction compile(struct jit* jit, lua_State* L, cfunction func, int ref)
+{
+    struct jit_head* code;
+    size_t codesz;
+    int err;
+
+    dasm_checkstep(jit, -1);
+    if ((err = dasm_link(jit, &codesz)) != 0) {
+        char buf[32];
+        sprintf(buf, "%x", err);
+        luaL_error(L, "dasm_link error %s", buf);
+    }
+
+    codesz += sizeof(struct jit_head);
+    code = (struct jit_head*) reserve_code(jit, L, codesz);
+    code->ref = ref;
+    code->size = codesz;
+    compile_extern_jump(jit, L, func, code->jump);
+
+    if ((err = dasm_encode(jit, code+1)) != 0) {
+        char buf[32];
+        sprintf(buf, "%x", err);
+        commit_code(jit, code, 0);
+        luaL_error(L, "dasm_encode error %s", buf);
+    }
+
+    commit_code(jit, code, codesz);
+    return (cfunction) (code+1);
+}
+
+typedef uint8_t jump_t[JUMP_SIZE];
+
+int get_extern(struct jit* jit, uint8_t* addr, int idx, int type)
+{
+    struct page* page = jit->pages[jit->pagenum-1];
+    jump_t* jumps = (jump_t*) (page+1);
+    struct jit_head* h = (struct jit_head*) ((uint8_t*) page + page->off);
+    uint8_t* jmp;
+    ptrdiff_t off;
+
+    if (idx == jit->function_extern) {
+       jmp = h->jump;
+    } else {
+       jmp = jumps[idx];
+    }
+
+    /* compensate for room taken up for the offset so that we can work rip
+     * relative */
+    addr += BRANCH_OFF;
+
+    /* see if we can fit the offset in the branch displacement, if not use the
+     * jump instruction */
+    off = *(uint8_t**) jmp - addr;
+
+    if (MIN_BRANCH <= off && off <= MAX_BRANCH) {
+        return (int32_t) off;
+    } else {
+        return (int32_t)(jmp + sizeof(uint8_t*) - addr);
+    }
+}
+
+static void* reserve_code(struct jit* jit, lua_State* L, size_t sz)
+{
+    struct page* page;
+    size_t off = (jit->pagenum > 0) ? jit->pages[jit->pagenum-1]->off : 0;
+    size_t size = (jit->pagenum > 0) ? jit->pages[jit->pagenum-1]->size : 0;
+
+    if (off + sz >= size) {
+        int i;
+        uint8_t* pdata;
+        cfunction func;
+
+        /* need to create a new page */
+        jit->pages = (struct page**) realloc(jit->pages, (++jit->pagenum) * sizeof(jit->pages[0]));
+
+        size = ALIGN_UP(sz + LINKTABLE_MAX_SIZE + sizeof(struct page), jit->align_page_size);
+
+        page = (struct page*) AllocPage(size);
+        jit->pages[jit->pagenum-1] = page;
+        pdata = (uint8_t*) page;
+        page->size = size;
+        page->off = sizeof(struct page);
+
+        lua_newtable(L);
+
+#define ADDFUNC(DLL, NAME) \
+        lua_pushliteral(L, #NAME); \
+        func = DLL ? (cfunction) GetProcAddressA(DLL, #NAME) : NULL; \
+        func = func ? func : (cfunction) &NAME; \
+        lua_pushcfunction(L, (lua_CFunction) func); \
+        lua_rawset(L, -3)
+
+        ADDFUNC(NULL, check_double);
+        ADDFUNC(NULL, check_float);
+        ADDFUNC(NULL, check_uint64);
+        ADDFUNC(NULL, check_int64);
+        ADDFUNC(NULL, check_int32);
+        ADDFUNC(NULL, check_uint32);
+        ADDFUNC(NULL, check_uintptr);
+        ADDFUNC(NULL, check_enum);
+        ADDFUNC(NULL, check_typed_pointer);
+        ADDFUNC(NULL, check_typed_cfunction);
+        ADDFUNC(NULL, check_complex_double);
+        ADDFUNC(NULL, check_complex_float);
+        ADDFUNC(NULL, unpack_varargs_stack);
+        ADDFUNC(NULL, unpack_varargs_stack_skip);
+        ADDFUNC(NULL, unpack_varargs_reg);
+        ADDFUNC(NULL, unpack_varargs_float);
+        ADDFUNC(NULL, unpack_varargs_int);
+        ADDFUNC(NULL, push_cdata);
+        ADDFUNC(NULL, push_int);
+        ADDFUNC(NULL, push_uint);
+        ADDFUNC(NULL, lua_pushinteger);
+        ADDFUNC(NULL, push_float);
+        ADDFUNC(jit->kernel32_dll, SetLastError);
+        ADDFUNC(jit->kernel32_dll, GetLastError);
+        ADDFUNC(jit->lua_dll, luaL_error);
+        ADDFUNC(jit->lua_dll, lua_pushnumber);
+        ADDFUNC(jit->lua_dll, lua_pushboolean);
+        ADDFUNC(jit->lua_dll, lua_gettop);
+        ADDFUNC(jit->lua_dll, lua_rawgeti);
+        ADDFUNC(jit->lua_dll, lua_pushnil);
+        ADDFUNC(jit->lua_dll, lua_callk);
+        ADDFUNC(jit->lua_dll, lua_settop);
+        ADDFUNC(jit->lua_dll, lua_remove);
+#undef ADDFUNC
+
+        for (i = 0; extnames[i] != NULL; i++) {
+
+            if (strcmp(extnames[i], "FUNCTION") == 0) {
+                shred(pdata + page->off, 0, JUMP_SIZE);
+                jit->function_extern = i;
+
+            } else {
+                lua_getfield(L, -1, extnames[i]);
+                func = (cfunction) lua_tocfunction(L, -1);
+
+                if (func == NULL) {
+                    luaL_error(L, "internal error: missing link for %s", extnames[i]);
+                }
+
+                compile_extern_jump(jit, L, func, pdata + page->off);
+                lua_pop(L, 1);
+            }
+
+            page->off += JUMP_SIZE;
+        }
+
+        page->freed = page->off;
+        lua_pop(L, 1);
+
+    } else {
+        page = jit->pages[jit->pagenum-1];
+        EnableWrite(page, page->size);
+    }
+
+    return (uint8_t*) page + page->off;
+}
+
+static void commit_code(struct jit* jit, void* code, size_t sz)
+{
+    struct page* page = jit->pages[jit->pagenum-1];
+    page->off += sz;
+    EnableExecute(page, page->size);
+    {
+#if 0
+        FILE* out = fopen("\\Hard Disk\\out.bin", "wb");
+        fwrite(page, page->off, 1, out);
+        fclose(out);
+#endif
+    }
+}
+
+/* push_func_ref pushes a copy of the upval table embedded in the compiled
+ * function func.
+ */
+void push_func_ref(lua_State* L, cfunction func)
+{
+    struct jit_head* h = ((struct jit_head*) func) - 1;
+    lua_rawgeti(L, LUA_REGISTRYINDEX, h->ref);
+}
+
+void free_code(struct jit* jit, lua_State* L, cfunction func)
+{
+    size_t i;
+    struct jit_head* h = ((struct jit_head*) func) - 1;
+    for (i = 0; i < jit->pagenum; i++) {
+        struct page* p = jit->pages[i];
+
+        if ((uint8_t*) h < (uint8_t*) p || (uint8_t*) p + p->size <= (uint8_t*) h) {
+            continue;
+        }
+
+        luaL_unref(L, LUA_REGISTRYINDEX, h->ref);
+
+        EnableWrite(p, p->size);
+        p->freed += h->size;
+
+        shred(h, 0, h->size);
+
+        if (p->freed < p->off) {
+            EnableExecute(p, p->size);
+            return;
+        }
+
+        FreePage(p, p->size);
+        memmove(&jit->pages[i], &jit->pages[i+1], (jit->pagenum - (i+1)) * sizeof(jit->pages[0]));
+        jit->pagenum--;
+        return;
+    }
+
+    assert(!"couldn't find func in the jit pages");
+}
+
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/call.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/call_arm.dasc
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/call_arm.dasc	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/call_arm.dasc	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,610 @@
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+|.arch arm
+|.actionlist build_actionlist
+|.globalnames globnames
+|.externnames extnames
+
+#define JUMP_SIZE 8
+#define MIN_BRANCH ((INT32_MIN) >> 8)
+#define MAX_BRANCH ((INT32_MAX) >> 8)
+#define BRANCH_OFF 4
+
+static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code)
+{
+    /* The jump code is the function pointer followed by a stub to call the
+     * function pointer. The stub exists so we can jump to functions with an
+     * offset greater than 32MB.
+     *
+     * Note we have to manually set this up since there are commands buffered
+     * in the jit state.
+     */
+    *(cfunction*) code = func;
+    /* ldr pc, [pc - 12] */
+    *(uint32_t*) &code[4] = 0xE51FF00CU;
+}
+
+|.define TOP, r4
+|.define L_ARG, r5
+|.define DATA, r6
+|.define DATA2, r7
+
+|.macro load32, reg, val
+| ldr reg, [pc]
+| b >5
+|.long val
+|5:
+|.endmacro
+
+|.macro lcall, func
+| mov r0, L_ARG
+| bl func
+|.endmacro
+
+void compile_globals(struct jit* jit, lua_State* L)
+{
+    (void) jit;
+}
+
+cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct)
+{
+    struct jit* Dst = get_jit(L);;
+    int i, nargs, num_upvals, ref;
+    const struct ctype* mt;
+
+    int top = lua_gettop(L);
+
+    ct_usr = lua_absindex(L, ct_usr);
+    fidx = lua_absindex(L, fidx);
+    nargs = (int) lua_rawlen(L, ct_usr);
+
+    dasm_setup(Dst, build_actionlist);
+
+    lua_newtable(L);
+    lua_pushvalue(L, -1);
+    ref = luaL_ref(L, LUA_REGISTRYINDEX);
+    num_upvals = 0;
+
+    if (ct->has_var_arg) {
+        luaL_error(L, "can't create callbacks with varargs");
+    }
+
+    /* prolog and get the upval table */
+    | mov r12, sp
+    | push {r0, r1, r2, r3} // do this first so that r0-r3 is right before stack bound arguments
+    | push {TOP, L_ARG, DATA, DATA2, r12, lr}
+    | sub DATA, r12, #16 // points to r0 on stack
+    | ldr L_ARG, [pc, #8]
+    | ldr r2, [pc, #8]
+    | ldr r1, [pc, #8]
+    | b >1
+    |.long L, ref, LUA_REGISTRYINDEX
+    |1:
+    | lcall extern lua_rawgeti
+
+    /* get the lua function */
+    lua_pushvalue(L, fidx);
+    lua_rawseti(L, -2, ++num_upvals);
+    | mov r2, #num_upvals
+    | mvn r1, #0 // -1
+    | lcall extern lua_rawgeti
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, i);
+        mt = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mt->pointers || mt->is_reference) {
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+
+            | mov r2, #num_upvals-1 // usr value
+            | mvn r1, #i // -i-1, stack is upval table, func, i-1 args
+            | lcall extern lua_rawgeti
+            | load32 r2, mt
+            | mvn r1, #0 // -1
+            | lcall extern push_cdata
+            | ldr r2, [DATA], #4
+            | str r2, [r0]
+            | mvn r1, #1 // -2
+            | lcall extern lua_remove // remove the usr value
+
+        } else {
+            switch (mt->type) {
+            case INT64_TYPE:
+                lua_rawseti(L, -2, ++num_upvals); /* mt */
+                | lcall extern lua_pushnil
+                | load32 r2, mt
+                | mvn r1, #0 // -1
+                | lcall extern push_cdata
+                | ldr r2, [DATA], #4
+                | ldr r3, [DATA], #4
+                | str r2, [r0]
+                | str r3, [r0, #4]
+                | mvn r1, #1 // -2
+                | lcall extern lua_remove // remove the nil usr
+                break;
+
+            case INTPTR_TYPE:
+                lua_rawseti(L, -2, ++num_upvals); /* mt */
+                | lcall extern lua_pushnil
+                | load32 r2, mt
+                | mvn r1, #0 // -1
+                | lcall extern push_cdata
+                | ldr r2, [DATA], #4
+                | str r2, [r0]
+                | mvn r1, #1 // -2
+                | lcall extern lua_remove // remove the nil usr
+                break;
+
+            case BOOL_TYPE:
+                lua_pop(L, 1);
+                | ldr r1, [DATA], #4
+                | lcall extern lua_pushboolean
+                break;
+
+            case INT8_TYPE:
+                lua_pop(L, 1);
+                | ldr r1, [DATA], #4
+                | mov r1, r1, lsl #24
+                if (mt->is_unsigned) {
+                    | mov r1, r1, lsr #24
+                } else {
+                    | mov r1, r1, asr #24
+                }
+                | lcall extern push_int
+                break;
+
+            case INT16_TYPE:
+                lua_pop(L, 1);
+                | ldr r1, [DATA], #4
+                | mov r1, r1, lsl #16
+                if (mt->is_unsigned) {
+                    | mov r1, r1, lsr #16
+                } else {
+                    | mov r1, r1, asr #16
+                }
+                | lcall extern push_int
+                break;
+
+            case ENUM_TYPE:
+            case INT32_TYPE:
+                lua_pop(L, 1);
+                | ldr r1, [DATA], #4
+                | lcall extern push_int
+                break;
+
+            case FLOAT_TYPE:
+                lua_pop(L, 1);
+                | ldr r1, [DATA], #4
+                | lcall extern push_float
+                break;
+
+            case DOUBLE_TYPE:
+                lua_pop(L, 1);
+                | ldmia DATA!, {r1, r2}
+                | lcall extern lua_pushnumber
+                break;
+
+            default:
+                luaL_error(L, "NYI: callback arg type");
+            }
+        }
+    }
+
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+
+    | mov r3, #0
+    | mov r2, #((mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0)
+    | mov r1, #nargs
+    | lcall extern lua_callk
+
+    if (mt->pointers || mt->is_reference) {
+        lua_getuservalue(L, -1);
+        lua_rawseti(L, -3, ++num_upvals); /* usr value */
+        lua_rawseti(L, -2, ++num_upvals); /* mt */
+
+        | mov r2, #num_upvals-1 // usr value
+        | mvn r1, #1 // -2 stack is (upval table, ret val)
+        | lcall extern lua_rawgeti
+        | load32 r3, mt
+        | mov r2, #0 // -1 - ct_usr
+        | mvn r1, #1 // -2 - val
+        | lcall extern to_typed_pointer
+        | mov DATA, r0
+        | mvn r1, #3 // -4 - remove 3 (upval table, ret val, usr value)
+        | lcall extern lua_settop
+        | mov r0, DATA
+    } else {
+        switch (mt->type) {
+        case ENUM_TYPE:
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+
+            | mov r2, #num_upvals-1 // usr value
+            | mvn r1, #1 // -2 stack is (upval table, ret val)
+            | lcall extern lua_rawgeti
+            | load32 r3, mt
+            | mvn r2, #0 // -1 - ct_usr
+            | mvn r1, #1 // -2 - val
+            | lcall extern to_enum
+            | mov DATA, r0
+            | mvn r1, #3 // -4 - remove 3 (upval table, ret val, usr value)
+            | lcall extern lua_settop
+            | mov r0, DATA
+            break;
+
+        case VOID_TYPE:
+            | mvn r1, #1 // -2
+            | lcall extern lua_settop
+            lua_pop(L, 1);
+            break;
+
+        case BOOL_TYPE:
+        case INT8_TYPE:
+        case INT16_TYPE:
+        case INT32_TYPE:
+            | mvn r1, #0 // -1
+            if (mt->is_unsigned) {
+                | lcall extern check_uint32
+            } else {
+                | lcall extern check_int32
+            }
+            goto single;
+
+        case INT64_TYPE:
+            | mvn r1, #0 // -1
+            if (mt->is_unsigned) {
+                | lcall extern check_uint64
+            } else {
+                | lcall extern check_int64
+            }
+            goto dual;
+
+        case INTPTR_TYPE:
+            | mvn r1, #0 // -1
+            | lcall extern check_intptr
+            goto single;
+
+        case FLOAT_TYPE:
+            | mvn r1, #0 // -1
+            | lcall extern check_float
+            goto single;
+
+        case DOUBLE_TYPE:
+            | mvn r1, #0 // -1
+            | lcall extern check_double
+            goto dual;
+
+        single:
+            | mov DATA, r0
+            | mvn r1, #2 // -3
+            | lcall extern lua_settop
+            | mov r0, DATA
+            lua_pop(L, 1);
+            break;
+
+        dual:
+            | mov DATA, r0
+            | mov DATA2, r1
+            | mvn r1, #2 // -3
+            | lcall extern lua_settop
+            | mov r0, DATA
+            | mov r1, DATA2
+            lua_pop(L, 1);
+            break;
+
+        default:
+            luaL_error(L, "NYI: callback return type");
+        }
+    }
+
+    | ldmia sp, {TOP, L_ARG, DATA, DATA2, sp, pc}
+
+    lua_pop(L, 1); /* upval table - already in registry */
+    assert(lua_gettop(L) == top);
+
+    {
+        void* p;
+        struct ctype ft;
+        cfunction func;
+
+        func = compile(Dst, L, NULL, ref);
+
+        ft = *ct;
+        ft.is_jitted = 1;
+        p = push_cdata(L, ct_usr, &ft);
+        *(cfunction*) p = func;
+
+        assert(lua_gettop(L) == top + 1);
+
+        return func;
+    }
+}
+
+void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct)
+{
+    struct jit* Dst = get_jit(L);;
+    int i, nargs, num_upvals;
+    const struct ctype* mt;
+    void* p;
+
+    int top = lua_gettop(L);
+
+    ct_usr = lua_absindex(L, ct_usr);
+    nargs = (int) lua_rawlen(L, ct_usr);
+
+    p = push_cdata(L, ct_usr, ct);
+    *(cfunction*) p = func;
+    num_upvals = 1;
+
+    dasm_setup(Dst, build_actionlist);
+
+    | mov r12, sp
+    | push {r0}
+    | push {TOP, L_ARG, DATA, DATA2, r11, r12, lr}
+    | sub r11, r12, #4
+    | mov L_ARG, r0
+    | lcall extern lua_gettop
+    | mov TOP, r0
+    | cmp TOP, #nargs
+    | // these should really be in globals - but for some reason dynasm breaks when you do that
+    if (ct->has_var_arg) {
+        | bge >1
+        | load32 r1, "too few arguments"
+        | lcall extern luaL_error
+        |1:
+    } else {
+        | beq >1
+        | load32 r1, "incorrect number of arguments"
+        | lcall extern luaL_error
+        |1:
+    }
+
+    /* reserve enough stack space for all of the arguments (8 bytes per
+     * argument for double and maintains alignment). Add an extra 16 bytes so
+     * that the pop {r0, r1, r2, r3} doesn't clean out our stack frame */
+    | sub sp, sp, TOP, lsl #3
+    | sub sp, sp, #16
+    | mov DATA, sp
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, i);
+        mt = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mt->pointers || mt->is_reference || mt->type == FUNCTION_PTR_TYPE || mt->type == ENUM_TYPE) {
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+
+            | ldr r3, [pc, #4]
+            | ldr r2, [pc, #4]
+            | b >1
+            |.long mt, lua_upvalueindex(num_upvals)
+            |1:
+            | mov r1, #i
+            | mov r0, L_ARG
+
+            if (mt->pointers || mt->is_reference) {
+                | bl extern to_typed_pointer
+            } else if (mt->type == FUNCTION_PTR_TYPE) {
+                | bl extern to_typed_function
+            } else if (mt->type == ENUM_TYPE) {
+                | bl extern to_enum
+            }
+
+            | str r0, [DATA], #4
+
+        } else {
+            lua_pop(L, 1);
+            | mov r1, #i
+
+            switch (mt->type) {
+            case INT8_TYPE:
+                | lcall extern check_int32
+                if (mt->is_unsigned) {
+                    | and r0, r0, #0xFF
+                } else {
+                    | mov r0, r0, lsl #24
+                    | mov r0, r0, asr #24                
+                }
+                | str r0, [DATA], #4
+                break;
+
+            case INT16_TYPE:
+                | lcall extern check_int32
+                if (mt->is_unsigned) {
+                    | mov r0, r0, lsl #16
+                    | mov r0, r0, lsr #16
+                } else {
+                    | mov r0, r0, lsl #16
+                    | mov r0, r0, asr #16                
+                }
+                | str r0, [DATA], #4
+                break;
+
+            case INT32_TYPE:
+                if (mt->is_unsigned) {
+                    | lcall extern check_uint32
+                } else {
+                    | lcall extern check_int32
+                }
+                | str r0, [DATA], #4
+                break;
+
+            case INT64_TYPE:
+                if (mt->is_unsigned) {
+                    | lcall extern check_uint64
+                } else {
+                    | lcall extern check_int64
+                }
+                | str r0, [DATA], #4
+                | str r1, [DATA], #4
+                break;
+
+            case DOUBLE_TYPE:
+                | lcall extern check_double
+                | str r0, [DATA], #4
+                | str r1, [DATA], #4
+                break;
+
+            case INTPTR_TYPE:
+                | lcall extern check_intptr
+                | str r0, [DATA], #4
+                break;
+
+            case FLOAT_TYPE:
+                | lcall extern check_float
+                | str r0, [DATA], #4
+                break;
+
+            default:
+                luaL_error(L, "NYI: call arg type");
+            }
+        }
+    }
+
+    if (ct->has_var_arg) {
+        | mov r3, DATA
+        | mov r2, TOP
+        | mov r1, #nargs+1
+        | lcall extern unpack_varargs_stack
+    }
+
+    | load32 r0, &Dst->last_errno
+    | ldr r0, [r0]
+    | bl extern SetLastError
+
+    | pop {r0, r1, r2, r3} // this pop is balanced with the sub sp, #16
+    | bl extern FUNCTION
+
+    |.macro get_errno
+    | bl extern GetLastError
+    | load32 r1, &Dst->last_errno
+    | str r0, [r1]
+    |.endmacro
+
+    |.macro return
+    | ldmdb r11, {TOP, L_ARG, DATA, r11, sp, pc}
+    |.endmacro
+
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+
+    if (mt->pointers || mt->is_reference) {
+        lua_getuservalue(L, -1);
+        num_upvals += 2;
+        | mov DATA, r0
+        | get_errno
+        | ldr r2, [pc, #4]
+        | ldr r1, [pc, #4]
+        | b >1
+        |.long mt, lua_upvalueindex(num_upvals)
+        |1:
+        | lcall extern push_cdata
+        | str DATA, [r0]
+        | mov r0, #1
+        | return
+
+    } else {
+        switch (mt->type) {
+        case INT64_TYPE:
+            num_upvals++;
+            | mov DATA, r0
+            | mov DATA2, r1
+            | get_errno
+            | lcall extern lua_pushnil
+            | load32 r2, mt
+            | mvn r1, #0 // -1
+            | lcall extern push_cdata
+            | str DATA, [r0]
+            | str DATA2, [r0, #4]
+            | mov r0, #1
+            | return
+            break;
+
+        case INTPTR_TYPE:
+            num_upvals++;
+            | mov DATA, r0
+            | get_errno
+            | lcall extern lua_pushnil
+            | load32 r2, mt
+            | mvn r1, #0 // -1
+            | lcall extern push_cdata
+            | str DATA, [r0]
+            | mov r0, #1
+            | return
+            break;
+
+        case VOID_TYPE:
+            lua_pop(L, 1);
+            | get_errno
+            | mov r0, #0
+            | return
+            break;
+
+        case BOOL_TYPE:
+            lua_pop(L, 1);
+            | mov DATA, r0
+            | get_errno
+            | mov r1, DATA
+            | lcall extern lua_pushboolean
+            | mov r0, #1
+            | return
+            break;
+
+        case INT8_TYPE:
+        case INT16_TYPE:
+        case INT32_TYPE:
+        case ENUM_TYPE:
+            lua_pop(L, 1);
+            | mov DATA, r0
+            | get_errno
+            | mov r1, DATA
+            if (mt->is_unsigned) {
+                | lcall extern push_uint
+            } else {
+                | lcall extern push_int
+            }
+            | mov r0, #1
+            | return
+            break;
+
+        case FLOAT_TYPE:
+            lua_pop(L, 1);
+            | mov DATA, r0
+            | get_errno
+            | mov r1, DATA
+            | lcall extern push_float
+            | mov r0, #1
+            | return
+            break;
+
+        case DOUBLE_TYPE:
+            lua_pop(L, 1);
+            | mov DATA, r0
+            | mov DATA2, r1
+            | get_errno
+            | mov r2, DATA2
+            | mov r1, DATA
+            | lcall extern lua_pushnumber
+            | mov r0, #1
+            | return
+            break;
+
+        default:
+            luaL_error(L, "NYI: call return type");
+        }
+    }
+
+    assert(lua_gettop(L) == top + num_upvals);
+    lua_pushcclosure(L, (lua_CFunction) compile(Dst, L, func, LUA_NOREF), num_upvals);
+}
+

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/call_arm.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/call_arm.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/call_arm.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,1013 @@
+/*
+** This file has been pre-processed with DynASM.
+** http://luajit.org/dynasm.html
+** DynASM version 1.3.0, DynASM arm version 1.3.0
+** DO NOT EDIT! The original file is in "call_arm.dasc".
+*/
+
+#if DASM_VERSION != 10300
+#error "Version mismatch between DynASM and included encoding engine"
+#endif
+
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+static const unsigned int build_actionlist[546] = {
+0xe1a0c00d,
+0xe92d000f,
+0xe92d50f0,
+0xe24c6010,
+0xe59f5008,
+0xe59f2008,
+0xe59f1008,
+0xea000000,
+0x00050001,
+0x00090000,
+0x00090000,
+0x00090000,
+0x0006000b,
+0xe1a00005,
+0xeb000000,
+0x00030000,
+0x00000000,
+0xe3a02000,
+0x000b0000,
+0xe3e01000,
+0xe1a00005,
+0xeb000000,
+0x00030000,
+0x00000000,
+0xe3a02000,
+0x000b0000,
+0xe3e01000,
+0x000b0000,
+0xe1a00005,
+0xeb000000,
+0x00030000,
+0xe59f2000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe3e01000,
+0xe1a00005,
+0xeb000000,
+0x00030001,
+0xe4962004,
+0xe5802000,
+0xe3e01001,
+0xe1a00005,
+0xeb000000,
+0x00030002,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x00030003,
+0xe59f2000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe3e01000,
+0xe1a00005,
+0xeb000000,
+0x00030001,
+0xe4962004,
+0xe4963004,
+0xe5802000,
+0xe5803004,
+0xe3e01001,
+0xe1a00005,
+0xeb000000,
+0x00030002,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x00030003,
+0xe59f2000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe3e01000,
+0xe1a00005,
+0xeb000000,
+0x00030001,
+0xe4962004,
+0xe5802000,
+0xe3e01001,
+0xe1a00005,
+0xeb000000,
+0x00030002,
+0x00000000,
+0xe4961004,
+0xe1a00005,
+0xeb000000,
+0x00030004,
+0x00000000,
+0xe4961004,
+0xe1a01c01,
+0x00000000,
+0xe1a01c21,
+0x00000000,
+0xe1a01c41,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x00030005,
+0x00000000,
+0xe4961004,
+0xe1a01801,
+0x00000000,
+0xe1a01821,
+0x00000000,
+0xe1a01841,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x00030005,
+0x00000000,
+0xe4961004,
+0xe1a00005,
+0xeb000000,
+0x00030005,
+0x00000000,
+0xe4961004,
+0xe1a00005,
+0xeb000000,
+0x00030006,
+0x00000000,
+0xe8b60006,
+0xe1a00005,
+0xeb000000,
+0x00030007,
+0x00000000,
+0xe3a03000,
+0xe3a02000,
+0x000b0000,
+0xe3a01000,
+0x000b0000,
+0xe1a00005,
+0xeb000000,
+0x00030008,
+0x00000000,
+0xe3a02000,
+0x000b0000,
+0xe3e01001,
+0xe1a00005,
+0xeb000000,
+0x00030000,
+0xe59f3000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe3a02000,
+0xe3e01001,
+0xe1a00005,
+0xeb000000,
+0x00030009,
+0xe1a06000,
+0xe3e01003,
+0xe1a00005,
+0xeb000000,
+0x0003000a,
+0xe1a00006,
+0x00000000,
+0xe3a02000,
+0x000b0000,
+0xe3e01001,
+0xe1a00005,
+0xeb000000,
+0x00030000,
+0xe59f3000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe3e02000,
+0xe3e01001,
+0xe1a00005,
+0xeb000000,
+0x0003000b,
+0xe1a06000,
+0xe3e01003,
+0xe1a00005,
+0xeb000000,
+0x0003000a,
+0xe1a00006,
+0x00000000,
+0xe3e01001,
+0xe1a00005,
+0xeb000000,
+0x0003000a,
+0x00000000,
+0xe3e01000,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003000c,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003000d,
+0x00000000,
+0xe3e01000,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003000e,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003000f,
+0x00000000,
+0xe3e01000,
+0xe1a00005,
+0xeb000000,
+0x00030010,
+0x00000000,
+0xe3e01000,
+0xe1a00005,
+0xeb000000,
+0x00030011,
+0x00000000,
+0xe3e01000,
+0xe1a00005,
+0xeb000000,
+0x00030012,
+0x00000000,
+0xe1a06000,
+0xe3e01002,
+0xe1a00005,
+0xeb000000,
+0x0003000a,
+0xe1a00006,
+0x00000000,
+0xe1a06000,
+0xe1a07001,
+0xe3e01002,
+0xe1a00005,
+0xeb000000,
+0x0003000a,
+0xe1a00006,
+0xe1a01007,
+0x00000000,
+0xe89da0f0,
+0x00000000,
+0xe1a0c00d,
+0xe92d0001,
+0xe92d58f0,
+0xe24cb004,
+0xe1a05000,
+0xe1a00005,
+0xeb000000,
+0x00030013,
+0xe1a04000,
+0xe3540000,
+0x000b0000,
+0x00000000,
+0xaa000000,
+0x00050001,
+0xe59f1000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe1a00005,
+0xeb000000,
+0x00030014,
+0x0006000b,
+0x00000000,
+0x0a000000,
+0x00050001,
+0xe59f1000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe1a00005,
+0xeb000000,
+0x00030014,
+0x0006000b,
+0x00000000,
+0xe04dd184,
+0xe24dd010,
+0xe1a0600d,
+0x00000000,
+0xe59f3004,
+0xe59f2004,
+0xea000000,
+0x00050001,
+0x00090000,
+0x00090000,
+0x0006000b,
+0xe3a01000,
+0x000b0000,
+0xe1a00005,
+0x00000000,
+0xeb000000,
+0x00030009,
+0x00000000,
+0xeb000000,
+0x00030015,
+0x00000000,
+0xeb000000,
+0x0003000b,
+0x00000000,
+0xe4860004,
+0x00000000,
+0xe3a01000,
+0x000b0000,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003000d,
+0x00000000,
+0xe20000ff,
+0x00000000,
+0xe1a00c00,
+0xe1a00c40,
+0x00000000,
+0xe4860004,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003000d,
+0x00000000,
+0xe1a00800,
+0xe1a00820,
+0x00000000,
+0xe1a00800,
+0xe1a00840,
+0x00000000,
+0xe4860004,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003000c,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003000d,
+0x00000000,
+0xe4860004,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003000e,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003000f,
+0x00000000,
+0xe4860004,
+0xe4861004,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x00030012,
+0xe4860004,
+0xe4861004,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x00030010,
+0xe4860004,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x00030011,
+0xe4860004,
+0x00000000,
+0xe1a03006,
+0xe1a02004,
+0xe3a01000,
+0x000b0000,
+0xe1a00005,
+0xeb000000,
+0x00030016,
+0x00000000,
+0xe59f0000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe5900000,
+0xeb000000,
+0x00030017,
+0x00000000,
+0xe8bd000f,
+0xeb000000,
+0x00030018,
+0x00000000,
+0xe1a06000,
+0xeb000000,
+0x00030019,
+0xe59f1000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe5810000,
+0xe59f2004,
+0xe59f1004,
+0xea000000,
+0x00050001,
+0x00090000,
+0x00090000,
+0x0006000b,
+0xe1a00005,
+0xeb000000,
+0x00030001,
+0xe5806000,
+0xe3a00001,
+0xe91ba870,
+0x00000000,
+0xe1a06000,
+0xe1a07001,
+0xeb000000,
+0x00030019,
+0xe59f1000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe5810000,
+0xe1a00005,
+0xeb000000,
+0x00030003,
+0xe59f2000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe3e01000,
+0xe1a00005,
+0xeb000000,
+0x00030001,
+0xe5806000,
+0xe5807004,
+0xe3a00001,
+0xe91ba870,
+0x00000000,
+0xe1a06000,
+0xeb000000,
+0x00030019,
+0xe59f1000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe5810000,
+0xe1a00005,
+0xeb000000,
+0x00030003,
+0xe59f2000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe3e01000,
+0xe1a00005,
+0xeb000000,
+0x00030001,
+0xe5806000,
+0xe3a00001,
+0xe91ba870,
+0x00000000,
+0xeb000000,
+0x00030019,
+0xe59f1000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe5810000,
+0xe3a00000,
+0xe91ba870,
+0x00000000,
+0xe1a06000,
+0xeb000000,
+0x00030019,
+0xe59f1000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe5810000,
+0xe1a01006,
+0xe1a00005,
+0xeb000000,
+0x00030004,
+0xe3a00001,
+0xe91ba870,
+0x00000000,
+0xe1a06000,
+0xeb000000,
+0x00030019,
+0xe59f1000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe5810000,
+0xe1a01006,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x0003001a,
+0x00000000,
+0xe1a00005,
+0xeb000000,
+0x00030005,
+0x00000000,
+0xe3a00001,
+0xe91ba870,
+0x00000000,
+0xe1a06000,
+0xeb000000,
+0x00030019,
+0xe59f1000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe5810000,
+0xe1a01006,
+0xe1a00005,
+0xeb000000,
+0x00030006,
+0xe3a00001,
+0xe91ba870,
+0x00000000,
+0xe1a06000,
+0xe1a07001,
+0xeb000000,
+0x00030019,
+0xe59f1000,
+0xea000000,
+0x00050005,
+0x00090000,
+0x0006000f,
+0xe5810000,
+0xe1a02007,
+0xe1a01006,
+0xe1a00005,
+0xeb000000,
+0x00030007,
+0xe3a00001,
+0xe91ba870,
+0x00000000
+};
+
+static const char *const globnames[] = {
+  (const char *)0
+};
+static const char *const extnames[] = {
+  "lua_rawgeti",
+  "push_cdata",
+  "lua_remove",
+  "lua_pushnil",
+  "lua_pushboolean",
+  "push_int",
+  "push_float",
+  "lua_pushnumber",
+  "lua_callk",
+  "to_typed_pointer",
+  "lua_settop",
+  "to_enum",
+  "check_uint32",
+  "check_int32",
+  "check_uint64",
+  "check_int64",
+  "check_intptr",
+  "check_float",
+  "check_double",
+  "lua_gettop",
+  "luaL_error",
+  "to_typed_function",
+  "unpack_varargs_stack",
+  "SetLastError",
+  "FUNCTION",
+  "GetLastError",
+  "push_uint",
+  (const char *)0
+};
+
+#define JUMP_SIZE 8
+#define MIN_BRANCH ((INT32_MIN) >> 8)
+#define MAX_BRANCH ((INT32_MAX) >> 8)
+#define BRANCH_OFF 4
+
+static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code)
+{
+    /* The jump code is the function pointer followed by a stub to call the
+     * function pointer. The stub exists so we can jump to functions with an
+     * offset greater than 32MB.
+     *
+     * Note we have to manually set this up since there are commands buffered
+     * in the jit state.
+     */
+    *(cfunction*) code = func;
+    /* ldr pc, [pc - 12] */
+    *(uint32_t*) &code[4] = 0xE51FF00CU;
+}
+
+
+
+
+void compile_globals(struct jit* jit, lua_State* L)
+{
+    (void) jit;
+}
+
+cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct)
+{
+    struct jit* Dst = get_jit(L);;
+    int i, nargs, num_upvals, ref;
+    const struct ctype* mt;
+
+    int top = lua_gettop(L);
+
+    ct_usr = lua_absindex(L, ct_usr);
+    fidx = lua_absindex(L, fidx);
+    nargs = (int) lua_rawlen(L, ct_usr);
+
+    dasm_setup(Dst, build_actionlist);
+
+    lua_newtable(L);
+    lua_pushvalue(L, -1);
+    ref = luaL_ref(L, LUA_REGISTRYINDEX);
+    num_upvals = 0;
+
+    if (ct->has_var_arg) {
+        luaL_error(L, "can't create callbacks with varargs");
+    }
+
+    /* prolog and get the upval table */
+    dasm_put(Dst, 0, (uintptr_t)(L), (uintptr_t)(ref), (uintptr_t)(LUA_REGISTRYINDEX));
+
+    /* get the lua function */
+    lua_pushvalue(L, fidx);
+    lua_rawseti(L, -2, ++num_upvals);
+    dasm_put(Dst, 17, num_upvals);
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, i);
+        mt = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mt->pointers || mt->is_reference) {
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+
+            dasm_put(Dst, 24, num_upvals-1, i, (uintptr_t)(mt));
+
+        } else {
+            switch (mt->type) {
+            case INT64_TYPE:
+                lua_rawseti(L, -2, ++num_upvals); /* mt */
+                dasm_put(Dst, 47, (uintptr_t)(mt));
+                break;
+
+            case INTPTR_TYPE:
+                lua_rawseti(L, -2, ++num_upvals); /* mt */
+                dasm_put(Dst, 68, (uintptr_t)(mt));
+                break;
+
+            case BOOL_TYPE:
+                lua_pop(L, 1);
+                dasm_put(Dst, 87);
+                break;
+
+            case INT8_TYPE:
+                lua_pop(L, 1);
+                dasm_put(Dst, 92);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 95);
+                } else {
+                    dasm_put(Dst, 97);
+                }
+                dasm_put(Dst, 99);
+                break;
+
+            case INT16_TYPE:
+                lua_pop(L, 1);
+                dasm_put(Dst, 103);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 106);
+                } else {
+                    dasm_put(Dst, 108);
+                }
+                dasm_put(Dst, 110);
+                break;
+
+            case ENUM_TYPE:
+            case INT32_TYPE:
+                lua_pop(L, 1);
+                dasm_put(Dst, 114);
+                break;
+
+            case FLOAT_TYPE:
+                lua_pop(L, 1);
+                dasm_put(Dst, 119);
+                break;
+
+            case DOUBLE_TYPE:
+                lua_pop(L, 1);
+                dasm_put(Dst, 124);
+                break;
+
+            default:
+                luaL_error(L, "NYI: callback arg type");
+            }
+        }
+    }
+
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+
+    dasm_put(Dst, 129, ((mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0), nargs);
+
+    if (mt->pointers || mt->is_reference) {
+        lua_getuservalue(L, -1);
+        lua_rawseti(L, -3, ++num_upvals); /* usr value */
+        lua_rawseti(L, -2, ++num_upvals); /* mt */
+
+        dasm_put(Dst, 138, num_upvals-1, (uintptr_t)(mt));
+    } else {
+        switch (mt->type) {
+        case ENUM_TYPE:
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+
+            dasm_put(Dst, 161, num_upvals-1, (uintptr_t)(mt));
+            break;
+
+        case VOID_TYPE:
+            dasm_put(Dst, 184);
+            lua_pop(L, 1);
+            break;
+
+        case BOOL_TYPE:
+        case INT8_TYPE:
+        case INT16_TYPE:
+        case INT32_TYPE:
+            dasm_put(Dst, 189);
+            if (mt->is_unsigned) {
+                dasm_put(Dst, 191);
+            } else {
+                dasm_put(Dst, 195);
+            }
+            goto single;
+
+        case INT64_TYPE:
+            dasm_put(Dst, 199);
+            if (mt->is_unsigned) {
+                dasm_put(Dst, 201);
+            } else {
+                dasm_put(Dst, 205);
+            }
+            goto dual;
+
+        case INTPTR_TYPE:
+            dasm_put(Dst, 209);
+            goto single;
+
+        case FLOAT_TYPE:
+            dasm_put(Dst, 214);
+            goto single;
+
+        case DOUBLE_TYPE:
+            dasm_put(Dst, 219);
+            goto dual;
+
+        single:
+            dasm_put(Dst, 224);
+            lua_pop(L, 1);
+            break;
+
+        dual:
+            dasm_put(Dst, 231);
+            lua_pop(L, 1);
+            break;
+
+        default:
+            luaL_error(L, "NYI: callback return type");
+        }
+    }
+
+    dasm_put(Dst, 240);
+
+    lua_pop(L, 1); /* upval table - already in registry */
+    assert(lua_gettop(L) == top);
+
+    {
+        void* p;
+        struct ctype ft;
+        cfunction func;
+
+        func = compile(Dst, L, NULL, ref);
+
+        ft = *ct;
+        ft.is_jitted = 1;
+        p = push_cdata(L, ct_usr, &ft);
+        *(cfunction*) p = func;
+
+        assert(lua_gettop(L) == top + 1);
+
+        return func;
+    }
+}
+
+void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct)
+{
+    struct jit* Dst = get_jit(L);;
+    int i, nargs, num_upvals;
+    const struct ctype* mt;
+    void* p;
+
+    int top = lua_gettop(L);
+
+    ct_usr = lua_absindex(L, ct_usr);
+    nargs = (int) lua_rawlen(L, ct_usr);
+
+    p = push_cdata(L, ct_usr, ct);
+    *(cfunction*) p = func;
+    num_upvals = 1;
+
+    dasm_setup(Dst, build_actionlist);
+
+    dasm_put(Dst, 242, nargs);
+    if (ct->has_var_arg) {
+        dasm_put(Dst, 254, (uintptr_t)("too few arguments"));
+    } else {
+        dasm_put(Dst, 266, (uintptr_t)("incorrect number of arguments"));
+    }
+
+    /* reserve enough stack space for all of the arguments (8 bytes per
+     * argument for double and maintains alignment). Add an extra 16 bytes so
+     * that the pop {r0, r1, r2, r3} doesn't clean out our stack frame */
+    dasm_put(Dst, 278);
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, i);
+        mt = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mt->pointers || mt->is_reference || mt->type == FUNCTION_PTR_TYPE || mt->type == ENUM_TYPE) {
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+
+            dasm_put(Dst, 282, (uintptr_t)(mt), (uintptr_t)(lua_upvalueindex(num_upvals)), i);
+
+            if (mt->pointers || mt->is_reference) {
+                dasm_put(Dst, 293);
+            } else if (mt->type == FUNCTION_PTR_TYPE) {
+                dasm_put(Dst, 296);
+            } else if (mt->type == ENUM_TYPE) {
+                dasm_put(Dst, 299);
+            }
+
+            dasm_put(Dst, 302);
+
+        } else {
+            lua_pop(L, 1);
+            dasm_put(Dst, 304, i);
+
+            switch (mt->type) {
+            case INT8_TYPE:
+                dasm_put(Dst, 307);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 311);
+                } else {
+                    dasm_put(Dst, 313);
+                }
+                dasm_put(Dst, 316);
+                break;
+
+            case INT16_TYPE:
+                dasm_put(Dst, 318);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 322);
+                } else {
+                    dasm_put(Dst, 325);
+                }
+                dasm_put(Dst, 328);
+                break;
+
+            case INT32_TYPE:
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 330);
+                } else {
+                    dasm_put(Dst, 334);
+                }
+                dasm_put(Dst, 338);
+                break;
+
+            case INT64_TYPE:
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 340);
+                } else {
+                    dasm_put(Dst, 344);
+                }
+                dasm_put(Dst, 348);
+                break;
+
+            case DOUBLE_TYPE:
+                dasm_put(Dst, 351);
+                break;
+
+            case INTPTR_TYPE:
+                dasm_put(Dst, 357);
+                break;
+
+            case FLOAT_TYPE:
+                dasm_put(Dst, 362);
+                break;
+
+            default:
+                luaL_error(L, "NYI: call arg type");
+            }
+        }
+    }
+
+    if (ct->has_var_arg) {
+        dasm_put(Dst, 367, nargs+1);
+    }
+
+    dasm_put(Dst, 375, (uintptr_t)(&Dst->last_errno));
+
+    dasm_put(Dst, 384);
+
+
+
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+
+    if (mt->pointers || mt->is_reference) {
+        lua_getuservalue(L, -1);
+        num_upvals += 2;
+        dasm_put(Dst, 388, (uintptr_t)(&Dst->last_errno), (uintptr_t)(mt), (uintptr_t)(lua_upvalueindex(num_upvals)));
+
+    } else {
+        switch (mt->type) {
+        case INT64_TYPE:
+            num_upvals++;
+            dasm_put(Dst, 411, (uintptr_t)(&Dst->last_errno), (uintptr_t)(mt));
+            break;
+
+        case INTPTR_TYPE:
+            num_upvals++;
+            dasm_put(Dst, 438, (uintptr_t)(&Dst->last_errno), (uintptr_t)(mt));
+            break;
+
+        case VOID_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 463, (uintptr_t)(&Dst->last_errno));
+            break;
+
+        case BOOL_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 474, (uintptr_t)(&Dst->last_errno));
+            break;
+
+        case INT8_TYPE:
+        case INT16_TYPE:
+        case INT32_TYPE:
+        case ENUM_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 490, (uintptr_t)(&Dst->last_errno));
+            if (mt->is_unsigned) {
+                dasm_put(Dst, 501);
+            } else {
+                dasm_put(Dst, 505);
+            }
+            dasm_put(Dst, 509);
+            break;
+
+        case FLOAT_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 512, (uintptr_t)(&Dst->last_errno));
+            break;
+
+        case DOUBLE_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 528, (uintptr_t)(&Dst->last_errno));
+            break;
+
+        default:
+            luaL_error(L, "NYI: call return type");
+        }
+    }
+
+    assert(lua_gettop(L) == top + num_upvals);
+    lua_pushcclosure(L, (lua_CFunction) compile(Dst, L, func, LUA_NOREF), num_upvals);
+}
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/call_arm.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x64.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x64.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x64.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,1204 @@
+/*
+** This file has been pre-processed with DynASM.
+** http://luajit.org/dynasm.html
+** DynASM version 1.3.0, DynASM x64 version 1.3.0
+** DO NOT EDIT! The original file is in "call_x86.dasc".
+*/
+
+#if DASM_VERSION != 10300
+#error "Version mismatch between DynASM and included encoding engine"
+#endif
+
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+static const unsigned char build_actionlist[2157] = {
+  72,139,141,233,255,72,137,132,253,36,233,255,221,133,233,255,217,133,233,
+  255,252,243,15,126,133,233,255,252,243,15,90,133,233,255,221,156,253,36,233,
+  255,217,156,253,36,233,255,102,15,214,132,253,36,233,255,252,242,15,90,192,
+  102,15,214,132,253,36,233,255,252,242,15,90,192,102,15,126,132,253,36,233,
+  255,85,72,137,229,65,84,72,129,252,236,239,102,15,214,69,252,240,102,15,214,
+  77,232,102,15,214,85,224,102,15,214,93,216,102,15,214,101,208,102,15,214,
+  109,200,102,15,214,117,192,102,15,214,125,184,72,137,125,176,72,137,117,168,
+  72,137,85,160,72,137,77,152,76,137,69,144,76,137,77,136,255,73,188,237,237,
+  255,72,199,194,237,72,199,198,237,76,137,231,232,251,1,0,255,72,199,194,237,
+  72,199,198,252,255,252,255,252,255,252,255,76,137,231,232,251,1,0,255,72,
+  199,194,237,72,199,198,237,76,137,231,232,251,1,0,72,186,237,237,72,199,198,
+  252,255,252,255,252,255,252,255,76,137,231,232,251,1,1,255,72,137,8,72,199,
+  198,252,254,252,255,252,255,252,255,76,137,231,232,251,1,2,255,72,186,237,
+  237,72,199,198,0,0,0,0,76,137,231,232,251,1,1,255,72,137,8,255,102,15,214,
+  0,255,217,24,255,217,88,4,255,102,15,214,64,8,255,76,137,231,232,251,1,3,
+  255,15,182,201,72,137,206,76,137,231,232,251,1,4,255,15,182,201,255,15,190,
+  201,255,72,137,206,76,137,231,232,251,1,5,255,15,183,201,255,15,191,201,255,
+  72,137,206,76,137,231,232,251,1,6,255,72,185,237,237,72,199,194,237,72,199,
+  198,237,76,137,231,232,251,1,7,255,72,199,194,237,72,199,198,252,254,252,
+  255,252,255,252,255,76,137,231,232,251,1,0,72,185,237,237,72,199,194,252,
+  255,252,255,252,255,252,255,72,199,198,252,254,252,255,252,255,252,255,76,
+  137,231,232,251,1,8,72,137,68,36,32,72,199,198,252,252,252,255,252,255,252,
+  255,76,137,231,232,251,1,9,72,139,68,36,32,255,72,199,194,237,72,199,198,
+  252,254,252,255,252,255,252,255,76,137,231,232,251,1,0,72,185,237,237,72,
+  199,194,252,255,252,255,252,255,252,255,72,199,198,252,254,252,255,252,255,
+  252,255,76,137,231,232,251,1,10,137,68,36,32,72,199,198,252,252,252,255,252,
+  255,252,255,76,137,231,232,251,1,9,139,68,36,32,255,72,199,198,252,254,252,
+  255,252,255,252,255,76,137,231,232,251,1,9,255,72,199,198,252,255,252,255,
+  252,255,252,255,76,137,231,232,251,1,11,255,72,199,198,252,255,252,255,252,
+  255,252,255,76,137,231,232,251,1,12,255,137,68,36,32,72,199,198,252,253,252,
+  255,252,255,252,255,76,137,231,232,251,1,9,139,68,36,32,255,72,199,198,252,
+  255,252,255,252,255,252,255,76,137,231,232,251,1,13,255,72,199,198,252,255,
+  252,255,252,255,252,255,76,137,231,232,251,1,14,255,72,137,68,36,32,72,199,
+  198,252,253,252,255,252,255,252,255,76,137,231,232,251,1,9,72,139,68,36,32,
+  255,72,199,198,252,255,252,255,252,255,252,255,76,137,231,232,251,1,15,72,
+  137,68,36,32,72,199,198,252,253,252,255,252,255,252,255,76,137,231,232,251,
+  1,9,72,139,68,36,32,255,72,199,198,252,255,252,255,252,255,252,255,76,137,
+  231,232,251,1,16,102,15,214,68,36,32,72,199,198,252,253,252,255,252,255,252,
+  255,76,137,231,232,251,1,9,255,252,242,15,90,68,36,32,255,252,243,15,126,
+  68,36,32,255,72,199,198,252,255,252,255,252,255,252,255,76,137,231,232,251,
+  1,17,102,15,214,68,36,32,72,199,198,252,253,252,255,252,255,252,255,76,137,
+  231,232,251,1,9,252,243,15,126,68,36,32,255,72,199,198,252,255,252,255,252,
+  255,252,255,76,137,231,232,251,1,18,102,15,214,68,36,32,102,15,214,76,36,
+  40,72,199,198,252,253,252,255,252,255,252,255,76,137,231,232,251,1,9,252,
+  243,15,126,68,36,32,252,243,15,126,76,36,40,255,72,139,141,233,72,199,194,
+  252,255,252,255,252,255,252,255,76,137,230,72,137,207,232,251,1,18,72,131,
+  252,236,4,72,199,198,252,253,252,255,252,255,252,255,76,137,231,232,251,1,
+  9,255,76,139,101,252,248,72,137,252,236,93,194,236,255,85,72,137,229,65,84,
+  65,85,73,137,252,252,76,137,231,232,251,1,19,73,137,197,72,129,252,248,239,
+  255,15,141,244,248,102,184,0,0,72,190,237,237,76,137,231,232,251,1,20,248,
+  2,15,142,244,247,102,184,0,0,72,190,237,237,76,137,231,232,251,1,20,255,15,
+  141,244,247,102,184,0,0,72,190,237,237,76,137,231,232,251,1,20,255,248,1,
+  255,72,193,224,4,72,41,196,72,129,252,236,239,255,72,186,237,237,72,199,198,
+  0,0,0,0,76,137,231,232,251,1,1,72,131,252,236,16,255,72,185,237,237,72,199,
+  194,237,72,199,198,237,76,137,231,232,251,1,8,255,72,185,237,237,72,199,194,
+  237,72,199,198,237,76,137,231,232,251,1,21,255,72,185,237,237,72,199,194,
+  237,72,199,198,237,76,137,231,232,251,1,10,255,72,199,198,237,76,137,231,
+  232,251,1,12,255,15,182,192,255,15,190,192,255,15,183,192,255,15,191,192,
+  255,72,199,198,237,76,137,231,232,251,1,12,131,252,248,0,15,149,208,15,182,
+  192,255,72,199,198,237,76,137,231,232,251,1,11,255,72,199,198,237,76,137,
+  231,232,251,1,15,255,72,199,198,237,76,137,231,232,251,1,13,255,72,199,198,
+  237,76,137,231,232,251,1,14,255,72,199,198,237,76,137,231,232,251,1,16,255,
+  72,199,198,237,76,137,231,232,251,1,18,255,252,243,15,126,193,255,72,141,
+  132,253,36,233,72,131,252,236,4,72,199,194,237,76,137,230,72,137,199,232,
+  251,1,18,255,72,199,198,237,76,137,231,232,251,1,17,255,72,199,198,237,76,
+  137,231,232,251,1,17,137,4,36,217,4,36,255,137,20,36,217,4,36,255,72,137,
+  224,72,129,192,239,73,137,192,72,199,193,237,76,137,252,234,72,199,198,237,
+  76,137,231,232,251,1,22,255,72,137,224,72,129,192,239,73,137,192,72,199,193,
+  237,76,137,252,234,72,199,198,237,76,137,231,232,251,1,23,255,72,137,224,
+  72,129,192,239,73,137,193,73,199,192,237,72,199,193,237,76,137,252,234,72,
+  199,198,237,76,137,231,232,251,1,24,255,72,185,237,237,139,1,72,137,199,232,
+  251,1,25,255,72,131,196,32,255,252,243,15,126,188,253,36,233,255,252,243,
+  15,126,180,253,36,233,255,252,243,15,126,172,253,36,233,255,252,243,15,126,
+  164,253,36,233,255,252,243,15,126,156,253,36,233,255,252,243,15,126,148,253,
+  36,233,255,252,243,15,126,140,253,36,233,255,252,243,15,126,132,253,36,233,
+  255,76,139,140,253,36,233,255,76,139,132,253,36,233,255,72,139,140,253,36,
+  233,255,72,139,148,253,36,233,255,72,139,180,253,36,233,255,72,139,60,36,
+  255,72,129,196,239,255,176,8,255,232,251,1,26,72,131,252,236,48,255,72,137,
+  68,36,32,232,251,1,27,72,185,237,237,137,1,72,186,237,237,72,199,198,237,
+  76,137,231,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109,252,
+  240,76,139,101,252,248,72,137,252,236,93,195,255,72,137,68,36,32,232,251,
+  1,27,72,185,237,237,137,1,72,139,68,36,32,72,137,198,76,137,231,232,251,1,
+  28,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,
+  255,72,137,68,36,32,232,251,1,27,72,185,237,237,137,1,72,186,237,237,72,199,
+  198,0,0,0,0,76,137,231,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,
+  139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,102,15,214,68,
+  36,32,232,251,1,27,72,185,237,237,137,1,72,186,237,237,72,199,198,237,76,
+  137,231,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109,252,240,
+  76,139,101,252,248,72,137,252,236,93,195,255,102,15,214,76,36,40,102,15,214,
+  68,36,32,232,251,1,27,72,185,237,237,137,1,72,186,237,237,72,199,198,237,
+  76,137,231,232,251,1,1,72,139,76,36,40,72,137,72,8,72,139,76,36,32,72,137,
+  8,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,
+  255,232,251,1,27,72,185,237,237,137,1,184,0,0,0,0,76,139,109,252,240,76,139,
+  101,252,248,72,137,252,236,93,195,255,15,182,192,137,68,36,32,232,251,1,27,
+  72,185,237,237,137,1,139,68,36,32,72,137,198,76,137,231,232,251,1,4,184,1,
+  0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,137,
+  68,36,32,232,251,1,27,72,185,237,237,137,1,139,68,36,32,72,137,198,76,137,
+  231,232,251,1,5,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,
+  252,236,93,195,255,137,68,36,32,232,251,1,27,72,185,237,237,137,1,139,68,
+  36,32,72,137,198,76,137,231,232,251,1,6,184,1,0,0,0,76,139,109,252,240,76,
+  139,101,252,248,72,137,252,236,93,195,255,252,243,15,90,192,102,15,214,68,
+  36,32,232,251,1,27,72,185,237,237,137,1,252,243,15,126,68,36,32,76,137,231,
+  232,251,1,3,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,
+  236,93,195,255
+};
+
+static const char *const globnames[] = {
+  (const char *)0
+};
+static const char *const extnames[] = {
+  "lua_rawgeti",
+  "push_cdata",
+  "lua_remove",
+  "lua_pushnumber",
+  "lua_pushboolean",
+  "push_int",
+  "push_uint",
+  "lua_callk",
+  "check_typed_pointer",
+  "lua_settop",
+  "check_enum",
+  "check_uint32",
+  "check_int32",
+  "check_uint64",
+  "check_int64",
+  "check_uintptr",
+  "check_double",
+  "check_complex_float",
+  "check_complex_double",
+  "lua_gettop",
+  "luaL_error",
+  "check_typed_cfunction",
+  "unpack_varargs_float",
+  "unpack_varargs_int",
+  "unpack_varargs_stack_skip",
+  "SetLastError",
+  "FUNCTION",
+  "GetLastError",
+  "lua_pushinteger",
+  (const char *)0
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#if defined _WIN64 || defined __amd64__
+#define JUMP_SIZE 14
+#else
+#define JUMP_SIZE 4
+#endif
+
+#define MIN_BRANCH INT32_MIN
+#define MAX_BRANCH INT32_MAX
+#define BRANCH_OFF 4
+
+static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code)
+{
+    /* The jump code is the function pointer followed by a stub to call the
+     * function pointer. The stub exists in 64 bit so we can jump to functions
+     * with an offset greater than 2 GB.
+     *
+     * Note we have to manually set this up since there are commands buffered
+     * in the jit state and dynasm doesn't support rip relative addressing.
+     *
+     * eg on 64 bit:
+     * 0-8: function ptr
+     * 8-14: jmp aword [rip-14]
+     *
+     * for 32 bit we only set the function ptr as it can always fit in a 32
+     * bit displacement
+     */
+#if defined _WIN64 || defined __amd64__
+    *(cfunction*) code = func;
+    code[8] = 0xFF; /* FF /4 operand for jmp */
+    code[9] = 0x25; /* RIP displacement */
+    *(int32_t*) &code[10] = -14;
+#else
+    *(cfunction*) code = func;
+#endif
+}
+
+void compile_globals(struct jit* jit, lua_State* L)
+{
+    struct jit* Dst = jit;
+    int* perr = &jit->last_errno;
+    dasm_setup(Dst, build_actionlist);
+
+    /* Note: since the return code uses EBP to reset the stack pointer, we
+     * don't have to track the amount of stack space used. It also means we
+     * can handle stdcall and cdecl with the same code.
+     */
+
+    /* Note the various call_* functions want 32 bytes of 16 byte aligned
+     * stack
+     */
+
+    compile(Dst, L, NULL, LUA_NOREF);
+}
+
+int x86_return_size(lua_State* L, int usr, const struct ctype* ct)
+{
+    int ret = 0;
+    const struct ctype* mt;
+
+    if (ct->calling_convention != C_CALL) {
+        size_t i;
+        size_t argn = lua_rawlen(L, usr);
+        for (i = 1; i <= argn; i++) {
+            lua_rawgeti(L, usr, (int) i);
+            mt = (const struct ctype*) lua_touserdata(L, -1);
+
+            if (mt->pointers || mt->is_reference) {
+                ret += sizeof(void*);
+            } else {
+                switch (mt->type) {
+                case DOUBLE_TYPE:
+                case COMPLEX_FLOAT_TYPE:
+                case INT64_TYPE:
+                    ret += 8;
+                    break;
+                case COMPLEX_DOUBLE_TYPE:
+                    ret += 16;
+                    break;
+                case INTPTR_TYPE:
+                    ret += sizeof(intptr_t);
+                    break;
+                case FUNCTION_PTR_TYPE:
+                    ret += sizeof(cfunction);
+                    break;
+                case BOOL_TYPE:
+                case FLOAT_TYPE:
+                case INT8_TYPE:
+                case INT16_TYPE:
+                case INT32_TYPE:
+                case ENUM_TYPE:
+                    ret += 4;
+                    break;
+                default:
+                    return luaL_error(L, "NYI - argument type");
+                }
+            }
+
+            lua_pop(L, 1);
+        }
+    }
+
+#if !defined _WIN64 && !defined __amd64__
+    lua_rawgeti(L, usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) {
+        ret += sizeof(void*);
+    }
+    lua_pop(L, 1);
+#endif
+
+    return ret;
+}
+
+#ifdef _WIN64
+#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */
+
+#elif defined __amd64__
+#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */
+#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */
+
+#else
+#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0)
+#define MAX_FLOAT_REGISTERS(ct) 0
+#endif
+
+struct reg_alloc {
+#ifdef _WIN64
+    int regs;
+    int is_float[4];
+    int is_int[4];
+#else
+    int floats;
+    int ints;
+#endif
+    int off;
+};
+
+#ifdef _WIN64
+#define REGISTER_STACK_SPACE(ct) (4*8)
+#elif defined __amd64__
+#define REGISTER_STACK_SPACE(ct) (14*8)
+#else
+#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15)
+#endif
+
+/* Fastcall:
+ * Uses ecx, edx as first two int registers
+ * Everything else on stack (include 64bit ints)
+ * No overflow stack space
+ * Pops the stack before returning
+ * Returns int in eax, float in ST0
+ * We use the same register allocation logic as posix x64 with 2 int regs and 0 float regs
+ */
+
+static void get_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_int64)
+{
+    /* grab the register from the shadow space */
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        dasm_put(Dst, 0, 16 + 8*reg->regs);
+        reg->regs++;
+    }
+#elif __amd64__
+    if (reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 0, - 80 - 8*reg->ints);
+        reg->ints++;
+    }
+#else
+    if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 1, - 8 - 4*reg->ints);
+        reg->ints++;
+    }
+#endif
+    else if (is_int64) {
+        dasm_put(Dst, 0, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 1, reg->off);
+        reg->off += 4;
+    }
+}
+
+static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_int64)
+{
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        dasm_put(Dst, 5, 32 + 8*(reg->regs));
+        reg->is_int[reg->regs++] = 1;
+    }
+#elif __amd64__
+    if (reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 5, 32 + 8*reg->ints);
+        reg->ints++;
+    }
+#else
+    if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 5, 32 + 4*reg->ints);
+        reg->ints++;
+    }
+#endif
+    else {
+#if defined _WIN64 || defined __amd64__
+        if (reg->off % 8 != 0) {
+            reg->off += 8 - (reg->off % 8);
+        }
+#endif
+        if (is_int64) {
+            dasm_put(Dst, 5, reg->off);
+            reg->off += 8;
+        } else {
+            dasm_put(Dst, 6, reg->off);
+            reg->off += 4;
+        }
+    }
+}
+
+static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double)
+{
+#if !defined _WIN64 && !defined __amd64__
+    assert(MAX_FLOAT_REGISTERS(ct) == 0);
+    if (is_double) {
+        dasm_put(Dst, 12, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 16, reg->off);
+        reg->off += 4;
+    }
+#else
+    int off;
+
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        off = -16 - 8*reg->regs;
+        reg->regs++;
+    }
+#else
+    if (reg->floats < MAX_FLOAT_REGISTERS(ct)) {
+        off = -16 - 8*reg->floats;
+        reg->floats++;
+    }
+#endif
+    else {
+        off = reg->off;
+        reg->off += is_double ? 8 : 4;
+    }
+
+    if (is_double) {
+        dasm_put(Dst, 20, off);
+    } else {
+        dasm_put(Dst, 27, off);
+    }
+#endif
+}
+
+static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double)
+{
+#if !defined _WIN64 && !defined __amd64__
+    assert(MAX_FLOAT_REGISTERS(ct) == 0);
+    if (is_double) {
+        dasm_put(Dst, 34, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 40, reg->off);
+        reg->off += 4;
+    }
+#else
+
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        if (is_double) {
+            dasm_put(Dst, 46, 32 + 8*(reg->regs));
+        } else {
+            dasm_put(Dst, 54, 32 + 8*(reg->regs));
+        }
+        reg->is_float[reg->regs++] = 1;
+    }
+#else
+    if (reg->floats < MAX_FLOAT_REGISTERS(ct)) {
+        if (is_double) {
+            dasm_put(Dst, 46, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats));
+        } else {
+            dasm_put(Dst, 54, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats));
+        }
+        reg->floats++;
+    }
+#endif
+
+    else if (is_double) {
+        dasm_put(Dst, 46, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 67, reg->off);
+        reg->off += 4;
+    }
+#endif
+}
+
+#if defined _WIN64 || defined __amd64__
+#define add_pointer(jit, ct, reg) add_int(jit, ct, reg, 1)
+#define get_pointer(jit, ct, reg) get_int(jit, ct, reg, 1)
+#else
+#define add_pointer(jit, ct, reg) add_int(jit, ct, reg, 0)
+#define get_pointer(jit, ct, reg) get_int(jit, ct, reg, 0)
+#endif
+
+cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct)
+{
+    int i, nargs;
+    cfunction* pf;
+    struct ctype ct2 = *ct;
+    const struct ctype* mt;
+    struct reg_alloc reg;
+    int num_upvals = 0;
+    int top = lua_gettop(L);
+    struct jit* Dst = get_jit(L);
+    int ref;
+    int hidden_arg_off = 0;
+
+    ct_usr = lua_absindex(L, ct_usr);
+    fidx = lua_absindex(L, fidx);
+
+    assert(lua_isnil(L, fidx) || lua_isfunction(L, fidx));
+
+    memset(&reg, 0, sizeof(reg));
+#ifdef _WIN64
+    reg.off = 16 + REGISTER_STACK_SPACE(ct); /* stack registers are above the shadow space */
+#elif __amd64__
+    reg.off = 16;
+#else
+    reg.off = 8;
+#endif
+
+    dasm_setup(Dst, build_actionlist);
+
+    // add a table to store ctype and function upvalues
+    // callback_set assumes the first value is the lua function
+    nargs = (int) lua_rawlen(L, ct_usr);
+    lua_newtable(L);
+    lua_pushvalue(L, -1);
+    ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+    if (ct->has_var_arg) {
+        luaL_error(L, "can't create callbacks with varargs");
+    }
+
+    // setup a stack frame to hold args for the call into lua_call
+
+    dasm_put(Dst, 80, 8 + 16 + 32 + REGISTER_STACK_SPACE(ct));
+    if (ct->calling_convention == FAST_CALL) {
+    }
+
+    // hardcode the lua_State* value into the assembly
+    dasm_put(Dst, 157, (unsigned int)((uintptr_t)(L)), (unsigned int)(((uintptr_t)(L))>>32));
+
+    /* get the upval table */
+    dasm_put(Dst, 162, ref, LUA_REGISTRYINDEX);
+
+    /* get the lua function */
+    lua_pushvalue(L, fidx);
+    lua_rawseti(L, -2, ++num_upvals);
+    assert(num_upvals == CALLBACK_FUNC_USR_IDX);
+    dasm_put(Dst, 178, num_upvals);
+
+#if !defined _WIN64 && !defined __amd64__
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) {
+        hidden_arg_off = reg.off;
+        reg.off += sizeof(void*);
+    }
+    lua_pop(L, 1);
+#else
+    (void) hidden_arg_off;
+#endif
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, i);
+        mt = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mt->pointers || mt->is_reference) {
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+            /* on the lua stack in the callback:
+             * upval tbl, lua func, i-1 args
+             */
+            dasm_put(Dst, 201, num_upvals-1, -i-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+            get_pointer(Dst, ct, &reg);
+            dasm_put(Dst, 239);
+        } else {
+            switch (mt->type) {
+            case INT64_TYPE:
+                lua_getuservalue(L, -1);
+                lua_rawseti(L, -3, ++num_upvals); /* mt */
+                lua_pop(L, 1);
+                dasm_put(Dst, 261, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+                get_int(Dst, ct, &reg, 1);
+                dasm_put(Dst, 280);
+                break;
+
+            case INTPTR_TYPE:
+                lua_getuservalue(L, -1);
+                lua_rawseti(L, -3, ++num_upvals); /* mt */
+                lua_pop(L, 1);
+                dasm_put(Dst, 261, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+                get_pointer(Dst, ct, &reg);
+                dasm_put(Dst, 280);
+                break;
+
+            case COMPLEX_FLOAT_TYPE:
+                lua_pop(L, 1);
+#if defined _WIN64 || defined __amd64__
+                /* complex floats are two floats packed into a double */
+                dasm_put(Dst, 261, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+                get_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 284);
+#else
+                /* complex floats are real followed by imag on the stack */
+                dasm_put(Dst, 261, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+                get_float(Dst, ct, &reg, 0);
+                dasm_put(Dst, 289);
+                get_float(Dst, ct, &reg, 0);
+                dasm_put(Dst, 292);
+#endif
+                break;
+
+            case COMPLEX_DOUBLE_TYPE:
+                lua_pop(L, 1);
+                dasm_put(Dst, 261, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+                /* real */
+                get_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 284);
+                /* imag */
+                get_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 296);
+                break;
+
+            case FLOAT_TYPE:
+            case DOUBLE_TYPE:
+                lua_pop(L, 1);
+                get_float(Dst, ct, &reg, mt->type == DOUBLE_TYPE);
+                dasm_put(Dst, 302);
+                break;
+
+            case BOOL_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                dasm_put(Dst, 310);
+                break;
+
+            case INT8_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 324);
+                } else {
+                    dasm_put(Dst, 328);
+                }
+                dasm_put(Dst, 332);
+                break;
+
+            case INT16_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 343);
+                } else {
+                    dasm_put(Dst, 347);
+                }
+                dasm_put(Dst, 332);
+                break;
+
+            case ENUM_TYPE:
+            case INT32_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 351);
+                } else {
+                    dasm_put(Dst, 332);
+                }
+                break;
+
+            default:
+                luaL_error(L, "NYI: callback arg type");
+            }
+        }
+    }
+
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+
+    dasm_put(Dst, 362, (unsigned int)((uintptr_t)(0)), (unsigned int)(((uintptr_t)(0))>>32), (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, nargs);
+
+    // Unpack the return argument if not "void", also clean-up the lua stack
+    // to remove the return argument and bind table. Use lua_settop rather
+    // than lua_pop as lua_pop is implemented as a macro.
+    if (mt->pointers || mt->is_reference) {
+        lua_getuservalue(L, -1);
+        lua_rawseti(L, -3, ++num_upvals); /* usr value */
+        lua_rawseti(L, -2, ++num_upvals); /* mt */
+        dasm_put(Dst, 382, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+
+    } else {
+        switch (mt->type) {
+        case ENUM_TYPE:
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+            dasm_put(Dst, 466, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+            break;
+
+        case VOID_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 548);
+            break;
+
+        case BOOL_TYPE:
+        case INT8_TYPE:
+        case INT16_TYPE:
+        case INT32_TYPE:
+            lua_pop(L, 1);
+            if (mt->is_unsigned) {
+                dasm_put(Dst, 567);
+            } else {
+                dasm_put(Dst, 586);
+            }
+            dasm_put(Dst, 605);
+            break;
+
+        case INT64_TYPE:
+            lua_pop(L, 1);
+
+            if (mt->is_unsigned) {
+                dasm_put(Dst, 632);
+            } else {
+                dasm_put(Dst, 651);
+            }
+
+            dasm_put(Dst, 670);
+            break;
+
+        case INTPTR_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 699);
+            break;
+
+        case FLOAT_TYPE:
+        case DOUBLE_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 746);
+            if (mt->type == FLOAT_TYPE) {
+                dasm_put(Dst, 789);
+            } else {
+                dasm_put(Dst, 797);
+            }
+            break;
+
+        case COMPLEX_FLOAT_TYPE:
+            lua_pop(L, 1);
+#if !defined HAVE_COMPLEX
+            luaL_error(L, "ffi lib compiled without complex number support");
+#endif
+            /* on 64 bit complex floats are two floats packed into a double,
+             * on 32 bit returned complex floats use eax and edx */
+            dasm_put(Dst, 805);
+            break;
+
+        case COMPLEX_DOUBLE_TYPE:
+            lua_pop(L, 1);
+#if !defined HAVE_COMPLEX
+            luaL_error(L, "ffi lib compiled without complex number support");
+#endif
+            /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit
+             * there is a hidden first parameter that points to 16 bytes where
+             * the returned arg is stored which is popped by the called
+             * function */
+#if defined _WIN64 || defined __amd64__
+            dasm_put(Dst, 855);
+#else
+            dasm_put(Dst, 918, hidden_arg_off);
+#endif
+            break;
+
+        default:
+            luaL_error(L, "NYI: callback return type");
+        }
+    }
+
+    dasm_put(Dst, 967, x86_return_size(L, ct_usr, ct));
+
+    lua_pop(L, 1); /* upval table - already in registry */
+    assert(lua_gettop(L) == top);
+
+    ct2.is_jitted = 1;
+    pf = (cfunction*) push_cdata(L, ct_usr, &ct2);
+    *pf = compile(Dst, L, NULL, ref);
+
+    assert(lua_gettop(L) == top + 1);
+
+    return *pf;
+}
+
+void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct)
+{
+    size_t i, nargs;
+    int num_upvals;
+    const struct ctype* mbr_ct;
+    struct jit* Dst = get_jit(L);
+    struct reg_alloc reg;
+    void* p;
+    int top = lua_gettop(L);
+    int* perr = &Dst->last_errno;
+
+    ct_usr = lua_absindex(L, ct_usr);
+
+    memset(&reg, 0, sizeof(reg));
+    reg.off = 32 + REGISTER_STACK_SPACE(ct);
+
+    dasm_setup(Dst, build_actionlist);
+
+    p = push_cdata(L, ct_usr, ct);
+    *(cfunction*) p = func;
+    num_upvals = 1;
+
+    nargs = lua_rawlen(L, ct_usr);
+
+    if (ct->calling_convention != C_CALL && ct->has_var_arg) {
+        luaL_error(L, "vararg is only allowed with the c calling convention");
+    }
+
+    dasm_put(Dst, 980, nargs);
+    if (!ct->has_var_arg) {
+        dasm_put(Dst, 1008, (unsigned int)((uintptr_t)(&"too few arguments")), (unsigned int)(((uintptr_t)(&"too few arguments"))>>32), (unsigned int)((uintptr_t)(&"too many arguments")), (unsigned int)(((uintptr_t)(&"too many arguments"))>>32));
+    } else {
+        dasm_put(Dst, 1049, (unsigned int)((uintptr_t)(&"too few arguments")), (unsigned int)(((uintptr_t)(&"too few arguments"))>>32));
+    }
+
+    dasm_put(Dst, 1069);
+
+    /* no need to zero extend eax returned by lua_gettop to rax as x86-64
+     * preguarentees that the upper 32 bits will be zero */
+    dasm_put(Dst, 1072, 32 + REGISTER_STACK_SPACE(ct));
+
+#if !defined _WIN64 && !defined __amd64__
+    /* Returned complex doubles require a hidden first parameter where the
+     * data is stored, which is popped by the calling code. */
+    lua_rawgeti(L, ct_usr, 0);
+    mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mbr_ct->pointers && !mbr_ct->is_reference && mbr_ct->type == COMPLEX_DOUBLE_TYPE) {
+        /* we can allocate more space for arguments as long as no add_*
+         * function has been called yet, mbr_ct will be added as an upvalue in
+         * the return processing later */
+        dasm_put(Dst, 1085, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32));
+        add_pointer(Dst, ct, &reg);
+    }
+    lua_pop(L, 1);
+#endif
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, (int) i);
+        mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mbr_ct->pointers || mbr_ct->is_reference) {
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1109, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i);
+            add_pointer(Dst, ct, &reg);
+        } else {
+            switch (mbr_ct->type) {
+            case FUNCTION_PTR_TYPE:
+                lua_getuservalue(L, -1);
+                num_upvals += 2;
+                dasm_put(Dst, 1129, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i);
+                add_pointer(Dst, ct, &reg);
+                break;
+
+            case ENUM_TYPE:
+                lua_getuservalue(L, -1);
+                num_upvals += 2;
+                dasm_put(Dst, 1149, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i);
+                add_int(Dst, ct, &reg, 0);
+                break;
+
+            case INT8_TYPE:
+                dasm_put(Dst, 1169, i);
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1181);
+                } else {
+                    dasm_put(Dst, 1185);
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INT16_TYPE:
+                dasm_put(Dst, 1169, i);
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1189);
+                } else {
+                    dasm_put(Dst, 1193);
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case BOOL_TYPE:
+                dasm_put(Dst, 1197, i);
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INT32_TYPE:
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1219, i);
+                } else {
+                    dasm_put(Dst, 1169, i);
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INTPTR_TYPE:
+                dasm_put(Dst, 1231, i);
+                add_pointer(Dst, ct, &reg);
+                lua_pop(L, 1);
+                break;
+
+            case INT64_TYPE:
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1243, i);
+                } else {
+                    dasm_put(Dst, 1255, i);
+                }
+                add_int(Dst, ct, &reg, 1);
+                lua_pop(L, 1);
+                break;
+
+            case DOUBLE_TYPE:
+                dasm_put(Dst, 1267, i);
+                add_float(Dst, ct, &reg, 1);
+                lua_pop(L, 1);
+                break;
+
+            case COMPLEX_DOUBLE_TYPE:
+                /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit
+                 * there is a hidden first parameter that points to 16 bytes where
+                 * the returned arg is stored (this is popped by the called
+                 * function) */
+#if defined _WIN64 || defined __amd64__
+                dasm_put(Dst, 1279, i);
+                add_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 1291);
+                add_float(Dst, ct, &reg, 1);
+#else
+                dasm_put(Dst, 1297, reg.off, i);
+                reg.off += 16;
+#endif
+                lua_pop(L, 1);
+                break;
+
+            case FLOAT_TYPE:
+                dasm_put(Dst, 1267, i);
+                add_float(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case COMPLEX_FLOAT_TYPE:
+#if defined _WIN64 || defined __amd64__
+                dasm_put(Dst, 1323, i);
+                /* complex floats are two floats packed into a double */
+                add_float(Dst, ct, &reg, 1);
+#else
+                /* returned complex floats use eax and edx */
+                dasm_put(Dst, 1335, i);
+                add_float(Dst, ct, &reg, 0);
+                dasm_put(Dst, 1353);
+                add_float(Dst, ct, &reg, 0);
+#endif
+                lua_pop(L, 1);
+                break;
+
+            default:
+                luaL_error(L, "NYI: call arg type");
+            }
+        }
+    }
+
+    if (ct->has_var_arg) {
+#ifdef _WIN64
+        if (reg.regs < MAX_REGISTERS(ct)) {
+            assert(reg.regs == nargs);
+        } else {
+        }
+
+        for (i = nargs; i < MAX_REGISTERS(ct); i++) {
+            reg.is_int[i] = reg.is_float[i] = 1;
+        }
+        reg.regs = MAX_REGISTERS(ct);
+#elif defined __amd64__
+        if (reg.floats < MAX_FLOAT_REGISTERS(ct)) {
+            dasm_put(Dst, 1360, 32 + 8*(MAX_INT_REGISTERS(ct) + reg.floats), MAX_FLOAT_REGISTERS(ct) - reg.floats, nargs+1);
+        }
+
+        if (reg.ints < MAX_INT_REGISTERS(ct)) {
+            dasm_put(Dst, 1390, 32 + 8*(reg.ints), MAX_INT_REGISTERS(ct) - reg.ints, nargs+1);
+        }
+
+        dasm_put(Dst, 1420, reg.off, MAX_FLOAT_REGISTERS(ct) - reg.floats, MAX_INT_REGISTERS(ct) - reg.ints, nargs+1);
+
+        reg.floats = MAX_FLOAT_REGISTERS(ct);
+        reg.ints = MAX_INT_REGISTERS(ct);
+#else
+#endif
+    }
+
+    dasm_put(Dst, 1454, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+
+    /* remove the stack space to call local functions */
+    dasm_put(Dst, 1468);
+
+#ifdef _WIN64
+    switch (reg.regs) {
+    case 4:
+        if (reg.is_float[3]) {
+        }
+        if (reg.is_int[3]) {
+        }
+    case 3:
+        if (reg.is_float[2]) {
+        }
+        if (reg.is_int[2]) {
+        }
+    case 2:
+        if (reg.is_float[1]) {
+        }
+        if (reg.is_int[1]) {
+        }
+    case 1:
+        if (reg.is_float[0]) {
+        }
+        if (reg.is_int[0]) {
+        }
+    case 0:
+        break;
+    }
+
+    /* don't remove the space for the registers as we need 32 bytes of register overflow space */
+    assert(REGISTER_STACK_SPACE(ct) == 32);
+
+#elif defined __amd64__
+    switch (reg.floats) {
+    case 8:
+        dasm_put(Dst, 1473, 8*(MAX_INT_REGISTERS(ct)+7));
+    case 7:
+        dasm_put(Dst, 1482, 8*(MAX_INT_REGISTERS(ct)+6));
+    case 6:
+        dasm_put(Dst, 1491, 8*(MAX_INT_REGISTERS(ct)+5));
+    case 5:
+        dasm_put(Dst, 1500, 8*(MAX_INT_REGISTERS(ct)+4));
+    case 4:
+        dasm_put(Dst, 1509, 8*(MAX_INT_REGISTERS(ct)+3));
+    case 3:
+        dasm_put(Dst, 1518, 8*(MAX_INT_REGISTERS(ct)+2));
+    case 2:
+        dasm_put(Dst, 1527, 8*(MAX_INT_REGISTERS(ct)+1));
+    case 1:
+        dasm_put(Dst, 1536, 8*(MAX_INT_REGISTERS(ct)));
+    case 0:
+        break;
+    }
+
+    switch (reg.ints) {
+    case 6:
+        dasm_put(Dst, 1545, 8*5);
+    case 5:
+        dasm_put(Dst, 1552, 8*4);
+    case 4:
+        dasm_put(Dst, 1559, 8*3);
+    case 3:
+        dasm_put(Dst, 1566, 8*2);
+    case 2:
+        dasm_put(Dst, 1573, 8*1);
+    case 1:
+        dasm_put(Dst, 1580);
+    case 0:
+        break;
+    }
+
+    dasm_put(Dst, 1585, REGISTER_STACK_SPACE(ct));
+#else
+    if (ct->calling_convention == FAST_CALL) {
+        switch (reg.ints) {
+        case 2:
+        case 1:
+        case 0:
+            break;
+        }
+
+    }
+#endif
+
+#ifdef __amd64__
+    if (ct->has_var_arg) {
+        /* al stores an upper limit on the number of float register, note that
+         * its allowed to be more than the actual number of float registers used as
+         * long as its 0-8 */
+        dasm_put(Dst, 1590);
+    }
+#endif
+
+    dasm_put(Dst, 1593);
+
+    /* note on windows X86 the stack may be only aligned to 4 (stdcall will
+     * have popped a multiple of 4 bytes), but we don't need 16 byte alignment on
+     * that platform
+     */
+
+    lua_rawgeti(L, ct_usr, 0);
+    mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+
+    if (mbr_ct->pointers || mbr_ct->is_reference || mbr_ct->type == INTPTR_TYPE) {
+        lua_getuservalue(L, -1);
+        num_upvals += 2;
+        dasm_put(Dst, 1603, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals));
+
+    } else {
+        switch (mbr_ct->type) {
+        case FUNCTION_PTR_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1603, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals));
+            break;
+
+        case INT64_TYPE:
+#if LUA_VERSION_NUM == 503
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1663, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            } else {
+                dasm_put(Dst, 1663, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            }
+#else
+            num_upvals++;
+            dasm_put(Dst, 1715, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32));
+#endif
+            break;
+
+        case COMPLEX_FLOAT_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1778, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals));
+            break;
+
+        case COMPLEX_DOUBLE_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1839, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals));
+            break;
+
+        case VOID_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 1915, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        case BOOL_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 1947, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        case INT8_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1181);
+            } else {
+                dasm_put(Dst, 1185);
+            }
+            dasm_put(Dst, 2000, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        case INT16_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1189);
+            } else {
+                dasm_put(Dst, 1193);
+            }
+            dasm_put(Dst, 2000, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        case INT32_TYPE:
+        case ENUM_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 2050, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            } else {
+                dasm_put(Dst, 2000, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            }
+            break;
+
+        case FLOAT_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 2100, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        case DOUBLE_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 2105, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        default:
+            luaL_error(L, "NYI: call return type");
+        }
+    }
+
+    assert(lua_gettop(L) == top + num_upvals);
+    {
+        cfunction f = compile(Dst, L, func, LUA_NOREF);
+        /* add a callback as an upval so that the jitted code gets cleaned up when
+         * the function gets gc'd */
+        push_callback(L, f, func);
+        lua_pushcclosure(L, (lua_CFunction) f, num_upvals+1);
+    }
+}
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x64.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x64win.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x64win.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x64win.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,1191 @@
+/*
+** This file has been pre-processed with DynASM.
+** http://luajit.org/dynasm.html
+** DynASM version 1.3.0, DynASM x64 version 1.3.0
+** DO NOT EDIT! The original file is in "call_x86.dasc".
+*/
+
+#if DASM_VERSION != 10300
+#error "Version mismatch between DynASM and included encoding engine"
+#endif
+
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+static const unsigned char build_actionlist[2100] = {
+  72,139,141,233,255,72,137,132,253,36,233,255,221,133,233,255,217,133,233,
+  255,252,243,15,126,133,233,255,252,243,15,90,133,233,255,221,156,253,36,233,
+  255,217,156,253,36,233,255,102,15,214,132,253,36,233,255,252,242,15,90,192,
+  102,15,214,132,253,36,233,255,252,242,15,90,192,102,15,126,132,253,36,233,
+  255,85,72,137,229,65,84,72,129,252,236,239,72,137,77,16,72,137,85,24,76,137,
+  69,32,76,137,77,40,102,15,214,69,252,240,102,15,214,77,232,102,15,214,85,
+  224,102,15,214,93,216,255,73,188,237,237,255,73,199,192,237,72,199,194,237,
+  76,137,225,232,251,1,0,255,73,199,192,237,72,199,194,252,255,252,255,252,
+  255,252,255,76,137,225,232,251,1,0,255,73,199,192,237,72,199,194,237,76,137,
+  225,232,251,1,0,73,184,237,237,72,199,194,252,255,252,255,252,255,252,255,
+  76,137,225,232,251,1,1,255,72,137,8,72,199,194,252,254,252,255,252,255,252,
+  255,76,137,225,232,251,1,2,255,73,184,237,237,72,199,194,0,0,0,0,76,137,225,
+  232,251,1,1,255,72,137,8,255,102,15,214,0,255,217,24,255,217,88,4,255,102,
+  15,214,64,8,255,252,243,15,126,200,76,137,225,232,251,1,3,255,15,182,201,
+  72,137,202,76,137,225,232,251,1,4,255,15,182,201,255,15,190,201,255,72,137,
+  202,76,137,225,232,251,1,5,255,15,183,201,255,15,191,201,255,72,137,202,76,
+  137,225,232,251,1,6,255,73,185,237,237,73,199,192,237,72,199,194,237,76,137,
+  225,232,251,1,7,255,73,199,192,237,72,199,194,252,254,252,255,252,255,252,
+  255,76,137,225,232,251,1,0,73,185,237,237,73,199,192,252,255,252,255,252,
+  255,252,255,72,199,194,252,254,252,255,252,255,252,255,76,137,225,232,251,
+  1,8,72,137,68,36,32,72,199,194,252,252,252,255,252,255,252,255,76,137,225,
+  232,251,1,9,72,139,68,36,32,255,73,199,192,237,72,199,194,252,254,252,255,
+  252,255,252,255,76,137,225,232,251,1,0,73,185,237,237,73,199,192,252,255,
+  252,255,252,255,252,255,72,199,194,252,254,252,255,252,255,252,255,76,137,
+  225,232,251,1,10,137,68,36,32,72,199,194,252,252,252,255,252,255,252,255,
+  76,137,225,232,251,1,9,139,68,36,32,255,72,199,194,252,254,252,255,252,255,
+  252,255,76,137,225,232,251,1,9,255,72,199,194,252,255,252,255,252,255,252,
+  255,76,137,225,232,251,1,11,255,72,199,194,252,255,252,255,252,255,252,255,
+  76,137,225,232,251,1,12,255,137,68,36,32,72,199,194,252,253,252,255,252,255,
+  252,255,76,137,225,232,251,1,9,139,68,36,32,255,72,199,194,252,255,252,255,
+  252,255,252,255,76,137,225,232,251,1,13,255,72,199,194,252,255,252,255,252,
+  255,252,255,76,137,225,232,251,1,14,255,72,137,68,36,32,72,199,194,252,253,
+  252,255,252,255,252,255,76,137,225,232,251,1,9,72,139,68,36,32,255,72,199,
+  194,252,255,252,255,252,255,252,255,76,137,225,232,251,1,15,72,137,68,36,
+  32,72,199,194,252,253,252,255,252,255,252,255,76,137,225,232,251,1,9,72,139,
+  68,36,32,255,72,199,194,252,255,252,255,252,255,252,255,76,137,225,232,251,
+  1,16,102,15,214,68,36,32,72,199,194,252,253,252,255,252,255,252,255,76,137,
+  225,232,251,1,9,255,252,242,15,90,68,36,32,255,252,243,15,126,68,36,32,255,
+  72,199,194,252,255,252,255,252,255,252,255,76,137,225,232,251,1,17,102,15,
+  214,68,36,32,72,199,194,252,253,252,255,252,255,252,255,76,137,225,232,251,
+  1,9,252,243,15,126,68,36,32,255,72,199,194,252,255,252,255,252,255,252,255,
+  76,137,225,232,251,1,18,102,15,214,68,36,32,102,15,214,76,36,40,72,199,194,
+  252,253,252,255,252,255,252,255,76,137,225,232,251,1,9,252,243,15,126,68,
+  36,32,252,243,15,126,76,36,40,255,72,139,141,233,73,199,192,252,255,252,255,
+  252,255,252,255,76,137,226,72,137,201,232,251,1,18,72,131,252,236,4,72,199,
+  194,252,253,252,255,252,255,252,255,76,137,225,232,251,1,9,255,76,139,101,
+  252,248,72,137,252,236,93,194,236,255,85,72,137,229,65,84,65,85,73,137,204,
+  72,131,252,236,32,76,137,225,232,251,1,19,73,137,197,72,129,252,248,239,255,
+  15,141,244,248,102,184,0,0,72,186,237,237,76,137,225,232,251,1,20,248,2,15,
+  142,244,247,102,184,0,0,72,186,237,237,76,137,225,232,251,1,20,255,15,141,
+  244,247,102,184,0,0,72,186,237,237,76,137,225,232,251,1,20,255,248,1,255,
+  72,193,224,4,72,41,196,72,129,252,236,239,255,73,184,237,237,72,199,194,0,
+  0,0,0,76,137,225,232,251,1,1,72,131,252,236,16,255,73,185,237,237,73,199,
+  192,237,72,199,194,237,76,137,225,232,251,1,8,255,73,185,237,237,73,199,192,
+  237,72,199,194,237,76,137,225,232,251,1,21,255,73,185,237,237,73,199,192,
+  237,72,199,194,237,76,137,225,232,251,1,10,255,72,199,194,237,76,137,225,
+  232,251,1,12,255,15,182,192,255,15,190,192,255,15,183,192,255,15,191,192,
+  255,72,199,194,237,76,137,225,232,251,1,12,131,252,248,0,15,149,208,15,182,
+  192,255,72,199,194,237,76,137,225,232,251,1,11,255,72,199,194,237,76,137,
+  225,232,251,1,15,255,72,199,194,237,76,137,225,232,251,1,13,255,72,199,194,
+  237,76,137,225,232,251,1,14,255,72,199,194,237,76,137,225,232,251,1,16,255,
+  72,199,194,237,76,137,225,232,251,1,18,255,252,243,15,126,193,255,72,141,
+  132,253,36,233,72,131,252,236,4,73,199,192,237,76,137,226,72,137,193,232,
+  251,1,18,255,72,199,194,237,76,137,225,232,251,1,17,255,72,199,194,237,76,
+  137,225,232,251,1,17,137,4,36,217,4,36,255,137,20,36,217,4,36,255,73,129,
+  252,253,239,15,142,244,247,72,137,224,72,129,192,239,73,137,193,77,137,232,
+  72,199,194,237,76,137,225,232,251,1,22,72,137,224,72,129,192,239,73,137,193,
+  73,199,192,237,72,199,194,237,76,137,225,232,251,1,23,252,233,244,248,248,
+  1,72,137,224,72,129,192,239,73,137,193,77,137,232,72,199,194,237,76,137,225,
+  232,251,1,23,248,2,255,72,137,224,72,129,192,239,73,137,193,77,137,232,72,
+  199,194,237,76,137,225,232,251,1,22,255,72,185,237,237,139,1,72,137,193,232,
+  251,1,24,255,72,131,196,32,255,252,243,15,126,156,253,36,233,255,76,139,140,
+  253,36,233,255,252,243,15,126,148,253,36,233,255,76,139,132,253,36,233,255,
+  252,243,15,126,140,253,36,233,255,72,139,148,253,36,233,255,252,243,15,126,
+  4,36,255,72,139,12,36,255,232,251,1,25,72,131,252,236,48,255,72,137,68,36,
+  32,232,251,1,26,72,185,237,237,137,1,73,184,237,237,72,199,194,237,76,137,
+  225,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109,252,240,76,
+  139,101,252,248,72,137,252,236,93,195,255,72,137,68,36,32,232,251,1,26,72,
+  185,237,237,137,1,72,139,68,36,32,72,137,194,76,137,225,232,251,1,27,184,
+  1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,72,
+  137,68,36,32,232,251,1,26,72,185,237,237,137,1,73,184,237,237,72,199,194,
+  0,0,0,0,76,137,225,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,
+  109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,102,15,214,68,36,
+  32,232,251,1,26,72,185,237,237,137,1,73,184,237,237,72,199,194,237,76,137,
+  225,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109,252,240,76,
+  139,101,252,248,72,137,252,236,93,195,255,102,15,214,76,36,40,102,15,214,
+  68,36,32,232,251,1,26,72,185,237,237,137,1,73,184,237,237,72,199,194,237,
+  76,137,225,232,251,1,1,72,139,76,36,40,72,137,72,8,72,139,76,36,32,72,137,
+  8,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,
+  255,232,251,1,26,72,185,237,237,137,1,184,0,0,0,0,76,139,109,252,240,76,139,
+  101,252,248,72,137,252,236,93,195,255,15,182,192,137,68,36,32,232,251,1,26,
+  72,185,237,237,137,1,139,68,36,32,72,137,194,76,137,225,232,251,1,4,184,1,
+  0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,137,
+  68,36,32,232,251,1,26,72,185,237,237,137,1,139,68,36,32,72,137,194,76,137,
+  225,232,251,1,5,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,
+  252,236,93,195,255,137,68,36,32,232,251,1,26,72,185,237,237,137,1,139,68,
+  36,32,72,137,194,76,137,225,232,251,1,6,184,1,0,0,0,76,139,109,252,240,76,
+  139,101,252,248,72,137,252,236,93,195,255,252,243,15,90,192,102,15,214,68,
+  36,32,232,251,1,26,72,185,237,237,137,1,252,243,15,126,76,36,32,76,137,225,
+  232,251,1,3,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,
+  236,93,195,255
+};
+
+static const char *const globnames[] = {
+  (const char *)0
+};
+static const char *const extnames[] = {
+  "lua_rawgeti",
+  "push_cdata",
+  "lua_remove",
+  "lua_pushnumber",
+  "lua_pushboolean",
+  "push_int",
+  "push_uint",
+  "lua_callk",
+  "check_typed_pointer",
+  "lua_settop",
+  "check_enum",
+  "check_uint32",
+  "check_int32",
+  "check_uint64",
+  "check_int64",
+  "check_uintptr",
+  "check_double",
+  "check_complex_float",
+  "check_complex_double",
+  "lua_gettop",
+  "luaL_error",
+  "check_typed_cfunction",
+  "unpack_varargs_stack",
+  "unpack_varargs_reg",
+  "SetLastError",
+  "FUNCTION",
+  "GetLastError",
+  "lua_pushinteger",
+  (const char *)0
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#if defined _WIN64 || defined __amd64__
+#define JUMP_SIZE 14
+#else
+#define JUMP_SIZE 4
+#endif
+
+#define MIN_BRANCH INT32_MIN
+#define MAX_BRANCH INT32_MAX
+#define BRANCH_OFF 4
+
+static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code)
+{
+    /* The jump code is the function pointer followed by a stub to call the
+     * function pointer. The stub exists in 64 bit so we can jump to functions
+     * with an offset greater than 2 GB.
+     *
+     * Note we have to manually set this up since there are commands buffered
+     * in the jit state and dynasm doesn't support rip relative addressing.
+     *
+     * eg on 64 bit:
+     * 0-8: function ptr
+     * 8-14: jmp aword [rip-14]
+     *
+     * for 32 bit we only set the function ptr as it can always fit in a 32
+     * bit displacement
+     */
+#if defined _WIN64 || defined __amd64__
+    *(cfunction*) code = func;
+    code[8] = 0xFF; /* FF /4 operand for jmp */
+    code[9] = 0x25; /* RIP displacement */
+    *(int32_t*) &code[10] = -14;
+#else
+    *(cfunction*) code = func;
+#endif
+}
+
+void compile_globals(struct jit* jit, lua_State* L)
+{
+    struct jit* Dst = jit;
+    int* perr = &jit->last_errno;
+    dasm_setup(Dst, build_actionlist);
+
+    /* Note: since the return code uses EBP to reset the stack pointer, we
+     * don't have to track the amount of stack space used. It also means we
+     * can handle stdcall and cdecl with the same code.
+     */
+
+    /* Note the various call_* functions want 32 bytes of 16 byte aligned
+     * stack
+     */
+
+    compile(Dst, L, NULL, LUA_NOREF);
+}
+
+int x86_return_size(lua_State* L, int usr, const struct ctype* ct)
+{
+    int ret = 0;
+    const struct ctype* mt;
+
+    if (ct->calling_convention != C_CALL) {
+        size_t i;
+        size_t argn = lua_rawlen(L, usr);
+        for (i = 1; i <= argn; i++) {
+            lua_rawgeti(L, usr, (int) i);
+            mt = (const struct ctype*) lua_touserdata(L, -1);
+
+            if (mt->pointers || mt->is_reference) {
+                ret += sizeof(void*);
+            } else {
+                switch (mt->type) {
+                case DOUBLE_TYPE:
+                case COMPLEX_FLOAT_TYPE:
+                case INT64_TYPE:
+                    ret += 8;
+                    break;
+                case COMPLEX_DOUBLE_TYPE:
+                    ret += 16;
+                    break;
+                case INTPTR_TYPE:
+                    ret += sizeof(intptr_t);
+                    break;
+                case FUNCTION_PTR_TYPE:
+                    ret += sizeof(cfunction);
+                    break;
+                case BOOL_TYPE:
+                case FLOAT_TYPE:
+                case INT8_TYPE:
+                case INT16_TYPE:
+                case INT32_TYPE:
+                case ENUM_TYPE:
+                    ret += 4;
+                    break;
+                default:
+                    return luaL_error(L, "NYI - argument type");
+                }
+            }
+
+            lua_pop(L, 1);
+        }
+    }
+
+#if !defined _WIN64 && !defined __amd64__
+    lua_rawgeti(L, usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) {
+        ret += sizeof(void*);
+    }
+    lua_pop(L, 1);
+#endif
+
+    return ret;
+}
+
+#ifdef _WIN64
+#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */
+
+#elif defined __amd64__
+#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */
+#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */
+
+#else
+#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0)
+#define MAX_FLOAT_REGISTERS(ct) 0
+#endif
+
+struct reg_alloc {
+#ifdef _WIN64
+    int regs;
+    int is_float[4];
+    int is_int[4];
+#else
+    int floats;
+    int ints;
+#endif
+    int off;
+};
+
+#ifdef _WIN64
+#define REGISTER_STACK_SPACE(ct) (4*8)
+#elif defined __amd64__
+#define REGISTER_STACK_SPACE(ct) (14*8)
+#else
+#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15)
+#endif
+
+/* Fastcall:
+ * Uses ecx, edx as first two int registers
+ * Everything else on stack (include 64bit ints)
+ * No overflow stack space
+ * Pops the stack before returning
+ * Returns int in eax, float in ST0
+ * We use the same register allocation logic as posix x64 with 2 int regs and 0 float regs
+ */
+
+static void get_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_int64)
+{
+    /* grab the register from the shadow space */
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        dasm_put(Dst, 0, 16 + 8*reg->regs);
+        reg->regs++;
+    }
+#elif __amd64__
+    if (reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 0, - 80 - 8*reg->ints);
+        reg->ints++;
+    }
+#else
+    if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 1, - 8 - 4*reg->ints);
+        reg->ints++;
+    }
+#endif
+    else if (is_int64) {
+        dasm_put(Dst, 0, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 1, reg->off);
+        reg->off += 4;
+    }
+}
+
+static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_int64)
+{
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        dasm_put(Dst, 5, 32 + 8*(reg->regs));
+        reg->is_int[reg->regs++] = 1;
+    }
+#elif __amd64__
+    if (reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 5, 32 + 8*reg->ints);
+        reg->ints++;
+    }
+#else
+    if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 5, 32 + 4*reg->ints);
+        reg->ints++;
+    }
+#endif
+    else {
+#if defined _WIN64 || defined __amd64__
+        if (reg->off % 8 != 0) {
+            reg->off += 8 - (reg->off % 8);
+        }
+#endif
+        if (is_int64) {
+            dasm_put(Dst, 5, reg->off);
+            reg->off += 8;
+        } else {
+            dasm_put(Dst, 6, reg->off);
+            reg->off += 4;
+        }
+    }
+}
+
+static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double)
+{
+#if !defined _WIN64 && !defined __amd64__
+    assert(MAX_FLOAT_REGISTERS(ct) == 0);
+    if (is_double) {
+        dasm_put(Dst, 12, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 16, reg->off);
+        reg->off += 4;
+    }
+#else
+    int off;
+
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        off = -16 - 8*reg->regs;
+        reg->regs++;
+    }
+#else
+    if (reg->floats < MAX_FLOAT_REGISTERS(ct)) {
+        off = -16 - 8*reg->floats;
+        reg->floats++;
+    }
+#endif
+    else {
+        off = reg->off;
+        reg->off += is_double ? 8 : 4;
+    }
+
+    if (is_double) {
+        dasm_put(Dst, 20, off);
+    } else {
+        dasm_put(Dst, 27, off);
+    }
+#endif
+}
+
+static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double)
+{
+#if !defined _WIN64 && !defined __amd64__
+    assert(MAX_FLOAT_REGISTERS(ct) == 0);
+    if (is_double) {
+        dasm_put(Dst, 34, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 40, reg->off);
+        reg->off += 4;
+    }
+#else
+
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        if (is_double) {
+            dasm_put(Dst, 46, 32 + 8*(reg->regs));
+        } else {
+            dasm_put(Dst, 54, 32 + 8*(reg->regs));
+        }
+        reg->is_float[reg->regs++] = 1;
+    }
+#else
+    if (reg->floats < MAX_FLOAT_REGISTERS(ct)) {
+        if (is_double) {
+            dasm_put(Dst, 46, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats));
+        } else {
+            dasm_put(Dst, 54, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats));
+        }
+        reg->floats++;
+    }
+#endif
+
+    else if (is_double) {
+        dasm_put(Dst, 46, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 67, reg->off);
+        reg->off += 4;
+    }
+#endif
+}
+
+#if defined _WIN64 || defined __amd64__
+#define add_pointer(jit, ct, reg) add_int(jit, ct, reg, 1)
+#define get_pointer(jit, ct, reg) get_int(jit, ct, reg, 1)
+#else
+#define add_pointer(jit, ct, reg) add_int(jit, ct, reg, 0)
+#define get_pointer(jit, ct, reg) get_int(jit, ct, reg, 0)
+#endif
+
+cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct)
+{
+    int i, nargs;
+    cfunction* pf;
+    struct ctype ct2 = *ct;
+    const struct ctype* mt;
+    struct reg_alloc reg;
+    int num_upvals = 0;
+    int top = lua_gettop(L);
+    struct jit* Dst = get_jit(L);
+    int ref;
+    int hidden_arg_off = 0;
+
+    ct_usr = lua_absindex(L, ct_usr);
+    fidx = lua_absindex(L, fidx);
+
+    assert(lua_isnil(L, fidx) || lua_isfunction(L, fidx));
+
+    memset(&reg, 0, sizeof(reg));
+#ifdef _WIN64
+    reg.off = 16 + REGISTER_STACK_SPACE(ct); /* stack registers are above the shadow space */
+#elif __amd64__
+    reg.off = 16;
+#else
+    reg.off = 8;
+#endif
+
+    dasm_setup(Dst, build_actionlist);
+
+    // add a table to store ctype and function upvalues
+    // callback_set assumes the first value is the lua function
+    nargs = (int) lua_rawlen(L, ct_usr);
+    lua_newtable(L);
+    lua_pushvalue(L, -1);
+    ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+    if (ct->has_var_arg) {
+        luaL_error(L, "can't create callbacks with varargs");
+    }
+
+    // setup a stack frame to hold args for the call into lua_call
+
+    dasm_put(Dst, 80, 8 + 16 + 32 + REGISTER_STACK_SPACE(ct));
+    if (ct->calling_convention == FAST_CALL) {
+    }
+
+    // hardcode the lua_State* value into the assembly
+    dasm_put(Dst, 129, (unsigned int)((uintptr_t)(L)), (unsigned int)(((uintptr_t)(L))>>32));
+
+    /* get the upval table */
+    dasm_put(Dst, 134, ref, LUA_REGISTRYINDEX);
+
+    /* get the lua function */
+    lua_pushvalue(L, fidx);
+    lua_rawseti(L, -2, ++num_upvals);
+    assert(num_upvals == CALLBACK_FUNC_USR_IDX);
+    dasm_put(Dst, 150, num_upvals);
+
+#if !defined _WIN64 && !defined __amd64__
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) {
+        hidden_arg_off = reg.off;
+        reg.off += sizeof(void*);
+    }
+    lua_pop(L, 1);
+#else
+    (void) hidden_arg_off;
+#endif
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, i);
+        mt = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mt->pointers || mt->is_reference) {
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+            /* on the lua stack in the callback:
+             * upval tbl, lua func, i-1 args
+             */
+            dasm_put(Dst, 173, num_upvals-1, -i-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+            get_pointer(Dst, ct, &reg);
+            dasm_put(Dst, 211);
+        } else {
+            switch (mt->type) {
+            case INT64_TYPE:
+                lua_getuservalue(L, -1);
+                lua_rawseti(L, -3, ++num_upvals); /* mt */
+                lua_pop(L, 1);
+                dasm_put(Dst, 233, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+                get_int(Dst, ct, &reg, 1);
+                dasm_put(Dst, 252);
+                break;
+
+            case INTPTR_TYPE:
+                lua_getuservalue(L, -1);
+                lua_rawseti(L, -3, ++num_upvals); /* mt */
+                lua_pop(L, 1);
+                dasm_put(Dst, 233, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+                get_pointer(Dst, ct, &reg);
+                dasm_put(Dst, 252);
+                break;
+
+            case COMPLEX_FLOAT_TYPE:
+                lua_pop(L, 1);
+#if defined _WIN64 || defined __amd64__
+                /* complex floats are two floats packed into a double */
+                dasm_put(Dst, 233, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+                get_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 256);
+#else
+                /* complex floats are real followed by imag on the stack */
+                dasm_put(Dst, 233, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+                get_float(Dst, ct, &reg, 0);
+                dasm_put(Dst, 261);
+                get_float(Dst, ct, &reg, 0);
+                dasm_put(Dst, 264);
+#endif
+                break;
+
+            case COMPLEX_DOUBLE_TYPE:
+                lua_pop(L, 1);
+                dasm_put(Dst, 233, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+                /* real */
+                get_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 256);
+                /* imag */
+                get_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 268);
+                break;
+
+            case FLOAT_TYPE:
+            case DOUBLE_TYPE:
+                lua_pop(L, 1);
+                get_float(Dst, ct, &reg, mt->type == DOUBLE_TYPE);
+                dasm_put(Dst, 274);
+                break;
+
+            case BOOL_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                dasm_put(Dst, 287);
+                break;
+
+            case INT8_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 301);
+                } else {
+                    dasm_put(Dst, 305);
+                }
+                dasm_put(Dst, 309);
+                break;
+
+            case INT16_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 320);
+                } else {
+                    dasm_put(Dst, 324);
+                }
+                dasm_put(Dst, 309);
+                break;
+
+            case ENUM_TYPE:
+            case INT32_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 328);
+                } else {
+                    dasm_put(Dst, 309);
+                }
+                break;
+
+            default:
+                luaL_error(L, "NYI: callback arg type");
+            }
+        }
+    }
+
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+
+    dasm_put(Dst, 339, (unsigned int)((uintptr_t)(0)), (unsigned int)(((uintptr_t)(0))>>32), (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, nargs);
+
+    // Unpack the return argument if not "void", also clean-up the lua stack
+    // to remove the return argument and bind table. Use lua_settop rather
+    // than lua_pop as lua_pop is implemented as a macro.
+    if (mt->pointers || mt->is_reference) {
+        lua_getuservalue(L, -1);
+        lua_rawseti(L, -3, ++num_upvals); /* usr value */
+        lua_rawseti(L, -2, ++num_upvals); /* mt */
+        dasm_put(Dst, 359, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+
+    } else {
+        switch (mt->type) {
+        case ENUM_TYPE:
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+            dasm_put(Dst, 443, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32));
+            break;
+
+        case VOID_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 525);
+            break;
+
+        case BOOL_TYPE:
+        case INT8_TYPE:
+        case INT16_TYPE:
+        case INT32_TYPE:
+            lua_pop(L, 1);
+            if (mt->is_unsigned) {
+                dasm_put(Dst, 544);
+            } else {
+                dasm_put(Dst, 563);
+            }
+            dasm_put(Dst, 582);
+            break;
+
+        case INT64_TYPE:
+            lua_pop(L, 1);
+
+            if (mt->is_unsigned) {
+                dasm_put(Dst, 609);
+            } else {
+                dasm_put(Dst, 628);
+            }
+
+            dasm_put(Dst, 647);
+            break;
+
+        case INTPTR_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 676);
+            break;
+
+        case FLOAT_TYPE:
+        case DOUBLE_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 723);
+            if (mt->type == FLOAT_TYPE) {
+                dasm_put(Dst, 766);
+            } else {
+                dasm_put(Dst, 774);
+            }
+            break;
+
+        case COMPLEX_FLOAT_TYPE:
+            lua_pop(L, 1);
+#if !defined HAVE_COMPLEX
+            luaL_error(L, "ffi lib compiled without complex number support");
+#endif
+            /* on 64 bit complex floats are two floats packed into a double,
+             * on 32 bit returned complex floats use eax and edx */
+            dasm_put(Dst, 782);
+            break;
+
+        case COMPLEX_DOUBLE_TYPE:
+            lua_pop(L, 1);
+#if !defined HAVE_COMPLEX
+            luaL_error(L, "ffi lib compiled without complex number support");
+#endif
+            /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit
+             * there is a hidden first parameter that points to 16 bytes where
+             * the returned arg is stored which is popped by the called
+             * function */
+#if defined _WIN64 || defined __amd64__
+            dasm_put(Dst, 832);
+#else
+            dasm_put(Dst, 895, hidden_arg_off);
+#endif
+            break;
+
+        default:
+            luaL_error(L, "NYI: callback return type");
+        }
+    }
+
+    dasm_put(Dst, 944, x86_return_size(L, ct_usr, ct));
+
+    lua_pop(L, 1); /* upval table - already in registry */
+    assert(lua_gettop(L) == top);
+
+    ct2.is_jitted = 1;
+    pf = (cfunction*) push_cdata(L, ct_usr, &ct2);
+    *pf = compile(Dst, L, NULL, ref);
+
+    assert(lua_gettop(L) == top + 1);
+
+    return *pf;
+}
+
+void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct)
+{
+    size_t i, nargs;
+    int num_upvals;
+    const struct ctype* mbr_ct;
+    struct jit* Dst = get_jit(L);
+    struct reg_alloc reg;
+    void* p;
+    int top = lua_gettop(L);
+    int* perr = &Dst->last_errno;
+
+    ct_usr = lua_absindex(L, ct_usr);
+
+    memset(&reg, 0, sizeof(reg));
+    reg.off = 32 + REGISTER_STACK_SPACE(ct);
+
+    dasm_setup(Dst, build_actionlist);
+
+    p = push_cdata(L, ct_usr, ct);
+    *(cfunction*) p = func;
+    num_upvals = 1;
+
+    nargs = lua_rawlen(L, ct_usr);
+
+    if (ct->calling_convention != C_CALL && ct->has_var_arg) {
+        luaL_error(L, "vararg is only allowed with the c calling convention");
+    }
+
+    dasm_put(Dst, 957, nargs);
+    if (!ct->has_var_arg) {
+        dasm_put(Dst, 989, (unsigned int)((uintptr_t)(&"too few arguments")), (unsigned int)(((uintptr_t)(&"too few arguments"))>>32), (unsigned int)((uintptr_t)(&"too many arguments")), (unsigned int)(((uintptr_t)(&"too many arguments"))>>32));
+    } else {
+        dasm_put(Dst, 1030, (unsigned int)((uintptr_t)(&"too few arguments")), (unsigned int)(((uintptr_t)(&"too few arguments"))>>32));
+    }
+
+    dasm_put(Dst, 1050);
+
+    /* no need to zero extend eax returned by lua_gettop to rax as x86-64
+     * preguarentees that the upper 32 bits will be zero */
+    dasm_put(Dst, 1053, 32 + REGISTER_STACK_SPACE(ct));
+
+#if !defined _WIN64 && !defined __amd64__
+    /* Returned complex doubles require a hidden first parameter where the
+     * data is stored, which is popped by the calling code. */
+    lua_rawgeti(L, ct_usr, 0);
+    mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mbr_ct->pointers && !mbr_ct->is_reference && mbr_ct->type == COMPLEX_DOUBLE_TYPE) {
+        /* we can allocate more space for arguments as long as no add_*
+         * function has been called yet, mbr_ct will be added as an upvalue in
+         * the return processing later */
+        dasm_put(Dst, 1066, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32));
+        add_pointer(Dst, ct, &reg);
+    }
+    lua_pop(L, 1);
+#endif
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, (int) i);
+        mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mbr_ct->pointers || mbr_ct->is_reference) {
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1090, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i);
+            add_pointer(Dst, ct, &reg);
+        } else {
+            switch (mbr_ct->type) {
+            case FUNCTION_PTR_TYPE:
+                lua_getuservalue(L, -1);
+                num_upvals += 2;
+                dasm_put(Dst, 1110, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i);
+                add_pointer(Dst, ct, &reg);
+                break;
+
+            case ENUM_TYPE:
+                lua_getuservalue(L, -1);
+                num_upvals += 2;
+                dasm_put(Dst, 1130, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i);
+                add_int(Dst, ct, &reg, 0);
+                break;
+
+            case INT8_TYPE:
+                dasm_put(Dst, 1150, i);
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1162);
+                } else {
+                    dasm_put(Dst, 1166);
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INT16_TYPE:
+                dasm_put(Dst, 1150, i);
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1170);
+                } else {
+                    dasm_put(Dst, 1174);
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case BOOL_TYPE:
+                dasm_put(Dst, 1178, i);
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INT32_TYPE:
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1200, i);
+                } else {
+                    dasm_put(Dst, 1150, i);
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INTPTR_TYPE:
+                dasm_put(Dst, 1212, i);
+                add_pointer(Dst, ct, &reg);
+                lua_pop(L, 1);
+                break;
+
+            case INT64_TYPE:
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1224, i);
+                } else {
+                    dasm_put(Dst, 1236, i);
+                }
+                add_int(Dst, ct, &reg, 1);
+                lua_pop(L, 1);
+                break;
+
+            case DOUBLE_TYPE:
+                dasm_put(Dst, 1248, i);
+                add_float(Dst, ct, &reg, 1);
+                lua_pop(L, 1);
+                break;
+
+            case COMPLEX_DOUBLE_TYPE:
+                /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit
+                 * there is a hidden first parameter that points to 16 bytes where
+                 * the returned arg is stored (this is popped by the called
+                 * function) */
+#if defined _WIN64 || defined __amd64__
+                dasm_put(Dst, 1260, i);
+                add_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 1272);
+                add_float(Dst, ct, &reg, 1);
+#else
+                dasm_put(Dst, 1278, reg.off, i);
+                reg.off += 16;
+#endif
+                lua_pop(L, 1);
+                break;
+
+            case FLOAT_TYPE:
+                dasm_put(Dst, 1248, i);
+                add_float(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case COMPLEX_FLOAT_TYPE:
+#if defined _WIN64 || defined __amd64__
+                dasm_put(Dst, 1304, i);
+                /* complex floats are two floats packed into a double */
+                add_float(Dst, ct, &reg, 1);
+#else
+                /* returned complex floats use eax and edx */
+                dasm_put(Dst, 1316, i);
+                add_float(Dst, ct, &reg, 0);
+                dasm_put(Dst, 1334);
+                add_float(Dst, ct, &reg, 0);
+#endif
+                lua_pop(L, 1);
+                break;
+
+            default:
+                luaL_error(L, "NYI: call arg type");
+            }
+        }
+    }
+
+    if (ct->has_var_arg) {
+#ifdef _WIN64
+        if (reg.regs < MAX_REGISTERS(ct)) {
+            assert(reg.regs == nargs);
+            dasm_put(Dst, 1341, MAX_REGISTERS(ct), 32 + 8*MAX_REGISTERS(ct), MAX_REGISTERS(ct)+1, 32 + 8*(reg.regs), MAX_REGISTERS(ct), nargs+1, 32 + 8*(reg.regs), nargs+1);
+        } else {
+            dasm_put(Dst, 1432, reg.off, nargs+1);
+        }
+
+        for (i = nargs; i < MAX_REGISTERS(ct); i++) {
+            reg.is_int[i] = reg.is_float[i] = 1;
+        }
+        reg.regs = MAX_REGISTERS(ct);
+#elif defined __amd64__
+        if (reg.floats < MAX_FLOAT_REGISTERS(ct)) {
+        }
+
+        if (reg.ints < MAX_INT_REGISTERS(ct)) {
+        }
+
+
+        reg.floats = MAX_FLOAT_REGISTERS(ct);
+        reg.ints = MAX_INT_REGISTERS(ct);
+#else
+#endif
+    }
+
+    dasm_put(Dst, 1457, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+
+    /* remove the stack space to call local functions */
+    dasm_put(Dst, 1471);
+
+#ifdef _WIN64
+    switch (reg.regs) {
+    case 4:
+        if (reg.is_float[3]) {
+            dasm_put(Dst, 1476, 8*3);
+        }
+        if (reg.is_int[3]) {
+            dasm_put(Dst, 1485, 8*3);
+        }
+    case 3:
+        if (reg.is_float[2]) {
+            dasm_put(Dst, 1492, 8*2);
+        }
+        if (reg.is_int[2]) {
+            dasm_put(Dst, 1501, 8*2);
+        }
+    case 2:
+        if (reg.is_float[1]) {
+            dasm_put(Dst, 1508, 8*1);
+        }
+        if (reg.is_int[1]) {
+            dasm_put(Dst, 1517, 8*1);
+        }
+    case 1:
+        if (reg.is_float[0]) {
+            dasm_put(Dst, 1524);
+        }
+        if (reg.is_int[0]) {
+            dasm_put(Dst, 1531);
+        }
+    case 0:
+        break;
+    }
+
+    /* don't remove the space for the registers as we need 32 bytes of register overflow space */
+    assert(REGISTER_STACK_SPACE(ct) == 32);
+
+#elif defined __amd64__
+    switch (reg.floats) {
+    case 8:
+    case 7:
+    case 6:
+    case 5:
+    case 4:
+    case 3:
+    case 2:
+    case 1:
+    case 0:
+        break;
+    }
+
+    switch (reg.ints) {
+    case 6:
+    case 5:
+    case 4:
+    case 3:
+    case 2:
+    case 1:
+    case 0:
+        break;
+    }
+
+#else
+    if (ct->calling_convention == FAST_CALL) {
+        switch (reg.ints) {
+        case 2:
+        case 1:
+        case 0:
+            break;
+        }
+
+    }
+#endif
+
+#ifdef __amd64__
+    if (ct->has_var_arg) {
+        /* al stores an upper limit on the number of float register, note that
+         * its allowed to be more than the actual number of float registers used as
+         * long as its 0-8 */
+    }
+#endif
+
+    dasm_put(Dst, 1536);
+
+    /* note on windows X86 the stack may be only aligned to 4 (stdcall will
+     * have popped a multiple of 4 bytes), but we don't need 16 byte alignment on
+     * that platform
+     */
+
+    lua_rawgeti(L, ct_usr, 0);
+    mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+
+    if (mbr_ct->pointers || mbr_ct->is_reference || mbr_ct->type == INTPTR_TYPE) {
+        lua_getuservalue(L, -1);
+        num_upvals += 2;
+        dasm_put(Dst, 1546, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals));
+
+    } else {
+        switch (mbr_ct->type) {
+        case FUNCTION_PTR_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1546, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals));
+            break;
+
+        case INT64_TYPE:
+#if LUA_VERSION_NUM == 503
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1606, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            } else {
+                dasm_put(Dst, 1606, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            }
+#else
+            num_upvals++;
+            dasm_put(Dst, 1658, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32));
+#endif
+            break;
+
+        case COMPLEX_FLOAT_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1721, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals));
+            break;
+
+        case COMPLEX_DOUBLE_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1782, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals));
+            break;
+
+        case VOID_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 1858, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        case BOOL_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 1890, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        case INT8_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1162);
+            } else {
+                dasm_put(Dst, 1166);
+            }
+            dasm_put(Dst, 1943, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        case INT16_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1170);
+            } else {
+                dasm_put(Dst, 1174);
+            }
+            dasm_put(Dst, 1943, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        case INT32_TYPE:
+        case ENUM_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1993, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            } else {
+                dasm_put(Dst, 1943, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            }
+            break;
+
+        case FLOAT_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 2043, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        case DOUBLE_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 2048, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32));
+            break;
+
+        default:
+            luaL_error(L, "NYI: call return type");
+        }
+    }
+
+    assert(lua_gettop(L) == top + num_upvals);
+    {
+        cfunction f = compile(Dst, L, func, LUA_NOREF);
+        /* add a callback as an upval so that the jitted code gets cleaned up when
+         * the function gets gc'd */
+        push_callback(L, f, func);
+        lua_pushcclosure(L, (lua_CFunction) f, num_upvals+1);
+    }
+}
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x64win.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x86.dasc
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x86.dasc	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x86.dasc	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,1640 @@
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+|.if X64
+|.arch x64
+|.else
+|.arch x86
+|.endif
+
+|.actionlist build_actionlist
+|.globalnames globnames
+|.externnames extnames
+
+|.if not X64
+|.define RET_H, edx // for int64_t returns
+|.define RET_L, eax
+|.endif
+
+|.if X64
+|.define L_ARG, r12
+|.define TOP, r13
+|.else
+|.define L_ARG, rdi
+|.define TOP, rsi
+|.endif
+
+|.if X64WIN
+|
+|.macro call_rrrp, func, arg0, arg1, arg2, arg3
+| mov64 r9, arg3
+| mov r8, arg2
+| mov rdx, arg1
+| mov rcx, arg0
+| call func
+|.endmacro
+|.macro call_rrrr, func, arg0, arg1, arg2, arg3
+| mov r9, arg3
+| mov r8, arg2
+| mov rdx, arg1
+| mov rcx, arg0
+| call func
+|.endmacro
+|
+|.macro call_rrp, func, arg0, arg1, arg2
+| mov64 r8, arg2
+| mov rdx, arg1
+| mov rcx, arg0
+| call func
+|.endmacro
+|.macro call_rrr, func, arg0, arg1, arg2
+| mov r8, arg2
+| mov rdx, arg1
+| mov rcx, arg0
+| call func
+|.endmacro
+|
+|.macro call_rp, func, arg0, arg1
+| mov64 rdx, arg1
+| mov rcx, arg0
+| call func
+|.endmacro
+|.macro call_rr, func, arg0, arg1
+| mov rdx, arg1
+| mov rcx, arg0
+| call func
+|.endmacro
+|
+|.macro call_r, func, arg0
+| mov rcx, arg0
+| call func
+|.endmacro
+|
+|.elif X64
+|
+| // the 5 and 6 arg forms are only used on posix x64
+|.macro call_rrrrrr, func, arg0, arg1, arg2, arg3, arg4, arg5
+| mov r9, arg5
+| mov r8, arg4
+| mov rcx, arg3
+| mov rdx, arg2
+| mov rsi, arg1
+| mov rdi, arg0
+| call func
+|.endmacro
+|.macro call_rrrrr, func, arg0, arg1, arg2, arg3, arg4
+| mov r8, arg4
+| mov rcx, arg3
+| mov rdx, arg2
+| mov rsi, arg1
+| mov rdi, arg0
+| call func
+|.endmacro
+|
+|.macro call_rrrp, func, arg0, arg1, arg2, arg3
+| mov64 rcx, arg3
+| mov rdx, arg2
+| mov rsi, arg1
+| mov rdi, arg0
+| call func
+|.endmacro
+|.macro call_rrrr, func, arg0, arg1, arg2, arg3
+| mov rcx, arg3
+| mov rdx, arg2
+| mov rsi, arg1
+| mov rdi, arg0
+| call func
+|.endmacro
+|
+|.macro call_rrp, func, arg0, arg1, arg2
+| mov64 rdx, arg2
+| mov rsi, arg1
+| mov rdi, arg0
+| call func
+|.endmacro
+|.macro call_rrr, func, arg0, arg1, arg2
+| mov rdx, arg2
+| mov rsi, arg1
+| mov rdi, arg0
+| call func
+|.endmacro
+|
+|.macro call_rp, func, arg0, arg1
+| mov64 rsi, arg1
+| mov rdi, arg0
+| call func
+|.endmacro
+|.macro call_rr, func, arg0, arg1
+| mov rsi, arg1
+| mov rdi, arg0
+| call func
+|.endmacro
+|
+|.macro call_r, func, arg0
+| mov rdi, arg0
+| call func
+|.endmacro
+|
+|.else
+| // define the 64bit registers to the 32 bit counterparts, so the common
+| // code can use r*x for all pointers
+|.define rax, eax
+|.define rcx, ecx
+|.define rdx, edx
+|.define rsp, esp
+|.define rbp, ebp
+|.define rdi, edi
+|.define rsi, esi
+|.define mov64, mov
+|
+|.macro call_rrrr, func, arg0, arg1, arg2, arg3
+| mov dword [rsp+12], arg3
+| mov dword [rsp+8], arg2
+| mov dword [rsp+4], arg1
+| mov dword [rsp], arg0
+| call func
+|.endmacro
+|.macro call_rrr, func, arg0, arg1, arg2
+| mov dword [rsp+8], arg2
+| mov dword [rsp+4], arg1
+| mov dword [rsp], arg0
+| call func
+|.endmacro
+|.macro call_rr, func, arg0, arg1
+| mov dword [rsp+4], arg1
+| mov dword [rsp], arg0
+| call func
+|.endmacro
+|.macro call_r, func, arg0
+| mov dword [rsp], arg0
+| call func
+|.endmacro
+|
+|.define call_rrrp, call_rrrr
+|.define call_rrp, call_rrr
+|.define call_rp, call_rr
+|
+|.endif
+
+|.macro epilog
+|.if X64
+| mov TOP, [rbp-16]
+| mov L_ARG, [rbp-8]
+|.else
+| mov TOP, [rbp-8]
+| mov L_ARG, [rbp-4]
+|.endif
+| mov rsp, rbp
+| pop rbp
+| ret
+|.endmacro
+
+|.macro get_errno // note trashes registers
+| call extern GetLastError
+| mov64 rcx, perr
+| mov dword [rcx], eax
+|.endmacro
+
+|.macro too_few_arguments
+| mov ax, 0
+| call_rp extern luaL_error, L_ARG, &"too few arguments"
+|.endmacro
+
+|.macro too_many_arguments
+| mov ax, 0
+| call_rp extern luaL_error, L_ARG, &"too many arguments"
+|.endmacro
+
+|.macro lua_return_arg
+| mov eax, 1
+| epilog
+|.endmacro
+
+|.macro lua_return_void
+| get_errno
+| mov eax, 0
+| epilog
+|.endmacro
+
+|.macro lua_return_double
+|.if X64
+| movq qword [rsp+32], xmm0
+|.else
+| fstp qword [rsp+4] // note get_errno doesn't require any stack on x86
+|.endif
+|
+| get_errno
+|
+|.if X64WIN
+| movq xmm1, qword [rsp+32]
+| mov rcx, L_ARG
+|.elif X64
+| movq xmm0, qword [rsp+32]
+| mov rdi, L_ARG
+|.else
+| mov [rsp], L_ARG
+|.endif
+| call extern lua_pushnumber
+| lua_return_arg
+|.endmacro
+
+|.macro lua_return_bool
+| movzx eax, al
+| mov [rsp+32], eax
+| get_errno
+| mov eax, [rsp+32]
+| call_rr extern lua_pushboolean, L_ARG, rax
+| lua_return_arg
+|.endmacro
+
+|.macro lua_return_int
+| mov [rsp+32], eax
+| get_errno
+| mov eax, [rsp+32]
+| call_rr extern push_int, L_ARG, rax
+| lua_return_arg
+|.endmacro
+
+|.macro lua_return_uint
+| mov [rsp+32], eax
+| get_errno
+| mov eax, [rsp+32]
+| call_rr extern push_uint, L_ARG, rax
+| lua_return_arg
+|.endmacro
+
+|.macro lua_return_long
+| mov [rsp+32], rax
+| get_errno
+| mov rax, [rsp+32]
+| call_rr extern lua_pushinteger, L_ARG, rax
+| lua_return_arg
+|.endmacro
+
+|.macro lua_return_ulong
+| mov [rsp+32], rax
+| get_errno
+| mov rax, [rsp+32]
+| call_rr extern lua_pushinteger, L_ARG, rax
+| lua_return_arg
+|.endmacro
+
+|.macro save_registers
+| // use rbp relative so we store values in the outer stack frame
+|.if X64WIN
+| // use the provided shadow space for int registers above prev rbp and
+| // return address
+| mov [rbp+16], rcx
+| mov [rbp+24], rdx
+| mov [rbp+32], r8
+| mov [rbp+40], r9
+| // use the extra space we added for float registers
+| // -16 to store underneath previous value of L_ARG
+| movq qword [rbp-16], xmm0
+| movq qword [rbp-24], xmm1
+| movq qword [rbp-32], xmm2
+| movq qword [rbp-40], xmm3
+|.elif X64
+| movq qword [rbp-16], xmm0
+| movq qword [rbp-24], xmm1
+| movq qword [rbp-32], xmm2
+| movq qword [rbp-40], xmm3
+| movq qword [rbp-48], xmm4
+| movq qword [rbp-56], xmm5
+| movq qword [rbp-64], xmm6
+| movq qword [rbp-72], xmm7
+| mov [rbp-80], rdi
+| mov [rbp-88], rsi
+| mov [rbp-96], rdx
+| mov [rbp-104], rcx
+| mov [rbp-112], r8
+| mov [rbp-120], r9
+|.else
+| // fastcall, -8 to store underneath previous value of L_ARG
+| mov [rbp-8], ecx
+| mov [rbp-12], edx
+|.endif
+|.endmacro
+
+#if defined _WIN64 || defined __amd64__
+#define JUMP_SIZE 14
+#else
+#define JUMP_SIZE 4
+#endif
+
+#define MIN_BRANCH INT32_MIN
+#define MAX_BRANCH INT32_MAX
+#define BRANCH_OFF 4
+
+static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code)
+{
+    /* The jump code is the function pointer followed by a stub to call the
+     * function pointer. The stub exists in 64 bit so we can jump to functions
+     * with an offset greater than 2 GB.
+     *
+     * Note we have to manually set this up since there are commands buffered
+     * in the jit state and dynasm doesn't support rip relative addressing.
+     *
+     * eg on 64 bit:
+     * 0-8: function ptr
+     * 8-14: jmp aword [rip-14]
+     *
+     * for 32 bit we only set the function ptr as it can always fit in a 32
+     * bit displacement
+     */
+#if defined _WIN64 || defined __amd64__
+    *(cfunction*) code = func;
+    code[8] = 0xFF; /* FF /4 operand for jmp */
+    code[9] = 0x25; /* RIP displacement */
+    *(int32_t*) &code[10] = -14;
+#else
+    *(cfunction*) code = func;
+#endif
+}
+
+void compile_globals(struct jit* jit, lua_State* L)
+{
+    struct jit* Dst = jit;
+    int* perr = &jit->last_errno;
+    dasm_setup(Dst, build_actionlist);
+
+    /* Note: since the return code uses EBP to reset the stack pointer, we
+     * don't have to track the amount of stack space used. It also means we
+     * can handle stdcall and cdecl with the same code.
+     */
+
+    /* Note the various call_* functions want 32 bytes of 16 byte aligned
+     * stack
+     */
+
+
+
+    compile(Dst, L, NULL, LUA_NOREF);
+}
+
+int x86_return_size(lua_State* L, int usr, const struct ctype* ct)
+{
+    int ret = 0;
+    const struct ctype* mt;
+
+    if (ct->calling_convention != C_CALL) {
+        size_t i;
+        size_t argn = lua_rawlen(L, usr);
+        for (i = 1; i <= argn; i++) {
+            lua_rawgeti(L, usr, (int) i);
+            mt = (const struct ctype*) lua_touserdata(L, -1);
+
+            if (mt->pointers || mt->is_reference) {
+                ret += sizeof(void*);
+            } else {
+                switch (mt->type) {
+                case DOUBLE_TYPE:
+                case COMPLEX_FLOAT_TYPE:
+                case INT64_TYPE:
+                    ret += 8;
+                    break;
+                case COMPLEX_DOUBLE_TYPE:
+                    ret += 16;
+                    break;
+                case INTPTR_TYPE:
+                    ret += sizeof(intptr_t);
+                    break;
+                case FUNCTION_PTR_TYPE:
+                    ret += sizeof(cfunction);
+                    break;
+                case BOOL_TYPE:
+                case FLOAT_TYPE:
+                case INT8_TYPE:
+                case INT16_TYPE:
+                case INT32_TYPE:
+                case ENUM_TYPE:
+                    ret += 4;
+                    break;
+                default:
+                    return luaL_error(L, "NYI - argument type");
+                }
+            }
+
+            lua_pop(L, 1);
+        }
+    }
+
+#if !defined _WIN64 && !defined __amd64__
+    lua_rawgeti(L, usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) {
+        ret += sizeof(void*);
+    }
+    lua_pop(L, 1);
+#endif
+
+    return ret;
+}
+
+#ifdef _WIN64
+#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */
+
+#elif defined __amd64__
+#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */
+#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */
+
+#else
+#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0)
+#define MAX_FLOAT_REGISTERS(ct) 0
+#endif
+
+struct reg_alloc {
+#ifdef _WIN64
+    int regs;
+    int is_float[4];
+    int is_int[4];
+#else
+    int floats;
+    int ints;
+#endif
+    int off;
+};
+
+#ifdef _WIN64
+#define REGISTER_STACK_SPACE(ct) (4*8)
+#elif defined __amd64__
+#define REGISTER_STACK_SPACE(ct) (14*8)
+#else
+#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15)
+#endif
+
+/* Fastcall:
+ * Uses ecx, edx as first two int registers
+ * Everything else on stack (include 64bit ints)
+ * No overflow stack space
+ * Pops the stack before returning
+ * Returns int in eax, float in ST0
+ * We use the same register allocation logic as posix x64 with 2 int regs and 0 float regs
+ */
+
+static void get_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_int64)
+{
+    /* grab the register from the shadow space */
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        | mov rcx, [rbp + 16 + 8*reg->regs]
+        reg->regs++;
+    }
+#elif __amd64__
+    if (reg->ints < MAX_INT_REGISTERS(ct)) {
+        | mov rcx, [rbp - 80 - 8*reg->ints]
+        reg->ints++;
+    }
+#else
+    if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) {
+        | mov ecx, [rbp - 8 - 4*reg->ints]
+        reg->ints++;
+    }
+#endif
+    else if (is_int64) {
+        |.if X64
+        | mov rcx, [rbp + reg->off]
+        |.else
+        | mov rcx, [rbp + reg->off]
+        | mov rdx, [rbp + reg->off + 4]
+        |.endif
+        reg->off += 8;
+    } else {
+        | mov ecx, [rbp + reg->off]
+        reg->off += 4;
+    }
+}
+
+static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_int64)
+{
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        | mov [rsp + 32 + 8*(reg->regs)], rax
+        reg->is_int[reg->regs++] = 1;
+    }
+#elif __amd64__
+    if (reg->ints < MAX_INT_REGISTERS(ct)) {
+        | mov [rsp + 32 + 8*reg->ints], rax
+        reg->ints++;
+    }
+#else
+    if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) {
+        | mov [rsp + 32 + 4*reg->ints], rax
+        reg->ints++;
+    }
+#endif
+    else {
+#if defined _WIN64 || defined __amd64__
+        if (reg->off % 8 != 0) {
+            reg->off += 8 - (reg->off % 8);
+        }
+#endif
+        if (is_int64) {
+            |.if X64
+            | mov [rsp + reg->off], rax
+            |.else
+            | mov [rsp + reg->off], RET_L
+            | mov [rsp + reg->off + 4], RET_H
+            |.endif
+            reg->off += 8;
+        } else {
+            | mov [rsp+reg->off], eax
+            reg->off += 4;
+        }
+    }
+}
+
+static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double)
+{
+#if !defined _WIN64 && !defined __amd64__
+    assert(MAX_FLOAT_REGISTERS(ct) == 0);
+    if (is_double) {
+        | fld qword [rbp + reg->off]
+        reg->off += 8;
+    } else {
+        | fld dword [rbp + reg->off]
+        reg->off += 4;
+    }
+#else
+    int off;
+
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        off = -16 - 8*reg->regs;
+        reg->regs++;
+    }
+#else
+    if (reg->floats < MAX_FLOAT_REGISTERS(ct)) {
+        off = -16 - 8*reg->floats;
+        reg->floats++;
+    }
+#endif
+    else {
+        off = reg->off;
+        reg->off += is_double ? 8 : 4;
+    }
+
+    if (is_double) {
+        | movq xmm0, qword [rbp + off]
+    } else {
+        | cvtss2sd xmm0, dword [rbp + off]
+    }
+#endif
+}
+
+static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double)
+{
+#if !defined _WIN64 && !defined __amd64__
+    assert(MAX_FLOAT_REGISTERS(ct) == 0);
+    if (is_double) {
+        | fstp qword [rsp + reg->off]
+        reg->off += 8;
+    } else {
+        | fstp dword [rsp + reg->off]
+        reg->off += 4;
+    }
+#else
+
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        if (is_double) {
+            | movq qword [rsp + 32 + 8*(reg->regs)], xmm0
+        } else {
+            | cvtsd2ss xmm0, xmm0
+            | movq qword [rsp + 32 + 8*(reg->regs)], xmm0
+        }
+        reg->is_float[reg->regs++] = 1;
+    }
+#else
+    if (reg->floats < MAX_FLOAT_REGISTERS(ct)) {
+        if (is_double) {
+            | movq qword [rsp + 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)], xmm0
+        } else {
+            | cvtsd2ss xmm0, xmm0
+            | movq qword [rsp + 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)], xmm0
+        }
+        reg->floats++;
+    }
+#endif
+
+    else if (is_double) {
+        | movq qword [rsp + reg->off], xmm0
+        reg->off += 8;
+    } else {
+        | cvtsd2ss xmm0, xmm0
+        | movd dword [rsp + reg->off], xmm0
+        reg->off += 4;
+    }
+#endif
+}
+
+#if defined _WIN64 || defined __amd64__
+#define add_pointer(jit, ct, reg) add_int(jit, ct, reg, 1)
+#define get_pointer(jit, ct, reg) get_int(jit, ct, reg, 1)
+#else
+#define add_pointer(jit, ct, reg) add_int(jit, ct, reg, 0)
+#define get_pointer(jit, ct, reg) get_int(jit, ct, reg, 0)
+#endif
+
+cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct)
+{
+    int i, nargs;
+    cfunction* pf;
+    struct ctype ct2 = *ct;
+    const struct ctype* mt;
+    struct reg_alloc reg;
+    int num_upvals = 0;
+    int top = lua_gettop(L);
+    struct jit* Dst = get_jit(L);
+    int ref;
+    int hidden_arg_off = 0;
+
+    ct_usr = lua_absindex(L, ct_usr);
+    fidx = lua_absindex(L, fidx);
+
+    assert(lua_isnil(L, fidx) || lua_isfunction(L, fidx));
+
+    memset(&reg, 0, sizeof(reg));
+#ifdef _WIN64
+    reg.off = 16 + REGISTER_STACK_SPACE(ct); /* stack registers are above the shadow space */
+#elif __amd64__
+    reg.off = 16;
+#else
+    reg.off = 8;
+#endif
+
+    dasm_setup(Dst, build_actionlist);
+
+    // add a table to store ctype and function upvalues
+    // callback_set assumes the first value is the lua function
+    nargs = (int) lua_rawlen(L, ct_usr);
+    lua_newtable(L);
+    lua_pushvalue(L, -1);
+    ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+    if (ct->has_var_arg) {
+        luaL_error(L, "can't create callbacks with varargs");
+    }
+
+    // setup a stack frame to hold args for the call into lua_call
+
+    | push rbp
+    | mov rbp, rsp
+    | push L_ARG
+    | // stack is 4 or 8 (mod 16) (L_ARG, rbp, rip)
+    |.if X64
+    | // 8 to realign, 16 for return vars, 32 for local calls, rest to save registers
+    | sub rsp, 8 + 16 + 32 + REGISTER_STACK_SPACE(ct)
+    | save_registers
+    |.else
+    | // 4 to realign, 16 for return vars, 32 for local calls, rest to save registers
+    | sub rsp, 4 + 16 + 32 + REGISTER_STACK_SPACE(ct)
+    if (ct->calling_convention == FAST_CALL) {
+        | save_registers
+    }
+    |.endif
+
+    // hardcode the lua_State* value into the assembly
+    | mov64 L_ARG, L
+
+    /* get the upval table */
+    | call_rrr extern lua_rawgeti, L_ARG, LUA_REGISTRYINDEX, ref
+
+    /* get the lua function */
+    lua_pushvalue(L, fidx);
+    lua_rawseti(L, -2, ++num_upvals);
+    assert(num_upvals == CALLBACK_FUNC_USR_IDX);
+    | call_rrr extern lua_rawgeti, L_ARG, -1, num_upvals
+
+#if !defined _WIN64 && !defined __amd64__
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) {
+        hidden_arg_off = reg.off;
+        reg.off += sizeof(void*);
+    }
+    lua_pop(L, 1);
+#else
+    (void) hidden_arg_off;
+#endif
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, i);
+        mt = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mt->pointers || mt->is_reference) {
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+            /* on the lua stack in the callback:
+             * upval tbl, lua func, i-1 args
+             */
+            | call_rrr extern lua_rawgeti, L_ARG, -i-1, num_upvals-1
+            | call_rrp extern push_cdata, L_ARG, -1, mt
+            get_pointer(Dst, ct, &reg);
+            | mov [rax], rcx
+            | call_rr, extern lua_remove, L_ARG, -2
+        } else {
+            switch (mt->type) {
+            case INT64_TYPE:
+                lua_getuservalue(L, -1);
+                lua_rawseti(L, -3, ++num_upvals); /* mt */
+                lua_pop(L, 1);
+                | call_rrp extern push_cdata, L_ARG, 0, mt
+                get_int(Dst, ct, &reg, 1);
+                |.if X64
+                | mov [rax], rcx
+                |.else
+                | mov [rax], ecx
+                | mov [rax+4], edx
+                |.endif
+                break;
+
+            case INTPTR_TYPE:
+                lua_getuservalue(L, -1);
+                lua_rawseti(L, -3, ++num_upvals); /* mt */
+                lua_pop(L, 1);
+                | call_rrp extern push_cdata, L_ARG, 0, mt
+                get_pointer(Dst, ct, &reg);
+                | mov [rax], rcx
+                break;
+
+            case COMPLEX_FLOAT_TYPE:
+                lua_pop(L, 1);
+#if defined _WIN64 || defined __amd64__
+                /* complex floats are two floats packed into a double */
+                | call_rrp extern push_cdata, L_ARG, 0, mt
+                get_float(Dst, ct, &reg, 1);
+                | movq qword [rax], xmm0
+#else
+                /* complex floats are real followed by imag on the stack */
+                | call_rrp extern push_cdata, L_ARG, 0, mt
+                get_float(Dst, ct, &reg, 0);
+                | fstp dword [rax]
+                get_float(Dst, ct, &reg, 0);
+                | fstp dword [rax+4]
+#endif
+                break;
+
+            case COMPLEX_DOUBLE_TYPE:
+                lua_pop(L, 1);
+                | call_rrp extern push_cdata, L_ARG, 0, mt
+                /* real */
+                get_float(Dst, ct, &reg, 1);
+                |.if X64
+                | movq qword [rax], xmm0
+                |.else
+                | fstp qword [rax]
+                |.endif
+                /* imag */
+                get_float(Dst, ct, &reg, 1);
+                |.if X64
+                | movq qword [rax+8], xmm0
+                |.else
+                | fstp qword [rax+8]
+                |.endif
+                break;
+
+            case FLOAT_TYPE:
+            case DOUBLE_TYPE:
+                lua_pop(L, 1);
+                get_float(Dst, ct, &reg, mt->type == DOUBLE_TYPE);
+                |.if X64WIN
+                | movq xmm1, xmm0
+                | mov rcx, L_ARG
+                |.elif X64
+                | // for 64bit xmm0 is already set
+                | mov rdi, L_ARG
+                |.else
+                | fstp qword [rsp+4]
+                | mov [rsp], L_ARG
+                |.endif
+                | call extern lua_pushnumber
+                break;
+
+            case BOOL_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                | movzx ecx, cl
+                | call_rr extern lua_pushboolean, L_ARG, rcx
+                break;
+
+            case INT8_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    | movzx ecx, cl
+                } else {
+                    | movsx ecx, cl
+                }
+                | call_rr extern push_int, L_ARG, rcx
+                break;
+
+            case INT16_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    | movzx ecx, cx
+                } else {
+                    | movsx ecx, cx
+                }
+                | call_rr extern push_int, L_ARG, rcx
+                break;
+
+            case ENUM_TYPE:
+            case INT32_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    | call_rr extern push_uint, L_ARG, rcx
+                } else {
+                    | call_rr extern push_int, L_ARG, rcx
+                }
+                break;
+
+            default:
+                luaL_error(L, "NYI: callback arg type");
+            }
+        }
+    }
+
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+
+    | call_rrrp extern lua_callk, L_ARG, nargs, (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, 0
+
+    // Unpack the return argument if not "void", also clean-up the lua stack
+    // to remove the return argument and bind table. Use lua_settop rather
+    // than lua_pop as lua_pop is implemented as a macro.
+    if (mt->pointers || mt->is_reference) {
+        lua_getuservalue(L, -1);
+        lua_rawseti(L, -3, ++num_upvals); /* usr value */
+        lua_rawseti(L, -2, ++num_upvals); /* mt */
+        | call_rrr extern lua_rawgeti, L_ARG, -2, num_upvals-1
+        | call_rrrp extern check_typed_pointer, L_ARG, -2, -1, mt
+        | mov [rsp+32], rax
+        | call_rr extern lua_settop, L_ARG, -4
+        | mov rax, [rsp+32]
+
+    } else {
+        switch (mt->type) {
+        case ENUM_TYPE:
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+            | call_rrr extern lua_rawgeti, L_ARG, -2, num_upvals-1
+            | call_rrrp, extern check_enum, L_ARG, -2, -1, mt
+            | mov [rsp+32], eax
+            | call_rr extern lua_settop, L_ARG, -4
+            | mov eax, [rsp+32]
+            break;
+
+        case VOID_TYPE:
+            lua_pop(L, 1);
+            | call_rr extern lua_settop, L_ARG, -2
+            break;
+
+        case BOOL_TYPE:
+        case INT8_TYPE:
+        case INT16_TYPE:
+        case INT32_TYPE:
+            lua_pop(L, 1);
+            if (mt->is_unsigned) {
+                | call_rr extern check_uint32, L_ARG, -1
+            } else {
+                | call_rr extern check_int32, L_ARG, -1
+            }
+            | mov [rsp+32], eax
+            | call_rr extern lua_settop, L_ARG, -3
+            | mov eax, [rsp+32]
+            break;
+
+        case INT64_TYPE:
+            lua_pop(L, 1);
+
+            if (mt->is_unsigned) {
+                | call_rr extern check_uint64, L_ARG, -1
+            } else {
+                | call_rr extern check_int64, L_ARG, -1
+            }
+
+            |.if X64
+            | mov [rsp+32], rax
+            |.else
+            | mov [rsp+32], RET_L
+            | mov [rsp+36], RET_H
+            |.endif
+            | call_rr extern lua_settop, L_ARG, -3
+            |.if X64
+            | mov rax, [rsp+32]
+            |.else
+            | mov RET_L, [rsp+32]
+            | mov RET_H, [rsp+36]
+            |.endif
+            break;
+
+        case INTPTR_TYPE:
+            lua_pop(L, 1);
+            | call_rr extern check_uintptr, L_ARG, -1
+            | mov [rsp+32], rax
+            | call_rr extern lua_settop, L_ARG, -3
+            | mov rax, [rsp+32]
+            break;
+
+        case FLOAT_TYPE:
+        case DOUBLE_TYPE:
+            lua_pop(L, 1);
+            | call_rr extern check_double, L_ARG, -1
+            |.if X64
+            | movq qword [rsp+32], xmm0
+            | call_rr extern lua_settop, L_ARG, -3
+            if (mt->type == FLOAT_TYPE) {
+                | cvtsd2ss xmm0, qword [rsp+32]
+            } else {
+                | movq xmm0, qword [rsp+32]
+            }
+            |.else
+            | fstp qword [rsp+32]
+            | call_rr extern lua_settop, L_ARG, -3
+            | fld qword [rsp+32]
+            |.endif
+            break;
+
+        case COMPLEX_FLOAT_TYPE:
+            lua_pop(L, 1);
+#if !defined HAVE_COMPLEX
+            luaL_error(L, "ffi lib compiled without complex number support");
+#endif
+            /* on 64 bit complex floats are two floats packed into a double,
+             * on 32 bit returned complex floats use eax and edx */
+            | call_rr extern check_complex_float, L_ARG, -1
+            |
+            |.if X64
+            | movq qword [rsp+32], xmm0
+            |.else
+            | mov [rsp+32], eax
+            | mov [rsp+36], edx
+            |.endif
+            |
+            | call_rr extern lua_settop, L_ARG, -3
+            |
+            |.if X64
+            | movq xmm0, qword [rsp+32]
+            |.else
+            | mov eax, [rsp+32]
+            | mov edx, [rsp+36]
+            |.endif
+            break;
+
+        case COMPLEX_DOUBLE_TYPE:
+            lua_pop(L, 1);
+#if !defined HAVE_COMPLEX
+            luaL_error(L, "ffi lib compiled without complex number support");
+#endif
+            /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit
+             * there is a hidden first parameter that points to 16 bytes where
+             * the returned arg is stored which is popped by the called
+             * function */
+#if defined _WIN64 || defined __amd64__
+            | call_rr extern check_complex_double, L_ARG, -1
+            | movq qword [rsp+32], xmm0
+            | movq qword [rsp+40], xmm1
+            | call_rr extern lua_settop, L_ARG, -3
+            | movq xmm0, qword [rsp+32]
+            | movq xmm1, qword [rsp+40]
+#else
+            | mov rcx, [rbp + hidden_arg_off]
+            | call_rrr extern check_complex_double, rcx, L_ARG, -1
+            | sub rsp, 4 // to realign from popped hidden arg
+            | call_rr extern lua_settop, L_ARG, -3
+#endif
+            break;
+
+        default:
+            luaL_error(L, "NYI: callback return type");
+        }
+    }
+
+    |.if X64
+    | mov L_ARG, [rbp-8]
+    |.else
+    | mov L_ARG, [rbp-4]
+    |.endif
+    | mov rsp, rbp
+    | pop rbp
+    | ret x86_return_size(L, ct_usr, ct)
+
+    lua_pop(L, 1); /* upval table - already in registry */
+    assert(lua_gettop(L) == top);
+
+    ct2.is_jitted = 1;
+    pf = (cfunction*) push_cdata(L, ct_usr, &ct2);
+    *pf = compile(Dst, L, NULL, ref);
+
+    assert(lua_gettop(L) == top + 1);
+
+    return *pf;
+}
+
+void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct)
+{
+    size_t i, nargs;
+    int num_upvals;
+    const struct ctype* mbr_ct;
+    struct jit* Dst = get_jit(L);
+    struct reg_alloc reg;
+    void* p;
+    int top = lua_gettop(L);
+    int* perr = &Dst->last_errno;
+
+    ct_usr = lua_absindex(L, ct_usr);
+
+    memset(&reg, 0, sizeof(reg));
+    reg.off = 32 + REGISTER_STACK_SPACE(ct);
+
+    dasm_setup(Dst, build_actionlist);
+
+    p = push_cdata(L, ct_usr, ct);
+    *(cfunction*) p = func;
+    num_upvals = 1;
+
+    nargs = lua_rawlen(L, ct_usr);
+
+    if (ct->calling_convention != C_CALL && ct->has_var_arg) {
+        luaL_error(L, "vararg is only allowed with the c calling convention");
+    }
+
+    | push rbp
+    | mov rbp, rsp
+    | push L_ARG
+    | push TOP
+    | // stack is 0 (mod 16) (TOP, L_ARG, rbp, rip)
+    |
+    | // Get L from our arguments and allocate some stack for lua_gettop
+    |.if X64WIN
+    | mov L_ARG, rcx
+    | sub rsp, 32 // shadow space
+    |.elif X64
+    | mov L_ARG, rdi
+    |.else
+    | mov L_ARG, [rbp + 8]
+    | sub rsp, 16
+    |.endif
+    |
+    | call_r extern lua_gettop, L_ARG
+    | mov TOP, rax // no need for movzxd rax, eax - high word guarenteed to be zero by x86-64
+    | cmp rax, nargs
+    if (!ct->has_var_arg) {
+        | jge >2
+        | too_few_arguments
+        | 2:
+        | jle >1
+        | too_many_arguments
+    } else {
+        | jge >1
+        | too_few_arguments
+    }
+
+    | 1:
+
+    /* no need to zero extend eax returned by lua_gettop to rax as x86-64
+     * preguarentees that the upper 32 bits will be zero */
+    | shl rax, 4 // reserve 16 bytes per argument - this maintains the alignment mod 16
+    | sub rsp, rax
+    | sub rsp, 32 + REGISTER_STACK_SPACE(ct) // reserve an extra 32 to call local functions
+
+#if !defined _WIN64 && !defined __amd64__
+    /* Returned complex doubles require a hidden first parameter where the
+     * data is stored, which is popped by the calling code. */
+    lua_rawgeti(L, ct_usr, 0);
+    mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mbr_ct->pointers && !mbr_ct->is_reference && mbr_ct->type == COMPLEX_DOUBLE_TYPE) {
+        /* we can allocate more space for arguments as long as no add_*
+         * function has been called yet, mbr_ct will be added as an upvalue in
+         * the return processing later */
+        | call_rrp extern push_cdata, L_ARG, 0, mbr_ct
+        | sub rsp, 16
+        add_pointer(Dst, ct, &reg);
+    }
+    lua_pop(L, 1);
+#endif
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, (int) i);
+        mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mbr_ct->pointers || mbr_ct->is_reference) {
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            | call_rrrp extern check_typed_pointer, L_ARG, i, lua_upvalueindex(num_upvals), mbr_ct
+            add_pointer(Dst, ct, &reg);
+        } else {
+            switch (mbr_ct->type) {
+            case FUNCTION_PTR_TYPE:
+                lua_getuservalue(L, -1);
+                num_upvals += 2;
+                | call_rrrp extern check_typed_cfunction, L_ARG, i, lua_upvalueindex(num_upvals), mbr_ct
+                add_pointer(Dst, ct, &reg);
+                break;
+
+            case ENUM_TYPE:
+                lua_getuservalue(L, -1);
+                num_upvals += 2;
+                | call_rrrp, extern check_enum, L_ARG, i, lua_upvalueindex(num_upvals), mbr_ct
+                add_int(Dst, ct, &reg, 0);
+                break;
+
+            case INT8_TYPE:
+                | call_rr extern check_int32, L_ARG, i
+                if (mbr_ct->is_unsigned) {
+                    | movzx eax, al
+                } else {
+                    | movsx eax, al
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INT16_TYPE:
+                | call_rr extern check_int32, L_ARG, i
+                if (mbr_ct->is_unsigned) {
+                    | movzx eax, ax
+                } else {
+                    | movsx eax, ax
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case BOOL_TYPE:
+                | call_rr extern check_int32, L_ARG, i
+                | cmp eax, 0
+                | setne al
+                | movzx eax, al
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INT32_TYPE:
+                if (mbr_ct->is_unsigned) {
+                    | call_rr extern check_uint32, L_ARG, i
+                } else {
+                    | call_rr extern check_int32, L_ARG, i
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INTPTR_TYPE:
+                | call_rr extern check_uintptr, L_ARG, i
+                add_pointer(Dst, ct, &reg);
+                lua_pop(L, 1);
+                break;
+
+            case INT64_TYPE:
+                if (mbr_ct->is_unsigned) {
+                    | call_rr extern check_uint64, L_ARG, i
+                } else {
+                    | call_rr extern check_int64, L_ARG, i
+                }
+                add_int(Dst, ct, &reg, 1);
+                lua_pop(L, 1);
+                break;
+
+            case DOUBLE_TYPE:
+                | call_rr extern check_double, L_ARG, i
+                add_float(Dst, ct, &reg, 1);
+                lua_pop(L, 1);
+                break;
+
+            case COMPLEX_DOUBLE_TYPE:
+                /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit
+                 * there is a hidden first parameter that points to 16 bytes where
+                 * the returned arg is stored (this is popped by the called
+                 * function) */
+#if defined _WIN64 || defined __amd64__
+                | call_rr extern check_complex_double, L_ARG, i
+                add_float(Dst, ct, &reg, 1);
+                | movq xmm0, xmm1
+                add_float(Dst, ct, &reg, 1);
+#else
+                | lea rax, [rsp+reg.off]
+                | sub rsp, 4
+                | call_rrr extern check_complex_double, rax, L_ARG, i
+                reg.off += 16;
+#endif
+                lua_pop(L, 1);
+                break;
+
+            case FLOAT_TYPE:
+                | call_rr extern check_double, L_ARG, i
+                add_float(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case COMPLEX_FLOAT_TYPE:
+#if defined _WIN64 || defined __amd64__
+                | call_rr extern check_complex_float, L_ARG, i
+                /* complex floats are two floats packed into a double */
+                add_float(Dst, ct, &reg, 1);
+#else
+                /* returned complex floats use eax and edx */
+                | call_rr extern check_complex_float, L_ARG, i
+                | mov [rsp], eax
+                | fld dword [rsp]
+                add_float(Dst, ct, &reg, 0);
+                | mov [rsp], edx
+                | fld dword [rsp]
+                add_float(Dst, ct, &reg, 0);
+#endif
+                lua_pop(L, 1);
+                break;
+
+            default:
+                luaL_error(L, "NYI: call arg type");
+            }
+        }
+    }
+
+    if (ct->has_var_arg) {
+#ifdef _WIN64
+        |.if X64WIN
+        if (reg.regs < MAX_REGISTERS(ct)) {
+            assert(reg.regs == nargs);
+            | cmp TOP, MAX_REGISTERS(ct)
+            | jle >1
+            | // unpack onto stack
+            | mov rax, rsp
+            | add rax, 32 + 8*MAX_REGISTERS(ct)
+            | call_rrrr extern unpack_varargs_stack, L_ARG, MAX_REGISTERS(ct)+1, TOP, rax
+            | // unpack to registers
+            | mov rax, rsp
+            | add rax, 32 + 8*(reg.regs)
+            | call_rrrr extern unpack_varargs_reg, L_ARG, nargs+1, MAX_REGISTERS(ct), rax
+            | jmp >2
+            |1:
+            | // unpack just to registers
+            | mov rax, rsp
+            | add rax, 32 + 8*(reg.regs)
+            | call_rrrr extern unpack_varargs_reg, L_ARG, nargs+1, TOP, rax
+            |2:
+        } else {
+            | // unpack just to stack
+            | mov rax, rsp
+            | add rax, reg.off
+            | call_rrrr extern unpack_varargs_stack, L_ARG, nargs+1, TOP, rax
+        }
+
+        for (i = nargs; i < MAX_REGISTERS(ct); i++) {
+            reg.is_int[i] = reg.is_float[i] = 1;
+        }
+        reg.regs = MAX_REGISTERS(ct);
+#elif defined __amd64__
+        |.elif X64
+        if (reg.floats < MAX_FLOAT_REGISTERS(ct)) {
+            | mov rax, rsp
+            | add rax, 32 + 8*(MAX_INT_REGISTERS(ct) + reg.floats)
+            | call_rrrrr extern unpack_varargs_float, L_ARG, nargs+1, TOP, MAX_FLOAT_REGISTERS(ct) - reg.floats, rax
+        }
+
+        if (reg.ints < MAX_INT_REGISTERS(ct)) {
+            | mov rax, rsp
+            | add rax, 32 + 8*(reg.ints)
+            | call_rrrrr extern unpack_varargs_int, L_ARG, nargs+1, TOP, MAX_INT_REGISTERS(ct) - reg.ints, rax
+        }
+
+        | mov rax, rsp
+        | add rax, reg.off
+        | call_rrrrrr extern unpack_varargs_stack_skip, L_ARG, nargs+1, TOP, MAX_INT_REGISTERS(ct) - reg.ints, MAX_FLOAT_REGISTERS(ct) - reg.floats, rax
+
+        reg.floats = MAX_FLOAT_REGISTERS(ct);
+        reg.ints = MAX_INT_REGISTERS(ct);
+#else
+        |.else
+        | mov rax, rsp
+        | add rax, reg.off
+        | call_rrrr extern unpack_varargs_stack, L_ARG, nargs+1, TOP, rax
+        |.endif
+#endif
+    }
+
+    | mov64 rcx, perr
+    | mov eax, dword [rcx]
+    | call_r extern SetLastError, rax
+
+    /* remove the stack space to call local functions */
+    |.if X32WIN
+    | add rsp, 28 // SetLastError will have already popped 4
+    |.else
+    | add rsp, 32
+    |.endif
+
+#ifdef _WIN64
+    |.if X64WIN
+    switch (reg.regs) {
+    case 4:
+        if (reg.is_float[3]) {
+            | movq xmm3, qword [rsp + 8*3]
+        }
+        if (reg.is_int[3]) {
+            | mov r9, [rsp + 8*3]
+        }
+    case 3:
+        if (reg.is_float[2]) {
+            | movq xmm2, qword [rsp + 8*2]
+        }
+        if (reg.is_int[2]) {
+            | mov r8, [rsp + 8*2]
+        }
+    case 2:
+        if (reg.is_float[1]) {
+            | movq xmm1, qword [rsp + 8*1]
+        }
+        if (reg.is_int[1]) {
+            | mov rdx, [rsp + 8*1]
+        }
+    case 1:
+        if (reg.is_float[0]) {
+            | movq xmm0, qword [rsp]
+        }
+        if (reg.is_int[0]) {
+            | mov rcx, [rsp]
+        }
+    case 0:
+        break;
+    }
+
+    /* don't remove the space for the registers as we need 32 bytes of register overflow space */
+    assert(REGISTER_STACK_SPACE(ct) == 32);
+
+#elif defined __amd64__
+    |.elif X64
+    switch (reg.floats) {
+    case 8:
+        | movq xmm7, qword [rsp + 8*(MAX_INT_REGISTERS(ct)+7)]
+    case 7:
+        | movq xmm6, qword [rsp + 8*(MAX_INT_REGISTERS(ct)+6)]
+    case 6:
+        | movq xmm5, qword [rsp + 8*(MAX_INT_REGISTERS(ct)+5)]
+    case 5:
+        | movq xmm4, qword [rsp + 8*(MAX_INT_REGISTERS(ct)+4)]
+    case 4:
+        | movq xmm3, qword [rsp + 8*(MAX_INT_REGISTERS(ct)+3)]
+    case 3:
+        | movq xmm2, qword [rsp + 8*(MAX_INT_REGISTERS(ct)+2)]
+    case 2:
+        | movq xmm1, qword [rsp + 8*(MAX_INT_REGISTERS(ct)+1)]
+    case 1:
+        | movq xmm0, qword [rsp + 8*(MAX_INT_REGISTERS(ct))]
+    case 0:
+        break;
+    }
+
+    switch (reg.ints) {
+    case 6:
+        | mov r9, [rsp + 8*5]
+    case 5:
+        | mov r8, [rsp + 8*4]
+    case 4:
+        | mov rcx, [rsp + 8*3]
+    case 3:
+        | mov rdx, [rsp + 8*2]
+    case 2:
+        | mov rsi, [rsp + 8*1]
+    case 1:
+        | mov rdi, [rsp]
+    case 0:
+        break;
+    }
+
+    | add rsp, REGISTER_STACK_SPACE(ct)
+#else
+    |.else
+    if (ct->calling_convention == FAST_CALL) {
+        switch (reg.ints) {
+        case 2:
+            | mov edx, [rsp + 4]
+        case 1:
+            | mov ecx, [rsp]
+        case 0:
+            break;
+        }
+
+        | add rsp, REGISTER_STACK_SPACE(ct)
+    }
+    |.endif
+#endif
+
+#ifdef __amd64__
+    if (ct->has_var_arg) {
+        /* al stores an upper limit on the number of float register, note that
+         * its allowed to be more than the actual number of float registers used as
+         * long as its 0-8 */
+        |.if X64 and not X64WIN
+        | mov al, 8
+        |.endif
+    }
+#endif
+
+    | call extern FUNCTION
+    | sub rsp, 48 // 32 to be able to call local functions, 16 so we can store some local variables
+
+    /* note on windows X86 the stack may be only aligned to 4 (stdcall will
+     * have popped a multiple of 4 bytes), but we don't need 16 byte alignment on
+     * that platform
+     */
+
+    lua_rawgeti(L, ct_usr, 0);
+    mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+
+    if (mbr_ct->pointers || mbr_ct->is_reference || mbr_ct->type == INTPTR_TYPE) {
+        lua_getuservalue(L, -1);
+        num_upvals += 2;
+        | mov [rsp+32], rax // save the pointer
+        | get_errno
+        | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct
+        | mov rcx, [rsp+32]
+        | mov [rax], rcx // *(void**) cdata = val
+        | lua_return_arg
+
+    } else {
+        switch (mbr_ct->type) {
+        case FUNCTION_PTR_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            | mov [rsp+32], rax // save the function pointer
+            | get_errno
+            | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct
+            | mov rcx, [rsp+32]
+            | mov [rax], rcx // *(cfunction**) cdata = val
+            | lua_return_arg
+            break;
+
+        case INT64_TYPE:
+#if LUA_VERSION_NUM == 503
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                | lua_return_ulong
+            } else {
+                | lua_return_long
+            }
+#else
+            num_upvals++;
+            | // save the return value
+            |.if X64
+            | mov [rsp+32], rax
+            |.else
+            | mov [rsp+36], edx // high
+            | mov [rsp+32], eax // low
+            |.endif
+            |
+            | get_errno
+            | call_rrp extern push_cdata, L_ARG, 0, mbr_ct
+            |
+            | // *(int64_t*) cdata = val
+            |.if X64
+            | mov rcx, [rsp+32]
+            | mov [rax], rcx
+            |.else
+            | mov rcx, [rsp+36]
+            | mov rdx, [rsp+32]
+            | mov [rax+4], rcx
+            | mov [rax], rdx
+            |.endif
+            |
+            | lua_return_arg
+#endif
+            break;
+
+        case COMPLEX_FLOAT_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            |.if X64
+            | // complex floats are returned as two floats packed into xmm0
+            | movq qword [rsp+32], xmm0
+            |.else
+            | // complex floats are returned as floats in eax and edx
+            | mov [rsp+32], eax
+            | mov [rsp+36], edx
+            |.endif
+            |
+            | get_errno
+            | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct
+            |
+            | // ((complex_float*) cdata) = val
+            |.if X64
+            | mov rcx, [rsp+32]
+            | mov [rax], rcx
+            |.else
+            | mov ecx, [rsp+32]
+            | mov [rax], ecx
+            | mov ecx, [rsp+36]
+            | mov [rax+4], ecx
+            |.endif
+            |
+            | lua_return_arg
+            break;
+
+        case COMPLEX_DOUBLE_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            |.if X64
+            | // complex doubles are returned as xmm0 and xmm1
+            | movq qword [rsp+40], xmm1
+            | movq qword [rsp+32], xmm0
+            |
+            | get_errno
+            | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct
+            |
+            | // ((complex_double*) cdata)->real = val0
+            | // ((complex_double*) cdata)->imag = val1
+            | mov rcx, [rsp+40]
+            | mov [rax+8], rcx
+            | mov rcx, [rsp+32]
+            | mov [rax], rcx
+            |
+            |.else
+            | // On 32 bit we have already handled this by pushing a new cdata
+            | // and handing the cdata ptr in as the hidden first param, but
+            | // still need to add mbr_ct as an upval as its used earlier.
+            | // Hidden param was popped by called function, we need to realign.
+            | sub rsp, 4
+            | get_errno
+            |.endif
+            |
+            | lua_return_arg
+            break;
+
+        case VOID_TYPE:
+            lua_pop(L, 1);
+            | lua_return_void
+            break;
+
+        case BOOL_TYPE:
+            lua_pop(L, 1);
+            | lua_return_bool
+            break;
+
+        case INT8_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                | movzx eax, al
+            } else {
+                | movsx eax, al
+            }
+            | lua_return_int
+            break;
+
+        case INT16_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                | movzx eax, ax
+            } else {
+                | movsx eax, ax
+            }
+            | lua_return_int
+            break;
+
+        case INT32_TYPE:
+        case ENUM_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                | lua_return_uint
+            } else {
+                | lua_return_int
+            }
+            break;
+
+        case FLOAT_TYPE:
+            lua_pop(L, 1);
+            |.if X64
+            | cvtss2sd xmm0, xmm0
+            |.endif
+            | lua_return_double
+            break;
+
+        case DOUBLE_TYPE:
+            lua_pop(L, 1);
+            | lua_return_double
+            break;
+
+        default:
+            luaL_error(L, "NYI: call return type");
+        }
+    }
+
+    assert(lua_gettop(L) == top + num_upvals);
+    {
+        cfunction f = compile(Dst, L, func, LUA_NOREF);
+        /* add a callback as an upval so that the jitted code gets cleaned up when
+         * the function gets gc'd */
+        push_callback(L, f, func);
+        lua_pushcclosure(L, (lua_CFunction) f, num_upvals+1);
+    }
+}
+

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x86.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x86.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x86.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,1172 @@
+/*
+** This file has been pre-processed with DynASM.
+** http://luajit.org/dynasm.html
+** DynASM version 1.3.0, DynASM x86 version 1.3.0
+** DO NOT EDIT! The original file is in "call_x86.dasc".
+*/
+
+#if DASM_VERSION != 10300
+#error "Version mismatch between DynASM and included encoding engine"
+#endif
+
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+static const unsigned char build_actionlist[1915] = {
+  139,141,233,255,139,141,233,139,149,233,255,137,132,253,36,233,255,137,132,
+  253,36,233,137,148,253,36,233,255,221,133,233,255,217,133,233,255,252,243,
+  15,126,133,233,255,252,243,15,90,133,233,255,221,156,253,36,233,255,217,156,
+  253,36,233,255,102,15,214,132,253,36,233,255,252,242,15,90,192,102,15,214,
+  132,253,36,233,255,252,242,15,90,192,102,15,126,132,253,36,233,255,85,137,
+  229,87,129,252,236,239,255,137,77,252,248,137,85,252,244,255,191,237,255,
+  199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,0,255,199,68,36,8,237,
+  199,68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,251,1,0,255,199,
+  68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,0,199,68,36,8,237,199,68,
+  36,4,252,255,252,255,252,255,252,255,137,60,36,232,251,1,1,255,137,8,199,
+  68,36,4,252,254,252,255,252,255,252,255,137,60,36,232,251,1,2,255,199,68,
+  36,8,237,199,68,36,4,0,0,0,0,137,60,36,232,251,1,1,255,137,8,137,80,4,255,
+  137,8,255,102,15,214,0,255,217,24,255,217,88,4,255,221,24,255,221,88,8,255,
+  221,92,36,4,137,60,36,232,251,1,3,255,15,182,201,137,76,36,4,137,60,36,232,
+  251,1,4,255,15,182,201,255,15,190,201,255,137,76,36,4,137,60,36,232,251,1,
+  5,255,15,183,201,255,15,191,201,255,137,76,36,4,137,60,36,232,251,1,6,255,
+  199,68,36,12,0,0,0,0,199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,
+  7,255,199,68,36,8,237,199,68,36,4,252,254,252,255,252,255,252,255,137,60,
+  36,232,251,1,0,199,68,36,12,237,199,68,36,8,252,255,252,255,252,255,252,255,
+  199,68,36,4,252,254,252,255,252,255,252,255,137,60,36,232,251,1,8,137,68,
+  36,32,199,68,36,4,252,252,252,255,252,255,252,255,137,60,36,232,251,1,9,139,
+  68,36,32,255,199,68,36,8,237,199,68,36,4,252,254,252,255,252,255,252,255,
+  137,60,36,232,251,1,0,199,68,36,12,237,199,68,36,8,252,255,252,255,252,255,
+  252,255,199,68,36,4,252,254,252,255,252,255,252,255,137,60,36,232,251,1,10,
+  137,68,36,32,199,68,36,4,252,252,252,255,252,255,252,255,137,60,36,232,251,
+  1,9,139,68,36,32,255,199,68,36,4,252,254,252,255,252,255,252,255,137,60,36,
+  232,251,1,9,255,199,68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,
+  251,1,11,255,199,68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,251,
+  1,12,255,137,68,36,32,199,68,36,4,252,253,252,255,252,255,252,255,137,60,
+  36,232,251,1,9,139,68,36,32,255,199,68,36,4,252,255,252,255,252,255,252,255,
+  137,60,36,232,251,1,13,255,199,68,36,4,252,255,252,255,252,255,252,255,137,
+  60,36,232,251,1,14,255,137,68,36,32,137,84,36,36,199,68,36,4,252,253,252,
+  255,252,255,252,255,137,60,36,232,251,1,9,139,68,36,32,139,84,36,36,255,199,
+  68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,251,1,15,137,68,36,
+  32,199,68,36,4,252,253,252,255,252,255,252,255,137,60,36,232,251,1,9,139,
+  68,36,32,255,199,68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,251,
+  1,16,255,221,92,36,32,199,68,36,4,252,253,252,255,252,255,252,255,137,60,
+  36,232,251,1,9,221,68,36,32,255,199,68,36,4,252,255,252,255,252,255,252,255,
+  137,60,36,232,251,1,17,137,68,36,32,137,84,36,36,199,68,36,4,252,253,252,
+  255,252,255,252,255,137,60,36,232,251,1,9,139,68,36,32,139,84,36,36,255,199,
+  68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,251,1,18,102,15,214,
+  68,36,32,102,15,214,76,36,40,199,68,36,4,252,253,252,255,252,255,252,255,
+  137,60,36,232,251,1,9,252,243,15,126,68,36,32,252,243,15,126,76,36,40,255,
+  139,141,233,199,68,36,8,252,255,252,255,252,255,252,255,137,124,36,4,137,
+  12,36,232,251,1,18,131,252,236,4,199,68,36,4,252,253,252,255,252,255,252,
+  255,137,60,36,232,251,1,9,255,139,125,252,252,137,252,236,93,194,236,255,
+  85,137,229,87,86,139,189,233,131,252,236,16,137,60,36,232,251,1,19,137,198,
+  129,252,248,239,255,15,141,244,248,102,184,0,0,199,68,36,4,237,137,60,36,
+  232,251,1,20,248,2,15,142,244,247,102,184,0,0,199,68,36,4,237,137,60,36,232,
+  251,1,20,255,15,141,244,247,102,184,0,0,199,68,36,4,237,137,60,36,232,251,
+  1,20,255,248,1,255,193,224,4,41,196,129,252,236,239,255,199,68,36,8,237,199,
+  68,36,4,0,0,0,0,137,60,36,232,251,1,1,131,252,236,16,255,199,68,36,12,237,
+  199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,8,255,199,68,36,12,237,
+  199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,21,255,199,68,36,12,237,
+  199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,10,255,199,68,36,4,237,
+  137,60,36,232,251,1,12,255,15,182,192,255,15,190,192,255,15,183,192,255,15,
+  191,192,255,199,68,36,4,237,137,60,36,232,251,1,12,131,252,248,0,15,149,208,
+  15,182,192,255,199,68,36,4,237,137,60,36,232,251,1,11,255,199,68,36,4,237,
+  137,60,36,232,251,1,15,255,199,68,36,4,237,137,60,36,232,251,1,13,255,199,
+  68,36,4,237,137,60,36,232,251,1,14,255,199,68,36,4,237,137,60,36,232,251,
+  1,16,255,199,68,36,4,237,137,60,36,232,251,1,18,255,252,243,15,126,193,255,
+  141,132,253,36,233,131,252,236,4,199,68,36,8,237,137,124,36,4,137,4,36,232,
+  251,1,18,255,199,68,36,4,237,137,60,36,232,251,1,17,255,199,68,36,4,237,137,
+  60,36,232,251,1,17,137,4,36,217,4,36,255,137,20,36,217,4,36,255,137,224,129,
+  192,239,137,68,36,12,137,116,36,8,199,68,36,4,237,137,60,36,232,251,1,22,
+  255,185,237,139,1,137,4,36,232,251,1,23,255,131,196,32,255,139,148,253,36,
+  233,255,139,12,36,255,129,196,239,255,232,251,1,24,131,252,236,48,255,137,
+  68,36,32,232,251,1,25,185,237,137,1,199,68,36,8,237,199,68,36,4,237,137,60,
+  36,232,251,1,1,139,76,36,32,137,8,184,1,0,0,0,139,117,252,248,139,125,252,
+  252,137,252,236,93,195,255,137,68,36,32,232,251,1,25,185,237,137,1,139,68,
+  36,32,137,68,36,4,137,60,36,232,251,1,26,184,1,0,0,0,139,117,252,248,139,
+  125,252,252,137,252,236,93,195,255,137,84,36,36,137,68,36,32,232,251,1,25,
+  185,237,137,1,199,68,36,8,237,199,68,36,4,0,0,0,0,137,60,36,232,251,1,1,139,
+  76,36,36,139,84,36,32,137,72,4,137,16,184,1,0,0,0,139,117,252,248,139,125,
+  252,252,137,252,236,93,195,255,137,68,36,32,137,84,36,36,232,251,1,25,185,
+  237,137,1,199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,1,139,76,36,
+  32,137,8,139,76,36,36,137,72,4,184,1,0,0,0,139,117,252,248,139,125,252,252,
+  137,252,236,93,195,255,131,252,236,4,232,251,1,25,185,237,137,1,184,1,0,0,
+  0,139,117,252,248,139,125,252,252,137,252,236,93,195,255,232,251,1,25,185,
+  237,137,1,184,0,0,0,0,139,117,252,248,139,125,252,252,137,252,236,93,195,
+  255,15,182,192,137,68,36,32,232,251,1,25,185,237,137,1,139,68,36,32,137,68,
+  36,4,137,60,36,232,251,1,4,184,1,0,0,0,139,117,252,248,139,125,252,252,137,
+  252,236,93,195,255,137,68,36,32,232,251,1,25,185,237,137,1,139,68,36,32,137,
+  68,36,4,137,60,36,232,251,1,5,184,1,0,0,0,139,117,252,248,139,125,252,252,
+  137,252,236,93,195,255,137,68,36,32,232,251,1,25,185,237,137,1,139,68,36,
+  32,137,68,36,4,137,60,36,232,251,1,6,184,1,0,0,0,139,117,252,248,139,125,
+  252,252,137,252,236,93,195,255,221,92,36,4,232,251,1,25,185,237,137,1,137,
+  60,36,232,251,1,3,184,1,0,0,0,139,117,252,248,139,125,252,252,137,252,236,
+  93,195,255
+};
+
+static const char *const globnames[] = {
+  (const char *)0
+};
+static const char *const extnames[] = {
+  "lua_rawgeti",
+  "push_cdata",
+  "lua_remove",
+  "lua_pushnumber",
+  "lua_pushboolean",
+  "push_int",
+  "push_uint",
+  "lua_callk",
+  "check_typed_pointer",
+  "lua_settop",
+  "check_enum",
+  "check_uint32",
+  "check_int32",
+  "check_uint64",
+  "check_int64",
+  "check_uintptr",
+  "check_double",
+  "check_complex_float",
+  "check_complex_double",
+  "lua_gettop",
+  "luaL_error",
+  "check_typed_cfunction",
+  "unpack_varargs_stack",
+  "SetLastError",
+  "FUNCTION",
+  "GetLastError",
+  "lua_pushinteger",
+  (const char *)0
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#if defined _WIN64 || defined __amd64__
+#define JUMP_SIZE 14
+#else
+#define JUMP_SIZE 4
+#endif
+
+#define MIN_BRANCH INT32_MIN
+#define MAX_BRANCH INT32_MAX
+#define BRANCH_OFF 4
+
+static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code)
+{
+    /* The jump code is the function pointer followed by a stub to call the
+     * function pointer. The stub exists in 64 bit so we can jump to functions
+     * with an offset greater than 2 GB.
+     *
+     * Note we have to manually set this up since there are commands buffered
+     * in the jit state and dynasm doesn't support rip relative addressing.
+     *
+     * eg on 64 bit:
+     * 0-8: function ptr
+     * 8-14: jmp aword [rip-14]
+     *
+     * for 32 bit we only set the function ptr as it can always fit in a 32
+     * bit displacement
+     */
+#if defined _WIN64 || defined __amd64__
+    *(cfunction*) code = func;
+    code[8] = 0xFF; /* FF /4 operand for jmp */
+    code[9] = 0x25; /* RIP displacement */
+    *(int32_t*) &code[10] = -14;
+#else
+    *(cfunction*) code = func;
+#endif
+}
+
+void compile_globals(struct jit* jit, lua_State* L)
+{
+    struct jit* Dst = jit;
+    int* perr = &jit->last_errno;
+    dasm_setup(Dst, build_actionlist);
+
+    /* Note: since the return code uses EBP to reset the stack pointer, we
+     * don't have to track the amount of stack space used. It also means we
+     * can handle stdcall and cdecl with the same code.
+     */
+
+    /* Note the various call_* functions want 32 bytes of 16 byte aligned
+     * stack
+     */
+
+    compile(Dst, L, NULL, LUA_NOREF);
+}
+
+int x86_return_size(lua_State* L, int usr, const struct ctype* ct)
+{
+    int ret = 0;
+    const struct ctype* mt;
+
+    if (ct->calling_convention != C_CALL) {
+        size_t i;
+        size_t argn = lua_rawlen(L, usr);
+        for (i = 1; i <= argn; i++) {
+            lua_rawgeti(L, usr, (int) i);
+            mt = (const struct ctype*) lua_touserdata(L, -1);
+
+            if (mt->pointers || mt->is_reference) {
+                ret += sizeof(void*);
+            } else {
+                switch (mt->type) {
+                case DOUBLE_TYPE:
+                case COMPLEX_FLOAT_TYPE:
+                case INT64_TYPE:
+                    ret += 8;
+                    break;
+                case COMPLEX_DOUBLE_TYPE:
+                    ret += 16;
+                    break;
+                case INTPTR_TYPE:
+                    ret += sizeof(intptr_t);
+                    break;
+                case FUNCTION_PTR_TYPE:
+                    ret += sizeof(cfunction);
+                    break;
+                case BOOL_TYPE:
+                case FLOAT_TYPE:
+                case INT8_TYPE:
+                case INT16_TYPE:
+                case INT32_TYPE:
+                case ENUM_TYPE:
+                    ret += 4;
+                    break;
+                default:
+                    return luaL_error(L, "NYI - argument type");
+                }
+            }
+
+            lua_pop(L, 1);
+        }
+    }
+
+#if !defined _WIN64 && !defined __amd64__
+    lua_rawgeti(L, usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) {
+        ret += sizeof(void*);
+    }
+    lua_pop(L, 1);
+#endif
+
+    return ret;
+}
+
+#ifdef _WIN64
+#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */
+
+#elif defined __amd64__
+#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */
+#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */
+
+#else
+#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0)
+#define MAX_FLOAT_REGISTERS(ct) 0
+#endif
+
+struct reg_alloc {
+#ifdef _WIN64
+    int regs;
+    int is_float[4];
+    int is_int[4];
+#else
+    int floats;
+    int ints;
+#endif
+    int off;
+};
+
+#ifdef _WIN64
+#define REGISTER_STACK_SPACE(ct) (4*8)
+#elif defined __amd64__
+#define REGISTER_STACK_SPACE(ct) (14*8)
+#else
+#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15)
+#endif
+
+/* Fastcall:
+ * Uses ecx, edx as first two int registers
+ * Everything else on stack (include 64bit ints)
+ * No overflow stack space
+ * Pops the stack before returning
+ * Returns int in eax, float in ST0
+ * We use the same register allocation logic as posix x64 with 2 int regs and 0 float regs
+ */
+
+static void get_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_int64)
+{
+    /* grab the register from the shadow space */
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        dasm_put(Dst, 0, 16 + 8*reg->regs);
+        reg->regs++;
+    }
+#elif __amd64__
+    if (reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 0, - 80 - 8*reg->ints);
+        reg->ints++;
+    }
+#else
+    if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 0, - 8 - 4*reg->ints);
+        reg->ints++;
+    }
+#endif
+    else if (is_int64) {
+        dasm_put(Dst, 4, reg->off, reg->off + 4);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 0, reg->off);
+        reg->off += 4;
+    }
+}
+
+static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_int64)
+{
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        dasm_put(Dst, 11, 32 + 8*(reg->regs));
+        reg->is_int[reg->regs++] = 1;
+    }
+#elif __amd64__
+    if (reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 11, 32 + 8*reg->ints);
+        reg->ints++;
+    }
+#else
+    if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) {
+        dasm_put(Dst, 11, 32 + 4*reg->ints);
+        reg->ints++;
+    }
+#endif
+    else {
+#if defined _WIN64 || defined __amd64__
+        if (reg->off % 8 != 0) {
+            reg->off += 8 - (reg->off % 8);
+        }
+#endif
+        if (is_int64) {
+            dasm_put(Dst, 17, reg->off, reg->off + 4);
+            reg->off += 8;
+        } else {
+            dasm_put(Dst, 11, reg->off);
+            reg->off += 4;
+        }
+    }
+}
+
+static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double)
+{
+#if !defined _WIN64 && !defined __amd64__
+    assert(MAX_FLOAT_REGISTERS(ct) == 0);
+    if (is_double) {
+        dasm_put(Dst, 28, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 32, reg->off);
+        reg->off += 4;
+    }
+#else
+    int off;
+
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        off = -16 - 8*reg->regs;
+        reg->regs++;
+    }
+#else
+    if (reg->floats < MAX_FLOAT_REGISTERS(ct)) {
+        off = -16 - 8*reg->floats;
+        reg->floats++;
+    }
+#endif
+    else {
+        off = reg->off;
+        reg->off += is_double ? 8 : 4;
+    }
+
+    if (is_double) {
+        dasm_put(Dst, 36, off);
+    } else {
+        dasm_put(Dst, 43, off);
+    }
+#endif
+}
+
+static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double)
+{
+#if !defined _WIN64 && !defined __amd64__
+    assert(MAX_FLOAT_REGISTERS(ct) == 0);
+    if (is_double) {
+        dasm_put(Dst, 50, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 56, reg->off);
+        reg->off += 4;
+    }
+#else
+
+#ifdef _WIN64
+    if (reg->regs < MAX_REGISTERS(ct)) {
+        if (is_double) {
+            dasm_put(Dst, 62, 32 + 8*(reg->regs));
+        } else {
+            dasm_put(Dst, 70, 32 + 8*(reg->regs));
+        }
+        reg->is_float[reg->regs++] = 1;
+    }
+#else
+    if (reg->floats < MAX_FLOAT_REGISTERS(ct)) {
+        if (is_double) {
+            dasm_put(Dst, 62, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats));
+        } else {
+            dasm_put(Dst, 70, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats));
+        }
+        reg->floats++;
+    }
+#endif
+
+    else if (is_double) {
+        dasm_put(Dst, 62, reg->off);
+        reg->off += 8;
+    } else {
+        dasm_put(Dst, 83, reg->off);
+        reg->off += 4;
+    }
+#endif
+}
+
+#if defined _WIN64 || defined __amd64__
+#define add_pointer(jit, ct, reg) add_int(jit, ct, reg, 1)
+#define get_pointer(jit, ct, reg) get_int(jit, ct, reg, 1)
+#else
+#define add_pointer(jit, ct, reg) add_int(jit, ct, reg, 0)
+#define get_pointer(jit, ct, reg) get_int(jit, ct, reg, 0)
+#endif
+
+cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct)
+{
+    int i, nargs;
+    cfunction* pf;
+    struct ctype ct2 = *ct;
+    const struct ctype* mt;
+    struct reg_alloc reg;
+    int num_upvals = 0;
+    int top = lua_gettop(L);
+    struct jit* Dst = get_jit(L);
+    int ref;
+    int hidden_arg_off = 0;
+
+    ct_usr = lua_absindex(L, ct_usr);
+    fidx = lua_absindex(L, fidx);
+
+    assert(lua_isnil(L, fidx) || lua_isfunction(L, fidx));
+
+    memset(&reg, 0, sizeof(reg));
+#ifdef _WIN64
+    reg.off = 16 + REGISTER_STACK_SPACE(ct); /* stack registers are above the shadow space */
+#elif __amd64__
+    reg.off = 16;
+#else
+    reg.off = 8;
+#endif
+
+    dasm_setup(Dst, build_actionlist);
+
+    // add a table to store ctype and function upvalues
+    // callback_set assumes the first value is the lua function
+    nargs = (int) lua_rawlen(L, ct_usr);
+    lua_newtable(L);
+    lua_pushvalue(L, -1);
+    ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+    if (ct->has_var_arg) {
+        luaL_error(L, "can't create callbacks with varargs");
+    }
+
+    // setup a stack frame to hold args for the call into lua_call
+
+    dasm_put(Dst, 96, 4 + 16 + 32 + REGISTER_STACK_SPACE(ct));
+    if (ct->calling_convention == FAST_CALL) {
+        dasm_put(Dst, 105);
+    }
+
+    // hardcode the lua_State* value into the assembly
+    dasm_put(Dst, 114, L);
+
+    /* get the upval table */
+    dasm_put(Dst, 117, ref, LUA_REGISTRYINDEX);
+
+    /* get the lua function */
+    lua_pushvalue(L, fidx);
+    lua_rawseti(L, -2, ++num_upvals);
+    assert(num_upvals == CALLBACK_FUNC_USR_IDX);
+    dasm_put(Dst, 135, num_upvals);
+
+#if !defined _WIN64 && !defined __amd64__
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) {
+        hidden_arg_off = reg.off;
+        reg.off += sizeof(void*);
+    }
+    lua_pop(L, 1);
+#else
+    (void) hidden_arg_off;
+#endif
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, i);
+        mt = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mt->pointers || mt->is_reference) {
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+            /* on the lua stack in the callback:
+             * upval tbl, lua func, i-1 args
+             */
+            dasm_put(Dst, 160, num_upvals-1, -i-1, mt);
+            get_pointer(Dst, ct, &reg);
+            dasm_put(Dst, 202);
+        } else {
+            switch (mt->type) {
+            case INT64_TYPE:
+                lua_getuservalue(L, -1);
+                lua_rawseti(L, -3, ++num_upvals); /* mt */
+                lua_pop(L, 1);
+                dasm_put(Dst, 224, mt);
+                get_int(Dst, ct, &reg, 1);
+                dasm_put(Dst, 245);
+                break;
+
+            case INTPTR_TYPE:
+                lua_getuservalue(L, -1);
+                lua_rawseti(L, -3, ++num_upvals); /* mt */
+                lua_pop(L, 1);
+                dasm_put(Dst, 224, mt);
+                get_pointer(Dst, ct, &reg);
+                dasm_put(Dst, 251);
+                break;
+
+            case COMPLEX_FLOAT_TYPE:
+                lua_pop(L, 1);
+#if defined _WIN64 || defined __amd64__
+                /* complex floats are two floats packed into a double */
+                dasm_put(Dst, 224, mt);
+                get_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 254);
+#else
+                /* complex floats are real followed by imag on the stack */
+                dasm_put(Dst, 224, mt);
+                get_float(Dst, ct, &reg, 0);
+                dasm_put(Dst, 259);
+                get_float(Dst, ct, &reg, 0);
+                dasm_put(Dst, 262);
+#endif
+                break;
+
+            case COMPLEX_DOUBLE_TYPE:
+                lua_pop(L, 1);
+                dasm_put(Dst, 224, mt);
+                /* real */
+                get_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 266);
+                /* imag */
+                get_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 269);
+                break;
+
+            case FLOAT_TYPE:
+            case DOUBLE_TYPE:
+                lua_pop(L, 1);
+                get_float(Dst, ct, &reg, mt->type == DOUBLE_TYPE);
+                dasm_put(Dst, 273);
+                break;
+
+            case BOOL_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                dasm_put(Dst, 285);
+                break;
+
+            case INT8_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 300);
+                } else {
+                    dasm_put(Dst, 304);
+                }
+                dasm_put(Dst, 308);
+                break;
+
+            case INT16_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 320);
+                } else {
+                    dasm_put(Dst, 324);
+                }
+                dasm_put(Dst, 308);
+                break;
+
+            case ENUM_TYPE:
+            case INT32_TYPE:
+                lua_pop(L, 1);
+                get_int(Dst, ct, &reg, 0);
+                if (mt->is_unsigned) {
+                    dasm_put(Dst, 328);
+                } else {
+                    dasm_put(Dst, 308);
+                }
+                break;
+
+            default:
+                luaL_error(L, "NYI: callback arg type");
+            }
+        }
+    }
+
+    lua_rawgeti(L, ct_usr, 0);
+    mt = (const struct ctype*) lua_touserdata(L, -1);
+
+    dasm_put(Dst, 340, (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, nargs);
+
+    // Unpack the return argument if not "void", also clean-up the lua stack
+    // to remove the return argument and bind table. Use lua_settop rather
+    // than lua_pop as lua_pop is implemented as a macro.
+    if (mt->pointers || mt->is_reference) {
+        lua_getuservalue(L, -1);
+        lua_rawseti(L, -3, ++num_upvals); /* usr value */
+        lua_rawseti(L, -2, ++num_upvals); /* mt */
+        dasm_put(Dst, 366, num_upvals-1, mt);
+
+    } else {
+        switch (mt->type) {
+        case ENUM_TYPE:
+            lua_getuservalue(L, -1);
+            lua_rawseti(L, -3, ++num_upvals); /* usr value */
+            lua_rawseti(L, -2, ++num_upvals); /* mt */
+            dasm_put(Dst, 454, num_upvals-1, mt);
+            break;
+
+        case VOID_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 542);
+            break;
+
+        case BOOL_TYPE:
+        case INT8_TYPE:
+        case INT16_TYPE:
+        case INT32_TYPE:
+            lua_pop(L, 1);
+            if (mt->is_unsigned) {
+                dasm_put(Dst, 562);
+            } else {
+                dasm_put(Dst, 582);
+            }
+            dasm_put(Dst, 602);
+            break;
+
+        case INT64_TYPE:
+            lua_pop(L, 1);
+
+            if (mt->is_unsigned) {
+                dasm_put(Dst, 630);
+            } else {
+                dasm_put(Dst, 650);
+            }
+
+            dasm_put(Dst, 670);
+            break;
+
+        case INTPTR_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 706);
+            break;
+
+        case FLOAT_TYPE:
+        case DOUBLE_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 753);
+            if (mt->type == FLOAT_TYPE) {
+            } else {
+            }
+            dasm_put(Dst, 773);
+            break;
+
+        case COMPLEX_FLOAT_TYPE:
+            lua_pop(L, 1);
+#if !defined HAVE_COMPLEX
+            luaL_error(L, "ffi lib compiled without complex number support");
+#endif
+            /* on 64 bit complex floats are two floats packed into a double,
+             * on 32 bit returned complex floats use eax and edx */
+            dasm_put(Dst, 801);
+            break;
+
+        case COMPLEX_DOUBLE_TYPE:
+            lua_pop(L, 1);
+#if !defined HAVE_COMPLEX
+            luaL_error(L, "ffi lib compiled without complex number support");
+#endif
+            /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit
+             * there is a hidden first parameter that points to 16 bytes where
+             * the returned arg is stored which is popped by the called
+             * function */
+#if defined _WIN64 || defined __amd64__
+            dasm_put(Dst, 856);
+#else
+            dasm_put(Dst, 921, hidden_arg_off);
+#endif
+            break;
+
+        default:
+            luaL_error(L, "NYI: callback return type");
+        }
+    }
+
+    dasm_put(Dst, 971, x86_return_size(L, ct_usr, ct));
+
+    lua_pop(L, 1); /* upval table - already in registry */
+    assert(lua_gettop(L) == top);
+
+    ct2.is_jitted = 1;
+    pf = (cfunction*) push_cdata(L, ct_usr, &ct2);
+    *pf = compile(Dst, L, NULL, ref);
+
+    assert(lua_gettop(L) == top + 1);
+
+    return *pf;
+}
+
+void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct)
+{
+    size_t i, nargs;
+    int num_upvals;
+    const struct ctype* mbr_ct;
+    struct jit* Dst = get_jit(L);
+    struct reg_alloc reg;
+    void* p;
+    int top = lua_gettop(L);
+    int* perr = &Dst->last_errno;
+
+    ct_usr = lua_absindex(L, ct_usr);
+
+    memset(&reg, 0, sizeof(reg));
+    reg.off = 32 + REGISTER_STACK_SPACE(ct);
+
+    dasm_setup(Dst, build_actionlist);
+
+    p = push_cdata(L, ct_usr, ct);
+    *(cfunction*) p = func;
+    num_upvals = 1;
+
+    nargs = lua_rawlen(L, ct_usr);
+
+    if (ct->calling_convention != C_CALL && ct->has_var_arg) {
+        luaL_error(L, "vararg is only allowed with the c calling convention");
+    }
+
+    dasm_put(Dst, 982, 8, nargs);
+    if (!ct->has_var_arg) {
+        dasm_put(Dst, 1008, (ptrdiff_t)("too few arguments"), (ptrdiff_t)("too many arguments"));
+    } else {
+        dasm_put(Dst, 1051, (ptrdiff_t)("too few arguments"));
+    }
+
+    dasm_put(Dst, 1072);
+
+    /* no need to zero extend eax returned by lua_gettop to rax as x86-64
+     * preguarentees that the upper 32 bits will be zero */
+    dasm_put(Dst, 1075, 32 + REGISTER_STACK_SPACE(ct));
+
+#if !defined _WIN64 && !defined __amd64__
+    /* Returned complex doubles require a hidden first parameter where the
+     * data is stored, which is popped by the calling code. */
+    lua_rawgeti(L, ct_usr, 0);
+    mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+    if (!mbr_ct->pointers && !mbr_ct->is_reference && mbr_ct->type == COMPLEX_DOUBLE_TYPE) {
+        /* we can allocate more space for arguments as long as no add_*
+         * function has been called yet, mbr_ct will be added as an upvalue in
+         * the return processing later */
+        dasm_put(Dst, 1085, mbr_ct);
+        add_pointer(Dst, ct, &reg);
+    }
+    lua_pop(L, 1);
+#endif
+
+    for (i = 1; i <= nargs; i++) {
+        lua_rawgeti(L, ct_usr, (int) i);
+        mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+
+        if (mbr_ct->pointers || mbr_ct->is_reference) {
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1110, mbr_ct, lua_upvalueindex(num_upvals), i);
+            add_pointer(Dst, ct, &reg);
+        } else {
+            switch (mbr_ct->type) {
+            case FUNCTION_PTR_TYPE:
+                lua_getuservalue(L, -1);
+                num_upvals += 2;
+                dasm_put(Dst, 1133, mbr_ct, lua_upvalueindex(num_upvals), i);
+                add_pointer(Dst, ct, &reg);
+                break;
+
+            case ENUM_TYPE:
+                lua_getuservalue(L, -1);
+                num_upvals += 2;
+                dasm_put(Dst, 1156, mbr_ct, lua_upvalueindex(num_upvals), i);
+                add_int(Dst, ct, &reg, 0);
+                break;
+
+            case INT8_TYPE:
+                dasm_put(Dst, 1179, i);
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1192);
+                } else {
+                    dasm_put(Dst, 1196);
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INT16_TYPE:
+                dasm_put(Dst, 1179, i);
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1200);
+                } else {
+                    dasm_put(Dst, 1204);
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case BOOL_TYPE:
+                dasm_put(Dst, 1208, i);
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INT32_TYPE:
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1231, i);
+                } else {
+                    dasm_put(Dst, 1179, i);
+                }
+                add_int(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case INTPTR_TYPE:
+                dasm_put(Dst, 1244, i);
+                add_pointer(Dst, ct, &reg);
+                lua_pop(L, 1);
+                break;
+
+            case INT64_TYPE:
+                if (mbr_ct->is_unsigned) {
+                    dasm_put(Dst, 1257, i);
+                } else {
+                    dasm_put(Dst, 1270, i);
+                }
+                add_int(Dst, ct, &reg, 1);
+                lua_pop(L, 1);
+                break;
+
+            case DOUBLE_TYPE:
+                dasm_put(Dst, 1283, i);
+                add_float(Dst, ct, &reg, 1);
+                lua_pop(L, 1);
+                break;
+
+            case COMPLEX_DOUBLE_TYPE:
+                /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit
+                 * there is a hidden first parameter that points to 16 bytes where
+                 * the returned arg is stored (this is popped by the called
+                 * function) */
+#if defined _WIN64 || defined __amd64__
+                dasm_put(Dst, 1296, i);
+                add_float(Dst, ct, &reg, 1);
+                dasm_put(Dst, 1309);
+                add_float(Dst, ct, &reg, 1);
+#else
+                dasm_put(Dst, 1315, reg.off, i);
+                reg.off += 16;
+#endif
+                lua_pop(L, 1);
+                break;
+
+            case FLOAT_TYPE:
+                dasm_put(Dst, 1283, i);
+                add_float(Dst, ct, &reg, 0);
+                lua_pop(L, 1);
+                break;
+
+            case COMPLEX_FLOAT_TYPE:
+#if defined _WIN64 || defined __amd64__
+                dasm_put(Dst, 1341, i);
+                /* complex floats are two floats packed into a double */
+                add_float(Dst, ct, &reg, 1);
+#else
+                /* returned complex floats use eax and edx */
+                dasm_put(Dst, 1354, i);
+                add_float(Dst, ct, &reg, 0);
+                dasm_put(Dst, 1373);
+                add_float(Dst, ct, &reg, 0);
+#endif
+                lua_pop(L, 1);
+                break;
+
+            default:
+                luaL_error(L, "NYI: call arg type");
+            }
+        }
+    }
+
+    if (ct->has_var_arg) {
+#ifdef _WIN64
+        if (reg.regs < MAX_REGISTERS(ct)) {
+            assert(reg.regs == nargs);
+        } else {
+        }
+
+        for (i = nargs; i < MAX_REGISTERS(ct); i++) {
+            reg.is_int[i] = reg.is_float[i] = 1;
+        }
+        reg.regs = MAX_REGISTERS(ct);
+#elif defined __amd64__
+        if (reg.floats < MAX_FLOAT_REGISTERS(ct)) {
+        }
+
+        if (reg.ints < MAX_INT_REGISTERS(ct)) {
+        }
+
+
+        reg.floats = MAX_FLOAT_REGISTERS(ct);
+        reg.ints = MAX_INT_REGISTERS(ct);
+#else
+        dasm_put(Dst, 1380, reg.off, nargs+1);
+#endif
+    }
+
+    dasm_put(Dst, 1406, perr);
+
+    /* remove the stack space to call local functions */
+    dasm_put(Dst, 1418);
+
+#ifdef _WIN64
+    switch (reg.regs) {
+    case 4:
+        if (reg.is_float[3]) {
+        }
+        if (reg.is_int[3]) {
+        }
+    case 3:
+        if (reg.is_float[2]) {
+        }
+        if (reg.is_int[2]) {
+        }
+    case 2:
+        if (reg.is_float[1]) {
+        }
+        if (reg.is_int[1]) {
+        }
+    case 1:
+        if (reg.is_float[0]) {
+        }
+        if (reg.is_int[0]) {
+        }
+    case 0:
+        break;
+    }
+
+    /* don't remove the space for the registers as we need 32 bytes of register overflow space */
+    assert(REGISTER_STACK_SPACE(ct) == 32);
+
+#elif defined __amd64__
+    switch (reg.floats) {
+    case 8:
+    case 7:
+    case 6:
+    case 5:
+    case 4:
+    case 3:
+    case 2:
+    case 1:
+    case 0:
+        break;
+    }
+
+    switch (reg.ints) {
+    case 6:
+    case 5:
+    case 4:
+    case 3:
+    case 2:
+    case 1:
+    case 0:
+        break;
+    }
+
+#else
+    if (ct->calling_convention == FAST_CALL) {
+        switch (reg.ints) {
+        case 2:
+            dasm_put(Dst, 1422, 4);
+        case 1:
+            dasm_put(Dst, 1428);
+        case 0:
+            break;
+        }
+
+        dasm_put(Dst, 1432, REGISTER_STACK_SPACE(ct));
+    }
+#endif
+
+#ifdef __amd64__
+    if (ct->has_var_arg) {
+        /* al stores an upper limit on the number of float register, note that
+         * its allowed to be more than the actual number of float registers used as
+         * long as its 0-8 */
+    }
+#endif
+
+    dasm_put(Dst, 1436);
+
+    /* note on windows X86 the stack may be only aligned to 4 (stdcall will
+     * have popped a multiple of 4 bytes), but we don't need 16 byte alignment on
+     * that platform
+     */
+
+    lua_rawgeti(L, ct_usr, 0);
+    mbr_ct = (const struct ctype*) lua_touserdata(L, -1);
+
+    if (mbr_ct->pointers || mbr_ct->is_reference || mbr_ct->type == INTPTR_TYPE) {
+        lua_getuservalue(L, -1);
+        num_upvals += 2;
+        dasm_put(Dst, 1445, perr, mbr_ct, lua_upvalueindex(num_upvals));
+
+    } else {
+        switch (mbr_ct->type) {
+        case FUNCTION_PTR_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1445, perr, mbr_ct, lua_upvalueindex(num_upvals));
+            break;
+
+        case INT64_TYPE:
+#if LUA_VERSION_NUM == 503
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1499, perr);
+            } else {
+                dasm_put(Dst, 1499, perr);
+            }
+#else
+            num_upvals++;
+            dasm_put(Dst, 1545, perr, mbr_ct);
+#endif
+            break;
+
+        case COMPLEX_FLOAT_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1613, perr, mbr_ct, lua_upvalueindex(num_upvals));
+            break;
+
+        case COMPLEX_DOUBLE_TYPE:
+            lua_getuservalue(L, -1);
+            num_upvals += 2;
+            dasm_put(Dst, 1678, perr);
+            break;
+
+        case VOID_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 1709, perr);
+            break;
+
+        case BOOL_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 1736, perr);
+            break;
+
+        case INT8_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1192);
+            } else {
+                dasm_put(Dst, 1196);
+            }
+            dasm_put(Dst, 1785, perr);
+            break;
+
+        case INT16_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1200);
+            } else {
+                dasm_put(Dst, 1204);
+            }
+            dasm_put(Dst, 1785, perr);
+            break;
+
+        case INT32_TYPE:
+        case ENUM_TYPE:
+            lua_pop(L, 1);
+            if (mbr_ct->is_unsigned) {
+                dasm_put(Dst, 1831, perr);
+            } else {
+                dasm_put(Dst, 1785, perr);
+            }
+            break;
+
+        case FLOAT_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 1877, perr);
+            break;
+
+        case DOUBLE_TYPE:
+            lua_pop(L, 1);
+            dasm_put(Dst, 1877, perr);
+            break;
+
+        default:
+            luaL_error(L, "NYI: call return type");
+        }
+    }
+
+    assert(lua_gettop(L) == top + num_upvals);
+    {
+        cfunction f = compile(Dst, L, func, LUA_NOREF);
+        /* add a callback as an upval so that the jitted code gets cleaned up when
+         * the function gets gc'd */
+        push_callback(L, f, func);
+        lua_pushcclosure(L, (lua_CFunction) f, num_upvals+1);
+    }
+}
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/call_x86.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/ctype.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/ctype.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/ctype.c	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,272 @@
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+#include "ffi.h"
+
+static int to_define_key;
+
+static void update_on_definition(lua_State* L, int ct_usr, int ct_idx)
+{
+    ct_usr = lua_absindex(L, ct_usr);
+    ct_idx = lua_absindex(L, ct_idx);
+
+    lua_pushlightuserdata(L, &to_define_key);
+    lua_rawget(L, ct_usr);
+
+    if (lua_isnil(L, -1)) {
+        lua_pop(L, 1); /* pop the nil */
+
+        /* {} */
+        lua_newtable(L);
+
+        /* {__mode='k'} */
+        lua_newtable(L);
+        lua_pushliteral(L, "k");
+        lua_setfield(L, -2, "__mode");
+
+        /* setmetatable({}, {__mode='k'}) */
+        lua_setmetatable(L, -2);
+
+        /* usr[TO_UPDATE_KEY] = setmetatable({}, {__mode='k'}) */
+        lua_pushlightuserdata(L, &to_define_key);
+        lua_pushvalue(L, -2);
+        lua_rawset(L, ct_usr);
+
+        /* leave the table on the stack */
+    }
+
+    /* to_update[ctype or cdata] = true */
+    lua_pushvalue(L, ct_idx);
+    lua_pushboolean(L, 1);
+    lua_rawset(L, -3);
+
+    /* pop the to_update table */
+    lua_pop(L, 1);
+}
+
+void set_defined(lua_State* L, int ct_usr, struct ctype* ct)
+{
+    ct_usr = lua_absindex(L, ct_usr);
+
+    ct->is_defined = 1;
+
+    /* update ctypes and cdatas that were created before the definition came in */
+    lua_pushlightuserdata(L, &to_define_key);
+    lua_rawget(L, ct_usr);
+
+    if (!lua_isnil(L, -1)) {
+        lua_pushnil(L);
+
+        while (lua_next(L, -2)) {
+            struct ctype* upd = (struct ctype*) lua_touserdata(L, -2);
+            upd->base_size = ct->base_size;
+            upd->align_mask = ct->align_mask;
+            upd->is_defined = 1;
+            upd->is_variable_struct = ct->is_variable_struct;
+            upd->variable_increment = ct->variable_increment;
+            assert(!upd->variable_size_known);
+            lua_pop(L, 1);
+        }
+
+        lua_pop(L, 1);
+        /* usr[TO_UPDATE_KEY] = nil */
+        lua_pushlightuserdata(L, &to_define_key);
+        lua_pushnil(L);
+        lua_rawset(L, ct_usr);
+    } else {
+        lua_pop(L, 1);
+    }
+}
+
+struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct)
+{
+    struct ctype* ret;
+    ct_usr = lua_absindex(L, ct_usr);
+
+    ret = (struct ctype*) lua_newuserdata(L, sizeof(struct ctype));
+    *ret = *ct;
+
+    push_upval(L, &ctype_mt_key);
+    lua_setmetatable(L, -2);
+
+#if LUA_VERSION_NUM == 501
+    if (!ct_usr || lua_isnil(L, ct_usr)) {
+        push_upval(L, &niluv_key);
+        lua_setfenv(L, -2);
+    }
+#endif
+
+    if (ct_usr && !lua_isnil(L, ct_usr)) {
+        lua_pushvalue(L, ct_usr);
+        lua_setuservalue(L, -2);
+    }
+
+    if (!ct->is_defined && ct_usr && !lua_isnil(L, ct_usr)) {
+        update_on_definition(L, ct_usr, -1);
+    }
+
+    return ret;
+}
+
+size_t ctype_size(lua_State* L, const struct ctype* ct)
+{
+    if (ct->pointers - ct->is_array) {
+        return sizeof(void*) * (ct->is_array ? ct->array_size : 1);
+
+    } else if (!ct->is_defined || ct->type == VOID_TYPE) {
+        return luaL_error(L, "can't calculate size of an undefined type");
+
+    } else if (ct->variable_size_known) {
+        assert(ct->is_variable_struct && !ct->is_array);
+        return ct->base_size + ct->variable_increment;
+
+    } else if (ct->is_variable_array || ct->is_variable_struct) {
+        return luaL_error(L, "internal error: calc size of variable type with unknown size");
+
+    } else {
+        return ct->base_size * (ct->is_array ? ct->array_size : 1);
+    }
+}
+
+void* push_cdata(lua_State* L, int ct_usr, const struct ctype* ct)
+{
+    struct cdata* cd;
+    size_t sz = ct->is_reference ? sizeof(void*) : ctype_size(L, ct);
+    ct_usr = lua_absindex(L, ct_usr);
+
+    /* This is to stop valgrind from complaining. Bitfields are accessed in 8
+     * byte chunks so that the code doesn't have to deal with different access
+     * patterns, but this means that occasionally it will read past the end of
+     * the struct. As its not setting the bits past the end (only reading and
+     * then writing the bits back) and the read is aligned its a non-issue,
+     * but valgrind complains nonetheless.
+     */
+    if (ct->has_bitfield) {
+        sz = ALIGN_UP(sz, 7);
+    }
+
+    cd = (struct cdata*) lua_newuserdata(L, sizeof(struct cdata) + sz);
+    *(struct ctype*) &cd->type = *ct;
+    memset(cd+1, 0, sz);
+
+    /* TODO: handle cases where lua_newuserdata returns a pointer that is not
+     * aligned */
+#if 0
+    assert((uintptr_t) (cd + 1) % 8 == 0);
+#endif
+
+#if LUA_VERSION_NUM == 501
+    if (!ct_usr || lua_isnil(L, ct_usr)) {
+        push_upval(L, &niluv_key);
+        lua_setfenv(L, -2);
+    }
+#endif
+
+    if (ct_usr && !lua_isnil(L, ct_usr)) {
+        lua_pushvalue(L, ct_usr);
+        lua_setuservalue(L, -2);
+    }
+
+    push_upval(L, &cdata_mt_key);
+    lua_setmetatable(L, -2);
+
+    if (!ct->is_defined && ct_usr && !lua_isnil(L, ct_usr)) {
+        update_on_definition(L, ct_usr, -1);
+    }
+
+    return cd+1;
+}
+
+void push_callback(lua_State* L, cfunction luafunc, cfunction cfunc)
+{
+    cfunction* pf = (cfunction*) lua_newuserdata(L, 2 * sizeof(cfunction));
+    pf[0] = luafunc;
+    pf[1] = cfunc;
+
+    push_upval(L, &callback_mt_key);
+    lua_setmetatable(L, -2);
+}
+
+/* returns the value as a ctype, pushes the user value onto the stack */
+void check_ctype(lua_State* L, int idx, struct ctype* ct)
+{
+    if (lua_isstring(L, idx)) {
+        struct parser P;
+        P.line = 1;
+        P.prev = P.next = lua_tostring(L, idx);
+        P.align_mask = DEFAULT_ALIGN_MASK;
+        parse_type(L, &P, ct);
+        parse_argument(L, &P, -1, ct, NULL, NULL);
+        lua_remove(L, -2); /* remove the user value from parse_type */
+
+    } else if (lua_getmetatable(L, idx)) {
+        if (!equals_upval(L, -1, &ctype_mt_key)
+                && !equals_upval(L, -1, &cdata_mt_key)) {
+            goto err;
+        }
+
+        lua_pop(L, 1); /* pop the metatable */
+        *ct = *(struct ctype*) lua_touserdata(L, idx);
+        lua_getuservalue(L, idx);
+
+    } else {
+        goto err;
+    }
+
+    return;
+
+err:
+    luaL_error(L, "expected cdata, ctype or string for arg #%d", idx);
+}
+
+/* to_cdata returns the struct cdata* and pushes the user value onto the
+ * stack. If the index is not a ctype then ct is set to the zero value such
+ * that ct->type is INVALID_TYPE, a nil is pushed, and NULL is returned. */
+void* to_cdata(lua_State* L, int idx, struct ctype* ct)
+{
+    struct cdata* cd;
+
+    memset(ct, 0, sizeof(struct ctype));
+    if (!lua_isuserdata(L, idx) || !lua_getmetatable(L, idx)) {
+        lua_pushnil(L);
+        return NULL;
+    }
+
+    if (!equals_upval(L, -1, &cdata_mt_key)) {
+        lua_pop(L, 1); /* mt */
+        lua_pushnil(L);
+        return NULL;
+    }
+
+    lua_pop(L, 1); /* mt */
+    cd = (struct cdata*) lua_touserdata(L, idx);
+    *ct = cd->type;
+    lua_getuservalue(L, idx);
+
+    if (ct->is_reference) {
+        return *(void**) (cd+1);
+
+    } else if (ct->pointers && !ct->is_array) {
+        return *(void**) (cd+1);
+
+    } else {
+        return cd + 1;
+    }
+}
+
+/* check_cdata returns the struct cdata* and pushes the user value onto the
+ * stack. Also dereferences references. */
+void* check_cdata(lua_State* L, int idx, struct ctype* ct)
+{
+    void* p = to_cdata(L, idx, ct);
+    if (ct->type == INVALID_TYPE) {
+        luaL_error(L, "expected cdata for arg #%d", idx);
+    }
+    return p;
+}
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/ctype.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,455 @@
+/*
+** DynASM ARM encoding engine.
+** Copyright (C) 2005-2011 Mike Pall. All rights reserved.
+** Released under the MIT/X license. See dynasm.lua for full copyright notice.
+*/
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define DASM_ARCH		"arm"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d)	0
+#endif
+
+/* Action definitions. */
+enum {
+  DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
+  /* The following actions need a buffer position. */
+  DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
+  /* The following actions also have an argument. */
+  DASM_REL_PC, DASM_LABEL_PC,
+  DASM_LONG, DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12,
+  DASM__MAX
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS		25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK		0x00000000
+#define DASM_S_NOMEM		0x01000000
+#define DASM_S_PHASE		0x02000000
+#define DASM_S_MATCH_SEC	0x03000000
+#define DASM_S_RANGE_I		0x11000000
+#define DASM_S_RANGE_SEC	0x12000000
+#define DASM_S_RANGE_LG		0x13000000
+#define DASM_S_RANGE_PC		0x14000000
+#define DASM_S_RANGE_REL	0x15000000
+#define DASM_S_UNDEF_LG		0x21000000
+#define DASM_S_UNDEF_PC		0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos)	((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos)	((pos)&0xff000000)
+#define DASM_SEC2POS(sec)	((sec)<<24)
+#define DASM_POS2SEC(pos)	((pos)>>24)
+#define DASM_POS2PTR(D, pos)	(D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned int *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+  int *rbuf;		/* Biased buffer pointer (negative section bias). */
+  int *buf;		/* True buffer pointer. */
+  size_t bsize;		/* Buffer size in bytes. */
+  int pos;		/* Biased buffer position. */
+  int epos;		/* End of biased buffer position - max single put. */
+  int ofs;		/* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+  size_t psize;			/* Allocated size of this structure. */
+  dasm_ActList actionlist;	/* Current actionlist pointer. */
+  int *lglabels;		/* Local/global chain/pos ptrs. */
+  size_t lgsize;
+  int *pclabels;		/* PC label chains/pos ptrs. */
+  size_t pcsize;
+  void **globals;		/* Array of globals (bias -10). */
+  dasm_Section *section;	/* Pointer to active section. */
+  size_t codesize;		/* Total size of all code sections. */
+  int maxsection;		/* 0 <= sectionidx < maxsection. */
+  int status;			/* Status code. */
+  dasm_Section sections[1];	/* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms)	(sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+  dasm_State *D;
+  size_t psz = 0;
+  int i;
+  Dst_REF = NULL;
+  DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+  D = Dst_REF;
+  D->psize = psz;
+  D->lglabels = NULL;
+  D->lgsize = 0;
+  D->pclabels = NULL;
+  D->pcsize = 0;
+  D->globals = NULL;
+  D->maxsection = maxsection;
+  for (i = 0; i < maxsection; i++) {
+    D->sections[i].buf = NULL;  /* Need this for pass3. */
+    D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+    D->sections[i].bsize = 0;
+    D->sections[i].epos = 0;  /* Wrong, but is recalculated after resize. */
+  }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+  dasm_State *D = Dst_REF;
+  int i;
+  for (i = 0; i < D->maxsection; i++)
+    if (D->sections[i].buf)
+      DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+  if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+  if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+  DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+  dasm_State *D = Dst_REF;
+  D->globals = gl - 10;  /* Negative bias to compensate for locals. */
+  DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+  dasm_State *D = Dst_REF;
+  size_t osz = D->pcsize;
+  DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+  memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+  dasm_State *D = Dst_REF;
+  int i;
+  D->actionlist = (dasm_ActList)actionlist;
+  D->status = DASM_S_OK;
+  D->section = &D->sections[0];
+  memset((void *)D->lglabels, 0, D->lgsize);
+  if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+  for (i = 0; i < D->maxsection; i++) {
+    D->sections[i].pos = DASM_SEC2POS(i);
+    D->sections[i].ofs = 0;
+  }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+  do { if (!(x)) { \
+    D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+  do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+    D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st)	((void)0)
+#define CKPL(kind, st)	((void)0)
+#endif
+
+static int dasm_imm12(unsigned int n)
+{
+  int i;
+  for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30))
+    if (n <= 255) return (int)(n + (i << 8));
+  return -1;
+}
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+  va_list ap;
+  dasm_State *D = Dst_REF;
+  dasm_ActList p = D->actionlist + start;
+  dasm_Section *sec = D->section;
+  int pos = sec->pos, ofs = sec->ofs;
+  int *b;
+
+  if (pos >= sec->epos) {
+    DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+      sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+    sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+    sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+  }
+
+  b = sec->rbuf;
+  b[pos++] = start;
+
+  va_start(ap, start);
+  while (1) {
+    unsigned int ins = *p++;
+    unsigned int action = (ins >> 16);
+    if (action >= DASM__MAX) {
+      ofs += 4;
+    } else {
+      int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
+      switch (action) {
+      case DASM_STOP: goto stop;
+      case DASM_SECTION:
+	n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
+	D->section = &D->sections[n]; goto stop;
+      case DASM_ESC: p++; ofs += 4; break;
+      case DASM_REL_EXT: break;
+      case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
+      case DASM_REL_LG:
+	n = (ins & 2047) - 10; pl = D->lglabels + n;
+	if (n >= 0) { CKPL(lg, LG); goto putrel; }  /* Bkwd rel or global. */
+	pl += 10; n = *pl;
+	if (n < 0) n = 0;  /* Start new chain for fwd rel if label exists. */
+	goto linkrel;
+      case DASM_REL_PC:
+	pl = D->pclabels + n; CKPL(pc, PC);
+      putrel:
+	n = *pl;
+	if (n < 0) {  /* Label exists. Get label pos and store it. */
+	  b[pos] = -n;
+	} else {
+      linkrel:
+	  b[pos] = n;  /* Else link to rel chain, anchored at label. */
+	  *pl = pos;
+	}
+	pos++;
+	break;
+      case DASM_LABEL_LG:
+	pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
+      case DASM_LABEL_PC:
+	pl = D->pclabels + n; CKPL(pc, PC);
+      putlabel:
+	n = *pl;  /* n > 0: Collapse rel chain and replace with label pos. */
+	while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
+	}
+	*pl = -pos;  /* Label exists now. */
+	b[pos++] = ofs;  /* Store pass1 offset estimate. */
+	break;
+      case DASM_LONG:
+        ofs += 4;
+        b[pos++] = n;
+        break;
+      case DASM_IMM:
+      case DASM_IMM16:
+#ifdef DASM_CHECKS
+	CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
+	if ((ins & 0x8000))
+	  CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
+	else
+	  CK((n>>((ins>>5)&31)) == 0, RANGE_I);
+#endif
+	b[pos++] = n;
+	break;
+      case DASM_IMML8:
+      case DASM_IMML12:
+	CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) :
+		    (((-n)>>((ins>>5)&31)) == 0), RANGE_I);
+	b[pos++] = n;
+	break;
+      case DASM_IMM12:
+	CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
+	b[pos++] = n;
+	break;
+      }
+    }
+  }
+stop:
+  va_end(ap);
+  sec->pos = pos;
+  sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+  dasm_State *D = Dst_REF;
+  int secnum;
+  int ofs = 0;
+
+#ifdef DASM_CHECKS
+  *szp = 0;
+  if (D->status != DASM_S_OK) return D->status;
+  {
+    int pc;
+    for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+      if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+  }
+#endif
+
+  { /* Handle globals not defined in this translation unit. */
+    int idx;
+    for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
+      int n = D->lglabels[idx];
+      /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+      while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+    }
+  }
+
+  /* Combine all code sections. No support for data sections (yet). */
+  for (secnum = 0; secnum < D->maxsection; secnum++) {
+    dasm_Section *sec = D->sections + secnum;
+    int *b = sec->rbuf;
+    int pos = DASM_SEC2POS(secnum);
+    int lastpos = sec->pos;
+
+    while (pos != lastpos) {
+      dasm_ActList p = D->actionlist + b[pos++];
+      while (1) {
+	unsigned int ins = *p++;
+	unsigned int action = (ins >> 16);
+	switch (action) {
+	case DASM_STOP: case DASM_SECTION: goto stop;
+	case DASM_ESC: p++; break;
+	case DASM_REL_EXT: break;
+	case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
+	case DASM_REL_LG: case DASM_REL_PC: pos++; break;
+	case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
+        case DASM_LONG: case DASM_IMM: case DASM_IMM12: case DASM_IMM16:
+	case DASM_IMML8: case DASM_IMML12: pos++; break;
+	}
+      }
+      stop: (void)0;
+    }
+    ofs += sec->ofs;  /* Next section starts right after current section. */
+  }
+
+  D->codesize = ofs;  /* Total size of all code sections */
+  *szp = ofs;
+  return DASM_S_OK;
+}
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+  do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
+#else
+#define CK(x, st)	((void)0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+  dasm_State *D = Dst_REF;
+  char *base = (char *)buffer;
+  unsigned int *cp = (unsigned int *)buffer;
+  int secnum;
+
+  /* Encode all code sections. No support for data sections (yet). */
+  for (secnum = 0; secnum < D->maxsection; secnum++) {
+    dasm_Section *sec = D->sections + secnum;
+    int *b = sec->buf;
+    int *endb = sec->rbuf + sec->pos;
+
+    while (b != endb) {
+      dasm_ActList p = D->actionlist + *b++;
+      while (1) {
+	unsigned int ins = *p++;
+	unsigned int action = (ins >> 16);
+	int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
+	switch (action) {
+	case DASM_STOP: case DASM_SECTION: goto stop;
+	case DASM_ESC: *cp++ = *p++; break;
+	case DASM_REL_EXT:
+	  n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
+	  goto patchrel;
+	case DASM_ALIGN:
+	  ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
+	  break;
+	case DASM_REL_LG:
+	  CK(n >= 0, UNDEF_LG);
+	case DASM_REL_PC:
+	  CK(n >= 0, UNDEF_PC);
+	  n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4;
+	patchrel:
+	  if ((ins & 0x800) == 0) {
+	    CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL);
+	    cp[-1] |= ((n >> 2) & 0x00ffffff);
+	  } else if ((ins & 0x1000)) {
+	    CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL);
+	    goto patchimml8;
+	  } else {
+	    CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL);
+	    goto patchimml12;
+	  }
+	  break;
+	case DASM_LABEL_LG:
+	  ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
+	  break;
+	case DASM_LABEL_PC: break;
+        case DASM_LONG:
+          *cp++ = n;
+          break;
+	case DASM_IMM:
+	  cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31);
+	  break;
+	case DASM_IMM12:
+	  cp[-1] |= dasm_imm12((unsigned int)n);
+	  break;
+	case DASM_IMM16:
+	  cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff);
+	  break;
+	case DASM_IMML8: patchimml8:
+	  cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) :
+			     ((-n & 0x0f) | ((-n & 0xf0) << 4));
+	  break;
+	case DASM_IMML12: patchimml12:
+	  cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n);
+	  break;
+	default: *cp++ = ins; break;
+	}
+      }
+      stop: (void)0;
+    }
+  }
+
+  if (base + D->codesize != (char *)cp)  /* Check for phase errors. */
+    return DASM_S_PHASE;
+  return DASM_S_OK;
+}
+#undef CK
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+  dasm_State *D = Dst_REF;
+  if (pc*sizeof(int) < D->pcsize) {
+    int pos = D->pclabels[pc];
+    if (pos < 0) return *DASM_POS2PTR(D, -pos);
+    if (pos > 0) return -1;  /* Undefined. */
+  }
+  return -2;  /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+  dasm_State *D = Dst_REF;
+  if (D->status == DASM_S_OK) {
+    int i;
+    for (i = 1; i <= 9; i++) {
+      if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
+      D->lglabels[i] = 0;
+    }
+  }
+  if (D->status == DASM_S_OK && secmatch >= 0 &&
+      D->section != &D->sections[secmatch])
+    D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
+  return D->status;
+}
+#endif
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.lua
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.lua	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.lua	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,952 @@
+------------------------------------------------------------------------------
+-- DynASM ARM module.
+--
+-- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+-- Module information:
+local _info = {
+  arch =	"arm",
+  description =	"DynASM ARM module",
+  version =	"1.3.0",
+  vernum =	 10300,
+  release =	"2011-05-05",
+  author =	"Mike Pall",
+  license =	"MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, setmetatable, rawget = assert, setmetatable, rawget
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub
+local concat, sort, insert = table.concat, table.sort, table.insert
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+  "STOP", "SECTION", "ESC", "REL_EXT",
+  "ALIGN", "REL_LG", "LABEL_LG",
+  "REL_PC", "LABEL_PC", "LONG", "IMM", "IMM12", "IMM16", "IMML8", "IMML12",
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number.
+local map_action = {}
+for n,name in ipairs(action_names) do
+  map_action[name] = n-1
+end
+
+-- Action list buffer.
+local actlist = {}
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Return 8 digit hex number.
+local function tohex(x)
+  return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua.
+end
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+  out:write("DynASM encoding engine action codes:\n")
+  for n,name in ipairs(action_names) do
+    local num = map_action[name]
+    out:write(format("  %-10s %02X  %d\n", name, num, num))
+  end
+  out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+  local nn = #actlist
+  if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
+  out:write("static const unsigned int ", name, "[", nn, "] = {\n")
+  for i = 1,nn-1 do
+    assert(out:write("0x", tohex(actlist[i]), ",\n"))
+  end
+  assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
+end
+
+------------------------------------------------------------------------------
+
+-- Add word to action list.
+local function wputxw(n)
+  assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+  actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, val, a, num)
+  local w = assert(map_action[action], "bad action name `"..action.."'")
+  wputxw(w * 0x10000 + (val or 0))
+  if a then actargs[#actargs+1] = a end
+  if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+  if #actlist == actargs[1] then return end -- Nothing to flush.
+  if not term then waction("STOP") end -- Terminate action list.
+  wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
+  actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+  secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped word.
+local function wputw(n)
+  if n <= 0x000fffff then waction("ESC") end
+  wputxw(n)
+end
+
+-- Reserve position for word.
+local function wpos()
+  local pos = #actlist+1
+  actlist[pos] = ""
+  return pos
+end
+
+-- Store word to reserved position.
+local function wputpos(pos, n)
+  assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+  if n <= 0x000fffff then
+    insert(actlist, pos+1, n)
+    n = map_action.ESC * 0x10000
+  end
+  actlist[pos] = n
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 20
+local map_global = setmetatable({}, { __index = function(t, name)
+  if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
+  local n = next_global
+  if n > 2047 then werror("too many global labels") end
+  next_global = n + 1
+  t[name] = n
+  return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+  local t = {}
+  for name, n in pairs(map_global) do t[n] = name end
+  out:write("Global labels:\n")
+  for i=20,next_global-1 do
+    out:write(format("  %s\n", t[i]))
+  end
+  out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+  local t = {}
+  for name, n in pairs(map_global) do t[n] = name end
+  out:write("enum {\n")
+  for i=20,next_global-1 do
+    out:write("  ", prefix, t[i], ",\n")
+  end
+  out:write("  ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+  local t = {}
+  for name, n in pairs(map_global) do t[n] = name end
+  out:write("static const char *const ", name, "[] = {\n")
+  for i=20,next_global-1 do
+    out:write("  \"", t[i], "\",\n")
+  end
+  out:write("  (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = 0
+local map_extern_ = {}
+local map_extern = setmetatable({}, { __index = function(t, name)
+  -- No restrictions on the name for now.
+  local n = next_extern
+  if n > 2047 then werror("too many extern labels") end
+  next_extern = n + 1
+  t[name] = n
+  map_extern_[n] = name
+  return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+  out:write("Extern labels:\n")
+  for i=0,next_extern-1 do
+    out:write(format("  %s\n", map_extern_[i]))
+  end
+  out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+  out:write("static const char *const ", name, "[] = {\n")
+  for i=0,next_extern-1 do
+    out:write("  \"", map_extern_[i], "\",\n")
+  end
+  out:write("  (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+
+-- Ext. register name -> int. name.
+local map_archdef = { sp = "r13", lr = "r14", pc = "r15", }
+
+-- Int. register name -> ext. name.
+local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", }
+
+local map_type = {}		-- Type name -> { ctype, reg }
+local ctypenum = 0		-- Type number (for Dt... macros).
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+  return map_reg_rev[s] or s
+end
+
+local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, }
+
+local map_cond = {
+  eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7,
+  hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14,
+  hs = 2, lo = 3,
+}
+
+------------------------------------------------------------------------------
+
+-- Template strings for ARM instructions.
+local map_op = {
+  -- Basic data processing instructions.
+  and_3 = "e0000000DNPs",
+  eor_3 = "e0200000DNPs",
+  sub_3 = "e0400000DNPs",
+  rsb_3 = "e0600000DNPs",
+  add_3 = "e0800000DNPs",
+  adc_3 = "e0a00000DNPs",
+  sbc_3 = "e0c00000DNPs",
+  rsc_3 = "e0e00000DNPs",
+  tst_2 = "e1100000NP",
+  teq_2 = "e1300000NP",
+  cmp_2 = "e1500000NP",
+  cmn_2 = "e1700000NP",
+  orr_3 = "e1800000DNPs",
+  mov_2 = "e1a00000DPs",
+  bic_3 = "e1c00000DNPs",
+  mvn_2 = "e1e00000DPs",
+
+  and_4 = "e0000000DNMps",
+  eor_4 = "e0200000DNMps",
+  sub_4 = "e0400000DNMps",
+  rsb_4 = "e0600000DNMps",
+  add_4 = "e0800000DNMps",
+  adc_4 = "e0a00000DNMps",
+  sbc_4 = "e0c00000DNMps",
+  rsc_4 = "e0e00000DNMps",
+  tst_3 = "e1100000NMp",
+  teq_3 = "e1300000NMp",
+  cmp_3 = "e1500000NMp",
+  cmn_3 = "e1700000NMp",
+  orr_4 = "e1800000DNMps",
+  mov_3 = "e1a00000DMps",
+  bic_4 = "e1c00000DNMps",
+  mvn_3 = "e1e00000DMps",
+
+  lsl_3 = "e1a00000DMws",
+  lsr_3 = "e1a00020DMws",
+  asr_3 = "e1a00040DMws",
+  ror_3 = "e1a00060DMws",
+  rrx_2 = "e1a00060DMs",
+
+  -- Multiply and multiply-accumulate.
+  mul_3 = "e0000090NMSs",
+  mla_4 = "e0200090NMSDs",
+  umaal_4 = "e0400090DNMSs",	-- v6
+  mls_4 = "e0600090DNMSs",	-- v6T2
+  umull_4 = "e0800090DNMSs",
+  umlal_4 = "e0a00090DNMSs",
+  smull_4 = "e0c00090DNMSs",
+  smlal_4 = "e0e00090DNMSs",
+
+  -- Halfword multiply and multiply-accumulate.
+  smlabb_4 = "e1000080NMSD",	-- v5TE
+  smlatb_4 = "e10000a0NMSD",	-- v5TE
+  smlabt_4 = "e10000c0NMSD",	-- v5TE
+  smlatt_4 = "e10000e0NMSD",	-- v5TE
+  smlawb_4 = "e1200080NMSD",	-- v5TE
+  smulwb_3 = "e12000a0NMS",	-- v5TE
+  smlawt_4 = "e12000c0NMSD",	-- v5TE
+  smulwt_3 = "e12000e0NMS",	-- v5TE
+  smlalbb_4 = "e1400080NMSD",	-- v5TE
+  smlaltb_4 = "e14000a0NMSD",	-- v5TE
+  smlalbt_4 = "e14000c0NMSD",	-- v5TE
+  smlaltt_4 = "e14000e0NMSD",	-- v5TE
+  smulbb_3 = "e1600080NMS",	-- v5TE
+  smultb_3 = "e16000a0NMS",	-- v5TE
+  smulbt_3 = "e16000c0NMS",	-- v5TE
+  smultt_3 = "e16000e0NMS",	-- v5TE
+
+  -- Miscellaneous data processing instructions.
+  clz_2 = "e16f0f10DM", -- v5T
+  rev_2 = "e6bf0f30DM", -- v6
+  rev16_2 = "e6bf0fb0DM", -- v6
+  revsh_2 = "e6ff0fb0DM", -- v6
+  sel_3 = "e6800fb0DNM", -- v6
+  usad8_3 = "e780f010NMS", -- v6
+  usada8_4 = "e7800010NMSD", -- v6
+  rbit_2 = "e6ff0f30DM", -- v6T2
+  movw_2 = "e3000000DW", -- v6T2
+  movt_2 = "e3400000DW", -- v6T2
+  -- Note: the X encodes width-1, not width.
+  sbfx_4 = "e7a00050DMvX", -- v6T2
+  ubfx_4 = "e7e00050DMvX", -- v6T2
+  -- Note: the X encodes the msb field, not the width.
+  bfc_3 = "e7c0001fDvX", -- v6T2
+  bfi_4 = "e7c00010DMvX", -- v6T2
+
+  -- Packing and unpacking instructions.
+  pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6
+  pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6
+  sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6
+  sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6
+  sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6
+  sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6
+  sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6
+  sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6
+  uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6
+  uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6
+  uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6
+  uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6
+  uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6
+  uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6
+
+  -- Saturating instructions.
+  qadd_3 = "e1000050DMN",	-- v5TE
+  qsub_3 = "e1200050DMN",	-- v5TE
+  qdadd_3 = "e1400050DMN",	-- v5TE
+  qdsub_3 = "e1600050DMN",	-- v5TE
+  -- Note: the X for ssat* encodes sat_imm-1, not sat_imm.
+  ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6
+  usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6
+  ssat16_3 = "e6a00f30DXM", -- v6
+  usat16_3 = "e6e00f30DXM", -- v6
+
+  -- Parallel addition and subtraction.
+  sadd16_3 = "e6100f10DNM", -- v6
+  sasx_3 = "e6100f30DNM", -- v6
+  ssax_3 = "e6100f50DNM", -- v6
+  ssub16_3 = "e6100f70DNM", -- v6
+  sadd8_3 = "e6100f90DNM", -- v6
+  ssub8_3 = "e6100ff0DNM", -- v6
+  qadd16_3 = "e6200f10DNM", -- v6
+  qasx_3 = "e6200f30DNM", -- v6
+  qsax_3 = "e6200f50DNM", -- v6
+  qsub16_3 = "e6200f70DNM", -- v6
+  qadd8_3 = "e6200f90DNM", -- v6
+  qsub8_3 = "e6200ff0DNM", -- v6
+  shadd16_3 = "e6300f10DNM", -- v6
+  shasx_3 = "e6300f30DNM", -- v6
+  shsax_3 = "e6300f50DNM", -- v6
+  shsub16_3 = "e6300f70DNM", -- v6
+  shadd8_3 = "e6300f90DNM", -- v6
+  shsub8_3 = "e6300ff0DNM", -- v6
+  uadd16_3 = "e6500f10DNM", -- v6
+  uasx_3 = "e6500f30DNM", -- v6
+  usax_3 = "e6500f50DNM", -- v6
+  usub16_3 = "e6500f70DNM", -- v6
+  uadd8_3 = "e6500f90DNM", -- v6
+  usub8_3 = "e6500ff0DNM", -- v6
+  uqadd16_3 = "e6600f10DNM", -- v6
+  uqasx_3 = "e6600f30DNM", -- v6
+  uqsax_3 = "e6600f50DNM", -- v6
+  uqsub16_3 = "e6600f70DNM", -- v6
+  uqadd8_3 = "e6600f90DNM", -- v6
+  uqsub8_3 = "e6600ff0DNM", -- v6
+  uhadd16_3 = "e6700f10DNM", -- v6
+  uhasx_3 = "e6700f30DNM", -- v6
+  uhsax_3 = "e6700f50DNM", -- v6
+  uhsub16_3 = "e6700f70DNM", -- v6
+  uhadd8_3 = "e6700f90DNM", -- v6
+  uhsub8_3 = "e6700ff0DNM", -- v6
+
+  -- Load/store instructions.
+  str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL",
+  strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL",
+  ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL",
+  ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL",
+  strh_2 = "e00000b0DL", strh_3 = "e00000b0DL",
+  ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL",
+  ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE
+  ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL",
+  strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE
+  ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL",
+
+  ldm_2 = "e8900000nR", ldmia_2 = "e8900000nR", ldmfd_2 = "e8900000nR",
+  ldmda_2 = "e8100000nR", ldmfa_2 = "e8100000nR",
+  ldmdb_2 = "e9100000nR", ldmea_2 = "e9100000nR",
+  ldmib_2 = "e9900000nR", ldmed_2 = "e9900000nR",
+  stm_2 = "e8800000nR", stmia_2 = "e8800000nR", stmfd_2 = "e8800000nR",
+  stmda_2 = "e8000000nR", stmfa_2 = "e8000000nR",
+  stmdb_2 = "e9000000nR", stmea_2 = "e9000000nR",
+  stmib_2 = "e9800000nR", stmed_2 = "e9800000nR",
+  pop_1 = "e8bd0000R", push_1 = "e92d0000R",
+
+  -- Branch instructions.
+  b_1 = "ea000000B",
+  bl_1 = "eb000000B",
+  blx_1 = "e12fff30C",
+  bx_1 = "e12fff10M",
+
+  -- Miscellaneous instructions.
+  nop_0 = "e1a00000",
+  mrs_1 = "e10f0000D",
+  bkpt_1 = "e1200070K", -- v5T
+  svc_1 = "ef000000T", swi_1 = "ef000000T",
+  ud_0 = "e7f001f0",
+
+  -- NYI: Advanced SIMD and VFP instructions.
+
+  -- NYI instructions, since I have no need for them right now:
+  -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh
+  -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe
+  -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb
+  -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2
+}
+
+-- Add mnemonics for "s" variants.
+do
+  local t = {}
+  for k,v in pairs(map_op) do
+    if sub(v, -1) == "s" then
+      local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2)
+      t[sub(k, 1, -3).."s"..sub(k, -2)] = v2
+    end
+  end
+  for k,v in pairs(t) do
+    map_op[k] = v
+  end
+end
+
+------------------------------------------------------------------------------
+
+local function parse_gpr(expr)
+  local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$")
+  local tp = map_type[tname or expr]
+  if tp then
+    local reg = ovreg or tp.reg
+    if not reg then
+      werror("type `"..(tname or expr).."' needs a register override")
+    end
+    expr = reg
+  end
+  local r = match(expr, "^r(1?[0-9])$")
+  if r then
+    r = tonumber(r)
+    if r <= 15 then return r, tp end
+  end
+  werror("bad register name `"..expr.."'")
+end
+
+local function parse_gpr_pm(expr)
+  local pm, expr2 = match(expr, "^([+-]?)(.*)$")
+  return parse_gpr(expr2), (pm == "-")
+end
+
+local function parse_reglist(reglist)
+  reglist = match(reglist, "^{%s*([^}]*)}$")
+  if not reglist then werror("register list expected") end
+  local rr = 0
+  for p in gmatch(reglist..",", "%s*([^,]*),") do
+    local rbit = 2^parse_gpr(gsub(p, "%s+$", ""))
+    if ((rr - (rr % rbit)) / rbit) % 2 ~= 0 then
+      werror("duplicate register `"..p.."'")
+    end
+    rr = rr + rbit
+  end
+  return rr
+end
+
+local function parse_imm(imm, bits, shift, scale, signed)
+  imm = match(imm, "^#(.*)$")
+  if not imm then werror("expected immediate operand") end
+  local n = tonumber(imm)
+  if n then
+    if n % 2^scale == 0 then
+      n = n / 2^scale
+      if signed then
+	if n >= 0 then
+	  if n < 2^(bits-1) then return n*2^shift end
+	else
+	  if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end
+	end
+      else
+	if n >= 0 and n <= 2^bits-1 then return n*2^shift end
+      end
+    end
+    werror("out of range immediate `"..imm.."'")
+  else
+    waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
+    return 0
+  end
+end
+
+local function parse_imm12(imm)
+  local n = tonumber(imm)
+  if n then
+    local m = n
+    for i=0,-15,-1 do
+      if m >= 0 and m <= 255 and n % 1 == 0 then return m + (i%16) * 256 end
+      local t = m % 4
+      m = (m - t) / 4 + t * 2^30
+    end
+    werror("out of range immediate `"..imm.."'")
+  else
+    waction("IMM12", 0, imm)
+    return 0
+  end
+end
+
+local function parse_imm16(imm)
+  imm = match(imm, "^#(.*)$")
+  if not imm then werror("expected immediate operand") end
+  local n = tonumber(imm)
+  if n then
+    if n >= 0 and n <= 65535 and n % 1 == 0 then
+      local t = n % 4096
+      return (n - t) * 16 + t
+    end
+    werror("out of range immediate `"..imm.."'")
+  else
+    waction("IMM16", 32*16, imm)
+    return 0
+  end
+end
+
+local function parse_imm_load(imm, ext)
+  local n = tonumber(imm)
+  if n then
+    if ext then
+      if n >= -255 and n <= 255 then
+	local up = 0x00800000
+	if n < 0 then n = -n; up = 0 end
+	return (n-(n%16))*16+(n%16) + up
+      end
+    else
+      if n >= -4095 and n <= 4095 then
+	if n >= 0 then return n+0x00800000 end
+	return -n
+      end
+    end
+    werror("out of range immediate `"..imm.."'")
+  else
+    waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), imm)
+    return 0
+  end
+end
+
+local function parse_shift(shift, gprok)
+  if shift == "rrx" then
+    return 3 * 32
+  else
+    local s, s2 = match(shift, "^(%S+)%s*(.*)$")
+    s = map_shift[s]
+    if not s then werror("expected shift operand") end
+    if sub(s2, 1, 1) == "#" then
+      return parse_imm(s2, 5, 7, 0, false) + s * 32
+    else
+      if not gprok then werror("expected immediate shift operand") end
+      return parse_gpr(s2) * 256 + s * 32 + 16
+    end
+  end
+end
+
+local function parse_label(label, def)
+  local prefix = sub(label, 1, 2)
+  -- =>label (pc label reference)
+  if prefix == "=>" then
+    return "PC", 0, sub(label, 3)
+  end
+  -- ->name (global label reference)
+  if prefix == "->" then
+    return "LG", map_global[sub(label, 3)]
+  end
+  if def then
+    -- [1-9] (local label definition)
+    if match(label, "^[1-9]$") then
+      return "LG", 10+tonumber(label)
+    end
+  else
+    -- [<>][1-9] (local label reference)
+    local dir, lnum = match(label, "^([<>])([1-9])$")
+    if dir then -- Fwd: 1-9, Bkwd: 11-19.
+      return "LG", lnum + (dir == ">" and 0 or 10)
+    end
+    -- extern label (extern label reference)
+    local extname = match(label, "^extern%s+(%S+)$")
+    if extname then
+      return "EXT", map_extern[extname]
+    end
+  end
+  werror("bad label `"..label.."'")
+end
+
+local function parse_load(params, nparams, n, op)
+  local oplo = op % 256
+  local ext, ldrd = (oplo ~= 0), (oplo == 208)
+  local d
+  if (ldrd or oplo == 240) then
+    d = ((op - (op % 4096)) / 4096) % 16
+    if d % 2 ~= 0 then werror("odd destination register") end
+  end
+  local pn = params[n]
+  local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$")
+  local p2 = params[n+1]
+  if not p1 then
+    if not p2 then
+      if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then
+	local mode, n, s = parse_label(pn, false)
+	waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1)
+	return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0)
+      end
+      local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$")
+      if reg and tailr ~= "" then
+	local d, tp = parse_gpr(reg)
+	if tp then
+	  waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12),
+		  format(tp.ctypefmt, tailr))
+	  return op + d * 65536 + 0x01000000 + (ext and 0x00400000 or 0)
+	end
+      end
+    end
+    werror("expected address operand")
+  end
+  if wb == "!" then op = op + 0x00200000 end
+  if p2 then
+    if wb == "!" then werror("bad use of '!'") end
+    local p3 = params[n+2]
+    op = op + parse_gpr(p1) * 65536
+    local imm = match(p2, "^#(.*)$")
+    if imm then
+      local m = parse_imm_load(imm, ext)
+      if p3 then werror("too many parameters") end
+      op = op + m + (ext and 0x00400000 or 0)
+    else
+      local m, neg = parse_gpr_pm(p2)
+      if ldrd and (m == d or m-1 == d) then werror("register conflict") end
+      op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000)
+      if p3 then op = op + parse_shift(p3) end
+    end
+  else
+    local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$")
+    op = op + parse_gpr(p1a) * 65536 + 0x01000000
+    if p2 ~= "" then
+      local imm = match(p2, "^,%s*#(.*)$")
+      if imm then
+	local m = parse_imm_load(imm, ext)
+	op = op + m + (ext and 0x00400000 or 0)
+      else
+	local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$")
+	local m, neg = parse_gpr_pm(p2a)
+	if ldrd and (m == d or m-1 == d) then werror("register conflict") end
+	op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000)
+	if p3 ~= "" then
+	  if ext then werror("too many parameters") end
+	  op = op + parse_shift(p3)
+	end
+      end
+    else
+      if wb == "!" then werror("bad use of '!'") end
+      op = op + (ext and 0x00c00000 or 0x00800000)
+    end
+  end
+  return op
+end
+
+------------------------------------------------------------------------------
+
+-- Handle opcodes defined with template strings.
+map_op[".template__"] = function(params, template, nparams)
+  if not params then return sub(template, 9) end
+  local op = tonumber(sub(template, 1, 8), 16)
+  local n = 1
+
+  -- Limit number of section buffer positions used by a single dasm_put().
+  -- A single opcode needs a maximum of 3 positions.
+  if secpos+3 > maxsecpos then wflush() end
+  local pos = wpos()
+
+  -- Process each character.
+  for p in gmatch(sub(template, 9), ".") do
+    if p == "D" then
+      op = op + parse_gpr(params[n]) * 4096; n = n + 1
+    elseif p == "N" then
+      op = op + parse_gpr(params[n]) * 65536; n = n + 1
+    elseif p == "S" then
+      op = op + parse_gpr(params[n]) * 256; n = n + 1
+    elseif p == "M" then
+      op = op + parse_gpr(params[n]); n = n + 1
+    elseif p == "P" then
+      local imm = match(params[n], "^#(.*)$")
+      if imm then
+	op = op + parse_imm12(imm) + 0x02000000
+      else
+	op = op + parse_gpr(params[n])
+      end
+      n = n + 1
+    elseif p == "p" then
+      op = op + parse_shift(params[n], true); n = n + 1
+    elseif p == "L" then
+      op = parse_load(params, nparams, n, op)
+    elseif p == "B" then
+      local mode, n, s = parse_label(params[n], false)
+      waction("REL_"..mode, n, s, 1)
+    elseif p == "C" then -- blx gpr vs. blx label.
+      local p = params[n]
+      if match(p, "^([%w_]+):(r1?[0-9])$") or match(p, "^r(1?[0-9])$") then
+	op = op + parse_gpr(p)
+      else
+	if op < 0xe0000000 then werror("unconditional instruction") end
+	local mode, n, s = parse_label(p, false)
+	waction("REL_"..mode, n, s, 1)
+	op = 0xfa000000
+      end
+    elseif p == "n" then
+      local r, wb = match(params[n], "^([^!]*)(!?)$")
+      op = op + parse_gpr(r) * 65536 + (wb == "!" and 0x00200000 or 0)
+      n = n + 1
+    elseif p == "R" then
+      op = op + parse_reglist(params[n]); n = n + 1
+    elseif p == "W" then
+      op = op + parse_imm16(params[n]); n = n + 1
+    elseif p == "v" then
+      op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1
+    elseif p == "w" then
+      local imm = match(params[n], "^#(.*)$")
+      if imm then
+	op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1
+      else
+	op = op + parse_gpr(params[n]) * 256 + 16
+      end
+    elseif p == "X" then
+      op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1
+    elseif p == "K" then
+      local imm = tonumber(match(params[n], "^#(.*)$")); n = n + 1
+      if not imm or imm % 1 ~= 0 or imm < 0 or imm > 0xffff then
+	werror("bad immediate operand")
+      end
+      local t = imm % 16
+      op = op + (imm - t) * 16 + t
+    elseif p == "T" then
+      op = op + parse_imm(params[n], 24, 0, 0, false); n = n + 1
+    elseif p == "s" then
+      -- Ignored.
+    else
+      assert(false)
+    end
+  end
+  wputpos(pos, op)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+  if not params then return "cvar" end
+  local name = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+  if not params then return "prefix" end
+  local prefix = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+  if not params then return "cvar" end
+  local name = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+  if not params then return "cvar" end
+  local name = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_1"] = function(params)
+  if not params then return "[1-9] | ->global | =>pcexpr" end
+  if secpos+1 > maxsecpos then wflush() end
+  local mode, n, s = parse_label(params[1], true)
+  if mode == "EXT" then werror("bad label definition") end
+  waction("LABEL_"..mode, n, s, 1)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+map_op[".long_*"] = function(params)
+  if not params then return "imm..." end
+  for _,p in ipairs(params) do
+    local n = tonumber(p)
+    if n then
+      if n < 0 then n = n + 2^32 end
+      wputw(n)
+      if secpos+2 > maxsecpos then wflush() end
+    else
+      waction("LONG", 0, format("(uintptr_t)(%s)", p))
+    end
+  end
+end
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+  if not params then return "numpow2" end
+  if secpos+1 > maxsecpos then wflush() end
+  local align = tonumber(params[1])
+  if align then
+    local x = align
+    -- Must be a power of 2 in the range (2 ... 256).
+    for i=1,8 do
+      x = x / 2
+      if x == 1 then
+	waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
+	return
+      end
+    end
+  end
+  werror("bad alignment")
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+  if not params then
+    return nparams == 2 and "name, ctype" or "name, ctype, reg"
+  end
+  local name, ctype, reg = params[1], params[2], params[3]
+  if not match(name, "^[%a_][%w_]*$") then
+    werror("bad type name `"..name.."'")
+  end
+  local tp = map_type[name]
+  if tp then
+    werror("duplicate type `"..name.."'")
+  end
+  -- Add #type to defines. A bit unclean to put it in map_archdef.
+  map_archdef["#"..name] = "sizeof("..ctype..")"
+  -- Add new type and emit shortcut define.
+  local num = ctypenum + 1
+  map_type[name] = {
+    ctype = ctype,
+    ctypefmt = format("Dt%X(%%s)", num),
+    reg = reg,
+  }
+  wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+  ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+  local t = {}
+  for name in pairs(map_type) do t[#t+1] = name end
+  sort(t)
+  out:write("Type definitions:\n")
+  for _,name in ipairs(t) do
+    local tp = map_type[name]
+    local reg = tp.reg or ""
+    out:write(format("  %-20s %-20s %s\n", name, tp.ctype, reg))
+  end
+  out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+  waction("SECTION", num)
+  wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+  out:write(format("DynASM %s version %s, released %s\n\n",
+    _info.arch, _info.version, _info.release))
+  dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+  dumptypes(out, lvl)
+  dumpglobals(out, lvl)
+  dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+  wline, werror, wfatal, wwarn = wl, we, wf, ww
+  return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+  g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+  setmetatable(map_op, { __index = function(t, k)
+    local v = map_coreop[k]
+    if v then return v end
+    local cc = sub(k, -4, -3)
+    local cv = map_cond[cc]
+    if cv then
+      local v = rawget(t, sub(k, 1, -5)..sub(k, -2))
+      if type(v) == "string" then return format("%x%s", cv, sub(v, 2)) end
+    end
+  end })
+  setmetatable(map_def, { __index = map_archdef })
+  return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,408 @@
+/*
+** DynASM PPC encoding engine.
+** Copyright (C) 2005-2011 Mike Pall. All rights reserved.
+** Released under the MIT/X license. See dynasm.lua for full copyright notice.
+*/
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define DASM_ARCH		"ppc"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d)	0
+#endif
+
+/* Action definitions. */
+enum {
+  DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
+  /* The following actions need a buffer position. */
+  DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
+  /* The following actions also have an argument. */
+  DASM_REL_PC, DASM_LABEL_PC, DASM_IMM,
+  DASM__MAX
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS		25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK		0x00000000
+#define DASM_S_NOMEM		0x01000000
+#define DASM_S_PHASE		0x02000000
+#define DASM_S_MATCH_SEC	0x03000000
+#define DASM_S_RANGE_I		0x11000000
+#define DASM_S_RANGE_SEC	0x12000000
+#define DASM_S_RANGE_LG		0x13000000
+#define DASM_S_RANGE_PC		0x14000000
+#define DASM_S_RANGE_REL	0x15000000
+#define DASM_S_UNDEF_LG		0x21000000
+#define DASM_S_UNDEF_PC		0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos)	((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos)	((pos)&0xff000000)
+#define DASM_SEC2POS(sec)	((sec)<<24)
+#define DASM_POS2SEC(pos)	((pos)>>24)
+#define DASM_POS2PTR(D, pos)	(D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned int *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+  int *rbuf;		/* Biased buffer pointer (negative section bias). */
+  int *buf;		/* True buffer pointer. */
+  size_t bsize;		/* Buffer size in bytes. */
+  int pos;		/* Biased buffer position. */
+  int epos;		/* End of biased buffer position - max single put. */
+  int ofs;		/* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+  size_t psize;			/* Allocated size of this structure. */
+  dasm_ActList actionlist;	/* Current actionlist pointer. */
+  int *lglabels;		/* Local/global chain/pos ptrs. */
+  size_t lgsize;
+  int *pclabels;		/* PC label chains/pos ptrs. */
+  size_t pcsize;
+  void **globals;		/* Array of globals (bias -10). */
+  dasm_Section *section;	/* Pointer to active section. */
+  size_t codesize;		/* Total size of all code sections. */
+  int maxsection;		/* 0 <= sectionidx < maxsection. */
+  int status;			/* Status code. */
+  dasm_Section sections[1];	/* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms)	(sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+  dasm_State *D;
+  size_t psz = 0;
+  int i;
+  Dst_REF = NULL;
+  DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+  D = Dst_REF;
+  D->psize = psz;
+  D->lglabels = NULL;
+  D->lgsize = 0;
+  D->pclabels = NULL;
+  D->pcsize = 0;
+  D->globals = NULL;
+  D->maxsection = maxsection;
+  for (i = 0; i < maxsection; i++) {
+    D->sections[i].buf = NULL;  /* Need this for pass3. */
+    D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+    D->sections[i].bsize = 0;
+    D->sections[i].epos = 0;  /* Wrong, but is recalculated after resize. */
+  }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+  dasm_State *D = Dst_REF;
+  int i;
+  for (i = 0; i < D->maxsection; i++)
+    if (D->sections[i].buf)
+      DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+  if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+  if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+  DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+  dasm_State *D = Dst_REF;
+  D->globals = gl - 10;  /* Negative bias to compensate for locals. */
+  DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+  dasm_State *D = Dst_REF;
+  size_t osz = D->pcsize;
+  DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+  memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+  dasm_State *D = Dst_REF;
+  int i;
+  D->actionlist = (dasm_ActList)actionlist;
+  D->status = DASM_S_OK;
+  D->section = &D->sections[0];
+  memset((void *)D->lglabels, 0, D->lgsize);
+  if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+  for (i = 0; i < D->maxsection; i++) {
+    D->sections[i].pos = DASM_SEC2POS(i);
+    D->sections[i].ofs = 0;
+  }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+  do { if (!(x)) { \
+    D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+  do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+    D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st)	((void)0)
+#define CKPL(kind, st)	((void)0)
+#endif
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+  va_list ap;
+  dasm_State *D = Dst_REF;
+  dasm_ActList p = D->actionlist + start;
+  dasm_Section *sec = D->section;
+  int pos = sec->pos, ofs = sec->ofs;
+  int *b;
+
+  if (pos >= sec->epos) {
+    DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+      sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+    sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+    sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+  }
+
+  b = sec->rbuf;
+  b[pos++] = start;
+
+  va_start(ap, start);
+  while (1) {
+    unsigned int ins = *p++;
+    unsigned int action = (ins >> 16);
+    if (action >= DASM__MAX) {
+      ofs += 4;
+    } else {
+      int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
+      switch (action) {
+      case DASM_STOP: goto stop;
+      case DASM_SECTION:
+	n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
+	D->section = &D->sections[n]; goto stop;
+      case DASM_ESC: p++; ofs += 4; break;
+      case DASM_REL_EXT: break;
+      case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
+      case DASM_REL_LG:
+	n = (ins & 2047) - 10; pl = D->lglabels + n;
+	if (n >= 0) { CKPL(lg, LG); goto putrel; }  /* Bkwd rel or global. */
+	pl += 10; n = *pl;
+	if (n < 0) n = 0;  /* Start new chain for fwd rel if label exists. */
+	goto linkrel;
+      case DASM_REL_PC:
+	pl = D->pclabels + n; CKPL(pc, PC);
+      putrel:
+	n = *pl;
+	if (n < 0) {  /* Label exists. Get label pos and store it. */
+	  b[pos] = -n;
+	} else {
+      linkrel:
+	  b[pos] = n;  /* Else link to rel chain, anchored at label. */
+	  *pl = pos;
+	}
+	pos++;
+	break;
+      case DASM_LABEL_LG:
+	pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
+      case DASM_LABEL_PC:
+	pl = D->pclabels + n; CKPL(pc, PC);
+      putlabel:
+	n = *pl;  /* n > 0: Collapse rel chain and replace with label pos. */
+	while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
+	}
+	*pl = -pos;  /* Label exists now. */
+	b[pos++] = ofs;  /* Store pass1 offset estimate. */
+	break;
+      case DASM_IMM:
+#ifdef DASM_CHECKS
+	CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
+	if (ins & 0x8000)
+	  CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
+	else
+	  CK((n>>((ins>>5)&31)) == 0, RANGE_I);
+#endif
+	b[pos++] = n;
+	break;
+      }
+    }
+  }
+stop:
+  va_end(ap);
+  sec->pos = pos;
+  sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+  dasm_State *D = Dst_REF;
+  int secnum;
+  int ofs = 0;
+
+#ifdef DASM_CHECKS
+  *szp = 0;
+  if (D->status != DASM_S_OK) return D->status;
+  {
+    int pc;
+    for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+      if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+  }
+#endif
+
+  { /* Handle globals not defined in this translation unit. */
+    int idx;
+    for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
+      int n = D->lglabels[idx];
+      /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+      while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+    }
+  }
+
+  /* Combine all code sections. No support for data sections (yet). */
+  for (secnum = 0; secnum < D->maxsection; secnum++) {
+    dasm_Section *sec = D->sections + secnum;
+    int *b = sec->rbuf;
+    int pos = DASM_SEC2POS(secnum);
+    int lastpos = sec->pos;
+
+    while (pos != lastpos) {
+      dasm_ActList p = D->actionlist + b[pos++];
+      while (1) {
+	unsigned int ins = *p++;
+	unsigned int action = (ins >> 16);
+	switch (action) {
+	case DASM_STOP: case DASM_SECTION: goto stop;
+	case DASM_ESC: p++; break;
+	case DASM_REL_EXT: break;
+	case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
+	case DASM_REL_LG: case DASM_REL_PC: pos++; break;
+	case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
+	case DASM_IMM: pos++; break;
+	}
+      }
+      stop: (void)0;
+    }
+    ofs += sec->ofs;  /* Next section starts right after current section. */
+  }
+
+  D->codesize = ofs;  /* Total size of all code sections */
+  *szp = ofs;
+  return DASM_S_OK;
+}
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+  do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
+#else
+#define CK(x, st)	((void)0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+  dasm_State *D = Dst_REF;
+  char *base = (char *)buffer;
+  unsigned int *cp = (unsigned int *)buffer;
+  int secnum;
+
+  /* Encode all code sections. No support for data sections (yet). */
+  for (secnum = 0; secnum < D->maxsection; secnum++) {
+    dasm_Section *sec = D->sections + secnum;
+    int *b = sec->buf;
+    int *endb = sec->rbuf + sec->pos;
+
+    while (b != endb) {
+      dasm_ActList p = D->actionlist + *b++;
+      while (1) {
+	unsigned int ins = *p++;
+	unsigned int action = (ins >> 16);
+	int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
+	switch (action) {
+	case DASM_STOP: case DASM_SECTION: goto stop;
+	case DASM_ESC: *cp++ = *p++; break;
+	case DASM_REL_EXT:
+	  n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1);
+	  goto patchrel;
+	case DASM_ALIGN:
+	  ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
+	  break;
+	case DASM_REL_LG:
+	  CK(n >= 0, UNDEF_LG);
+	case DASM_REL_PC:
+	  CK(n >= 0, UNDEF_PC);
+	  n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base);
+	patchrel:
+	  CK((n & 3) == 0 &&
+	      (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >>
+	       ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL);
+	  cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc));
+	  break;
+	case DASM_LABEL_LG:
+	  ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
+	  break;
+	case DASM_LABEL_PC: break;
+	case DASM_IMM:
+	  cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31);
+	  break;
+	default: *cp++ = ins; break;
+	}
+      }
+      stop: (void)0;
+    }
+  }
+
+  if (base + D->codesize != (char *)cp)  /* Check for phase errors. */
+    return DASM_S_PHASE;
+  return DASM_S_OK;
+}
+#undef CK
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+  dasm_State *D = Dst_REF;
+  if (pc*sizeof(int) < D->pcsize) {
+    int pos = D->pclabels[pc];
+    if (pos < 0) return *DASM_POS2PTR(D, -pos);
+    if (pos > 0) return -1;  /* Undefined. */
+  }
+  return -2;  /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+  dasm_State *D = Dst_REF;
+  if (D->status == DASM_S_OK) {
+    int i;
+    for (i = 1; i <= 9; i++) {
+      if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
+      D->lglabels[i] = 0;
+    }
+  }
+  if (D->status == DASM_S_OK && secmatch >= 0 &&
+      D->section != &D->sections[secmatch])
+    D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
+  return D->status;
+}
+#endif
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.lua
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.lua	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.lua	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,1225 @@
+------------------------------------------------------------------------------
+-- DynASM PPC module.
+--
+-- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+-- Module information:
+local _info = {
+  arch =	"ppc",
+  description =	"DynASM PPC module",
+  version =	"1.3.0",
+  vernum =	 10300,
+  release =	"2011-05-05",
+  author =	"Mike Pall",
+  license =	"MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, setmetatable = assert, setmetatable
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local match, gmatch = _s.match, _s.gmatch
+local concat, sort = table.concat, table.sort
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+  "STOP", "SECTION", "ESC", "REL_EXT",
+  "ALIGN", "REL_LG", "LABEL_LG",
+  "REL_PC", "LABEL_PC", "IMM",
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number.
+local map_action = {}
+for n,name in ipairs(action_names) do
+  map_action[name] = n-1
+end
+
+-- Action list buffer.
+local actlist = {}
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Return 8 digit hex number.
+local function tohex(x)
+  return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua.
+end
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+  out:write("DynASM encoding engine action codes:\n")
+  for n,name in ipairs(action_names) do
+    local num = map_action[name]
+    out:write(format("  %-10s %02X  %d\n", name, num, num))
+  end
+  out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+  local nn = #actlist
+  if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
+  out:write("static const unsigned int ", name, "[", nn, "] = {\n")
+  for i = 1,nn-1 do
+    assert(out:write("0x", tohex(actlist[i]), ",\n"))
+  end
+  assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
+end
+
+------------------------------------------------------------------------------
+
+-- Add word to action list.
+local function wputxw(n)
+  assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+  actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, val, a, num)
+  local w = assert(map_action[action], "bad action name `"..action.."'")
+  wputxw(w * 0x10000 + (val or 0))
+  if a then actargs[#actargs+1] = a end
+  if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+  if #actlist == actargs[1] then return end -- Nothing to flush.
+  if not term then waction("STOP") end -- Terminate action list.
+  wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
+  actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+  secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped word.
+local function wputw(n)
+  if n <= 0xffffff then waction("ESC") end
+  wputxw(n)
+end
+
+-- Reserve position for word.
+local function wpos()
+  local pos = #actlist+1
+  actlist[pos] = ""
+  return pos
+end
+
+-- Store word to reserved position.
+local function wputpos(pos, n)
+  assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+  actlist[pos] = n
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 20
+local map_global = setmetatable({}, { __index = function(t, name)
+  if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
+  local n = next_global
+  if n > 2047 then werror("too many global labels") end
+  next_global = n + 1
+  t[name] = n
+  return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+  local t = {}
+  for name, n in pairs(map_global) do t[n] = name end
+  out:write("Global labels:\n")
+  for i=20,next_global-1 do
+    out:write(format("  %s\n", t[i]))
+  end
+  out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+  local t = {}
+  for name, n in pairs(map_global) do t[n] = name end
+  out:write("enum {\n")
+  for i=20,next_global-1 do
+    out:write("  ", prefix, t[i], ",\n")
+  end
+  out:write("  ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+  local t = {}
+  for name, n in pairs(map_global) do t[n] = name end
+  out:write("static const char *const ", name, "[] = {\n")
+  for i=20,next_global-1 do
+    out:write("  \"", t[i], "\",\n")
+  end
+  out:write("  (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = 0
+local map_extern_ = {}
+local map_extern = setmetatable({}, { __index = function(t, name)
+  -- No restrictions on the name for now.
+  local n = next_extern
+  if n > 2047 then werror("too many extern labels") end
+  next_extern = n + 1
+  t[name] = n
+  map_extern_[n] = name
+  return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+  out:write("Extern labels:\n")
+  for i=0,next_extern-1 do
+    out:write(format("  %s\n", map_extern_[i]))
+  end
+  out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+  out:write("static const char *const ", name, "[] = {\n")
+  for i=0,next_extern-1 do
+    out:write("  \"", map_extern_[i], "\",\n")
+  end
+  out:write("  (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+local map_archdef = { sp = "r1" } -- Ext. register name -> int. name.
+
+local map_type = {}		-- Type name -> { ctype, reg }
+local ctypenum = 0		-- Type number (for Dt... macros).
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+  if s == "r1" then return "sp" end
+  return s
+end
+
+local map_cond = {
+  lt = 0, gt = 1, eq = 2, so = 3,
+  ge = 4, le = 5, ne = 6, ns = 7,
+}
+
+------------------------------------------------------------------------------
+
+-- Template strings for PPC instructions.
+local map_op = {
+  tdi_3 =	"08000000ARI",
+  twi_3 =	"0c000000ARI",
+  mulli_3 =	"1c000000RRI",
+  subfic_3 =	"20000000RRI",
+  cmplwi_3 =	"28000000XRU",
+  cmplwi_2 =	"28000000-RU",
+  cmpldi_3 =	"28200000XRU",
+  cmpldi_2 =	"28200000-RU",
+  cmpwi_3 =	"2c000000XRI",
+  cmpwi_2 =	"2c000000-RI",
+  cmpdi_3 =	"2c200000XRI",
+  cmpdi_2 =	"2c200000-RI",
+  addic_3 =	"30000000RRI",
+  ["addic._3"] = "34000000RRI",
+  addi_3 =	"38000000RR0I",
+  li_2 =	"38000000RI",
+  la_2 =	"38000000RD",
+  addis_3 =	"3c000000RR0I",
+  lis_2 =	"3c000000RI",
+  lus_2 =	"3c000000RU",
+  bc_3 =	"40000000AAK",
+  bcl_3 =	"40000001AAK",
+  bdnz_1 =	"42000000K",
+  bdz_1 =	"42400000K",
+  sc_0 =	"44000000",
+  b_1 =		"48000000J",
+  bl_1 =	"48000001J",
+  rlwimi_5 =	"50000000RR~AAA.",
+  rlwinm_5 =	"54000000RR~AAA.",
+  rlwnm_5 =	"5c000000RR~RAA.",
+  ori_3 =	"60000000RR~U",
+  nop_0 =	"60000000",
+  oris_3 =	"64000000RR~U",
+  xori_3 =	"68000000RR~U",
+  xoris_3 =	"6c000000RR~U",
+  ["andi._3"] =	"70000000RR~U",
+  ["andis._3"] = "74000000RR~U",
+  lwz_2 =	"80000000RD",
+  lwzu_2 =	"84000000RD",
+  lbz_2 =	"88000000RD",
+  lbzu_2 =	"8c000000RD",
+  stw_2 =	"90000000RD",
+  stwu_2 =	"94000000RD",
+  stb_2 =	"98000000RD",
+  stbu_2 =	"9c000000RD",
+  lhz_2 =	"a0000000RD",
+  lhzu_2 =	"a4000000RD",
+  lha_2 =	"a8000000RD",
+  lhau_2 =	"ac000000RD",
+  sth_2 =	"b0000000RD",
+  sthu_2 =	"b4000000RD",
+  lmw_2 =	"b8000000RD",
+  stmw_2 =	"bc000000RD",
+  lfs_2 =	"c0000000FD",
+  lfsu_2 =	"c4000000FD",
+  lfd_2 =	"c8000000FD",
+  lfdu_2 =	"cc000000FD",
+  stfs_2 =	"d0000000FD",
+  stfsu_2 =	"d4000000FD",
+  stfd_2 =	"d8000000FD",
+  stfdu_2 =	"dc000000FD",
+  ld_2 =	"e8000000RD", -- NYI: displacement must be divisible by 4.
+  ldu_2 =	"e8000001RD",
+  lwa_2 =	"e8000002RD",
+  std_2 =	"f8000000RD",
+  stdu_2 =	"f8000001RD",
+
+  -- Primary opcode 19:
+  mcrf_2 =	"4c000000XX",
+  isync_0 =	"4c00012c",
+  crnor_3 =	"4c000042CCC",
+  crnot_2 =	"4c000042CC=",
+  crandc_3 =	"4c000102CCC",
+  crxor_3 =	"4c000182CCC",
+  crclr_1 =	"4c000182C==",
+  crnand_3 =	"4c0001c2CCC",
+  crand_3 =	"4c000202CCC",
+  creqv_3 =	"4c000242CCC",
+  crset_1 =	"4c000242C==",
+  crorc_3 =	"4c000342CCC",
+  cror_3 =	"4c000382CCC",
+  crmove_2 =	"4c000382CC=",
+  bclr_2 =	"4c000020AA",
+  bclrl_2 =	"4c000021AA",
+  bcctr_2 =	"4c000420AA",
+  bcctrl_2 =	"4c000421AA",
+  blr_0 =	"4e800020",
+  blrl_0 =	"4e800021",
+  bctr_0 =	"4e800420",
+  bctrl_0 =	"4e800421",
+
+  -- Primary opcode 31:
+  cmpw_3 =	"7c000000XRR",
+  cmpw_2 =	"7c000000-RR",
+  cmpd_3 =	"7c200000XRR",
+  cmpd_2 =	"7c200000-RR",
+  tw_3 =	"7c000008ARR",
+  subfc_3 =	"7c000010RRR.",
+  subc_3 =	"7c000010RRR~.",
+  mulhdu_3 =	"7c000012RRR.",
+  addc_3 =	"7c000014RRR.",
+  mulhwu_3 =	"7c000016RRR.",
+  isel_4 =	"7c00001eRRRC",
+  isellt_3 =	"7c00001eRRR",
+  iselgt_3 =	"7c00005eRRR",
+  iseleq_3 =	"7c00009eRRR",
+  mfcr_1 =	"7c000026R",
+  -- NYI: mtcrf, mtocrf, mfocrf
+  lwarx_3 =	"7c000028RR0R",
+  ldx_3 =	"7c00002aRR0R",
+  lwzx_3 =	"7c00002eRR0R",
+  slw_3 =	"7c000030RR~R.",
+  cntlzw_2 =	"7c000034RR~",
+  sld_3 =	"7c000036RR~R.",
+  and_3 =	"7c000038RR~R.",
+  cmplw_3 =	"7c000040XRR",
+  cmplw_2 =	"7c000040-RR",
+  cmpld_3 =	"7c200040XRR",
+  cmpld_2 =	"7c200040-RR",
+  subf_3 =	"7c000050RRR.",
+  sub_3 =	"7c000050RRR~.",
+  ldux_3 =	"7c00006aRR0R",
+  dcbst_2 =	"7c00006c-RR",
+  lwzux_3 =	"7c00006eRR0R",
+  cntlzd_2 =	"7c000074RR~",
+  andc_3 =	"7c000078RR~R.",
+  td_3 =	"7c000088ARR",
+  mulhd_3 =	"7c000092RRR.",
+  mulhw_3 =	"7c000096RRR.",
+  ldarx_3 =	"7c0000a8RR0R",
+  dcbf_2 =	"7c0000ac-RR",
+  lbzx_3 =	"7c0000aeRR0R",
+  neg_2 =	"7c0000d0RR.",
+  lbzux_3 =	"7c0000eeRR0R",
+  popcntb_2 =	"7c0000f4RR~",
+  not_2 =	"7c0000f8RR~%.",
+  nor_3 =	"7c0000f8RR~R.",
+  subfe_3 =	"7c000110RRR.",
+  sube_3 =	"7c000110RRR~.",
+  adde_3 =	"7c000114RRR.",
+  stdx_3 =	"7c00012aRR0R",
+  stwcx_3 =	"7c00012cRR0R.",
+  stwx_3 =	"7c00012eRR0R",
+  prtyw_2 =	"7c000134RR~",
+  stdux_3 =	"7c00016aRR0R",
+  stwux_3 =	"7c00016eRR0R",
+  prtyd_2 =	"7c000174RR~",
+  subfze_2 =	"7c000190RR.",
+  addze_2 =	"7c000194RR.",
+  stdcx_3 =	"7c0001acRR0R.",
+  stbx_3 =	"7c0001aeRR0R",
+  subfme_2 =	"7c0001d0RR.",
+  mulld_3 =	"7c0001d2RRR.",
+  addme_2 =	"7c0001d4RR.",
+  mullw_3 =	"7c0001d6RRR.",
+  dcbtst_2 =	"7c0001ec-RR",
+  stbux_3 =	"7c0001eeRR0R",
+  add_3 =	"7c000214RRR.",
+  dcbt_2 =	"7c00022c-RR",
+  lhzx_3 =	"7c00022eRR0R",
+  eqv_3 =	"7c000238RR~R.",
+  eciwx_3 =	"7c00026cRR0R",
+  lhzux_3 =	"7c00026eRR0R",
+  xor_3 =	"7c000278RR~R.",
+  mfspefscr_1 =	"7c0082a6R",
+  mfxer_1 =	"7c0102a6R",
+  mflr_1 =	"7c0802a6R",
+  mfctr_1 =	"7c0902a6R",
+  lwax_3 =	"7c0002aaRR0R",
+  lhax_3 =	"7c0002aeRR0R",
+  mftb_1 =	"7c0c42e6R",
+  mftbu_1 =	"7c0d42e6R",
+  lwaux_3 =	"7c0002eaRR0R",
+  lhaux_3 =	"7c0002eeRR0R",
+  sthx_3 =	"7c00032eRR0R",
+  orc_3 =	"7c000338RR~R.",
+  ecowx_3 =	"7c00036cRR0R",
+  sthux_3 =	"7c00036eRR0R",
+  or_3 =	"7c000378RR~R.",
+  mr_2 =	"7c000378RR~%.",
+  divdu_3 =	"7c000392RRR.",
+  divwu_3 =	"7c000396RRR.",
+  mtspefscr_1 =	"7c0083a6R",
+  mtxer_1 =	"7c0103a6R",
+  mtlr_1 =	"7c0803a6R",
+  mtctr_1 =	"7c0903a6R",
+  dcbi_2 =	"7c0003ac-RR",
+  nand_3 =	"7c0003b8RR~R.",
+  divd_3 =	"7c0003d2RRR.",
+  divw_3 =	"7c0003d6RRR.",
+  cmpb_3 =	"7c0003f8RR~R.",
+  mcrxr_1 =	"7c000400X",
+  subfco_3 =	"7c000410RRR.",
+  subco_3 =	"7c000410RRR~.",
+  addco_3 =	"7c000414RRR.",
+  ldbrx_3 =	"7c000428RR0R",
+  lswx_3 =	"7c00042aRR0R",
+  lwbrx_3 =	"7c00042cRR0R",
+  lfsx_3 =	"7c00042eFR0R",
+  srw_3 =	"7c000430RR~R.",
+  srd_3 =	"7c000436RR~R.",
+  subfo_3 =	"7c000450RRR.",
+  subo_3 =	"7c000450RRR~.",
+  lfsux_3 =	"7c00046eFR0R",
+  lswi_3 =	"7c0004aaRR0A",
+  sync_0 =	"7c0004ac",
+  lwsync_0 =	"7c2004ac",
+  ptesync_0 =	"7c4004ac",
+  lfdx_3 =	"7c0004aeFR0R",
+  nego_2 =	"7c0004d0RR.",
+  lfdux_3 =	"7c0004eeFR0R",
+  subfeo_3 =	"7c000510RRR.",
+  subeo_3 =	"7c000510RRR~.",
+  addeo_3 =	"7c000514RRR.",
+  stdbrx_3 =	"7c000528RR0R",
+  stswx_3 =	"7c00052aRR0R",
+  stwbrx_3 =	"7c00052cRR0R",
+  stfsx_3 =	"7c00052eFR0R",
+  stfsux_3 =	"7c00056eFR0R",
+  subfzeo_2 =	"7c000590RR.",
+  addzeo_2 =	"7c000594RR.",
+  stswi_3 =	"7c0005aaRR0A",
+  stfdx_3 =	"7c0005aeFR0R",
+  subfmeo_2 =	"7c0005d0RR.",
+  mulldo_3 =	"7c0005d2RRR.",
+  addmeo_2 =	"7c0005d4RR.",
+  mullwo_3 =	"7c0005d6RRR.",
+  dcba_2 =	"7c0005ec-RR",
+  stfdux_3 =	"7c0005eeFR0R",
+  addo_3 =	"7c000614RRR.",
+  lhbrx_3 =	"7c00062cRR0R",
+  sraw_3 =	"7c000630RR~R.",
+  srad_3 =	"7c000634RR~R.",
+  srawi_3 =	"7c000670RR~A.",
+  eieio_0 =	"7c0006ac",
+  lfiwax_3 =	"7c0006aeFR0R",
+  sthbrx_3 =	"7c00072cRR0R",
+  extsh_2 =	"7c000734RR~.",
+  extsb_2 =	"7c000774RR~.",
+  divduo_3 =	"7c000792RRR.",
+  divwou_3 =	"7c000796RRR.",
+  icbi_2 =	"7c0007ac-RR",
+  stfiwx_3 =	"7c0007aeFR0R",
+  extsw_2 =	"7c0007b4RR~.",
+  divdo_3 =	"7c0007d2RRR.",
+  divwo_3 =	"7c0007d6RRR.",
+  dcbz_2 =	"7c0007ec-RR",
+
+  -- Primary opcode 59:
+  fdivs_3 =	"ec000024FFF.",
+  fsubs_3 =	"ec000028FFF.",
+  fadds_3 =	"ec00002aFFF.",
+  fsqrts_2 =	"ec00002cF-F.",
+  fres_2 =	"ec000030F-F.",
+  fmuls_3 =	"ec000032FF-F.",
+  frsqrtes_2 =	"ec000034F-F.",
+  fmsubs_4 =	"ec000038FFFF~.",
+  fmadds_4 =	"ec00003aFFFF~.",
+  fnmsubs_4 =	"ec00003cFFFF~.",
+  fnmadds_4 =	"ec00003eFFFF~.",
+
+  -- Primary opcode 63:
+  fdiv_3 =	"fc000024FFF.",
+  fsub_3 =	"fc000028FFF.",
+  fadd_3 =	"fc00002aFFF.",
+  fsqrt_2 =	"fc00002cF-F.",
+  fsel_4 =	"fc00002eFFFF~.",
+  fre_2 =	"fc000030F-F.",
+  fmul_3 =	"fc000032FF-F.",
+  frsqrte_2 =	"fc000034F-F.",
+  fmsub_4 =	"fc000038FFFF~.",
+  fmadd_4 =	"fc00003aFFFF~.",
+  fnmsub_4 =	"fc00003cFFFF~.",
+  fnmadd_4 =	"fc00003eFFFF~.",
+  fcmpu_3 =	"fc000000XFF",
+  fcpsgn_3 =	"fc000010FFF.",
+  fcmpo_3 =	"fc000040XFF",
+  mtfsb1_1 =	"fc00004cA",
+  fneg_2 =	"fc000050F-F.",
+  mcrfs_2 =	"fc000080XX",
+  mtfsb0_1 =	"fc00008cA",
+  fmr_2 =	"fc000090F-F.",
+  frsp_2 =	"fc000018F-F.",
+  fctiw_2 =	"fc00001cF-F.",
+  fctiwz_2 =	"fc00001eF-F.",
+  mtfsfi_2 =	"fc00010cAA", -- NYI: upshift.
+  fnabs_2 =	"fc000110F-F.",
+  fabs_2 =	"fc000210F-F.",
+  frin_2 =	"fc000310F-F.",
+  friz_2 =	"fc000350F-F.",
+  frip_2 =	"fc000390F-F.",
+  frim_2 =	"fc0003d0F-F.",
+  mffs_1 =	"fc00048eF.",
+  mtfsf_1 =	"fc00058eF.",
+  fctid_2 =	"fc00065cF-F.",
+  fctidz_2 =	"fc00065eF-F.",
+  fcfid_2 =	"fc00069cF-F.",
+
+  -- Primary opcode 4, SPE APU extension:
+  evaddw_3 =		"10000200RRR",
+  evaddiw_3 =		"10000202RAR~",
+  evsubw_3 =		"10000204RRR~",
+  evsubiw_3 =		"10000206RAR~",
+  evabs_2 =		"10000208RR",
+  evneg_2 =		"10000209RR",
+  evextsb_2 =		"1000020aRR",
+  evextsh_2 =		"1000020bRR",
+  evrndw_2 =		"1000020cRR",
+  evcntlzw_2 =		"1000020dRR",
+  evcntlsw_2 =		"1000020eRR",
+  brinc_3 =		"1000020fRRR",
+  evand_3 =		"10000211RRR",
+  evandc_3 =		"10000212RRR",
+  evxor_3 =		"10000216RRR",
+  evor_3 =		"10000217RRR",
+  evmr_2 =		"10000217RR=",
+  evnor_3 =		"10000218RRR",
+  evnot_2 =		"10000218RR=",
+  eveqv_3 =		"10000219RRR",
+  evorc_3 =		"1000021bRRR",
+  evnand_3 =		"1000021eRRR",
+  evsrwu_3 =		"10000220RRR",
+  evsrws_3 =		"10000221RRR",
+  evsrwiu_3 =		"10000222RRA",
+  evsrwis_3 =		"10000223RRA",
+  evslw_3 =		"10000224RRR",
+  evslwi_3 =		"10000226RRA",
+  evrlw_3 =		"10000228RRR",
+  evsplati_2 =		"10000229RS",
+  evrlwi_3 =		"1000022aRRA",
+  evsplatfi_2 =		"1000022bRS",
+  evmergehi_3 =		"1000022cRRR",
+  evmergelo_3 =		"1000022dRRR",
+  evcmpgtu_3 =		"10000230XRR",
+  evcmpgtu_2 =		"10000230-RR",
+  evcmpgts_3 =		"10000231XRR",
+  evcmpgts_2 =		"10000231-RR",
+  evcmpltu_3 =		"10000232XRR",
+  evcmpltu_2 =		"10000232-RR",
+  evcmplts_3 =		"10000233XRR",
+  evcmplts_2 =		"10000233-RR",
+  evcmpeq_3 =		"10000234XRR",
+  evcmpeq_2 =		"10000234-RR",
+  evsel_4 =		"10000278RRRW",
+  evsel_3 =		"10000278RRR",
+  evfsadd_3 =		"10000280RRR",
+  evfssub_3 =		"10000281RRR",
+  evfsabs_2 =		"10000284RR",
+  evfsnabs_2 =		"10000285RR",
+  evfsneg_2 =		"10000286RR",
+  evfsmul_3 =		"10000288RRR",
+  evfsdiv_3 =		"10000289RRR",
+  evfscmpgt_3 =		"1000028cXRR",
+  evfscmpgt_2 =		"1000028c-RR",
+  evfscmplt_3 =		"1000028dXRR",
+  evfscmplt_2 =		"1000028d-RR",
+  evfscmpeq_3 =		"1000028eXRR",
+  evfscmpeq_2 =		"1000028e-RR",
+  evfscfui_2 =		"10000290R-R",
+  evfscfsi_2 =		"10000291R-R",
+  evfscfuf_2 =		"10000292R-R",
+  evfscfsf_2 =		"10000293R-R",
+  evfsctui_2 =		"10000294R-R",
+  evfsctsi_2 =		"10000295R-R",
+  evfsctuf_2 =		"10000296R-R",
+  evfsctsf_2 =		"10000297R-R",
+  evfsctuiz_2 =		"10000298R-R",
+  evfsctsiz_2 =		"1000029aR-R",
+  evfststgt_3 =		"1000029cXRR",
+  evfststgt_2 =		"1000029c-RR",
+  evfststlt_3 =		"1000029dXRR",
+  evfststlt_2 =		"1000029d-RR",
+  evfststeq_3 =		"1000029eXRR",
+  evfststeq_2 =		"1000029e-RR",
+  efsadd_3 =		"100002c0RRR",
+  efssub_3 =		"100002c1RRR",
+  efsabs_2 =		"100002c4RR",
+  efsnabs_2 =		"100002c5RR",
+  efsneg_2 =		"100002c6RR",
+  efsmul_3 =		"100002c8RRR",
+  efsdiv_3 =		"100002c9RRR",
+  efscmpgt_3 =		"100002ccXRR",
+  efscmpgt_2 =		"100002cc-RR",
+  efscmplt_3 =		"100002cdXRR",
+  efscmplt_2 =		"100002cd-RR",
+  efscmpeq_3 =		"100002ceXRR",
+  efscmpeq_2 =		"100002ce-RR",
+  efscfd_2 =		"100002cfR-R",
+  efscfui_2 =		"100002d0R-R",
+  efscfsi_2 =		"100002d1R-R",
+  efscfuf_2 =		"100002d2R-R",
+  efscfsf_2 =		"100002d3R-R",
+  efsctui_2 =		"100002d4R-R",
+  efsctsi_2 =		"100002d5R-R",
+  efsctuf_2 =		"100002d6R-R",
+  efsctsf_2 =		"100002d7R-R",
+  efsctuiz_2 =		"100002d8R-R",
+  efsctsiz_2 =		"100002daR-R",
+  efststgt_3 =		"100002dcXRR",
+  efststgt_2 =		"100002dc-RR",
+  efststlt_3 =		"100002ddXRR",
+  efststlt_2 =		"100002dd-RR",
+  efststeq_3 =		"100002deXRR",
+  efststeq_2 =		"100002de-RR",
+  efdadd_3 =		"100002e0RRR",
+  efdsub_3 =		"100002e1RRR",
+  efdcfuid_2 =		"100002e2R-R",
+  efdcfsid_2 =		"100002e3R-R",
+  efdabs_2 =		"100002e4RR",
+  efdnabs_2 =		"100002e5RR",
+  efdneg_2 =		"100002e6RR",
+  efdmul_3 =		"100002e8RRR",
+  efddiv_3 =		"100002e9RRR",
+  efdctuidz_2 =		"100002eaR-R",
+  efdctsidz_2 =		"100002ebR-R",
+  efdcmpgt_3 =		"100002ecXRR",
+  efdcmpgt_2 =		"100002ec-RR",
+  efdcmplt_3 =		"100002edXRR",
+  efdcmplt_2 =		"100002ed-RR",
+  efdcmpeq_3 =		"100002eeXRR",
+  efdcmpeq_2 =		"100002ee-RR",
+  efdcfs_2 =		"100002efR-R",
+  efdcfui_2 =		"100002f0R-R",
+  efdcfsi_2 =		"100002f1R-R",
+  efdcfuf_2 =		"100002f2R-R",
+  efdcfsf_2 =		"100002f3R-R",
+  efdctui_2 =		"100002f4R-R",
+  efdctsi_2 =		"100002f5R-R",
+  efdctuf_2 =		"100002f6R-R",
+  efdctsf_2 =		"100002f7R-R",
+  efdctuiz_2 =		"100002f8R-R",
+  efdctsiz_2 =		"100002faR-R",
+  efdtstgt_3 =		"100002fcXRR",
+  efdtstgt_2 =		"100002fc-RR",
+  efdtstlt_3 =		"100002fdXRR",
+  efdtstlt_2 =		"100002fd-RR",
+  efdtsteq_3 =		"100002feXRR",
+  efdtsteq_2 =		"100002fe-RR",
+  evlddx_3 =		"10000300RR0R",
+  evldd_2 =		"10000301R8",
+  evldwx_3 =		"10000302RR0R",
+  evldw_2 =		"10000303R8",
+  evldhx_3 =		"10000304RR0R",
+  evldh_2 =		"10000305R8",
+  evlwhex_3 =		"10000310RR0R",
+  evlwhe_2 =		"10000311R4",
+  evlwhoux_3 =		"10000314RR0R",
+  evlwhou_2 =		"10000315R4",
+  evlwhosx_3 =		"10000316RR0R",
+  evlwhos_2 =		"10000317R4",
+  evstddx_3 =		"10000320RR0R",
+  evstdd_2 =		"10000321R8",
+  evstdwx_3 =		"10000322RR0R",
+  evstdw_2 =		"10000323R8",
+  evstdhx_3 =		"10000324RR0R",
+  evstdh_2 =		"10000325R8",
+  evstwhex_3 =		"10000330RR0R",
+  evstwhe_2 =		"10000331R4",
+  evstwhox_3 =		"10000334RR0R",
+  evstwho_2 =		"10000335R4",
+  evstwwex_3 =		"10000338RR0R",
+  evstwwe_2 =		"10000339R4",
+  evstwwox_3 =		"1000033cRR0R",
+  evstwwo_2 =		"1000033dR4",
+  evmhessf_3 =		"10000403RRR",
+  evmhossf_3 =		"10000407RRR",
+  evmheumi_3 =		"10000408RRR",
+  evmhesmi_3 =		"10000409RRR",
+  evmhesmf_3 =		"1000040bRRR",
+  evmhoumi_3 =		"1000040cRRR",
+  evmhosmi_3 =		"1000040dRRR",
+  evmhosmf_3 =		"1000040fRRR",
+  evmhessfa_3 =		"10000423RRR",
+  evmhossfa_3 =		"10000427RRR",
+  evmheumia_3 =		"10000428RRR",
+  evmhesmia_3 =		"10000429RRR",
+  evmhesmfa_3 =		"1000042bRRR",
+  evmhoumia_3 =		"1000042cRRR",
+  evmhosmia_3 =		"1000042dRRR",
+  evmhosmfa_3 =		"1000042fRRR",
+  evmwhssf_3 =		"10000447RRR",
+  evmwlumi_3 =		"10000448RRR",
+  evmwhumi_3 =		"1000044cRRR",
+  evmwhsmi_3 =		"1000044dRRR",
+  evmwhsmf_3 =		"1000044fRRR",
+  evmwssf_3 =		"10000453RRR",
+  evmwumi_3 =		"10000458RRR",
+  evmwsmi_3 =		"10000459RRR",
+  evmwsmf_3 =		"1000045bRRR",
+  evmwhssfa_3 =		"10000467RRR",
+  evmwlumia_3 =		"10000468RRR",
+  evmwhumia_3 =		"1000046cRRR",
+  evmwhsmia_3 =		"1000046dRRR",
+  evmwhsmfa_3 =		"1000046fRRR",
+  evmwssfa_3 =		"10000473RRR",
+  evmwumia_3 =		"10000478RRR",
+  evmwsmia_3 =		"10000479RRR",
+  evmwsmfa_3 =		"1000047bRRR",
+  evmra_2 =		"100004c4RR",
+  evdivws_3 =		"100004c6RRR",
+  evdivwu_3 =		"100004c7RRR",
+  evmwssfaa_3 =		"10000553RRR",
+  evmwumiaa_3 =		"10000558RRR",
+  evmwsmiaa_3 =		"10000559RRR",
+  evmwsmfaa_3 =		"1000055bRRR",
+  evmwssfan_3 =		"100005d3RRR",
+  evmwumian_3 =		"100005d8RRR",
+  evmwsmian_3 =		"100005d9RRR",
+  evmwsmfan_3 =		"100005dbRRR",
+  evmergehilo_3 =	"1000022eRRR",
+  evmergelohi_3 =	"1000022fRRR",
+  evlhhesplatx_3 =	"10000308RR0R",
+  evlhhesplat_2 =	"10000309R2",
+  evlhhousplatx_3 =	"1000030cRR0R",
+  evlhhousplat_2 =	"1000030dR2",
+  evlhhossplatx_3 =	"1000030eRR0R",
+  evlhhossplat_2 =	"1000030fR2",
+  evlwwsplatx_3 =	"10000318RR0R",
+  evlwwsplat_2 =	"10000319R4",
+  evlwhsplatx_3 =	"1000031cRR0R",
+  evlwhsplat_2 =	"1000031dR4",
+  evaddusiaaw_2 =	"100004c0RR",
+  evaddssiaaw_2 =	"100004c1RR",
+  evsubfusiaaw_2 =	"100004c2RR",
+  evsubfssiaaw_2 =	"100004c3RR",
+  evaddumiaaw_2 =	"100004c8RR",
+  evaddsmiaaw_2 =	"100004c9RR",
+  evsubfumiaaw_2 =	"100004caRR",
+  evsubfsmiaaw_2 =	"100004cbRR",
+  evmheusiaaw_3 =	"10000500RRR",
+  evmhessiaaw_3 =	"10000501RRR",
+  evmhessfaaw_3 =	"10000503RRR",
+  evmhousiaaw_3 =	"10000504RRR",
+  evmhossiaaw_3 =	"10000505RRR",
+  evmhossfaaw_3 =	"10000507RRR",
+  evmheumiaaw_3 =	"10000508RRR",
+  evmhesmiaaw_3 =	"10000509RRR",
+  evmhesmfaaw_3 =	"1000050bRRR",
+  evmhoumiaaw_3 =	"1000050cRRR",
+  evmhosmiaaw_3 =	"1000050dRRR",
+  evmhosmfaaw_3 =	"1000050fRRR",
+  evmhegumiaa_3 =	"10000528RRR",
+  evmhegsmiaa_3 =	"10000529RRR",
+  evmhegsmfaa_3 =	"1000052bRRR",
+  evmhogumiaa_3 =	"1000052cRRR",
+  evmhogsmiaa_3 =	"1000052dRRR",
+  evmhogsmfaa_3 =	"1000052fRRR",
+  evmwlusiaaw_3 =	"10000540RRR",
+  evmwlssiaaw_3 =	"10000541RRR",
+  evmwlumiaaw_3 =	"10000548RRR",
+  evmwlsmiaaw_3 =	"10000549RRR",
+  evmheusianw_3 =	"10000580RRR",
+  evmhessianw_3 =	"10000581RRR",
+  evmhessfanw_3 =	"10000583RRR",
+  evmhousianw_3 =	"10000584RRR",
+  evmhossianw_3 =	"10000585RRR",
+  evmhossfanw_3 =	"10000587RRR",
+  evmheumianw_3 =	"10000588RRR",
+  evmhesmianw_3 =	"10000589RRR",
+  evmhesmfanw_3 =	"1000058bRRR",
+  evmhoumianw_3 =	"1000058cRRR",
+  evmhosmianw_3 =	"1000058dRRR",
+  evmhosmfanw_3 =	"1000058fRRR",
+  evmhegumian_3 =	"100005a8RRR",
+  evmhegsmian_3 =	"100005a9RRR",
+  evmhegsmfan_3 =	"100005abRRR",
+  evmhogumian_3 =	"100005acRRR",
+  evmhogsmian_3 =	"100005adRRR",
+  evmhogsmfan_3 =	"100005afRRR",
+  evmwlusianw_3 =	"100005c0RRR",
+  evmwlssianw_3 =	"100005c1RRR",
+  evmwlumianw_3 =	"100005c8RRR",
+  evmwlsmianw_3 =	"100005c9RRR",
+
+  -- NYI: some 64 bit PowerPC and Book E instructions:
+  --   rldicl, rldicr, rldic, rldimi, rldcl, rldcr, sradi, 64 bit ext. add/sub,
+  --   extended addressing branches, cache management, loads and stores
+}
+
+-- Add mnemonics for "." variants.
+do
+  local t = {}
+  for k,v in pairs(map_op) do
+    if sub(v, -1) == "." then
+      local v2 = sub(v, 1, 7)..char(byte(v, 8)+1)..sub(v, 9, -2)
+      t[sub(k, 1, -3).."."..sub(k, -2)] = v2
+    end
+  end
+  for k,v in pairs(t) do
+    map_op[k] = v
+  end
+end
+
+-- Add more branch mnemonics.
+for cond,c in pairs(map_cond) do
+  local b1 = "b"..cond
+  local c1 = (c%4)*0x00010000 + (c < 4 and 0x01000000 or 0)
+  -- bX[l]
+  map_op[b1.."_1"] = tohex(0x40800000 + c1).."K"
+  map_op[b1.."l_1"] = tohex(0x40800001 + c1).."K"
+  map_op[b1.."_2"] = tohex(0x40800000 + c1).."-XK"
+  map_op[b1.."l_2"] = tohex(0x40800001 + c1).."-XK"
+  -- bXlr[l]
+  map_op[b1.."lr_0"] = tohex(0x4c800020 + c1)
+  map_op[b1.."lrl_0"] = tohex(0x4c800021 + c1)
+  map_op[b1.."ctr_0"] = tohex(0x4c800420 + c1)
+  map_op[b1.."ctrl_0"] = tohex(0x4c800421 + c1)
+  -- bXctr[l]
+  map_op[b1.."lr_1"] = tohex(0x4c800020 + c1).."-X"
+  map_op[b1.."lrl_1"] = tohex(0x4c800021 + c1).."-X"
+  map_op[b1.."ctr_1"] = tohex(0x4c800420 + c1).."-X"
+  map_op[b1.."ctrl_1"] = tohex(0x4c800421 + c1).."-X"
+end
+
+------------------------------------------------------------------------------
+
+local function parse_gpr(expr)
+  local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$")
+  local tp = map_type[tname or expr]
+  if tp then
+    local reg = ovreg or tp.reg
+    if not reg then
+      werror("type `"..(tname or expr).."' needs a register override")
+    end
+    expr = reg
+  end
+  local r = match(expr, "^r([1-3]?[0-9])$")
+  if r then
+    r = tonumber(r)
+    if r <= 31 then return r, tp end
+  end
+  werror("bad register name `"..expr.."'")
+end
+
+local function parse_fpr(expr)
+  local r = match(expr, "^f([1-3]?[0-9])$")
+  if r then
+    r = tonumber(r)
+    if r <= 31 then return r end
+  end
+  werror("bad register name `"..expr.."'")
+end
+
+local function parse_cr(expr)
+  local r = match(expr, "^cr([0-7])$")
+  if r then return tonumber(r) end
+  werror("bad condition register name `"..expr.."'")
+end
+
+local function parse_cond(expr)
+  local r, cond = match(expr, "^4%*cr([0-7])%+(%w%w)$")
+  if r then
+    r = tonumber(r)
+    local c = map_cond[cond]
+    if c and c < 4 then return r*4+c end
+  end
+  werror("bad condition bit name `"..expr.."'")
+end
+
+local function parse_imm(imm, bits, shift, scale, signed)
+  local n = tonumber(imm)
+  if n then
+    if n % 2^scale == 0 then
+      n = n / 2^scale
+      if signed then
+	if n >= 0 then
+	  if n < 2^(bits-1) then return n*2^shift end
+	else
+	  if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end
+	end
+      else
+	if n >= 0 and n <= 2^bits-1 then return n*2^shift end
+      end
+    end
+    werror("out of range immediate `"..imm.."'")
+  elseif match(imm, "^r([1-3]?[0-9])$") or
+	 match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then
+    werror("expected immediate operand, got register")
+  else
+    waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
+    return 0
+  end
+end
+
+local function parse_disp(disp)
+  local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
+  if imm then
+    local r = parse_gpr(reg)
+    if r == 0 then werror("cannot use r0 in displacement") end
+    return r*65536 + parse_imm(imm, 16, 0, 0, true)
+  end
+  local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
+  if reg and tailr ~= "" then
+    local r, tp = parse_gpr(reg)
+    if r == 0 then werror("cannot use r0 in displacement") end
+    if tp then
+      waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr))
+      return r*65536
+    end
+  end
+  werror("bad displacement `"..disp.."'")
+end
+
+local function parse_u5disp(disp, scale)
+  local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
+  if imm then
+    local r = parse_gpr(reg)
+    if r == 0 then werror("cannot use r0 in displacement") end
+    return r*65536 + parse_imm(imm, 5, 11, scale, false)
+  end
+  local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
+  if reg and tailr ~= "" then
+    local r, tp = parse_gpr(reg)
+    if r == 0 then werror("cannot use r0 in displacement") end
+    if tp then
+      waction("IMM", scale*1024+5*32+11, format(tp.ctypefmt, tailr))
+      return r*65536
+    end
+  end
+  werror("bad displacement `"..disp.."'")
+end
+
+local function parse_label(label, def)
+  local prefix = sub(label, 1, 2)
+  -- =>label (pc label reference)
+  if prefix == "=>" then
+    return "PC", 0, sub(label, 3)
+  end
+  -- ->name (global label reference)
+  if prefix == "->" then
+    return "LG", map_global[sub(label, 3)]
+  end
+  if def then
+    -- [1-9] (local label definition)
+    if match(label, "^[1-9]$") then
+      return "LG", 10+tonumber(label)
+    end
+  else
+    -- [<>][1-9] (local label reference)
+    local dir, lnum = match(label, "^([<>])([1-9])$")
+    if dir then -- Fwd: 1-9, Bkwd: 11-19.
+      return "LG", lnum + (dir == ">" and 0 or 10)
+    end
+    -- extern label (extern label reference)
+    local extname = match(label, "^extern%s+(%S+)$")
+    if extname then
+      return "EXT", map_extern[extname]
+    end
+  end
+  werror("bad label `"..label.."'")
+end
+
+------------------------------------------------------------------------------
+
+-- Handle opcodes defined with template strings.
+map_op[".template__"] = function(params, template, nparams)
+  if not params then return sub(template, 9) end
+  local op = tonumber(sub(template, 1, 8), 16)
+  local n, rs = 1, 26
+
+  -- Limit number of section buffer positions used by a single dasm_put().
+  -- A single opcode needs a maximum of 3 positions (rlwinm).
+  if secpos+3 > maxsecpos then wflush() end
+  local pos = wpos()
+
+  -- Process each character.
+  for p in gmatch(sub(template, 9), ".") do
+    if p == "R" then
+      rs = rs - 5; op = op + parse_gpr(params[n]) * 2^rs; n = n + 1
+    elseif p == "F" then
+      rs = rs - 5; op = op + parse_fpr(params[n]) * 2^rs; n = n + 1
+    elseif p == "A" then
+      rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, false); n = n + 1
+    elseif p == "S" then
+      rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, true); n = n + 1
+    elseif p == "I" then
+      op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1
+    elseif p == "U" then
+      op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1
+    elseif p == "D" then
+      op = op + parse_disp(params[n]); n = n + 1
+    elseif p == "2" then
+      op = op + parse_u5disp(params[n], 1); n = n + 1
+    elseif p == "4" then
+      op = op + parse_u5disp(params[n], 2); n = n + 1
+    elseif p == "8" then
+      op = op + parse_u5disp(params[n], 3); n = n + 1
+    elseif p == "C" then
+      rs = rs - 5; op = op + parse_cond(params[n]) * 2^rs; n = n + 1
+    elseif p == "X" then
+      rs = rs - 5; op = op + parse_cr(params[n]) * 2^(rs+2); n = n + 1
+    elseif p == "W" then
+      op = op + parse_cr(params[n]); n = n + 1
+    elseif p == "J" or p == "K" then
+      local mode, n, s = parse_label(params[n], false)
+      if p == "K" then n = n + 2048 end
+      waction("REL_"..mode, n, s, 1)
+      n = n + 1
+    elseif p == "0" then
+      local mm = 2^rs
+      local t = op % mm
+      if ((op - t) / mm) % 32 == 0 then werror("cannot use r0") end
+    elseif p == "=" or p == "%" then
+      local mm = 2^(rs + (p == "%" and 5 or 0))
+      local t = ((op - op % mm) / mm) % 32
+      rs = rs - 5
+      op = op + t * 2^rs
+    elseif p == "~" then
+      local mm = 2^rs
+      local t1l = op % mm
+      local t1h = (op - t1l) / mm
+      local t2l = t1h % 32
+      local t2h = (t1h - t2l) / 32
+      local t3l = t2h % 32
+      op = ((t2h - t3l + t2l)*32 + t3l)*mm + t1l
+    elseif p == "-" then
+      rs = rs - 5
+    elseif p == "." then
+      -- Ignored.
+    else
+      assert(false)
+    end
+  end
+  wputpos(pos, op)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+  if not params then return "cvar" end
+  local name = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+  if not params then return "prefix" end
+  local prefix = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+  if not params then return "cvar" end
+  local name = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+  if not params then return "cvar" end
+  local name = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_1"] = function(params)
+  if not params then return "[1-9] | ->global | =>pcexpr" end
+  if secpos+1 > maxsecpos then wflush() end
+  local mode, n, s = parse_label(params[1], true)
+  if mode == "EXT" then werror("bad label definition") end
+  waction("LABEL_"..mode, n, s, 1)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+map_op[".long_*"] = function(params)
+  if not params then return "imm..." end
+  for _,p in ipairs(params) do
+    local n = tonumber(p)
+    if not n then werror("bad immediate `"..p.."'") end
+    if n < 0 then n = n + 2^32 end
+    wputw(n)
+    if secpos+2 > maxsecpos then wflush() end
+  end
+end
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+  if not params then return "numpow2" end
+  if secpos+1 > maxsecpos then wflush() end
+  local align = tonumber(params[1])
+  if align then
+    local x = align
+    -- Must be a power of 2 in the range (2 ... 256).
+    for i=1,8 do
+      x = x / 2
+      if x == 1 then
+	waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
+	return
+      end
+    end
+  end
+  werror("bad alignment")
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+  if not params then
+    return nparams == 2 and "name, ctype" or "name, ctype, reg"
+  end
+  local name, ctype, reg = params[1], params[2], params[3]
+  if not match(name, "^[%a_][%w_]*$") then
+    werror("bad type name `"..name.."'")
+  end
+  local tp = map_type[name]
+  if tp then
+    werror("duplicate type `"..name.."'")
+  end
+  -- Add #type to defines. A bit unclean to put it in map_archdef.
+  map_archdef["#"..name] = "sizeof("..ctype..")"
+  -- Add new type and emit shortcut define.
+  local num = ctypenum + 1
+  map_type[name] = {
+    ctype = ctype,
+    ctypefmt = format("Dt%X(%%s)", num),
+    reg = reg,
+  }
+  wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+  ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+  local t = {}
+  for name in pairs(map_type) do t[#t+1] = name end
+  sort(t)
+  out:write("Type definitions:\n")
+  for _,name in ipairs(t) do
+    local tp = map_type[name]
+    local reg = tp.reg or ""
+    out:write(format("  %-20s %-20s %s\n", name, tp.ctype, reg))
+  end
+  out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+  waction("SECTION", num)
+  wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+  out:write(format("DynASM %s version %s, released %s\n\n",
+    _info.arch, _info.version, _info.release))
+  dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+  dumptypes(out, lvl)
+  dumpglobals(out, lvl)
+  dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+  wline, werror, wfatal, wwarn = wl, we, wf, ww
+  return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+  g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+  setmetatable(map_op, { __index = map_coreop })
+  setmetatable(map_def, { __index = map_archdef })
+  return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_proto.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_proto.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_proto.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,83 @@
+/*
+** DynASM encoding engine prototypes.
+** Copyright (C) 2005-2011 Mike Pall. All rights reserved.
+** Released under the MIT/X license. See dynasm.lua for full copyright notice.
+*/
+
+#ifndef _DASM_PROTO_H
+#define _DASM_PROTO_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+#define DASM_IDENT	"DynASM 1.3.0"
+#define DASM_VERSION	10300	/* 1.3.0 */
+
+#ifndef Dst_DECL
+#define Dst_DECL	dasm_State **Dst
+#endif
+
+#ifndef Dst_REF
+#define Dst_REF		(*Dst)
+#endif
+
+#ifndef DASM_FDEF
+#define DASM_FDEF	extern
+#endif
+
+#ifndef DASM_M_GROW
+#define DASM_M_GROW(ctx, t, p, sz, need) \
+  do { \
+    size_t _sz = (sz), _need = (need); \
+    if (_sz < _need) { \
+      if (_sz < 16) _sz = 16; \
+      while (_sz < _need) _sz += _sz; \
+      (p) = (t *)realloc((p), _sz); \
+      if ((p) == NULL) exit(1); \
+      (sz) = _sz; \
+    } \
+  } while(0)
+#endif
+
+#ifndef DASM_M_FREE
+#define DASM_M_FREE(ctx, p, sz)	free(p)
+#endif
+
+/* Internal DynASM encoder state. */
+typedef struct dasm_State dasm_State;
+
+
+/* Initialize and free DynASM state. */
+DASM_FDEF void dasm_init(Dst_DECL, int maxsection);
+DASM_FDEF void dasm_free(Dst_DECL);
+
+/* Setup global array. Must be called before dasm_setup(). */
+DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl);
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc);
+
+/* Setup encoder. */
+DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist);
+
+/* Feed encoder with actions. Calls are generated by pre-processor. */
+DASM_FDEF void dasm_put(Dst_DECL, int start, ...);
+
+/* Link sections and return the resulting size. */
+DASM_FDEF int dasm_link(Dst_DECL, size_t *szp);
+
+/* Encode sections into buffer. */
+DASM_FDEF int dasm_encode(Dst_DECL, void *buffer);
+
+/* Get PC label offset. */
+DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc);
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch);
+#else
+#define dasm_checkstep(a, b)	0
+#endif
+
+
+#endif /* _DASM_PROTO_H */


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_proto.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x64.lua
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x64.lua	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x64.lua	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,12 @@
+------------------------------------------------------------------------------
+-- DynASM x64 module.
+--
+-- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+-- This module just sets 64 bit mode for the combined x86/x64 module.
+-- All the interesting stuff is there.
+------------------------------------------------------------------------------
+
+x64 = true -- Using a global is an ugly, but effective solution.
+return require("dasm_x86")

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,470 @@
+/*
+** DynASM x86 encoding engine.
+** Copyright (C) 2005-2011 Mike Pall. All rights reserved.
+** Released under the MIT/X license. See dynasm.lua for full copyright notice.
+*/
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define DASM_ARCH		"x86"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d)	0
+#endif
+
+/* Action definitions. DASM_STOP must be 255. */
+enum {
+  DASM_DISP = 233,
+  DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB,
+  DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC,
+  DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN,
+  DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS		25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK		0x00000000
+#define DASM_S_NOMEM		0x01000000
+#define DASM_S_PHASE		0x02000000
+#define DASM_S_MATCH_SEC	0x03000000
+#define DASM_S_RANGE_I		0x11000000
+#define DASM_S_RANGE_SEC	0x12000000
+#define DASM_S_RANGE_LG		0x13000000
+#define DASM_S_RANGE_PC		0x14000000
+#define DASM_S_RANGE_VREG	0x15000000
+#define DASM_S_UNDEF_L		0x21000000
+#define DASM_S_UNDEF_PC		0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos)	((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos)	((pos)&0xff000000)
+#define DASM_SEC2POS(sec)	((sec)<<24)
+#define DASM_POS2SEC(pos)	((pos)>>24)
+#define DASM_POS2PTR(D, pos)	(D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned char *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+  int *rbuf;		/* Biased buffer pointer (negative section bias). */
+  int *buf;		/* True buffer pointer. */
+  size_t bsize;		/* Buffer size in bytes. */
+  int pos;		/* Biased buffer position. */
+  int epos;		/* End of biased buffer position - max single put. */
+  int ofs;		/* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+  size_t psize;			/* Allocated size of this structure. */
+  dasm_ActList actionlist;	/* Current actionlist pointer. */
+  int *lglabels;		/* Local/global chain/pos ptrs. */
+  size_t lgsize;
+  int *pclabels;		/* PC label chains/pos ptrs. */
+  size_t pcsize;
+  void **globals;		/* Array of globals (bias -10). */
+  dasm_Section *section;	/* Pointer to active section. */
+  size_t codesize;		/* Total size of all code sections. */
+  int maxsection;		/* 0 <= sectionidx < maxsection. */
+  int status;			/* Status code. */
+  dasm_Section sections[1];	/* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms)	(sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+  dasm_State *D;
+  size_t psz = 0;
+  int i;
+  Dst_REF = NULL;
+  DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+  D = Dst_REF;
+  D->psize = psz;
+  D->lglabels = NULL;
+  D->lgsize = 0;
+  D->pclabels = NULL;
+  D->pcsize = 0;
+  D->globals = NULL;
+  D->maxsection = maxsection;
+  for (i = 0; i < maxsection; i++) {
+    D->sections[i].buf = NULL;  /* Need this for pass3. */
+    D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+    D->sections[i].bsize = 0;
+    D->sections[i].epos = 0;  /* Wrong, but is recalculated after resize. */
+  }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+  dasm_State *D = Dst_REF;
+  int i;
+  for (i = 0; i < D->maxsection; i++)
+    if (D->sections[i].buf)
+      DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+  if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+  if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+  DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+  dasm_State *D = Dst_REF;
+  D->globals = gl - 10;  /* Negative bias to compensate for locals. */
+  DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+  dasm_State *D = Dst_REF;
+  size_t osz = D->pcsize;
+  DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+  memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+  dasm_State *D = Dst_REF;
+  int i;
+  D->actionlist = (dasm_ActList)actionlist;
+  D->status = DASM_S_OK;
+  D->section = &D->sections[0];
+  memset((void *)D->lglabels, 0, D->lgsize);
+  if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+  for (i = 0; i < D->maxsection; i++) {
+    D->sections[i].pos = DASM_SEC2POS(i);
+    D->sections[i].ofs = 0;
+  }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+  do { if (!(x)) { \
+    D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+  do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+    D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st)	((void)0)
+#define CKPL(kind, st)	((void)0)
+#endif
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+  va_list ap;
+  dasm_State *D = Dst_REF;
+  dasm_ActList p = D->actionlist + start;
+  dasm_Section *sec = D->section;
+  int pos = sec->pos, ofs = sec->ofs, mrm = 4;
+  int *b;
+
+  if (pos >= sec->epos) {
+    DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+      sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+    sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+    sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+  }
+
+  b = sec->rbuf;
+  b[pos++] = start;
+
+  va_start(ap, start);
+  while (1) {
+    int action = *p++;
+    if (action < DASM_DISP) {
+      ofs++;
+    } else if (action <= DASM_REL_A) {
+      int n = va_arg(ap, int);
+      b[pos++] = n;
+      switch (action) {
+      case DASM_DISP:
+	if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; }
+      case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob;
+      case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */
+      case DASM_IMM_D: ofs += 4; break;
+      case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob;
+      case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break;
+      case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob;
+      case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break;
+      case DASM_SPACE: p++; ofs += n; break;
+      case DASM_SETLABEL: b[pos-2] = -0x40000000; break;  /* Neg. label ofs. */
+      case DASM_VREG: CK((n&-8) == 0 && (n != 4 || (*p&1) == 0), RANGE_VREG);
+	if (*p++ == 1 && *p == DASM_DISP) mrm = n; continue;
+      }
+      mrm = 4;
+    } else {
+      int *pl, n;
+      switch (action) {
+      case DASM_REL_LG:
+      case DASM_IMM_LG:
+	n = *p++; pl = D->lglabels + n;
+	if (n <= 246) { CKPL(lg, LG); goto putrel; }  /* Bkwd rel or global. */
+	pl -= 246; n = *pl;
+	if (n < 0) n = 0;  /* Start new chain for fwd rel if label exists. */
+	goto linkrel;
+      case DASM_REL_PC:
+      case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
+      putrel:
+	n = *pl;
+	if (n < 0) {  /* Label exists. Get label pos and store it. */
+	  b[pos] = -n;
+	} else {
+      linkrel:
+	  b[pos] = n;  /* Else link to rel chain, anchored at label. */
+	  *pl = pos;
+	}
+	pos++;
+	ofs += 4;  /* Maximum offset needed. */
+	if (action == DASM_REL_LG || action == DASM_REL_PC)
+	  b[pos++] = ofs;  /* Store pass1 offset estimate. */
+	break;
+      case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel;
+      case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
+      putlabel:
+	n = *pl;  /* n > 0: Collapse rel chain and replace with label pos. */
+	while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; }
+	*pl = -pos;  /* Label exists now. */
+	b[pos++] = ofs;  /* Store pass1 offset estimate. */
+	break;
+      case DASM_ALIGN:
+	ofs += *p++;  /* Maximum alignment needed (arg is 2**n-1). */
+	b[pos++] = ofs;  /* Store pass1 offset estimate. */
+	break;
+      case DASM_EXTERN: p += 2; ofs += 4; break;
+      case DASM_ESC: p++; ofs++; break;
+      case DASM_MARK: mrm = p[-2]; break;
+      case DASM_SECTION:
+	n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n];
+      case DASM_STOP: goto stop;
+      }
+    }
+  }
+stop:
+  va_end(ap);
+  sec->pos = pos;
+  sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+  dasm_State *D = Dst_REF;
+  int secnum;
+  int ofs = 0;
+
+#ifdef DASM_CHECKS
+  *szp = 0;
+  if (D->status != DASM_S_OK) return D->status;
+  {
+    int pc;
+    for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+      if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+  }
+#endif
+
+  { /* Handle globals not defined in this translation unit. */
+    int idx;
+    for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
+      int n = D->lglabels[idx];
+      /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+      while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+    }
+  }
+
+  /* Combine all code sections. No support for data sections (yet). */
+  for (secnum = 0; secnum < D->maxsection; secnum++) {
+    dasm_Section *sec = D->sections + secnum;
+    int *b = sec->rbuf;
+    int pos = DASM_SEC2POS(secnum);
+    int lastpos = sec->pos;
+
+    while (pos != lastpos) {
+      dasm_ActList p = D->actionlist + b[pos++];
+      while (1) {
+	int op, action = *p++;
+	switch (action) {
+	case DASM_REL_LG: p++; op = p[-3]; goto rel_pc;
+	case DASM_REL_PC: op = p[-2]; rel_pc: {
+	  int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0);
+	  if (shrink) {  /* Shrinkable branch opcode? */
+	    int lofs, lpos = b[pos];
+	    if (lpos < 0) goto noshrink;  /* Ext global? */
+	    lofs = *DASM_POS2PTR(D, lpos);
+	    if (lpos > pos) {  /* Fwd label: add cumulative section offsets. */
+	      int i;
+	      for (i = secnum; i < DASM_POS2SEC(lpos); i++)
+		lofs += D->sections[i].ofs;
+	    } else {
+	      lofs -= ofs;  /* Bkwd label: unfix offset. */
+	    }
+	    lofs -= b[pos+1];  /* Short branch ok? */
+	    if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink;  /* Yes. */
+	    else { noshrink: shrink = 0; }  /* No, cannot shrink op. */
+	  }
+	  b[pos+1] = shrink;
+	  pos += 2;
+	  break;
+	}
+	case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++;
+	case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W:
+	case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB:
+	case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break;
+	case DASM_LABEL_LG: p++;
+	case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */
+	case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */
+	case DASM_EXTERN: p += 2; break;
+	case DASM_ESC: p++; break;
+	case DASM_MARK: break;
+	case DASM_SECTION: case DASM_STOP: goto stop;
+	}
+      }
+      stop: (void)0;
+    }
+    ofs += sec->ofs;  /* Next section starts right after current section. */
+  }
+
+  D->codesize = ofs;  /* Total size of all code sections */
+  *szp = ofs;
+  return DASM_S_OK;
+}
+
+#define dasmb(x)	*cp++ = (unsigned char)(x)
+#ifndef DASM_ALIGNED_WRITES
+#define dasmw(x) \
+  do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0)
+#define dasmd(x) \
+  do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0)
+#else
+#define dasmw(x)	do { dasmb(x); dasmb((x)>>8); } while (0)
+#define dasmd(x)	do { dasmw(x); dasmw((x)>>16); } while (0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+  dasm_State *D = Dst_REF;
+  unsigned char *base = (unsigned char *)buffer;
+  unsigned char *cp = base;
+  int secnum;
+
+  /* Encode all code sections. No support for data sections (yet). */
+  for (secnum = 0; secnum < D->maxsection; secnum++) {
+    dasm_Section *sec = D->sections + secnum;
+    int *b = sec->buf;
+    int *endb = sec->rbuf + sec->pos;
+
+    while (b != endb) {
+      dasm_ActList p = D->actionlist + *b++;
+      unsigned char *mark = NULL;
+      while (1) {
+	int action = *p++;
+	int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0;
+	switch (action) {
+	case DASM_DISP: if (!mark) mark = cp; {
+	  unsigned char *mm = mark;
+	  if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL;
+	  if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7;
+	    if (mrm != 5) { mm[-1] -= 0x80; break; } }
+	  if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40;
+	}
+	case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break;
+	case DASM_IMM_DB: if (((n+128)&-256) == 0) {
+	    db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb;
+	  } else mark = NULL;
+	case DASM_IMM_D: wd: dasmd(n); break;
+	case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL;
+	case DASM_IMM_W: dasmw(n); break;
+	case DASM_VREG: { int t = *p++; if (t >= 2) n<<=3; cp[-1] |= n; break; }
+	case DASM_REL_LG: p++; if (n >= 0) goto rel_pc;
+	  b++; n = (int)(ptrdiff_t)D->globals[-n];
+	case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */
+	case DASM_REL_PC: rel_pc: {
+	  int shrink = *b++;
+	  int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; }
+	  n = *pb - ((int)(cp-base) + 4-shrink);
+	  if (shrink == 0) goto wd;
+	  if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb;
+	  goto wb;
+	}
+	case DASM_IMM_LG:
+	  p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; }
+	case DASM_IMM_PC: {
+	  int *pb = DASM_POS2PTR(D, n);
+	  n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base);
+	  goto wd;
+	}
+	case DASM_LABEL_LG: {
+	  int idx = *p++;
+	  if (idx >= 10)
+	    D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n));
+	  break;
+	}
+	case DASM_LABEL_PC: case DASM_SETLABEL: break;
+	case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; }
+	case DASM_ALIGN:
+	  n = *p++;
+	  while (((cp-base) & n)) *cp++ = 0x90; /* nop */
+	  break;
+	case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd;
+	case DASM_MARK: mark = cp; break;
+	case DASM_ESC: action = *p++;
+	default: *cp++ = action; break;
+	case DASM_SECTION: case DASM_STOP: goto stop;
+	}
+      }
+      stop: (void)0;
+    }
+  }
+
+  if (base + D->codesize != cp)  /* Check for phase errors. */
+    return DASM_S_PHASE;
+  return DASM_S_OK;
+}
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+  dasm_State *D = Dst_REF;
+  if (pc*sizeof(int) < D->pcsize) {
+    int pos = D->pclabels[pc];
+    if (pos < 0) return *DASM_POS2PTR(D, -pos);
+    if (pos > 0) return -1;  /* Undefined. */
+  }
+  return -2;  /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+  dasm_State *D = Dst_REF;
+  if (D->status == DASM_S_OK) {
+    int i;
+    for (i = 1; i <= 9; i++) {
+      if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; }
+      D->lglabels[i] = 0;
+    }
+  }
+  if (D->status == DASM_S_OK && secmatch >= 0 &&
+      D->section != &D->sections[secmatch])
+    D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections);
+  return D->status;
+}
+#endif
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.lua
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.lua	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.lua	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,1931 @@
+------------------------------------------------------------------------------
+-- DynASM x86/x64 module.
+--
+-- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+local x64 = x64
+
+-- Module information:
+local _info = {
+  arch =	x64 and "x64" or "x86",
+  description =	"DynASM x86/x64 module",
+  version =	"1.3.0",
+  vernum =	 10300,
+  release =	"2011-05-05",
+  author =	"Mike Pall",
+  license =	"MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, unpack, setmetatable = assert, unpack or table.unpack, setmetatable
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub
+local concat, sort = table.concat, table.sort
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+  -- int arg, 1 buffer pos:
+  "DISP",  "IMM_S", "IMM_B", "IMM_W", "IMM_D",  "IMM_WB", "IMM_DB",
+  -- action arg (1 byte), int arg, 1 buffer pos (reg/num):
+  "VREG", "SPACE", -- !x64: VREG support NYI.
+  -- ptrdiff_t arg, 1 buffer pos (address): !x64
+  "SETLABEL", "REL_A",
+  -- action arg (1 byte) or int arg, 2 buffer pos (link, offset):
+  "REL_LG", "REL_PC",
+  -- action arg (1 byte) or int arg, 1 buffer pos (link):
+  "IMM_LG", "IMM_PC",
+  -- action arg (1 byte) or int arg, 1 buffer pos (offset):
+  "LABEL_LG", "LABEL_PC",
+  -- action arg (1 byte), 1 buffer pos (offset):
+  "ALIGN",
+  -- action args (2 bytes), no buffer pos.
+  "EXTERN",
+  -- action arg (1 byte), no buffer pos.
+  "ESC",
+  -- no action arg, no buffer pos.
+  "MARK",
+  -- action arg (1 byte), no buffer pos, terminal action:
+  "SECTION",
+  -- no args, no buffer pos, terminal action:
+  "STOP"
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number (dynamically generated below).
+local map_action = {}
+-- First action number. Everything below does not need to be escaped.
+local actfirst = 256-#action_names
+
+-- Action list buffer and string (only used to remove dupes).
+local actlist = {}
+local actstr = ""
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Compute action numbers for action names.
+for n,name in ipairs(action_names) do
+  local num = actfirst + n - 1
+  map_action[name] = num
+end
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+  out:write("DynASM encoding engine action codes:\n")
+  for n,name in ipairs(action_names) do
+    local num = map_action[name]
+    out:write(format("  %-10s %02X  %d\n", name, num, num))
+  end
+  out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+  local nn = #actlist
+  local last = actlist[nn] or 255
+  actlist[nn] = nil -- Remove last byte.
+  if nn == 0 then nn = 1 end
+  out:write("static const unsigned char ", name, "[", nn, "] = {\n")
+  local s = "  "
+  for n,b in ipairs(actlist) do
+    s = s..b..","
+    if #s >= 75 then
+      assert(out:write(s, "\n"))
+      s = "  "
+    end
+  end
+  out:write(s, last, "\n};\n\n") -- Add last byte back.
+end
+
+------------------------------------------------------------------------------
+
+-- Add byte to action list.
+local function wputxb(n)
+  assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range")
+  actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, a, num)
+  wputxb(assert(map_action[action], "bad action name `"..action.."'"))
+  if a then actargs[#actargs+1] = a end
+  if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Add call to embedded DynASM C code.
+local function wcall(func, args)
+  wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true)
+end
+
+-- Delete duplicate action list chunks. A tad slow, but so what.
+local function dedupechunk(offset)
+  local al, as = actlist, actstr
+  local chunk = char(unpack(al, offset+1, #al))
+  local orig = find(as, chunk, 1, true)
+  if orig then
+    actargs[1] = orig-1 -- Replace with original offset.
+    for i=offset+1,#al do al[i] = nil end -- Kill dupe.
+  else
+    actstr = as..chunk
+  end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+  local offset = actargs[1]
+  if #actlist == offset then return end -- Nothing to flush.
+  if not term then waction("STOP") end -- Terminate action list.
+  dedupechunk(offset)
+  wcall("put", actargs) -- Add call to dasm_put().
+  actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+  secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped byte.
+local function wputb(n)
+  if n >= actfirst then waction("ESC") end -- Need to escape byte.
+  wputxb(n)
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 10
+local map_global = setmetatable({}, { __index = function(t, name)
+  if not match(name, "^[%a_][%w_@]*$") then werror("bad global label") end
+  local n = next_global
+  if n > 246 then werror("too many global labels") end
+  next_global = n + 1
+  t[name] = n
+  return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+  local t = {}
+  for name, n in pairs(map_global) do t[n] = name end
+  out:write("Global labels:\n")
+  for i=10,next_global-1 do
+    out:write(format("  %s\n", t[i]))
+  end
+  out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+  local t = {}
+  for name, n in pairs(map_global) do t[n] = name end
+  out:write("enum {\n")
+  for i=10,next_global-1 do
+    out:write("  ", prefix, gsub(t[i], "@.*", ""), ",\n")
+  end
+  out:write("  ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+  local t = {}
+  for name, n in pairs(map_global) do t[n] = name end
+  out:write("static const char *const ", name, "[] = {\n")
+  for i=10,next_global-1 do
+    out:write("  \"", t[i], "\",\n")
+  end
+  out:write("  (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = -1
+local map_extern = setmetatable({}, { __index = function(t, name)
+  -- No restrictions on the name for now.
+  local n = next_extern
+  if n < -256 then werror("too many extern labels") end
+  next_extern = n - 1
+  t[name] = n
+  return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+  local t = {}
+  for name, n in pairs(map_extern) do t[-n] = name end
+  out:write("Extern labels:\n")
+  for i=1,-next_extern-1 do
+    out:write(format("  %s\n", t[i]))
+  end
+  out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+  local t = {}
+  for name, n in pairs(map_extern) do t[-n] = name end
+  out:write("static const char *const ", name, "[] = {\n")
+  for i=1,-next_extern-1 do
+    out:write("  \"", t[i], "\",\n")
+  end
+  out:write("  (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+local map_archdef = {}		-- Ext. register name -> int. name.
+local map_reg_rev = {}		-- Int. register name -> ext. name.
+local map_reg_num = {}		-- Int. register name -> register number.
+local map_reg_opsize = {}	-- Int. register name -> operand size.
+local map_reg_valid_base = {}	-- Int. register name -> valid base register?
+local map_reg_valid_index = {}	-- Int. register name -> valid index register?
+local map_reg_needrex = {}	-- Int. register name -> need rex vs. no rex.
+local reg_list = {}		-- Canonical list of int. register names.
+
+local map_type = {}		-- Type name -> { ctype, reg }
+local ctypenum = 0		-- Type number (for _PTx macros).
+
+local addrsize = x64 and "q" or "d"	-- Size for address operands.
+
+-- Helper functions to fill register maps.
+local function mkrmap(sz, cl, names)
+  local cname = format("@%s", sz)
+  reg_list[#reg_list+1] = cname
+  map_archdef[cl] = cname
+  map_reg_rev[cname] = cl
+  map_reg_num[cname] = -1
+  map_reg_opsize[cname] = sz
+  if sz == addrsize or sz == "d" then
+    map_reg_valid_base[cname] = true
+    map_reg_valid_index[cname] = true
+  end
+  if names then
+    for n,name in ipairs(names) do
+      local iname = format("@%s%x", sz, n-1)
+      reg_list[#reg_list+1] = iname
+      map_archdef[name] = iname
+      map_reg_rev[iname] = name
+      map_reg_num[iname] = n-1
+      map_reg_opsize[iname] = sz
+      if sz == "b" and n > 4 then map_reg_needrex[iname] = false end
+      if sz == addrsize or sz == "d" then
+	map_reg_valid_base[iname] = true
+	map_reg_valid_index[iname] = true
+      end
+    end
+  end
+  for i=0,(x64 and sz ~= "f") and 15 or 7 do
+    local needrex = sz == "b" and i > 3
+    local iname = format("@%s%x%s", sz, i, needrex and "R" or "")
+    if needrex then map_reg_needrex[iname] = true end
+    local name
+    if sz == "o" then name = format("xmm%d", i)
+    elseif sz == "f" then name = format("st%d", i)
+    else name = format("r%d%s", i, sz == addrsize and "" or sz) end
+    map_archdef[name] = iname
+    if not map_reg_rev[iname] then
+      reg_list[#reg_list+1] = iname
+      map_reg_rev[iname] = name
+      map_reg_num[iname] = i
+      map_reg_opsize[iname] = sz
+      if sz == addrsize or sz == "d" then
+	map_reg_valid_base[iname] = true
+	map_reg_valid_index[iname] = true
+      end
+    end
+  end
+  reg_list[#reg_list+1] = ""
+end
+
+-- Integer registers (qword, dword, word and byte sized).
+if x64 then
+  mkrmap("q", "Rq", {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"})
+end
+mkrmap("d", "Rd", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"})
+mkrmap("w", "Rw", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"})
+mkrmap("b", "Rb", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"})
+map_reg_valid_index[map_archdef.esp] = false
+if x64 then map_reg_valid_index[map_archdef.rsp] = false end
+map_archdef["Ra"] = "@"..addrsize
+
+-- FP registers (internally tword sized, but use "f" as operand size).
+mkrmap("f", "Rf")
+
+-- SSE registers (oword sized, but qword and dword accessible).
+mkrmap("o", "xmm")
+
+-- Operand size prefixes to codes.
+local map_opsize = {
+  byte = "b", word = "w", dword = "d", qword = "q", oword = "o", tword = "t",
+  aword = addrsize,
+}
+
+-- Operand size code to number.
+local map_opsizenum = {
+  b = 1, w = 2, d = 4, q = 8, o = 16, t = 10,
+}
+
+-- Operand size code to name.
+local map_opsizename = {
+  b = "byte", w = "word", d = "dword", q = "qword", o = "oword", t = "tword",
+  f = "fpword",
+}
+
+-- Valid index register scale factors.
+local map_xsc = {
+  ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3,
+}
+
+-- Condition codes.
+local map_cc = {
+  o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7,
+  s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15,
+  c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7,
+  pe = 10, po = 11, nge = 12, ge = 13, ng = 14, g = 15,
+}
+
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+  return gsub(s, "@%w+", map_reg_rev)
+end
+
+-- Dump register names and numbers
+local function dumpregs(out)
+  out:write("Register names, sizes and internal numbers:\n")
+  for _,reg in ipairs(reg_list) do
+    if reg == "" then
+      out:write("\n")
+    else
+      local name = map_reg_rev[reg]
+      local num = map_reg_num[reg]
+      local opsize = map_opsizename[map_reg_opsize[reg]]
+      out:write(format("  %-5s %-8s %s\n", name, opsize,
+		       num < 0 and "(variable)" or num))
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC).
+local function wputlabel(aprefix, imm, num)
+  if type(imm) == "number" then
+    if imm < 0 then
+      waction("EXTERN")
+      wputxb(aprefix == "IMM_" and 0 or 1)
+      imm = -imm-1
+    else
+      waction(aprefix.."LG", nil, num);
+    end
+    wputxb(imm)
+  else
+    waction(aprefix.."PC", imm, num)
+  end
+end
+
+-- Put signed byte or arg.
+local function wputsbarg(n)
+  if type(n) == "number" then
+    if n < -128 or n > 127 then
+      werror("signed immediate byte out of range")
+    end
+    if n < 0 then n = n + 256 end
+    wputb(n)
+  else waction("IMM_S", n) end
+end
+
+-- Put unsigned byte or arg.
+local function wputbarg(n)
+  if type(n) == "number" then
+    if n < 0 or n > 255 then
+      werror("unsigned immediate byte out of range")
+    end
+    wputb(n)
+  else waction("IMM_B", n) end
+end
+
+-- Put unsigned word or arg.
+local function wputwarg(n)
+  if type(n) == "number" then
+    if n < 0 or n > 65535 then
+      werror("unsigned immediate word out of range")
+    end
+    local r = n%256; n = (n-r)/256; wputb(r); wputb(n);
+  else waction("IMM_W", n) end
+end
+
+-- Put signed or unsigned dword or arg.
+local function wputdarg(n)
+  local tn = type(n)
+  if tn == "number" then
+    if n < 0 then n = n + 4294967296 end
+    local r = n%256; n = (n-r)/256; wputb(r);
+    r = n%256; n = (n-r)/256; wputb(r);
+    r = n%256; n = (n-r)/256; wputb(r); wputb(n);
+  elseif tn == "table" then
+    wputlabel("IMM_", n[1], 1)
+  else
+    waction("IMM_D", n)
+  end
+end
+
+-- Put operand-size dependent number or arg (defaults to dword).
+local function wputszarg(sz, n)
+  if not sz or sz == "d" or sz == "q" then wputdarg(n)
+  elseif sz == "w" then wputwarg(n)
+  elseif sz == "b" then wputbarg(n)
+  elseif sz == "s" then wputsbarg(n)
+  else werror("bad operand size") end
+end
+
+-- Put multi-byte opcode with operand-size dependent modifications.
+local function wputop(sz, op, rex)
+  local r
+  if rex ~= 0 and not x64 then werror("bad operand size") end
+  if sz == "w" then wputb(102) end
+  -- Needs >32 bit numbers, but only for crc32 eax, word [ebx]
+  if op >= 4294967296 then r = op%4294967296 wputb((op-r)/4294967296) op = r end
+  if op >= 16777216 then r = op % 16777216 wputb((op-r) / 16777216) op = r end
+  if op >= 65536 then
+    if rex ~= 0 then
+      local opc3 = op - op % 256
+      if opc3 == 0x0f3a00 or opc3 == 0x0f3800 then
+	wputb(64 + rex % 16); rex = 0
+      end
+    end
+    r = op % 65536 wputb((op-r) / 65536) op = r
+  end
+  if op >= 256 then
+    r = op % 256
+    local b = (op-r) / 256
+    if b == 15 and rex ~= 0 then wputb(64 + rex % 16); rex = 0 end
+    wputb(b)
+    op = r
+  end
+  if rex ~= 0 then wputb(64 + rex % 16) end
+  if sz == "b" then op = op - 1 end
+  wputb(op)
+end
+
+-- Put ModRM or SIB formatted byte.
+local function wputmodrm(m, s, rm, vs, vrm)
+  assert(m < 4 and s < 16 and rm < 16, "bad modrm operands")
+  wputb(64*m + 8*(s%8) + (rm%8))
+end
+
+-- Put ModRM/SIB plus optional displacement.
+local function wputmrmsib(t, imark, s, vsreg)
+  local vreg, vxreg
+  local reg, xreg = t.reg, t.xreg
+  if reg and reg < 0 then reg = 0; vreg = t.vreg end
+  if xreg and xreg < 0 then xreg = 0; vxreg = t.vxreg end
+  if s < 0 then s = 0 end
+
+  -- Register mode.
+  if sub(t.mode, 1, 1) == "r" then
+    wputmodrm(3, s, reg)
+    if vsreg then waction("VREG", vsreg); wputxb(2) end
+    if vreg then waction("VREG", vreg); wputxb(0) end
+    return
+  end
+
+  local disp = t.disp
+  local tdisp = type(disp)
+  -- No base register?
+  if not reg then
+    local riprel = false
+    if xreg then
+      -- Indexed mode with index register only.
+      -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp)
+      wputmodrm(0, s, 4)
+      if imark == "I" then waction("MARK") end
+      if vsreg then waction("VREG", vsreg); wputxb(2) end
+      wputmodrm(t.xsc, xreg, 5)
+      if vxreg then waction("VREG", vxreg); wputxb(3) end
+    else
+      -- Pure 32 bit displacement.
+      if x64 and tdisp ~= "table" then
+	wputmodrm(0, s, 4) -- [disp] -> (0, s, esp) (0, esp, ebp)
+	if imark == "I" then waction("MARK") end
+	wputmodrm(0, 4, 5)
+      else
+	riprel = x64
+	wputmodrm(0, s, 5) -- [disp|rip-label] -> (0, s, ebp)
+	if imark == "I" then waction("MARK") end
+      end
+      if vsreg then waction("VREG", vsreg); wputxb(2) end
+    end
+    if riprel then -- Emit rip-relative displacement.
+      if match("UWSiI", imark) then
+	werror("NYI: rip-relative displacement followed by immediate")
+      end
+      -- The previous byte in the action buffer cannot be 0xe9 or 0x80-0x8f.
+      wputlabel("REL_", disp[1], 2)
+    else
+      wputdarg(disp)
+    end
+    return
+  end
+
+  local m
+  if tdisp == "number" then -- Check displacement size at assembly time.
+    if disp == 0 and (reg%8) ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too)
+      if not vreg then m = 0 end -- Force DISP to allow [Rd(5)] -> [ebp+0]
+    elseif disp >= -128 and disp <= 127 then m = 1
+    else m = 2 end
+  elseif tdisp == "table" then
+    m = 2
+  end
+
+  -- Index register present or esp as base register: need SIB encoding.
+  if xreg or (reg%8) == 4 then
+    wputmodrm(m or 2, s, 4) -- ModRM.
+    if m == nil or imark == "I" then waction("MARK") end
+    if vsreg then waction("VREG", vsreg); wputxb(2) end
+    wputmodrm(t.xsc or 0, xreg or 4, reg) -- SIB.
+    if vxreg then waction("VREG", vxreg); wputxb(3) end
+    if vreg then waction("VREG", vreg); wputxb(1) end
+  else
+    wputmodrm(m or 2, s, reg) -- ModRM.
+    if (imark == "I" and (m == 1 or m == 2)) or
+       (m == nil and (vsreg or vreg)) then waction("MARK") end
+    if vsreg then waction("VREG", vsreg); wputxb(2) end
+    if vreg then waction("VREG", vreg); wputxb(1) end
+  end
+
+  -- Put displacement.
+  if m == 1 then wputsbarg(disp)
+  elseif m == 2 then wputdarg(disp)
+  elseif m == nil then waction("DISP", disp) end
+end
+
+------------------------------------------------------------------------------
+
+-- Return human-readable operand mode string.
+local function opmodestr(op, args)
+  local m = {}
+  for i=1,#args do
+    local a = args[i]
+    m[#m+1] = sub(a.mode, 1, 1)..(a.opsize or "?")
+  end
+  return op.." "..concat(m, ",")
+end
+
+-- Convert number to valid integer or nil.
+local function toint(expr)
+  local n = tonumber(expr)
+  if n then
+    if n % 1 ~= 0 or n < -2147483648 or n > 4294967295 then
+      werror("bad integer number `"..expr.."'")
+    end
+    return n
+  end
+end
+
+-- Parse immediate expression.
+local function immexpr(expr)
+  -- &expr (pointer)
+  if sub(expr, 1, 1) == "&" then
+    return "iPJ", format("(ptrdiff_t)(%s)", sub(expr,2))
+  end
+
+  local prefix = sub(expr, 1, 2)
+  -- =>expr (pc label reference)
+  if prefix == "=>" then
+    return "iJ", sub(expr, 3)
+  end
+  -- ->name (global label reference)
+  if prefix == "->" then
+    return "iJ", map_global[sub(expr, 3)]
+  end
+
+  -- [<>][1-9] (local label reference)
+  local dir, lnum = match(expr, "^([<>])([1-9])$")
+  if dir then -- Fwd: 247-255, Bkwd: 1-9.
+    return "iJ", lnum + (dir == ">" and 246 or 0)
+  end
+
+  local extname = match(expr, "^extern%s+(%S+)$")
+  if extname then
+    return "iJ", map_extern[extname]
+  end
+
+  -- expr (interpreted as immediate)
+  return "iI", expr
+end
+
+-- Parse displacement expression: +-num, +-expr, +-opsize*num
+local function dispexpr(expr)
+  local disp = expr == "" and 0 or toint(expr)
+  if disp then return disp end
+  local c, dispt = match(expr, "^([+-])%s*(.+)$")
+  if c == "+" then
+    expr = dispt
+  elseif not c then
+    werror("bad displacement expression `"..expr.."'")
+  end
+  local opsize, tailops = match(dispt, "^(%w+)%s*%*%s*(.+)$")
+  local ops, imm = map_opsize[opsize], toint(tailops)
+  if ops and imm then
+    if c == "-" then imm = -imm end
+    return imm*map_opsizenum[ops]
+  end
+  local mode, iexpr = immexpr(dispt)
+  if mode == "iJ" then
+    if c == "-" then werror("cannot invert label reference") end
+    return { iexpr }
+  end
+  return expr -- Need to return original signed expression.
+end
+
+-- Parse register or type expression.
+local function rtexpr(expr)
+  if not expr then return end
+  local tname, ovreg = match(expr, "^([%w_]+):(@[%w_]+)$")
+  local tp = map_type[tname or expr]
+  if tp then
+    local reg = ovreg or tp.reg
+    local rnum = map_reg_num[reg]
+    if not rnum then
+      werror("type `"..(tname or expr).."' needs a register override")
+    end
+    if not map_reg_valid_base[reg] then
+      werror("bad base register override `"..(map_reg_rev[reg] or reg).."'")
+    end
+    return reg, rnum, tp
+  end
+  return expr, map_reg_num[expr]
+end
+
+-- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }.
+local function parseoperand(param)
+  local t = {}
+
+  local expr = param
+  local opsize, tailops = match(param, "^(%w+)%s*(.+)$")
+  if opsize then
+    t.opsize = map_opsize[opsize]
+    if t.opsize then expr = tailops end
+  end
+
+  local br = match(expr, "^%[%s*(.-)%s*%]$")
+  repeat
+    if br then
+      t.mode = "xm"
+
+      -- [disp]
+      t.disp = toint(br)
+      if t.disp then
+	t.mode = x64 and "xm" or "xmO"
+	break
+      end
+
+      -- [reg...]
+      local tp
+      local reg, tailr = match(br, "^([@%w_:]+)%s*(.*)$")
+      reg, t.reg, tp = rtexpr(reg)
+      if not t.reg then
+	-- [expr]
+	t.mode = x64 and "xm" or "xmO"
+	t.disp = dispexpr("+"..br)
+	break
+      end
+
+      if t.reg == -1 then
+	t.vreg, tailr = match(tailr, "^(%b())(.*)$")
+	if not t.vreg then werror("bad variable register expression") end
+      end
+
+      -- [xreg*xsc] or [xreg*xsc+-disp] or [xreg*xsc+-expr]
+      local xsc, tailsc = match(tailr, "^%*%s*([1248])%s*(.*)$")
+      if xsc then
+	if not map_reg_valid_index[reg] then
+	  werror("bad index register `"..map_reg_rev[reg].."'")
+	end
+	t.xsc = map_xsc[xsc]
+	t.xreg = t.reg
+	t.vxreg = t.vreg
+	t.reg = nil
+	t.vreg = nil
+	t.disp = dispexpr(tailsc)
+	break
+      end
+      if not map_reg_valid_base[reg] then
+	werror("bad base register `"..map_reg_rev[reg].."'")
+      end
+
+      -- [reg] or [reg+-disp]
+      t.disp = toint(tailr) or (tailr == "" and 0)
+      if t.disp then break end
+
+      -- [reg+xreg...]
+      local xreg, tailx = match(tailr, "^+%s*([@%w_:]+)%s*(.*)$")
+      xreg, t.xreg, tp = rtexpr(xreg)
+      if not t.xreg then
+	-- [reg+-expr]
+	t.disp = dispexpr(tailr)
+	break
+      end
+      if not map_reg_valid_index[xreg] then
+	werror("bad index register `"..map_reg_rev[xreg].."'")
+      end
+
+      if t.xreg == -1 then
+	t.vxreg, tailx = match(tailx, "^(%b())(.*)$")
+	if not t.vxreg then werror("bad variable register expression") end
+      end
+
+      -- [reg+xreg*xsc...]
+      local xsc, tailsc = match(tailx, "^%*%s*([1248])%s*(.*)$")
+      if xsc then
+	t.xsc = map_xsc[xsc]
+	tailx = tailsc
+      end
+
+      -- [...] or [...+-disp] or [...+-expr]
+      t.disp = dispexpr(tailx)
+    else
+      -- imm or opsize*imm
+      local imm = toint(expr)
+      if not imm and sub(expr, 1, 1) == "*" and t.opsize then
+	imm = toint(sub(expr, 2))
+	if imm then
+	  imm = imm * map_opsizenum[t.opsize]
+	  t.opsize = nil
+	end
+      end
+      if imm then
+	if t.opsize then werror("bad operand size override") end
+	local m = "i"
+	if imm == 1 then m = m.."1" end
+	if imm >= 4294967168 and imm <= 4294967295 then imm = imm-4294967296 end
+	if imm >= -128 and imm <= 127 then m = m.."S" end
+	t.imm = imm
+	t.mode = m
+	break
+      end
+
+      local tp
+      local reg, tailr = match(expr, "^([@%w_:]+)%s*(.*)$")
+      reg, t.reg, tp = rtexpr(reg)
+      if t.reg then
+	if t.reg == -1 then
+	  t.vreg, tailr = match(tailr, "^(%b())(.*)$")
+	  if not t.vreg then werror("bad variable register expression") end
+	end
+	-- reg
+	if tailr == "" then
+	  if t.opsize then werror("bad operand size override") end
+	  t.opsize = map_reg_opsize[reg]
+	  if t.opsize == "f" then
+	    t.mode = t.reg == 0 and "fF" or "f"
+	  else
+	    if reg == "@w4" or (x64 and reg == "@d4") then
+	      wwarn("bad idea, try again with `"..(x64 and "rsp'" or "esp'"))
+	    end
+	    t.mode = t.reg == 0 and "rmR" or (reg == "@b1" and "rmC" or "rm")
+	  end
+	  t.needrex = map_reg_needrex[reg]
+	  break
+	end
+
+	-- type[idx], type[idx].field, type->field -> [reg+offset_expr]
+	if not tp then werror("bad operand `"..param.."'") end
+	t.mode = "xm"
+	t.disp = format(tp.ctypefmt, tailr)
+      else
+	t.mode, t.imm = immexpr(expr)
+	if sub(t.mode, -1) == "J" then
+	  if t.opsize and t.opsize ~= addrsize then
+	    werror("bad operand size override")
+	  end
+	  t.opsize = addrsize
+	end
+      end
+    end
+  until true
+  return t
+end
+
+------------------------------------------------------------------------------
+-- x86 Template String Description
+-- ===============================
+--
+-- Each template string is a list of [match:]pattern pairs,
+-- separated by "|". The first match wins. No match means a
+-- bad or unsupported combination of operand modes or sizes.
+--
+-- The match part and the ":" is omitted if the operation has
+-- no operands. Otherwise the first N characters are matched
+-- against the mode strings of each of the N operands.
+--
+-- The mode string for each operand type is (see parseoperand()):
+--   Integer register: "rm", +"R" for eax, ax, al, +"C" for cl
+--   FP register:      "f",  +"F" for st0
+--   Index operand:    "xm", +"O" for [disp] (pure offset)
+--   Immediate:        "i",  +"S" for signed 8 bit, +"1" for 1,
+--                     +"I" for arg, +"P" for pointer
+--   Any:              +"J" for valid jump targets
+--
+-- So a match character "m" (mixed) matches both an integer register
+-- and an index operand (to be encoded with the ModRM/SIB scheme).
+-- But "r" matches only a register and "x" only an index operand
+-- (e.g. for FP memory access operations).
+--
+-- The operand size match string starts right after the mode match
+-- characters and ends before the ":". "dwb" or "qdwb" is assumed, if empty.
+-- The effective data size of the operation is matched against this list.
+--
+-- If only the regular "b", "w", "d", "q", "t" operand sizes are
+-- present, then all operands must be the same size. Unspecified sizes
+-- are ignored, but at least one operand must have a size or the pattern
+-- won't match (use the "byte", "word", "dword", "qword", "tword"
+-- operand size overrides. E.g.: mov dword [eax], 1).
+--
+-- If the list has a "1" or "2" prefix, the operand size is taken
+-- from the respective operand and any other operand sizes are ignored.
+-- If the list contains only ".", all operand sizes are ignored.
+-- If the list has a "/" prefix, the concatenated (mixed) operand sizes
+-- are compared to the match.
+--
+-- E.g. "rrdw" matches for either two dword registers or two word
+-- registers. "Fx2dq" matches an st0 operand plus an index operand
+-- pointing to a dword (float) or qword (double).
+--
+-- Every character after the ":" is part of the pattern string:
+--   Hex chars are accumulated to form the opcode (left to right).
+--   "n"       disables the standard opcode mods
+--             (otherwise: -1 for "b", o16 prefix for "w", rex.w for "q")
+--   "X"       Force REX.W.
+--   "r"/"R"   adds the reg. number from the 1st/2nd operand to the opcode.
+--   "m"/"M"   generates ModRM/SIB from the 1st/2nd operand.
+--             The spare 3 bits are either filled with the last hex digit or
+--             the result from a previous "r"/"R". The opcode is restored.
+--
+-- All of the following characters force a flush of the opcode:
+--   "o"/"O"   stores a pure 32 bit disp (offset) from the 1st/2nd operand.
+--   "S"       stores a signed 8 bit immediate from the last operand.
+--   "U"       stores an unsigned 8 bit immediate from the last operand.
+--   "W"       stores an unsigned 16 bit immediate from the last operand.
+--   "i"       stores an operand sized immediate from the last operand.
+--   "I"       dito, but generates an action code to optionally modify
+--             the opcode (+2) for a signed 8 bit immediate.
+--   "J"       generates one of the REL action codes from the last operand.
+--
+------------------------------------------------------------------------------
+
+-- Template strings for x86 instructions. Ordered by first opcode byte.
+-- Unimplemented opcodes (deliberate omissions) are marked with *.
+local map_op = {
+  -- 00-05: add...
+  -- 06: *push es
+  -- 07: *pop es
+  -- 08-0D: or...
+  -- 0E: *push cs
+  -- 0F: two byte opcode prefix
+  -- 10-15: adc...
+  -- 16: *push ss
+  -- 17: *pop ss
+  -- 18-1D: sbb...
+  -- 1E: *push ds
+  -- 1F: *pop ds
+  -- 20-25: and...
+  es_0 =	"26",
+  -- 27: *daa
+  -- 28-2D: sub...
+  cs_0 =	"2E",
+  -- 2F: *das
+  -- 30-35: xor...
+  ss_0 =	"36",
+  -- 37: *aaa
+  -- 38-3D: cmp...
+  ds_0 =	"3E",
+  -- 3F: *aas
+  inc_1 =	x64 and "m:FF0m" or "rdw:40r|m:FF0m",
+  dec_1 =	x64 and "m:FF1m" or "rdw:48r|m:FF1m",
+  push_1 =	(x64 and "rq:n50r|rw:50r|mq:nFF6m|mw:FF6m" or
+			 "rdw:50r|mdw:FF6m").."|S.:6AS|ib:n6Ai|i.:68i",
+  pop_1 =	x64 and "rq:n58r|rw:58r|mq:n8F0m|mw:8F0m" or "rdw:58r|mdw:8F0m",
+  -- 60: *pusha, *pushad, *pushaw
+  -- 61: *popa, *popad, *popaw
+  -- 62: *bound rdw,x
+  -- 63: x86: *arpl mw,rw
+  movsxd_2 =	x64 and "rm/qd:63rM",
+  fs_0 =	"64",
+  gs_0 =	"65",
+  o16_0 =	"66",
+  a16_0 =	not x64 and "67" or nil,
+  a32_0 =	x64 and "67",
+  -- 68: push idw
+  -- 69: imul rdw,mdw,idw
+  -- 6A: push ib
+  -- 6B: imul rdw,mdw,S
+  -- 6C: *insb
+  -- 6D: *insd, *insw
+  -- 6E: *outsb
+  -- 6F: *outsd, *outsw
+  -- 70-7F: jcc lb
+  -- 80: add... mb,i
+  -- 81: add... mdw,i
+  -- 82: *undefined
+  -- 83: add... mdw,S
+  test_2 =	"mr:85Rm|rm:85rM|Ri:A9ri|mi:F70mi",
+  -- 86: xchg rb,mb
+  -- 87: xchg rdw,mdw
+  -- 88: mov mb,r
+  -- 89: mov mdw,r
+  -- 8A: mov r,mb
+  -- 8B: mov r,mdw
+  -- 8C: *mov mdw,seg
+  lea_2 =	"rx1dq:8DrM",
+  -- 8E: *mov seg,mdw
+  -- 8F: pop mdw
+  nop_0 =	"90",
+  xchg_2 =	"Rrqdw:90R|rRqdw:90r|rm:87rM|mr:87Rm",
+  cbw_0 =	"6698",
+  cwde_0 =	"98",
+  cdqe_0 =	"4898",
+  cwd_0 =	"6699",
+  cdq_0 =	"99",
+  cqo_0 =	"4899",
+  -- 9A: *call iw:idw
+  wait_0 =	"9B",
+  fwait_0 =	"9B",
+  pushf_0 =	"9C",
+  pushfd_0 =	not x64 and "9C",
+  pushfq_0 =	x64 and "9C",
+  popf_0 =	"9D",
+  popfd_0 =	not x64 and "9D",
+  popfq_0 =	x64 and "9D",
+  sahf_0 =	"9E",
+  lahf_0 =	"9F",
+  mov_2 =	"OR:A3o|RO:A1O|mr:89Rm|rm:8BrM|rib:nB0ri|ridw:B8ri|mi:C70mi",
+  movsb_0 =	"A4",
+  movsw_0 =	"66A5",
+  movsd_0 =	"A5",
+  cmpsb_0 =	"A6",
+  cmpsw_0 =	"66A7",
+  cmpsd_0 =	"A7",
+  -- A8: test Rb,i
+  -- A9: test Rdw,i
+  stosb_0 =	"AA",
+  stosw_0 =	"66AB",
+  stosd_0 =	"AB",
+  lodsb_0 =	"AC",
+  lodsw_0 =	"66AD",
+  lodsd_0 =	"AD",
+  scasb_0 =	"AE",
+  scasw_0 =	"66AF",
+  scasd_0 =	"AF",
+  -- B0-B7: mov rb,i
+  -- B8-BF: mov rdw,i
+  -- C0: rol... mb,i
+  -- C1: rol... mdw,i
+  ret_1 =	"i.:nC2W",
+  ret_0 =	"C3",
+  -- C4: *les rdw,mq
+  -- C5: *lds rdw,mq
+  -- C6: mov mb,i
+  -- C7: mov mdw,i
+  -- C8: *enter iw,ib
+  leave_0 =	"C9",
+  -- CA: *retf iw
+  -- CB: *retf
+  int3_0 =	"CC",
+  int_1 =	"i.:nCDU",
+  into_0 =	"CE",
+  -- CF: *iret
+  -- D0: rol... mb,1
+  -- D1: rol... mdw,1
+  -- D2: rol... mb,cl
+  -- D3: rol... mb,cl
+  -- D4: *aam ib
+  -- D5: *aad ib
+  -- D6: *salc
+  -- D7: *xlat
+  -- D8-DF: floating point ops
+  -- E0: *loopne
+  -- E1: *loope
+  -- E2: *loop
+  -- E3: *jcxz, *jecxz
+  -- E4: *in Rb,ib
+  -- E5: *in Rdw,ib
+  -- E6: *out ib,Rb
+  -- E7: *out ib,Rdw
+  call_1 =	x64 and "mq:nFF2m|J.:E8nJ" or "md:FF2m|J.:E8J",
+  jmp_1 =	x64 and "mq:nFF4m|J.:E9nJ" or "md:FF4m|J.:E9J", -- short: EB
+  -- EA: *jmp iw:idw
+  -- EB: jmp ib
+  -- EC: *in Rb,dx
+  -- ED: *in Rdw,dx
+  -- EE: *out dx,Rb
+  -- EF: *out dx,Rdw
+  -- F0: *lock
+  int1_0 =	"F1",
+  repne_0 =	"F2",
+  repnz_0 =	"F2",
+  rep_0 =	"F3",
+  repe_0 =	"F3",
+  repz_0 =	"F3",
+  -- F4: *hlt
+  cmc_0 =	"F5",
+  -- F6: test... mb,i; div... mb
+  -- F7: test... mdw,i; div... mdw
+  clc_0 =	"F8",
+  stc_0 =	"F9",
+  -- FA: *cli
+  cld_0 =	"FC",
+  std_0 =	"FD",
+  -- FE: inc... mb
+  -- FF: inc... mdw
+
+  -- misc ops
+  not_1 =	"m:F72m",
+  neg_1 =	"m:F73m",
+  mul_1 =	"m:F74m",
+  imul_1 =	"m:F75m",
+  div_1 =	"m:F76m",
+  idiv_1 =	"m:F77m",
+
+  imul_2 =	"rmqdw:0FAFrM|rIqdw:69rmI|rSqdw:6BrmS|riqdw:69rmi",
+  imul_3 =	"rmIqdw:69rMI|rmSqdw:6BrMS|rmiqdw:69rMi",
+
+  movzx_2 =	"rm/db:0FB6rM|rm/qb:|rm/wb:0FB6rM|rm/dw:0FB7rM|rm/qw:",
+  movsx_2 =	"rm/db:0FBErM|rm/qb:|rm/wb:0FBErM|rm/dw:0FBFrM|rm/qw:",
+
+  bswap_1 =	"rqd:0FC8r",
+  bsf_2 =	"rmqdw:0FBCrM",
+  bsr_2 =	"rmqdw:0FBDrM",
+  bt_2 =	"mrqdw:0FA3Rm|miqdw:0FBA4mU",
+  btc_2 =	"mrqdw:0FBBRm|miqdw:0FBA7mU",
+  btr_2 =	"mrqdw:0FB3Rm|miqdw:0FBA6mU",
+  bts_2 =	"mrqdw:0FABRm|miqdw:0FBA5mU",
+
+  rdtsc_0 =	"0F31", -- P1+
+  cpuid_0 =	"0FA2", -- P1+
+
+  -- floating point ops
+  fst_1 =	"ff:DDD0r|xd:D92m|xq:nDD2m",
+  fstp_1 =	"ff:DDD8r|xd:D93m|xq:nDD3m|xt:DB7m",
+  fld_1 =	"ff:D9C0r|xd:D90m|xq:nDD0m|xt:DB5m",
+
+  fpop_0 =	"DDD8", -- Alias for fstp st0.
+
+  fist_1 =	"xw:nDF2m|xd:DB2m",
+  fistp_1 =	"xw:nDF3m|xd:DB3m|xq:nDF7m",
+  fild_1 =	"xw:nDF0m|xd:DB0m|xq:nDF5m",
+
+  fxch_0 =	"D9C9",
+  fxch_1 =	"ff:D9C8r",
+  fxch_2 =	"fFf:D9C8r|Fff:D9C8R",
+
+  fucom_1 =	"ff:DDE0r",
+  fucom_2 =	"Fff:DDE0R",
+  fucomp_1 =	"ff:DDE8r",
+  fucomp_2 =	"Fff:DDE8R",
+  fucomi_1 =	"ff:DBE8r", -- P6+
+  fucomi_2 =	"Fff:DBE8R", -- P6+
+  fucomip_1 =	"ff:DFE8r", -- P6+
+  fucomip_2 =	"Fff:DFE8R", -- P6+
+  fcomi_1 =	"ff:DBF0r", -- P6+
+  fcomi_2 =	"Fff:DBF0R", -- P6+
+  fcomip_1 =	"ff:DFF0r", -- P6+
+  fcomip_2 =	"Fff:DFF0R", -- P6+
+  fucompp_0 =	"DAE9",
+  fcompp_0 =	"DED9",
+
+  fldcw_1 =	"xw:nD95m",
+  fstcw_1 =	"xw:n9BD97m",
+  fnstcw_1 =	"xw:nD97m",
+  fstsw_1 =	"Rw:n9BDFE0|xw:n9BDD7m",
+  fnstsw_1 =	"Rw:nDFE0|xw:nDD7m",
+  fclex_0 =	"9BDBE2",
+  fnclex_0 =	"DBE2",
+
+  fnop_0 =	"D9D0",
+  -- D9D1-D9DF: unassigned
+
+  fchs_0 =	"D9E0",
+  fabs_0 =	"D9E1",
+  -- D9E2: unassigned
+  -- D9E3: unassigned
+  ftst_0 =	"D9E4",
+  fxam_0 =	"D9E5",
+  -- D9E6: unassigned
+  -- D9E7: unassigned
+  fld1_0 =	"D9E8",
+  fldl2t_0 =	"D9E9",
+  fldl2e_0 =	"D9EA",
+  fldpi_0 =	"D9EB",
+  fldlg2_0 =	"D9EC",
+  fldln2_0 =	"D9ED",
+  fldz_0 =	"D9EE",
+  -- D9EF: unassigned
+
+  f2xm1_0 =	"D9F0",
+  fyl2x_0 =	"D9F1",
+  fptan_0 =	"D9F2",
+  fpatan_0 =	"D9F3",
+  fxtract_0 =	"D9F4",
+  fprem1_0 =	"D9F5",
+  fdecstp_0 =	"D9F6",
+  fincstp_0 =	"D9F7",
+  fprem_0 =	"D9F8",
+  fyl2xp1_0 =	"D9F9",
+  fsqrt_0 =	"D9FA",
+  fsincos_0 =	"D9FB",
+  frndint_0 =	"D9FC",
+  fscale_0 =	"D9FD",
+  fsin_0 =	"D9FE",
+  fcos_0 =	"D9FF",
+
+  -- SSE, SSE2
+  andnpd_2 =	"rmo:660F55rM",
+  andnps_2 =	"rmo:0F55rM",
+  andpd_2 =	"rmo:660F54rM",
+  andps_2 =	"rmo:0F54rM",
+  clflush_1 =	"x.:0FAE7m",
+  cmppd_3 =	"rmio:660FC2rMU",
+  cmpps_3 =	"rmio:0FC2rMU",
+  cmpsd_3 =	"rrio:F20FC2rMU|rxi/oq:",
+  cmpss_3 =	"rrio:F30FC2rMU|rxi/od:",
+  comisd_2 =	"rro:660F2FrM|rx/oq:",
+  comiss_2 =	"rro:0F2FrM|rx/od:",
+  cvtdq2pd_2 =	"rro:F30FE6rM|rx/oq:",
+  cvtdq2ps_2 =	"rmo:0F5BrM",
+  cvtpd2dq_2 =	"rmo:F20FE6rM",
+  cvtpd2ps_2 =	"rmo:660F5ArM",
+  cvtpi2pd_2 =	"rx/oq:660F2ArM",
+  cvtpi2ps_2 =	"rx/oq:0F2ArM",
+  cvtps2dq_2 =	"rmo:660F5BrM",
+  cvtps2pd_2 =	"rro:0F5ArM|rx/oq:",
+  cvtsd2si_2 =	"rr/do:F20F2DrM|rr/qo:|rx/dq:|rxq:",
+  cvtsd2ss_2 =	"rro:F20F5ArM|rx/oq:",
+  cvtsi2sd_2 =	"rm/od:F20F2ArM|rm/oq:F20F2ArXM",
+  cvtsi2ss_2 =	"rm/od:F30F2ArM|rm/oq:F30F2ArXM",
+  cvtss2sd_2 =	"rro:F30F5ArM|rx/od:",
+  cvtss2si_2 =	"rr/do:F20F2CrM|rr/qo:|rxd:|rx/qd:",
+  cvttpd2dq_2 =	"rmo:660FE6rM",
+  cvttps2dq_2 =	"rmo:F30F5BrM",
+  cvttsd2si_2 =	"rr/do:F20F2CrM|rr/qo:|rx/dq:|rxq:",
+  cvttss2si_2 =	"rr/do:F30F2CrM|rr/qo:|rxd:|rx/qd:",
+  ldmxcsr_1 =	"xd:0FAE2m",
+  lfence_0 =	"0FAEE8",
+  maskmovdqu_2 = "rro:660FF7rM",
+  mfence_0 =	"0FAEF0",
+  movapd_2 =	"rmo:660F28rM|mro:660F29Rm",
+  movaps_2 =	"rmo:0F28rM|mro:0F29Rm",
+  movd_2 =	"rm/od:660F6ErM|rm/oq:660F6ErXM|mr/do:660F7ERm|mr/qo:",
+  movdqa_2 =	"rmo:660F6FrM|mro:660F7FRm",
+  movdqu_2 =	"rmo:F30F6FrM|mro:F30F7FRm",
+  movhlps_2 =	"rro:0F12rM",
+  movhpd_2 =	"rx/oq:660F16rM|xr/qo:n660F17Rm",
+  movhps_2 =	"rx/oq:0F16rM|xr/qo:n0F17Rm",
+  movlhps_2 =	"rro:0F16rM",
+  movlpd_2 =	"rx/oq:660F12rM|xr/qo:n660F13Rm",
+  movlps_2 =	"rx/oq:0F12rM|xr/qo:n0F13Rm",
+  movmskpd_2 =	"rr/do:660F50rM",
+  movmskps_2 =	"rr/do:0F50rM",
+  movntdq_2 =	"xro:660FE7Rm",
+  movnti_2 =	"xrqd:0FC3Rm",
+  movntpd_2 =	"xro:660F2BRm",
+  movntps_2 =	"xro:0F2BRm",
+  movq_2 =	"rro:F30F7ErM|rx/oq:|xr/qo:n660FD6Rm",
+  movsd_2 =	"rro:F20F10rM|rx/oq:|xr/qo:nF20F11Rm",
+  movss_2 =	"rro:F30F10rM|rx/od:|xr/do:F30F11Rm",
+  movupd_2 =	"rmo:660F10rM|mro:660F11Rm",
+  movups_2 =	"rmo:0F10rM|mro:0F11Rm",
+  orpd_2 =	"rmo:660F56rM",
+  orps_2 =	"rmo:0F56rM",
+  packssdw_2 =	"rmo:660F6BrM",
+  packsswb_2 =	"rmo:660F63rM",
+  packuswb_2 =	"rmo:660F67rM",
+  paddb_2 =	"rmo:660FFCrM",
+  paddd_2 =	"rmo:660FFErM",
+  paddq_2 =	"rmo:660FD4rM",
+  paddsb_2 =	"rmo:660FECrM",
+  paddsw_2 =	"rmo:660FEDrM",
+  paddusb_2 =	"rmo:660FDCrM",
+  paddusw_2 =	"rmo:660FDDrM",
+  paddw_2 =	"rmo:660FFDrM",
+  pand_2 =	"rmo:660FDBrM",
+  pandn_2 =	"rmo:660FDFrM",
+  pause_0 =	"F390",
+  pavgb_2 =	"rmo:660FE0rM",
+  pavgw_2 =	"rmo:660FE3rM",
+  pcmpeqb_2 =	"rmo:660F74rM",
+  pcmpeqd_2 =	"rmo:660F76rM",
+  pcmpeqw_2 =	"rmo:660F75rM",
+  pcmpgtb_2 =	"rmo:660F64rM",
+  pcmpgtd_2 =	"rmo:660F66rM",
+  pcmpgtw_2 =	"rmo:660F65rM",
+  pextrw_3 =	"rri/do:660FC5rMU|xri/wo:660F3A15nrMU", -- Mem op: SSE4.1 only.
+  pinsrw_3 =	"rri/od:660FC4rMU|rxi/ow:",
+  pmaddwd_2 =	"rmo:660FF5rM",
+  pmaxsw_2 =	"rmo:660FEErM",
+  pmaxub_2 =	"rmo:660FDErM",
+  pminsw_2 =	"rmo:660FEArM",
+  pminub_2 =	"rmo:660FDArM",
+  pmovmskb_2 =	"rr/do:660FD7rM",
+  pmulhuw_2 =	"rmo:660FE4rM",
+  pmulhw_2 =	"rmo:660FE5rM",
+  pmullw_2 =	"rmo:660FD5rM",
+  pmuludq_2 =	"rmo:660FF4rM",
+  por_2 =	"rmo:660FEBrM",
+  prefetchnta_1 = "xb:n0F180m",
+  prefetcht0_1 = "xb:n0F181m",
+  prefetcht1_1 = "xb:n0F182m",
+  prefetcht2_1 = "xb:n0F183m",
+  psadbw_2 =	"rmo:660FF6rM",
+  pshufd_3 =	"rmio:660F70rMU",
+  pshufhw_3 =	"rmio:F30F70rMU",
+  pshuflw_3 =	"rmio:F20F70rMU",
+  pslld_2 =	"rmo:660FF2rM|rio:660F726mU",
+  pslldq_2 =	"rio:660F737mU",
+  psllq_2 =	"rmo:660FF3rM|rio:660F736mU",
+  psllw_2 =	"rmo:660FF1rM|rio:660F716mU",
+  psrad_2 =	"rmo:660FE2rM|rio:660F724mU",
+  psraw_2 =	"rmo:660FE1rM|rio:660F714mU",
+  psrld_2 =	"rmo:660FD2rM|rio:660F722mU",
+  psrldq_2 =	"rio:660F733mU",
+  psrlq_2 =	"rmo:660FD3rM|rio:660F732mU",
+  psrlw_2 =	"rmo:660FD1rM|rio:660F712mU",
+  psubb_2 =	"rmo:660FF8rM",
+  psubd_2 =	"rmo:660FFArM",
+  psubq_2 =	"rmo:660FFBrM",
+  psubsb_2 =	"rmo:660FE8rM",
+  psubsw_2 =	"rmo:660FE9rM",
+  psubusb_2 =	"rmo:660FD8rM",
+  psubusw_2 =	"rmo:660FD9rM",
+  psubw_2 =	"rmo:660FF9rM",
+  punpckhbw_2 =	"rmo:660F68rM",
+  punpckhdq_2 =	"rmo:660F6ArM",
+  punpckhqdq_2 = "rmo:660F6DrM",
+  punpckhwd_2 =	"rmo:660F69rM",
+  punpcklbw_2 =	"rmo:660F60rM",
+  punpckldq_2 =	"rmo:660F62rM",
+  punpcklqdq_2 = "rmo:660F6CrM",
+  punpcklwd_2 =	"rmo:660F61rM",
+  pxor_2 =	"rmo:660FEFrM",
+  rcpps_2 =	"rmo:0F53rM",
+  rcpss_2 =	"rro:F30F53rM|rx/od:",
+  rsqrtps_2 =	"rmo:0F52rM",
+  rsqrtss_2 =	"rmo:F30F52rM",
+  sfence_0 =	"0FAEF8",
+  shufpd_3 =	"rmio:660FC6rMU",
+  shufps_3 =	"rmio:0FC6rMU",
+  stmxcsr_1 =   "xd:0FAE3m",
+  ucomisd_2 =	"rro:660F2ErM|rx/oq:",
+  ucomiss_2 =	"rro:0F2ErM|rx/od:",
+  unpckhpd_2 =	"rmo:660F15rM",
+  unpckhps_2 =	"rmo:0F15rM",
+  unpcklpd_2 =	"rmo:660F14rM",
+  unpcklps_2 =	"rmo:0F14rM",
+  xorpd_2 =	"rmo:660F57rM",
+  xorps_2 =	"rmo:0F57rM",
+
+  -- SSE3 ops
+  fisttp_1 =	"xw:nDF1m|xd:DB1m|xq:nDD1m",
+  addsubpd_2 =	"rmo:660FD0rM",
+  addsubps_2 =	"rmo:F20FD0rM",
+  haddpd_2 =	"rmo:660F7CrM",
+  haddps_2 =	"rmo:F20F7CrM",
+  hsubpd_2 =	"rmo:660F7DrM",
+  hsubps_2 =	"rmo:F20F7DrM",
+  lddqu_2 =	"rxo:F20FF0rM",
+  movddup_2 =	"rmo:F20F12rM",
+  movshdup_2 =	"rmo:F30F16rM",
+  movsldup_2 =	"rmo:F30F12rM",
+
+  -- SSSE3 ops
+  pabsb_2 =	"rmo:660F381CrM",
+  pabsd_2 =	"rmo:660F381ErM",
+  pabsw_2 =	"rmo:660F381DrM",
+  palignr_3 =	"rmio:660F3A0FrMU",
+  phaddd_2 =	"rmo:660F3802rM",
+  phaddsw_2 =	"rmo:660F3803rM",
+  phaddw_2 =	"rmo:660F3801rM",
+  phsubd_2 =	"rmo:660F3806rM",
+  phsubsw_2 =	"rmo:660F3807rM",
+  phsubw_2 =	"rmo:660F3805rM",
+  pmaddubsw_2 =	"rmo:660F3804rM",
+  pmulhrsw_2 =	"rmo:660F380BrM",
+  pshufb_2 =	"rmo:660F3800rM",
+  psignb_2 =	"rmo:660F3808rM",
+  psignd_2 =	"rmo:660F380ArM",
+  psignw_2 =	"rmo:660F3809rM",
+
+  -- SSE4.1 ops
+  blendpd_3 =	"rmio:660F3A0DrMU",
+  blendps_3 =	"rmio:660F3A0CrMU",
+  blendvpd_3 =	"rmRo:660F3815rM",
+  blendvps_3 =	"rmRo:660F3814rM",
+  dppd_3 =	"rmio:660F3A41rMU",
+  dpps_3 =	"rmio:660F3A40rMU",
+  extractps_3 =	"mri/do:660F3A17RmU|rri/qo:660F3A17RXmU",
+  insertps_3 =	"rrio:660F3A41rMU|rxi/od:",
+  movntdqa_2 =	"rmo:660F382ArM",
+  mpsadbw_3 =	"rmio:660F3A42rMU",
+  packusdw_2 =	"rmo:660F382BrM",
+  pblendvb_3 =	"rmRo:660F3810rM",
+  pblendw_3 =	"rmio:660F3A0ErMU",
+  pcmpeqq_2 =	"rmo:660F3829rM",
+  pextrb_3 =	"rri/do:660F3A14nRmU|rri/qo:|xri/bo:",
+  pextrd_3 =	"mri/do:660F3A16RmU",
+  pextrq_3 =	"mri/qo:660F3A16RmU",
+  -- pextrw is SSE2, mem operand is SSE4.1 only
+  phminposuw_2 = "rmo:660F3841rM",
+  pinsrb_3 =	"rri/od:660F3A20nrMU|rxi/ob:",
+  pinsrd_3 =	"rmi/od:660F3A22rMU",
+  pinsrq_3 =	"rmi/oq:660F3A22rXMU",
+  pmaxsb_2 =	"rmo:660F383CrM",
+  pmaxsd_2 =	"rmo:660F383DrM",
+  pmaxud_2 =	"rmo:660F383FrM",
+  pmaxuw_2 =	"rmo:660F383ErM",
+  pminsb_2 =	"rmo:660F3838rM",
+  pminsd_2 =	"rmo:660F3839rM",
+  pminud_2 =	"rmo:660F383BrM",
+  pminuw_2 =	"rmo:660F383ArM",
+  pmovsxbd_2 =	"rro:660F3821rM|rx/od:",
+  pmovsxbq_2 =	"rro:660F3822rM|rx/ow:",
+  pmovsxbw_2 =	"rro:660F3820rM|rx/oq:",
+  pmovsxdq_2 =	"rro:660F3825rM|rx/oq:",
+  pmovsxwd_2 =	"rro:660F3823rM|rx/oq:",
+  pmovsxwq_2 =	"rro:660F3824rM|rx/od:",
+  pmovzxbd_2 =	"rro:660F3831rM|rx/od:",
+  pmovzxbq_2 =	"rro:660F3832rM|rx/ow:",
+  pmovzxbw_2 =	"rro:660F3830rM|rx/oq:",
+  pmovzxdq_2 =	"rro:660F3835rM|rx/oq:",
+  pmovzxwd_2 =	"rro:660F3833rM|rx/oq:",
+  pmovzxwq_2 =	"rro:660F3834rM|rx/od:",
+  pmuldq_2 =	"rmo:660F3828rM",
+  pmulld_2 =	"rmo:660F3840rM",
+  ptest_2 =	"rmo:660F3817rM",
+  roundpd_3 =	"rmio:660F3A09rMU",
+  roundps_3 =	"rmio:660F3A08rMU",
+  roundsd_3 =	"rrio:660F3A0BrMU|rxi/oq:",
+  roundss_3 =	"rrio:660F3A0ArMU|rxi/od:",
+
+  -- SSE4.2 ops
+  crc32_2 =	"rmqd:F20F38F1rM|rm/dw:66F20F38F1rM|rm/db:F20F38F0rM|rm/qb:",
+  pcmpestri_3 =	"rmio:660F3A61rMU",
+  pcmpestrm_3 =	"rmio:660F3A60rMU",
+  pcmpgtq_2 =	"rmo:660F3837rM",
+  pcmpistri_3 =	"rmio:660F3A63rMU",
+  pcmpistrm_3 =	"rmio:660F3A62rMU",
+  popcnt_2 =	"rmqdw:F30FB8rM",
+
+  -- SSE4a
+  extrq_2 =	"rro:660F79rM",
+  extrq_3 =	"riio:660F780mUU",
+  insertq_2 =	"rro:F20F79rM",
+  insertq_4 =	"rriio:F20F78rMUU",
+  lzcnt_2 =	"rmqdw:F30FBDrM",
+  movntsd_2 =	"xr/qo:nF20F2BRm",
+  movntss_2 =	"xr/do:F30F2BRm",
+  -- popcnt is also in SSE4.2
+}
+
+------------------------------------------------------------------------------
+
+-- Arithmetic ops.
+for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3,
+		     ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do
+  local n8 = n * 8
+  map_op[name.."_2"] = format(
+    "mr:%02XRm|rm:%02XrM|mI1qdw:81%XmI|mS1qdw:83%XmS|Ri1qdwb:%02Xri|mi1qdwb:81%Xmi",
+    1+n8, 3+n8, n, n, 5+n8, n)
+end
+
+-- Shift ops.
+for name,n in pairs{ rol = 0, ror = 1, rcl = 2, rcr = 3,
+		     shl = 4, shr = 5,          sar = 7, sal = 4 } do
+  map_op[name.."_2"] = format("m1:D1%Xm|mC1qdwb:D3%Xm|mi:C1%XmU", n, n, n)
+end
+
+-- Conditional ops.
+for cc,n in pairs(map_cc) do
+  map_op["j"..cc.."_1"] = format("J.:n0F8%XJ", n) -- short: 7%X
+  map_op["set"..cc.."_1"] = format("mb:n0F9%X2m", n)
+  map_op["cmov"..cc.."_2"] = format("rmqdw:0F4%XrM", n) -- P6+
+end
+
+-- FP arithmetic ops.
+for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3,
+		     sub = 4, subr = 5, div = 6, divr = 7 } do
+  local nc = 192 + n * 8
+  local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8))
+  local fn = "f"..name
+  map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:nDC%Xm", nc, n, n)
+  if n == 2 or n == 3 then
+    map_op[fn.."_2"] = format("Fff:D8%02XR|Fx2d:D8%XM|Fx2q:nDC%XM", nc, n, n)
+  else
+    map_op[fn.."_2"] = format("Fff:D8%02XR|fFf:DC%02Xr|Fx2d:D8%XM|Fx2q:nDC%XM", nc, nr, n, n)
+    map_op[fn.."p_1"] = format("ff:DE%02Xr", nr)
+    map_op[fn.."p_2"] = format("fFf:DE%02Xr", nr)
+  end
+  map_op["fi"..name.."_1"] = format("xd:DA%Xm|xw:nDE%Xm", n, n)
+end
+
+-- FP conditional moves.
+for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do
+  local n4 = n % 4
+  local nc = 56000 + n4 * 8 + (n-n4) * 64
+  map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+
+  map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+
+end
+
+-- SSE FP arithmetic ops.
+for name,n in pairs{ sqrt = 1, add = 8, mul = 9,
+		     sub = 12, min = 13, div = 14, max = 15 } do
+  map_op[name.."ps_2"] = format("rmo:0F5%XrM", n)
+  map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n)
+  map_op[name.."pd_2"] = format("rmo:660F5%XrM", n)
+  map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n)
+end
+
+------------------------------------------------------------------------------
+
+-- Process pattern string.
+local function dopattern(pat, args, sz, op, needrex)
+  local digit, addin
+  local opcode = 0
+  local szov = sz
+  local narg = 1
+  local rex = 0
+
+  -- Limit number of section buffer positions used by a single dasm_put().
+  -- A single opcode needs a maximum of 5 positions.
+  if secpos+5 > maxsecpos then wflush() end
+
+  -- Process each character.
+  for c in gmatch(pat.."|", ".") do
+    if match(c, "%x") then	-- Hex digit.
+      digit = byte(c) - 48
+      if digit > 48 then digit = digit - 39
+      elseif digit > 16 then digit = digit - 7 end
+      opcode = opcode*16 + digit
+      addin = nil
+    elseif c == "n" then	-- Disable operand size mods for opcode.
+      szov = nil
+    elseif c == "X" then	-- Force REX.W.
+      rex = 8
+    elseif c == "r" then	-- Merge 1st operand regno. into opcode.
+      addin = args[1]; opcode = opcode + (addin.reg % 8)
+      if narg < 2 then narg = 2 end
+    elseif c == "R" then	-- Merge 2nd operand regno. into opcode.
+      addin = args[2]; opcode = opcode + (addin.reg % 8)
+      narg = 3
+    elseif c == "m" or c == "M" then	-- Encode ModRM/SIB.
+      local s
+      if addin then
+	s = addin.reg
+	opcode = opcode - (s%8)	-- Undo regno opcode merge.
+      else
+	s = opcode % 16		-- Undo last digit.
+	opcode = (opcode - s) / 16
+      end
+      local nn = c == "m" and 1 or 2
+      local t = args[nn]
+      if narg <= nn then narg = nn + 1 end
+      if szov == "q" and rex == 0 then rex = rex + 8 end
+      if t.reg and t.reg > 7 then rex = rex + 1 end
+      if t.xreg and t.xreg > 7 then rex = rex + 2 end
+      if s > 7 then rex = rex + 4 end
+      if needrex then rex = rex + 16 end
+      wputop(szov, opcode, rex); opcode = nil
+      local imark = sub(pat, -1) -- Force a mark (ugly).
+      -- Put ModRM/SIB with regno/last digit as spare.
+      wputmrmsib(t, imark, s, addin and addin.vreg)
+      addin = nil
+    else
+      if opcode then -- Flush opcode.
+	if szov == "q" and rex == 0 then rex = rex + 8 end
+	if needrex then rex = rex + 16 end
+	if addin and addin.reg == -1 then
+	  wputop(szov, opcode - 7, rex)
+	  waction("VREG", addin.vreg); wputxb(0)
+	else
+	  if addin and addin.reg > 7 then rex = rex + 1 end
+	  wputop(szov, opcode, rex)
+	end
+	opcode = nil
+      end
+      if c == "|" then break end
+      if c == "o" then -- Offset (pure 32 bit displacement).
+	wputdarg(args[1].disp); if narg < 2 then narg = 2 end
+      elseif c == "O" then
+	wputdarg(args[2].disp); narg = 3
+      else
+	-- Anything else is an immediate operand.
+	local a = args[narg]
+	narg = narg + 1
+	local mode, imm = a.mode, a.imm
+	if mode == "iJ" and not match("iIJ", c) then
+	  werror("bad operand size for label")
+	end
+	if c == "S" then
+	  wputsbarg(imm)
+	elseif c == "U" then
+	  wputbarg(imm)
+	elseif c == "W" then
+	  wputwarg(imm)
+	elseif c == "i" or c == "I" then
+	  if mode == "iJ" then
+	    wputlabel("IMM_", imm, 1)
+	  elseif mode == "iI" and c == "I" then
+	    waction(sz == "w" and "IMM_WB" or "IMM_DB", imm)
+	  else
+	    wputszarg(sz, imm)
+	  end
+	elseif c == "J" then
+	  if mode == "iPJ" then
+	    waction("REL_A", imm) -- !x64 (secpos)
+	  else
+	    wputlabel("REL_", imm, 2)
+	  end
+	else
+	  werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'")
+	end
+      end
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Mapping of operand modes to short names. Suppress output with '#'.
+local map_modename = {
+  r = "reg", R = "eax", C = "cl", x = "mem", m = "mrm", i = "imm",
+  f = "stx", F = "st0", J = "lbl", ["1"] = "1",
+  I = "#", S = "#", O = "#",
+}
+
+-- Return a table/string showing all possible operand modes.
+local function templatehelp(template, nparams)
+  if nparams == 0 then return "" end
+  local t = {}
+  for tm in gmatch(template, "[^%|]+") do
+    local s = map_modename[sub(tm, 1, 1)]
+    s = s..gsub(sub(tm, 2, nparams), ".", function(c)
+      return ", "..map_modename[c]
+    end)
+    if not match(s, "#") then t[#t+1] = s end
+  end
+  return t
+end
+
+-- Match operand modes against mode match part of template.
+local function matchtm(tm, args)
+  for i=1,#args do
+    if not match(args[i].mode, sub(tm, i, i)) then return end
+  end
+  return true
+end
+
+-- Handle opcodes defined with template strings.
+map_op[".template__"] = function(params, template, nparams)
+  if not params then return templatehelp(template, nparams) end
+  local args = {}
+
+  -- Zero-operand opcodes have no match part.
+  if #params == 0 then
+    dopattern(template, args, "d", params.op, nil)
+    return
+  end
+
+  -- Determine common operand size (coerce undefined size) or flag as mixed.
+  local sz, szmix, needrex
+  for i,p in ipairs(params) do
+    args[i] = parseoperand(p)
+    local nsz = args[i].opsize
+    if nsz then
+      if sz and sz ~= nsz then szmix = true else sz = nsz end
+    end
+    local nrex = args[i].needrex
+    if nrex ~= nil then
+      if needrex == nil then
+	needrex = nrex
+      elseif needrex ~= nrex then
+	werror("bad mix of byte-addressable registers")
+      end
+    end
+  end
+
+  -- Try all match:pattern pairs (separated by '|').
+  local gotmatch, lastpat
+  for tm in gmatch(template, "[^%|]+") do
+    -- Split off size match (starts after mode match) and pattern string.
+    local szm, pat = match(tm, "^(.-):(.*)$", #args+1)
+    if pat == "" then pat = lastpat else lastpat = pat end
+    if matchtm(tm, args) then
+      local prefix = sub(szm, 1, 1)
+      if prefix == "/" then -- Match both operand sizes.
+	if args[1].opsize == sub(szm, 2, 2) and
+	   args[2].opsize == sub(szm, 3, 3) then
+	  dopattern(pat, args, sz, params.op, needrex) -- Process pattern.
+	  return
+	end
+      else -- Match common operand size.
+	local szp = sz
+	if szm == "" then szm = x64 and "qdwb" or "dwb" end -- Default sizes.
+	if prefix == "1" then szp = args[1].opsize; szmix = nil
+	elseif prefix == "2" then szp = args[2].opsize; szmix = nil end
+	if not szmix and (prefix == "." or match(szm, szp or "#")) then
+	  dopattern(pat, args, szp, params.op, needrex) -- Process pattern.
+	  return
+	end
+      end
+      gotmatch = true
+    end
+  end
+
+  local msg = "bad operand mode"
+  if gotmatch then
+    if szmix then
+      msg = "mixed operand size"
+    else
+      msg = sz and "bad operand size" or "missing operand size"
+    end
+  end
+
+  werror(msg.." in `"..opmodestr(params.op, args).."'")
+end
+
+------------------------------------------------------------------------------
+
+-- x64-specific opcode for 64 bit immediates and displacements.
+if x64 then
+  function map_op.mov64_2(params)
+    if not params then return { "reg, imm", "reg, [disp]", "[disp], reg" } end
+    if secpos+2 > maxsecpos then wflush() end
+    local opcode, op64, sz, rex
+    local op64 = match(params[1], "^%[%s*(.-)%s*%]$")
+    if op64 then
+      local a = parseoperand(params[2])
+      if a.mode ~= "rmR" then werror("bad operand mode") end
+      sz = a.opsize
+      rex = sz == "q" and 8 or 0
+      opcode = 0xa3
+    else
+      op64 = match(params[2], "^%[%s*(.-)%s*%]$")
+      local a = parseoperand(params[1])
+      if op64 then
+	if a.mode ~= "rmR" then werror("bad operand mode") end
+	sz = a.opsize
+	rex = sz == "q" and 8 or 0
+	opcode = 0xa1
+      else
+	if sub(a.mode, 1, 1) ~= "r" or a.opsize ~= "q" then
+	  werror("bad operand mode")
+	end
+	op64 = params[2]
+	opcode = 0xb8 + (a.reg%8) -- !x64: no VREG support.
+	rex = a.reg > 7 and 9 or 8
+      end
+    end
+    wputop(sz, opcode, rex)
+    waction("IMM_D", format("(unsigned int)((uintptr_t)(%s))", op64))
+    waction("IMM_D", format("(unsigned int)(((uintptr_t)(%s))>>32)", op64))
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+local function op_data(params)
+  if not params then return "imm..." end
+  local sz = sub(params.op, 2, 2)
+  if sz == "a" then sz = addrsize end
+  for _,p in ipairs(params) do
+    local a = parseoperand(p)
+    if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then
+      werror("bad mode or size in `"..p.."'")
+    end
+    if a.mode == "iJ" then
+      wputlabel("IMM_", a.imm, 1)
+    else
+      wputszarg(sz, a.imm)
+    end
+    if secpos+2 > maxsecpos then wflush() end
+  end
+end
+
+map_op[".byte_*"] = op_data
+map_op[".sbyte_*"] = op_data
+map_op[".word_*"] = op_data
+map_op[".dword_*"] = op_data
+map_op[".aword_*"] = op_data
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+  if not params then return "cvar" end
+  local name = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+  if not params then return "prefix" end
+  local prefix = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+  if not params then return "cvar" end
+  local name = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+  if not params then return "cvar" end
+  local name = params[1] -- No syntax check. You get to keep the pieces.
+  wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_2"] = function(params)
+  if not params then return "[1-9] | ->global | =>pcexpr  [, addr]" end
+  if secpos+2 > maxsecpos then wflush() end
+  local a = parseoperand(params[1])
+  local mode, imm = a.mode, a.imm
+  if type(imm) == "number" and (mode == "iJ" or (imm >= 1 and imm <= 9)) then
+    -- Local label (1: ... 9:) or global label (->global:).
+    waction("LABEL_LG", nil, 1)
+    wputxb(imm)
+  elseif mode == "iJ" then
+    -- PC label (=>pcexpr:).
+    waction("LABEL_PC", imm)
+  else
+    werror("bad label definition")
+  end
+  -- SETLABEL must immediately follow LABEL_LG/LABEL_PC.
+  local addr = params[2]
+  if addr then
+    local a = parseoperand(addr)
+    if a.mode == "iPJ" then
+      waction("SETLABEL", a.imm)
+    else
+      werror("bad label assignment")
+    end
+  end
+end
+map_op[".label_1"] = map_op[".label_2"]
+
+------------------------------------------------------------------------------
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+  if not params then return "numpow2" end
+  if secpos+1 > maxsecpos then wflush() end
+  local align = tonumber(params[1]) or map_opsizenum[map_opsize[params[1]]]
+  if align then
+    local x = align
+    -- Must be a power of 2 in the range (2 ... 256).
+    for i=1,8 do
+      x = x / 2
+      if x == 1 then
+	waction("ALIGN", nil, 1)
+	wputxb(align-1) -- Action byte is 2**n-1.
+	return
+      end
+    end
+  end
+  werror("bad alignment")
+end
+
+-- Spacing pseudo-opcode.
+map_op[".space_2"] = function(params)
+  if not params then return "num [, filler]" end
+  if secpos+1 > maxsecpos then wflush() end
+  waction("SPACE", params[1])
+  local fill = params[2]
+  if fill then
+    fill = tonumber(fill)
+    if not fill or fill < 0 or fill > 255 then werror("bad filler") end
+  end
+  wputxb(fill or 0)
+end
+map_op[".space_1"] = map_op[".space_2"]
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+  if not params then
+    return nparams == 2 and "name, ctype" or "name, ctype, reg"
+  end
+  local name, ctype, reg = params[1], params[2], params[3]
+  if not match(name, "^[%a_][%w_]*$") then
+    werror("bad type name `"..name.."'")
+  end
+  local tp = map_type[name]
+  if tp then
+    werror("duplicate type `"..name.."'")
+  end
+  if reg and not map_reg_valid_base[reg] then
+    werror("bad base register `"..(map_reg_rev[reg] or reg).."'")
+  end
+  -- Add #type to defines. A bit unclean to put it in map_archdef.
+  map_archdef["#"..name] = "sizeof("..ctype..")"
+  -- Add new type and emit shortcut define.
+  local num = ctypenum + 1
+  map_type[name] = {
+    ctype = ctype,
+    ctypefmt = format("Dt%X(%%s)", num),
+    reg = reg,
+  }
+  wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+  ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+  local t = {}
+  for name in pairs(map_type) do t[#t+1] = name end
+  sort(t)
+  out:write("Type definitions:\n")
+  for _,name in ipairs(t) do
+    local tp = map_type[name]
+    local reg = tp.reg and map_reg_rev[tp.reg] or ""
+    out:write(format("  %-20s %-20s %s\n", name, tp.ctype, reg))
+  end
+  out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+  waction("SECTION")
+  wputxb(num)
+  wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+  out:write(format("DynASM %s version %s, released %s\n\n",
+    _info.arch, _info.version, _info.release))
+  dumpregs(out)
+  dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+  dumptypes(out, lvl)
+  dumpglobals(out, lvl)
+  dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+  wline, werror, wfatal, wwarn = wl, we, wf, ww
+  return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+  g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+  setmetatable(map_op, { __index = map_coreop })
+  setmetatable(map_def, { __index = map_archdef })
+  return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dynasm.lua
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dynasm.lua	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/dynasm/dynasm.lua	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,1096 @@
+------------------------------------------------------------------------------
+-- DynASM. A dynamic assembler for code generation engines.
+-- Originally designed and implemented for LuaJIT.
+--
+-- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
+-- See below for full copyright notice.
+------------------------------------------------------------------------------
+
+-- Application information.
+local _info = {
+  name =	"DynASM",
+  description =	"A dynamic assembler for code generation engines",
+  version =	"1.3.0",
+  vernum =	 10300,
+  release =	"2011-05-05",
+  author =	"Mike Pall",
+  url =		"http://luajit.org/dynasm.html",
+  license =	"MIT",
+  copyright =	[[
+Copyright (C) 2005-2011 Mike Pall. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+[ MIT license: http://www.opensource.org/licenses/mit-license.php ]
+]],
+}
+
+-- Cache library functions.
+local type, pairs, ipairs = type, pairs, ipairs
+local pcall, error, assert = pcall, error, assert
+local _s = string
+local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub
+local format, rep, upper = _s.format, _s.rep, _s.upper
+local _t = table
+local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort
+local exit = os.exit
+local io = io
+local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr
+
+------------------------------------------------------------------------------
+
+-- Program options.
+local g_opt = {}
+
+-- Global state for current file.
+local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch
+local g_errcount = 0
+
+-- Write buffer for output file.
+local g_wbuffer, g_capbuffer
+
+------------------------------------------------------------------------------
+
+-- Write an output line (or callback function) to the buffer.
+local function wline(line, needindent)
+  local buf = g_capbuffer or g_wbuffer
+  buf[#buf+1] = needindent and g_indent..line or line
+  g_synclineno = g_synclineno + 1
+end
+
+-- Write assembler line as a comment, if requestd.
+local function wcomment(aline)
+  if g_opt.comment then
+    wline(g_opt.comment..aline..g_opt.endcomment, true)
+  end
+end
+
+-- Resync CPP line numbers.
+local function wsync()
+  if g_synclineno ~= g_lineno and g_opt.cpp then
+    wline("# "..g_lineno..' "'..g_fname..'"')
+    g_synclineno = g_lineno
+  end
+end
+
+-- Dummy action flush function. Replaced with arch-specific function later.
+local function wflush(term)
+end
+
+-- Dump all buffered output lines.
+local function wdumplines(out, buf)
+  for _,line in ipairs(buf) do
+    if type(line) == "string" then
+      assert(out:write(line, "\n"))
+    else
+      -- Special callback to dynamically insert lines after end of processing.
+      line(out)
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Emit an error. Processing continues with next statement.
+local function werror(msg)
+  if g_opt.vserror then
+    error(format("%s(%s) : error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0)
+  else
+    error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0)
+  end
+end
+
+-- Emit a fatal error. Processing stops.
+local function wfatal(msg)
+  g_errcount = "fatal"
+  werror(msg)
+end
+
+-- Print a warning. Processing continues.
+local function wwarn(msg)
+  stderr:write(format("%s:%s: warning: %s:\n%s\n",
+    g_fname, g_lineno, msg, g_curline))
+end
+
+-- Print caught error message. But suppress excessive errors.
+local function wprinterr(...)
+  if type(g_errcount) == "number" then
+    -- Regular error.
+    g_errcount = g_errcount + 1
+    if g_errcount < 21 then -- Seems to be a reasonable limit.
+      stderr:write(...)
+    elseif g_errcount == 21 then
+      stderr:write(g_fname,
+	":*: warning: too many errors (suppressed further messages).\n")
+    end
+  else
+    -- Fatal error.
+    stderr:write(...)
+    return true -- Stop processing.
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Map holding all option handlers.
+local opt_map = {}
+local opt_current
+
+-- Print error and exit with error status.
+local function opterror(...)
+  stderr:write("dynasm.lua: ERROR: ", ...)
+  stderr:write("\n")
+  exit(1)
+end
+
+-- Get option parameter.
+local function optparam(args)
+  local argn = args.argn
+  local p = args[argn]
+  if not p then
+    opterror("missing parameter for option `", opt_current, "'.")
+  end
+  args.argn = argn + 1
+  return p
+end
+
+------------------------------------------------------------------------------
+
+-- Core pseudo-opcodes.
+local map_coreop = {}
+-- Dummy opcode map. Replaced by arch-specific map.
+local map_op = {}
+
+-- Forward declarations.
+local dostmt
+local readfile
+
+------------------------------------------------------------------------------
+
+-- Map for defines (initially empty, chains to arch-specific map).
+local map_def = {}
+
+-- Pseudo-opcode to define a substitution.
+map_coreop[".define_2"] = function(params, nparams)
+  if not params then return nparams == 1 and "name" or "name, subst" end
+  local name, def = params[1], params[2] or "1"
+  if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end
+  map_def[name] = def
+end
+map_coreop[".define_1"] = map_coreop[".define_2"]
+
+-- Define a substitution on the command line.
+function opt_map.D(args)
+  local namesubst = optparam(args)
+  local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$")
+  if name then
+    map_def[name] = subst
+  elseif match(namesubst, "^[%a_][%w_]*$") then
+    map_def[namesubst] = "1"
+  else
+    opterror("bad define")
+  end
+end
+
+-- Undefine a substitution on the command line.
+function opt_map.U(args)
+  local name = optparam(args)
+  if match(name, "^[%a_][%w_]*$") then
+    map_def[name] = nil
+  else
+    opterror("bad define")
+  end
+end
+
+-- Helper for definesubst.
+local gotsubst
+
+local function definesubst_one(word)
+  local subst = map_def[word]
+  if subst then gotsubst = word; return subst else return word end
+end
+
+-- Iteratively substitute defines.
+local function definesubst(stmt)
+  -- Limit number of iterations.
+  for i=1,100 do
+    gotsubst = false
+    stmt = gsub(stmt, "#?[%w_]+", definesubst_one)
+    if not gotsubst then break end
+  end
+  if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end
+  return stmt
+end
+
+-- Dump all defines.
+local function dumpdefines(out, lvl)
+  local t = {}
+  for name in pairs(map_def) do
+    t[#t+1] = name
+  end
+  sort(t)
+  out:write("Defines:\n")
+  for _,name in ipairs(t) do
+    local subst = map_def[name]
+    if g_arch then subst = g_arch.revdef(subst) end
+    out:write(format("  %-20s %s\n", name, subst))
+  end
+  out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Support variables for conditional assembly.
+local condlevel = 0
+local condstack = {}
+
+local function loadin(source, env)
+  if setfenv then
+    local func, err = loadstring(source)
+    if func then
+      setfenv(func, env)
+    end
+    return func, err
+  else
+    return load(source, nil, nil, env)
+  end
+end
+
+-- Evaluate condition with a Lua expression. Substitutions already performed.
+local function cond_eval(cond)
+  -- No globals. All unknown identifiers evaluate to nil.
+  local func, err = loadin("return "..cond, {})
+  if func then
+    local ok, res = pcall(func)
+    if ok then
+      if res == 0 then return false end -- Oh well.
+      return not not res
+    end
+    err = res
+  end
+  wfatal("bad condition: "..err)
+end
+
+-- Skip statements until next conditional pseudo-opcode at the same level.
+local function stmtskip()
+  local dostmt_save = dostmt
+  local lvl = 0
+  dostmt = function(stmt)
+    local op = match(stmt, "^%s*(%S+)")
+    if op == ".if" then
+      lvl = lvl + 1
+    elseif lvl ~= 0 then
+      if op == ".endif" then lvl = lvl - 1 end
+    elseif op == ".elif" or op == ".else" or op == ".endif" then
+      dostmt = dostmt_save
+      dostmt(stmt)
+    end
+  end
+end
+
+-- Pseudo-opcodes for conditional assembly.
+map_coreop[".if_1"] = function(params)
+  if not params then return "condition" end
+  local lvl = condlevel + 1
+  local res = cond_eval(params[1])
+  condlevel = lvl
+  condstack[lvl] = res
+  if not res then stmtskip() end
+end
+
+map_coreop[".elif_1"] = function(params)
+  if not params then return "condition" end
+  if condlevel == 0 then wfatal(".elif without .if") end
+  local lvl = condlevel
+  local res = condstack[lvl]
+  if res then
+    if res == "else" then wfatal(".elif after .else") end
+  else
+    res = cond_eval(params[1])
+    if res then
+      condstack[lvl] = res
+      return
+    end
+  end
+  stmtskip()
+end
+
+map_coreop[".else_0"] = function(params)
+  if condlevel == 0 then wfatal(".else without .if") end
+  local lvl = condlevel
+  local res = condstack[lvl]
+  condstack[lvl] = "else"
+  if res then
+    if res == "else" then wfatal(".else after .else") end
+    stmtskip()
+  end
+end
+
+map_coreop[".endif_0"] = function(params)
+  local lvl = condlevel
+  if lvl == 0 then wfatal(".endif without .if") end
+  condlevel = lvl - 1
+end
+
+-- Check for unfinished conditionals.
+local function checkconds()
+  if g_errcount ~= "fatal" and condlevel ~= 0 then
+    wprinterr(g_fname, ":*: error: unbalanced conditional\n")
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Search for a file in the given path and open it for reading.
+local function pathopen(path, name)
+  local dirsep = match(package.path, "\\") and "\\" or "/"
+  for _,p in ipairs(path) do
+    local fullname = p == "" and name or p..dirsep..name
+    local fin = io.open(fullname, "r")
+    if fin then
+      g_fname = fullname
+      return fin
+    end
+  end
+end
+
+-- Include a file.
+map_coreop[".include_1"] = function(params)
+  if not params then return "filename" end
+  local name = params[1]
+  -- Save state. Ugly, I know. but upvalues are fast.
+  local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent
+  -- Read the included file.
+  local fatal = readfile(pathopen(g_opt.include, name) or
+			 wfatal("include file `"..name.."' not found"))
+  -- Restore state.
+  g_synclineno = -1
+  g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi
+  if fatal then wfatal("in include file") end
+end
+
+-- Make .include and conditionals initially available, too.
+map_op[".include_1"] = map_coreop[".include_1"]
+map_op[".if_1"] = map_coreop[".if_1"]
+map_op[".elif_1"] = map_coreop[".elif_1"]
+map_op[".else_0"] = map_coreop[".else_0"]
+map_op[".endif_0"] = map_coreop[".endif_0"]
+
+------------------------------------------------------------------------------
+
+-- Support variables for macros.
+local mac_capture, mac_lineno, mac_name
+local mac_active = {}
+local mac_list = {}
+
+-- Pseudo-opcode to define a macro.
+map_coreop[".macro_*"] = function(mparams)
+  if not mparams then return "name [, params...]" end
+  -- Split off and validate macro name.
+  local name = remove(mparams, 1)
+  if not name then werror("missing macro name") end
+  if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]+$")) then
+    wfatal("bad macro name `"..name.."'")
+  end
+  -- Validate macro parameter names.
+  local mdup = {}
+  for _,mp in ipairs(mparams) do
+    if not match(mp, "^[%a_][%w_]*$") then
+      wfatal("bad macro parameter name `"..mp.."'")
+    end
+    if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end
+    mdup[mp] = true
+  end
+  -- Check for duplicate or recursive macro definitions.
+  local opname = name.."_"..#mparams
+  if map_op[opname] or map_op[name.."_*"] then
+    wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)")
+  end
+  if mac_capture then wfatal("recursive macro definition") end
+
+  -- Enable statement capture.
+  local lines = {}
+  mac_lineno = g_lineno
+  mac_name = name
+  mac_capture = function(stmt) -- Statement capture function.
+    -- Stop macro definition with .endmacro pseudo-opcode.
+    if not match(stmt, "^%s*.endmacro%s*$") then
+      lines[#lines+1] = stmt
+      return
+    end
+    mac_capture = nil
+    mac_lineno = nil
+    mac_name = nil
+    mac_list[#mac_list+1] = opname
+    -- Add macro-op definition.
+    map_op[opname] = function(params)
+      if not params then return mparams, lines end
+      -- Protect against recursive macro invocation.
+      if mac_active[opname] then wfatal("recursive macro invocation") end
+      mac_active[opname] = true
+      -- Setup substitution map.
+      local subst = {}
+      for i,mp in ipairs(mparams) do subst[mp] = params[i] end
+      local mcom
+      if g_opt.maccomment and g_opt.comment then
+	mcom = " MACRO "..name.." ("..#mparams..")"
+	wcomment("{"..mcom)
+      end
+      -- Loop through all captured statements
+      for _,stmt in ipairs(lines) do
+	-- Substitute macro parameters.
+	local st = gsub(stmt, "[%w_]+", subst)
+	st = definesubst(st)
+	st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b.
+	if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end
+	-- Emit statement. Use a protected call for better diagnostics.
+	local ok, err = pcall(dostmt, st)
+	if not ok then
+	  -- Add the captured statement to the error.
+	  wprinterr(err, "\n", g_indent, "|  ", stmt,
+		    "\t[MACRO ", name, " (", #mparams, ")]\n")
+	end
+      end
+      if mcom then wcomment("}"..mcom) end
+      mac_active[opname] = nil
+    end
+  end
+end
+
+-- An .endmacro pseudo-opcode outside of a macro definition is an error.
+map_coreop[".endmacro_0"] = function(params)
+  wfatal(".endmacro without .macro")
+end
+
+-- Dump all macros and their contents (with -PP only).
+local function dumpmacros(out, lvl)
+  sort(mac_list)
+  out:write("Macros:\n")
+  for _,opname in ipairs(mac_list) do
+    local name = sub(opname, 1, -3)
+    local params, lines = map_op[opname]()
+    out:write(format("  %-20s %s\n", name, concat(params, ", ")))
+    if lvl > 1 then
+      for _,line in ipairs(lines) do
+	out:write("  |", line, "\n")
+      end
+      out:write("\n")
+    end
+  end
+  out:write("\n")
+end
+
+-- Check for unfinished macro definitions.
+local function checkmacros()
+  if mac_capture then
+    wprinterr(g_fname, ":", mac_lineno,
+	      ": error: unfinished .macro `", mac_name ,"'\n")
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Support variables for captures.
+local cap_lineno, cap_name
+local cap_buffers = {}
+local cap_used = {}
+
+-- Start a capture.
+map_coreop[".capture_1"] = function(params)
+  if not params then return "name" end
+  wflush()
+  local name = params[1]
+  if not match(name, "^[%a_][%w_]*$") then
+    wfatal("bad capture name `"..name.."'")
+  end
+  if cap_name then
+    wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno)
+  end
+  cap_name = name
+  cap_lineno = g_lineno
+  -- Create or continue a capture buffer and start the output line capture.
+  local buf = cap_buffers[name]
+  if not buf then buf = {}; cap_buffers[name] = buf end
+  g_capbuffer = buf
+  g_synclineno = 0
+end
+
+-- Stop a capture.
+map_coreop[".endcapture_0"] = function(params)
+  wflush()
+  if not cap_name then wfatal(".endcapture without a valid .capture") end
+  cap_name = nil
+  cap_lineno = nil
+  g_capbuffer = nil
+  g_synclineno = 0
+end
+
+-- Dump a capture buffer.
+map_coreop[".dumpcapture_1"] = function(params)
+  if not params then return "name" end
+  wflush()
+  local name = params[1]
+  if not match(name, "^[%a_][%w_]*$") then
+    wfatal("bad capture name `"..name.."'")
+  end
+  cap_used[name] = true
+  wline(function(out)
+    local buf = cap_buffers[name]
+    if buf then wdumplines(out, buf) end
+  end)
+  g_synclineno = 0
+end
+
+-- Dump all captures and their buffers (with -PP only).
+local function dumpcaptures(out, lvl)
+  out:write("Captures:\n")
+  for name,buf in pairs(cap_buffers) do
+    out:write(format("  %-20s %4s)\n", name, "("..#buf))
+    if lvl > 1 then
+      local bar = rep("=", 76)
+      out:write("  ", bar, "\n")
+      for _,line in ipairs(buf) do
+	out:write("  ", line, "\n")
+      end
+      out:write("  ", bar, "\n\n")
+    end
+  end
+  out:write("\n")
+end
+
+-- Check for unfinished or unused captures.
+local function checkcaptures()
+  if cap_name then
+    wprinterr(g_fname, ":", cap_lineno,
+	      ": error: unfinished .capture `", cap_name,"'\n")
+    return
+  end
+  for name in pairs(cap_buffers) do
+    if not cap_used[name] then
+      wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n")
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Sections names.
+local map_sections = {}
+
+-- Pseudo-opcode to define code sections.
+-- TODO: Data sections, BSS sections. Needs extra C code and API.
+map_coreop[".section_*"] = function(params)
+  if not params then return "name..." end
+  if #map_sections > 0 then werror("duplicate section definition") end
+  wflush()
+  for sn,name in ipairs(params) do
+    local opname = "."..name.."_0"
+    if not match(name, "^[%a][%w_]*$") or
+       map_op[opname] or map_op["."..name.."_*"] then
+      werror("bad section name `"..name.."'")
+    end
+    map_sections[#map_sections+1] = name
+    wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1))
+    map_op[opname] = function(params) g_arch.section(sn-1) end
+  end
+  wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections))
+end
+
+-- Dump all sections.
+local function dumpsections(out, lvl)
+  out:write("Sections:\n")
+  for _,name in ipairs(map_sections) do
+    out:write(format("  %s\n", name))
+  end
+  out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Load architecture-specific module.
+local function loadarch(arch)
+  if not match(arch, "^[%w_]+$") then return "bad arch name" end
+  local ok, m_arch = pcall(require, "dasm_"..arch)
+  if not ok then return "cannot load module: "..m_arch end
+  g_arch = m_arch
+  wflush = m_arch.passcb(wline, werror, wfatal, wwarn)
+  m_arch.setup(arch, g_opt)
+  map_op, map_def = m_arch.mergemaps(map_coreop, map_def)
+end
+
+-- Dump architecture description.
+function opt_map.dumparch(args)
+  local name = optparam(args)
+  if not g_arch then
+    local err = loadarch(name)
+    if err then opterror(err) end
+  end
+
+  local t = {}
+  for name in pairs(map_coreop) do t[#t+1] = name end
+  for name in pairs(map_op) do t[#t+1] = name end
+  sort(t)
+
+  local out = stdout
+  local _arch = g_arch._info
+  out:write(format("%s version %s, released %s, %s\n",
+    _info.name, _info.version, _info.release, _info.url))
+  g_arch.dumparch(out)
+
+  local pseudo = true
+  out:write("Pseudo-Opcodes:\n")
+  for _,sname in ipairs(t) do
+    local name, nparam = match(sname, "^(.+)_([0-9%*])$")
+    if name then
+      if pseudo and sub(name, 1, 1) ~= "." then
+	out:write("\nOpcodes:\n")
+	pseudo = false
+      end
+      local f = map_op[sname]
+      local s
+      if nparam ~= "*" then nparam = nparam + 0 end
+      if nparam == 0 then
+	s = ""
+      elseif type(f) == "string" then
+	s = map_op[".template__"](nil, f, nparam)
+      else
+	s = f(nil, nparam)
+      end
+      if type(s) == "table" then
+	for _,s2 in ipairs(s) do
+	  out:write(format("  %-12s %s\n", name, s2))
+	end
+      else
+	out:write(format("  %-12s %s\n", name, s))
+      end
+    end
+  end
+  out:write("\n")
+  exit(0)
+end
+
+-- Pseudo-opcode to set the architecture.
+-- Only initially available (map_op is replaced when called).
+map_op[".arch_1"] = function(params)
+  if not params then return "name" end
+  local err = loadarch(params[1])
+  if err then wfatal(err) end
+end
+
+-- Dummy .arch pseudo-opcode to improve the error report.
+map_coreop[".arch_1"] = function(params)
+  if not params then return "name" end
+  wfatal("duplicate .arch statement")
+end
+
+------------------------------------------------------------------------------
+
+-- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'.
+map_coreop[".nop_*"] = function(params)
+  if not params then return "[ignored...]" end
+end
+
+-- Pseudo-opcodes to raise errors.
+map_coreop[".error_1"] = function(params)
+  if not params then return "message" end
+  werror(params[1])
+end
+
+map_coreop[".fatal_1"] = function(params)
+  if not params then return "message" end
+  wfatal(params[1])
+end
+
+-- Dump all user defined elements.
+local function dumpdef(out)
+  local lvl = g_opt.dumpdef
+  if lvl == 0 then return end
+  dumpsections(out, lvl)
+  dumpdefines(out, lvl)
+  if g_arch then g_arch.dumpdef(out, lvl) end
+  dumpmacros(out, lvl)
+  dumpcaptures(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Helper for splitstmt.
+local splitlvl
+
+local function splitstmt_one(c)
+  if c == "(" then
+    splitlvl = ")"..splitlvl
+  elseif c == "[" then
+    splitlvl = "]"..splitlvl
+  elseif c == "{" then
+    splitlvl = "}"..splitlvl
+  elseif c == ")" or c == "]" or c == "}" then
+    if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end
+    splitlvl = sub(splitlvl, 2)
+  elseif splitlvl == "" then
+    return " \0 "
+  end
+  return c
+end
+
+-- Split statement into (pseudo-)opcode and params.
+local function splitstmt(stmt)
+  -- Convert label with trailing-colon into .label statement.
+  local label = match(stmt, "^%s*(.+):%s*$")
+  if label then return ".label", {label} end
+
+  -- Split at commas and equal signs, but obey parentheses and brackets.
+  splitlvl = ""
+  stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one)
+  if splitlvl ~= "" then werror("unbalanced () or []") end
+
+  -- Split off opcode.
+  local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$")
+  if not op then werror("bad statement syntax") end
+
+  -- Split parameters.
+  local params = {}
+  for p in gmatch(other, "%s*(%Z+)%z?") do
+    params[#params+1] = gsub(p, "%s+$", "")
+  end
+  if #params > 16 then werror("too many parameters") end
+
+  params.op = op
+  return op, params
+end
+
+-- Process a single statement.
+dostmt = function(stmt)
+  -- Ignore empty statements.
+  if match(stmt, "^%s*$") then return end
+
+  -- Capture macro defs before substitution.
+  if mac_capture then return mac_capture(stmt) end
+  stmt = definesubst(stmt)
+
+  -- Emit C code without parsing the line.
+  if sub(stmt, 1, 1) == "|" then
+    local tail = sub(stmt, 2)
+    wflush()
+    if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end
+    return
+  end
+
+  -- Split into (pseudo-)opcode and params.
+  local op, params = splitstmt(stmt)
+
+  -- Get opcode handler (matching # of parameters or generic handler).
+  local f = map_op[op.."_"..#params] or map_op[op.."_*"]
+  if not f then
+    if not g_arch then wfatal("first statement must be .arch") end
+    -- Improve error report.
+    for i=0,9 do
+      if map_op[op.."_"..i] then
+	werror("wrong number of parameters for `"..op.."'")
+      end
+    end
+    werror("unknown statement `"..op.."'")
+  end
+
+  -- Call opcode handler or special handler for template strings.
+  if type(f) == "string" then
+    map_op[".template__"](params, f)
+  else
+    f(params)
+  end
+end
+
+-- Process a single line.
+local function doline(line)
+  if g_opt.flushline then wflush() end
+
+  -- Assembler line?
+  local indent, aline = match(line, "^(%s*)%|(.*)$")
+  if not aline then
+    -- No, plain C code line, need to flush first.
+    wflush()
+    wsync()
+    wline(line, false)
+    return
+  end
+
+  g_indent = indent -- Remember current line indentation.
+
+  -- Emit C code (even from macros). Avoids echo and line parsing.
+  if sub(aline, 1, 1) == "|" then
+    if not mac_capture then
+      wsync()
+    elseif g_opt.comment then
+      wsync()
+      wcomment(aline)
+    end
+    dostmt(aline)
+    return
+  end
+
+  -- Echo assembler line as a comment.
+  if g_opt.comment then
+    wsync()
+    wcomment(aline)
+  end
+
+  -- Strip assembler comments.
+  aline = gsub(aline, "//.*$", "")
+
+  -- Split line into statements at semicolons.
+  if match(aline, ";") then
+    for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end
+  else
+    dostmt(aline)
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Write DynASM header.
+local function dasmhead(out)
+  out:write(format([[
+/*
+** This file has been pre-processed with DynASM.
+** %s
+** DynASM version %s, DynASM %s version %s
+** DO NOT EDIT! The original file is in "%s".
+*/
+
+#if DASM_VERSION != %d
+#error "Version mismatch between DynASM and included encoding engine"
+#endif
+
+]], _info.url,
+    _info.version, g_arch._info.arch, g_arch._info.version,
+    g_fname, _info.vernum))
+end
+
+-- Read input file.
+readfile = function(fin)
+  g_indent = ""
+  g_lineno = 0
+  g_synclineno = -1
+
+  -- Process all lines.
+  for line in fin:lines() do
+    g_lineno = g_lineno + 1
+    g_curline = line
+    local ok, err = pcall(doline, line)
+    if not ok and wprinterr(err, "\n") then return true end
+  end
+  wflush()
+
+  -- Close input file.
+  assert(fin == stdin or fin:close())
+end
+
+-- Write output file.
+local function writefile(outfile)
+  local fout
+
+  -- Open output file.
+  if outfile == nil or outfile == "-" then
+    fout = stdout
+  else
+    fout = assert(io.open(outfile, "w"))
+  end
+
+  -- Write all buffered lines
+  wdumplines(fout, g_wbuffer)
+
+  -- Close output file.
+  assert(fout == stdout or fout:close())
+
+  -- Optionally dump definitions.
+  dumpdef(fout == stdout and stderr or stdout)
+end
+
+-- Translate an input file to an output file.
+local function translate(infile, outfile)
+  g_wbuffer = {}
+  g_indent = ""
+  g_lineno = 0
+  g_synclineno = -1
+
+  -- Put header.
+  wline(dasmhead)
+
+  -- Read input file.
+  local fin
+  if infile == "-" then
+    g_fname = "(stdin)"
+    fin = stdin
+  else
+    g_fname = infile
+    fin = assert(io.open(infile, "r"))
+  end
+  readfile(fin)
+
+  -- Check for errors.
+  if not g_arch then
+    wprinterr(g_fname, ":*: error: missing .arch directive\n")
+  end
+  checkconds()
+  checkmacros()
+  checkcaptures()
+
+  if g_errcount ~= 0 then
+    stderr:write(g_fname, ":*: info: ", g_errcount, " error",
+      (type(g_errcount) == "number" and g_errcount > 1) and "s" or "",
+      " in input file -- no output file generated.\n")
+    dumpdef(stderr)
+    exit(1)
+  end
+
+  -- Write output file.
+  writefile(outfile)
+end
+
+------------------------------------------------------------------------------
+
+-- Print help text.
+function opt_map.help()
+  stdout:write("DynASM -- ", _info.description, ".\n")
+  stdout:write("DynASM ", _info.version, " ", _info.release, "  ", _info.url, "\n")
+  stdout:write[[
+
+Usage: dynasm [OPTION]... INFILE.dasc|-
+
+  -h, --help           Display this help text.
+  -V, --version        Display version and copyright information.
+
+  -o, --outfile FILE   Output file name (default is stdout).
+  -I, --include DIR    Add directory to the include search path.
+
+  -c, --ccomment       Use /* */ comments for assembler lines.
+  -C, --cppcomment     Use // comments for assembler lines (default).
+  -N, --nocomment      Suppress assembler lines in output.
+  -M, --maccomment     Show macro expansions as comments (default off).
+
+  -L, --nolineno       Suppress CPP line number information in output.
+  -F, --flushline      Flush action list for every line.
+
+  -E, --vserror        Use Visual Studio style errors file(line) vs file:line
+
+  -D NAME[=SUBST]      Define a substitution.
+  -U NAME              Undefine a substitution.
+
+  -P, --dumpdef        Dump defines, macros, etc. Repeat for more output.
+  -A, --dumparch ARCH  Load architecture ARCH and dump description.
+]]
+  exit(0)
+end
+
+-- Print version information.
+function opt_map.version()
+  stdout:write(format("%s version %s, released %s\n%s\n\n%s",
+    _info.name, _info.version, _info.release, _info.url, _info.copyright))
+  exit(0)
+end
+
+-- Misc. options.
+function opt_map.outfile(args) g_opt.outfile = optparam(args) end
+function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end
+function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end
+function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end
+function opt_map.nocomment() g_opt.comment = false end
+function opt_map.maccomment() g_opt.maccomment = true end
+function opt_map.nolineno() g_opt.cpp = false end
+function opt_map.flushline() g_opt.flushline = true end
+function opt_map.vserror() g_opt.vserror = true end
+function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end
+
+------------------------------------------------------------------------------
+
+-- Short aliases for long options.
+local opt_alias = {
+  h = "help", ["?"] = "help", V = "version",
+  o = "outfile", I = "include",
+  c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment",
+  L = "nolineno", F = "flushline",
+  E = "vserror",
+  P = "dumpdef", A = "dumparch",
+}
+
+-- Parse single option.
+local function parseopt(opt, args)
+  opt_current = #opt == 1 and "-"..opt or "--"..opt
+  local f = opt_map[opt] or opt_map[opt_alias[opt]]
+  if not f then
+    opterror("unrecognized option `", opt_current, "'. Try `--help'.\n")
+  end
+  f(args)
+end
+
+-- Parse arguments.
+local function parseargs(args)
+  -- Default options.
+  g_opt.comment = "//|"
+  g_opt.endcomment = ""
+  g_opt.cpp = true
+  g_opt.dumpdef = 0
+  g_opt.include = { "" }
+
+  -- Process all option arguments.
+  args.argn = 1
+  repeat
+    local a = args[args.argn]
+    if not a then break end
+    local lopt, opt = match(a, "^%-(%-?)(.+)")
+    if not opt then break end
+    args.argn = args.argn + 1
+    if lopt == "" then
+      -- Loop through short options.
+      for o in gmatch(opt, ".") do parseopt(o, args) end
+    else
+      -- Long option.
+      parseopt(opt, args)
+    end
+  until false
+
+  -- Check for proper number of arguments.
+  local nargs = #args - args.argn + 1
+  if nargs ~= 1 then
+    if nargs == 0 then
+      if g_opt.dumpdef > 0 then return dumpdef(stdout) end
+    end
+    opt_map.help()
+  end
+
+  -- Translate a single input file to a single output file
+  -- TODO: Handle multiple files?
+  translate(args[args.argn], g_opt.outfile)
+end
+
+------------------------------------------------------------------------------
+
+-- Add the directory dynasm.lua resides in to the Lua module search path.
+local arg = arg
+if arg and arg[0] then
+  local prefix = match(arg[0], "^(.*[/\\])")
+  if prefix then package.path = prefix.."?.lua;"..package.path end
+end
+
+-- Start DynASM.
+parseargs{...}
+
+------------------------------------------------------------------------------
+

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.c	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,3614 @@
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+#include "ffi.h"
+#include <math.h>
+#include <inttypes.h>
+
+/* Set to 1 to get extra debugging on print */
+#define DEBUG_TOSTRING 0
+
+int jit_key;
+int ctype_mt_key;
+int cdata_mt_key;
+int callback_mt_key;
+int cmodule_mt_key;
+int constants_key;
+int types_key;
+int gc_key;
+int callbacks_key;
+int functions_key;
+int abi_key;
+int next_unnamed_key;
+int niluv_key;
+int asmname_key;
+
+void push_upval(lua_State* L, int* key)
+{
+    lua_pushlightuserdata(L, key);
+    lua_rawget(L, LUA_REGISTRYINDEX);
+}
+
+void set_upval(lua_State* L, int* key)
+{
+    lua_pushlightuserdata(L, key);
+    lua_insert(L, -2);
+    lua_rawset(L, LUA_REGISTRYINDEX);
+}
+
+int equals_upval(lua_State* L, int idx, int* key)
+{
+    int ret;
+    lua_pushvalue(L, idx);
+    push_upval(L, key);
+    ret = lua_rawequal(L, -2, -1);
+    lua_pop(L, 2);
+    return ret;
+}
+
+struct jit* get_jit(lua_State* L)
+{
+    struct jit* jit;
+    push_upval(L, &jit_key);
+    jit = (struct jit*) lua_touserdata(L, -1);
+    jit->L = L;
+    lua_pop(L, 1); /* still in registry */
+    return jit;
+}
+
+static int type_error(lua_State* L, int idx, const char* to_type, int to_usr, const struct ctype* to_ct)
+{
+    luaL_Buffer B;
+    struct ctype ft;
+
+    assert(to_type || (to_usr && to_ct));
+    if (to_usr) {
+        to_usr = lua_absindex(L, to_usr);
+    }
+
+    idx = lua_absindex(L, idx);
+
+    luaL_buffinit(L, &B);
+    to_cdata(L, idx, &ft);
+
+    if (ft.type != INVALID_TYPE) {
+        push_type_name(L, -1, &ft);
+        lua_pushfstring(L, "unable to convert argument %d from cdata<%s> to cdata<", idx, lua_tostring(L, -1));
+        lua_remove(L, -2);
+        luaL_addvalue(&B);
+    } else {
+        lua_pushfstring(L, "unable to convert argument %d from lua<%s> to cdata<", idx, luaL_typename(L, idx));
+        luaL_addvalue(&B);
+    }
+
+    if (to_ct) {
+        push_type_name(L, to_usr, to_ct);
+        luaL_addvalue(&B);
+    } else {
+        luaL_addstring(&B, to_type);
+    }
+
+    luaL_addchar(&B, '>');
+
+    luaL_pushresult(&B);
+    return lua_error(L);
+}
+
+static void* userdata_toptr(lua_State* L, int idx)
+{
+    void* ptr = lua_touserdata(L, idx);
+    int isfile;
+
+    // check for FILE*
+    lua_getmetatable(L, idx);
+    luaL_getmetatable(L, LUA_FILEHANDLE);
+    isfile = lua_rawequal(L, -1, -2);
+    lua_pop(L, 2);
+
+    if (isfile) {
+#if LUA_VERSION_NUM == 501
+        FILE** stream = (FILE**) ptr;
+        return *stream;
+#else
+        luaL_Stream* stream = (luaL_Stream*) ptr;
+        return stream->f;
+#endif
+    }
+
+    return ptr;
+}
+
+static int cdata_tointeger(lua_State* L, int idx, ptrdiff_t* val)
+{
+    struct ctype ct;
+    void* addr = to_cdata(L, idx, &ct);
+    lua_pop(L, 1);
+
+    if (ct.pointers) {
+        return 0;
+    }
+
+    switch (ct.type) {
+    case INT8_TYPE:
+        *val = *(int8_t*)addr;
+        return 1;
+    case INT16_TYPE:
+        *val = *(int16_t*)addr;
+        return 1;
+    case INT32_TYPE:
+        *val = *(int32_t*)addr;
+        return 1;
+    case INT64_TYPE:
+        *val = *(int64_t*)addr;
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+static int64_t check_intptr(lua_State* L, int idx, void* p, struct ctype* ct)
+{
+    if (ct->type == INVALID_TYPE) {
+        int64_t ret;
+        memset(ct, 0, sizeof(*ct));
+        ct->base_size = 8;
+        ct->type = INT64_TYPE;
+        ct->is_defined = 1;
+        ret = luaL_checknumber(L, idx);
+        return ret;
+
+    } else if (ct->pointers) {
+        return (intptr_t) p;
+    }
+
+    switch (ct->type) {
+    case INTPTR_TYPE:
+    case FUNCTION_PTR_TYPE:
+        return *(intptr_t*) p;
+
+    case INT64_TYPE:
+        return *(int64_t*) p;
+
+    case INT32_TYPE:
+        return ct->is_unsigned ? (int64_t) *(uint32_t*) p : (int64_t) *(int32_t*) p;
+
+    case INT16_TYPE:
+        return ct->is_unsigned ? (int64_t) *(uint16_t*) p : (int64_t) *(int16_t*) p;
+
+    case INT8_TYPE:
+        return ct->is_unsigned ? (int64_t) *(uint8_t*) p : (int64_t) *(int8_t*) p;
+
+    default:
+        type_error(L, idx, "intptr_t", 0, NULL);
+        return 0;
+    }
+}
+
+static int get_cfunction_address(lua_State* L, int idx, cfunction* addr);
+
+#define TO_NUMBER(TYPE, ALLOW_POINTERS, LUA_TONUMBER)                       \
+    TYPE ret = 0;                                                           \
+    void* p;                                                                \
+    struct ctype ct;                                                        \
+    cfunction f;                                                            \
+                                                                            \
+    switch (lua_type(L, idx)) {                                             \
+    case LUA_TBOOLEAN:                                                      \
+        ret = (TYPE) lua_toboolean(L, idx);                                 \
+        break;                                                              \
+                                                                            \
+    case LUA_TNUMBER:                                                       \
+        ret = (TYPE) LUA_TONUMBER(L, idx);                                  \
+        break;                                                              \
+                                                                            \
+    case LUA_TSTRING:                                                       \
+        if (!ALLOW_POINTERS) {                                              \
+            type_error(L, idx, #TYPE, 0, NULL);                             \
+        }                                                                   \
+        ret = (TYPE) (intptr_t) lua_tostring(L, idx);                       \
+        break;                                                              \
+                                                                            \
+    case LUA_TLIGHTUSERDATA:                                                \
+        if (!ALLOW_POINTERS) {                                              \
+            type_error(L, idx, #TYPE, 0, NULL);                             \
+        }                                                                   \
+        ret = (TYPE) (intptr_t) lua_topointer(L, idx);                      \
+        break;                                                              \
+                                                                            \
+    case LUA_TFUNCTION:                                                     \
+        if (!ALLOW_POINTERS) {                                              \
+            type_error(L, idx, #TYPE, 0, NULL);                             \
+        }                                                                   \
+        if (!get_cfunction_address(L, idx, &f)) {                           \
+            type_error(L, idx, #TYPE, 0, NULL);                             \
+        }                                                                   \
+        ret = (TYPE) (intptr_t) f;                                          \
+        break;                                                              \
+                                                                            \
+    case LUA_TUSERDATA:                                                     \
+        p = to_cdata(L, idx, &ct);                                          \
+                                                                            \
+        if (ct.type == INVALID_TYPE) {                                      \
+            if (!ALLOW_POINTERS) {                                          \
+                type_error(L, idx, #TYPE, 0, NULL);                         \
+            }                                                               \
+            ret = (TYPE) (intptr_t) userdata_toptr(L, idx);                 \
+        } else if (ct.pointers || ct.type == STRUCT_TYPE || ct.type == UNION_TYPE) {\
+            if (!ALLOW_POINTERS) {                                          \
+                type_error(L, idx, #TYPE, 0, NULL);                         \
+            }                                                               \
+            ret = (TYPE) (intptr_t) p;                                      \
+        } else if (ct.type == COMPLEX_DOUBLE_TYPE) {                        \
+            ret = (TYPE) creal(*(complex_double*) p);                       \
+        } else if (ct.type == COMPLEX_FLOAT_TYPE) {                         \
+            ret = (TYPE) crealf(*(complex_float*) p);                       \
+        } else if (ct.type == DOUBLE_TYPE) {                                \
+            ret = (TYPE) *(double*) p;                                      \
+        } else if (ct.type == FLOAT_TYPE) {                                 \
+            ret = (TYPE) *(float*) p;                                       \
+        } else {                                                            \
+            ret = check_intptr(L, idx, p, &ct);                             \
+        }                                                                   \
+        lua_pop(L, 1);                                                      \
+        break;                                                              \
+                                                                            \
+    case LUA_TNIL:                                                          \
+        ret = (TYPE) 0;                                                     \
+        break;                                                              \
+                                                                            \
+    default:                                                                \
+        type_error(L, idx, #TYPE, 0, NULL);                                 \
+    }                                                                       \
+
+static int64_t cast_int64(lua_State* L, int idx, int is_cast)
+{ TO_NUMBER(int64_t, is_cast, lua_tointeger); return ret; }
+
+static uint64_t cast_uint64(lua_State* L, int idx, int is_cast)
+{ TO_NUMBER(uint64_t, is_cast, lua_tointeger); return ret; }
+
+int32_t check_int32(lua_State* L, int idx)
+{ return (int32_t) cast_int64(L, idx, 0); }
+
+uint32_t check_uint32(lua_State* L, int idx)
+{ return (uint32_t) cast_uint64(L, idx, 0); }
+
+int64_t check_int64(lua_State* L, int idx)
+{ return cast_int64(L, idx, 0); }
+
+uint64_t check_uint64(lua_State* L, int idx)
+{ return cast_uint64(L, idx, 0); }
+
+double check_double(lua_State* L, int idx)
+{ TO_NUMBER(double, 0, lua_tonumber); return ret; }
+
+float check_float(lua_State* L, int idx)
+{ TO_NUMBER(double, 0, lua_tonumber); return ret; }
+
+uintptr_t check_uintptr(lua_State* L, int idx)
+{ TO_NUMBER(uintptr_t, 1, lua_tointeger); return ret; }
+
+complex_double check_complex_double(lua_State* L, int idx)
+{
+    double real = 0, imag = 0;
+    void* p;
+    struct ctype ct;
+
+    switch (lua_type(L, idx)) {
+    case LUA_TNUMBER:
+        real = (double) lua_tonumber(L, idx);
+        break;
+    case LUA_TTABLE:
+        lua_rawgeti(L, idx, 1);
+        real = check_double(L, -1);
+        lua_pop(L, 1);
+
+        lua_rawgeti(L, idx, 2);
+        if (lua_isnil(L, -1)) {
+            imag = real;
+        }  else {
+            imag = check_double(L, -1);
+        }
+        lua_pop(L, 1);
+        break;
+    case LUA_TUSERDATA:
+        p = to_cdata(L, idx, &ct);
+        if (ct.type == COMPLEX_DOUBLE_TYPE) {
+            real = creal(*(complex_double*) p);
+            imag = cimag(*(complex_double*) p);
+        } else if (ct.type == COMPLEX_FLOAT_TYPE) {
+            real = crealf(*(complex_float*) p);
+            imag = cimagf(*(complex_float*) p);
+        } else if (ct.type == DOUBLE_TYPE) {
+            real = *(double*) p;
+        } else if (ct.type == FLOAT_TYPE) {
+            real = *(float*) p;
+        } else {
+            real = check_intptr(L, idx, p, &ct);
+        }
+        lua_pop(L, 1);
+        break;
+
+    default:
+        type_error(L, idx, "complex", 0, NULL);
+    }
+
+    return mk_complex_double(real, imag);
+}
+
+complex_float check_complex_float(lua_State* L, int idx)
+{
+    complex_double d = check_complex_double(L, idx);
+    return mk_complex_float(creal(d), cimag(d));
+}
+
+static size_t unpack_vararg(lua_State* L, int i, char* to)
+{
+    void* p;
+    struct ctype ct;
+
+    switch (lua_type(L, i)) {
+    case LUA_TBOOLEAN:
+        *(int*) to = lua_toboolean(L, i);
+        return sizeof(int);
+
+    case LUA_TNUMBER:
+        *(double*) to = lua_tonumber(L, i); // TODO in Lua 5.3: lua_tointeger sometimes should be here
+        return sizeof(double);
+
+    case LUA_TSTRING:
+        *(const char**) to = lua_tostring(L, i);
+        return sizeof(const char*);
+
+    case LUA_TLIGHTUSERDATA:
+        *(void**) to = lua_touserdata(L, i);
+        return sizeof(void*);
+
+    case LUA_TUSERDATA:
+        p = to_cdata(L, i, &ct);
+        lua_pop(L, 1);
+
+        if (ct.type == INVALID_TYPE) {
+            *(void**) to = userdata_toptr(L, i);
+            return sizeof(void*);
+
+        } else if (ct.pointers || ct.type == INTPTR_TYPE) {
+            *(void**) to = p;
+            return sizeof(void*);
+
+        } else if (ct.type == INT32_TYPE) {
+            *(int32_t*) to = *(int32_t*) p;
+            return sizeof(int32_t);
+
+        } else if (ct.type == INT64_TYPE) {
+            *(int64_t*) to = *(int64_t*) p;
+            return sizeof(int64_t);
+        }
+        goto err;
+
+    case LUA_TNIL:
+        *(void**) to = NULL;
+        return sizeof(void*);
+
+    default:
+        goto err;
+    }
+
+err:
+    return type_error(L, i, "vararg", 0, NULL);
+}
+
+void unpack_varargs_stack(lua_State* L, int first, int last, char* to)
+{
+    int i;
+
+    for (i = first; i <= last; i++) {
+        to += unpack_vararg(L, i, to);
+    }
+}
+
+void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_skip, int floats_to_skip, char* to)
+{
+    int i;
+
+    for (i = first; i <= last; i++) {
+        int type = lua_type(L, i);
+
+        if (type == LUA_TNUMBER && --floats_to_skip >= 0) {
+            continue;
+        } else if (type != LUA_TNUMBER && --ints_to_skip >= 0) {
+            continue;
+        }
+
+        to += unpack_vararg(L, i, to);
+    }
+}
+
+void unpack_varargs_float(lua_State* L, int first, int last, int max, char* to)
+{
+    int i;
+
+    for (i = first; i <= last && max > 0; i++) {
+        if (lua_type(L, i) == LUA_TNUMBER) {
+            unpack_vararg(L, i, to);
+            to += sizeof(double);
+            max--;
+        }
+    }
+}
+
+void unpack_varargs_int(lua_State* L, int first, int last, int max, char* to)
+{
+    int i;
+
+    for (i = first; i <= last && max > 0; i++) {
+        if (lua_type(L, i) != LUA_TNUMBER) {
+            unpack_vararg(L, i, to);
+            to += sizeof(void*);
+            max--;
+        }
+    }
+}
+
+void unpack_varargs_reg(lua_State* L, int first, int last, char* to)
+{
+    int i;
+
+    for (i = first; i <= last; i++) {
+        unpack_vararg(L, i, to);
+        to += sizeof(double);
+    }
+}
+
+/* to_enum tries to convert a value at idx to the enum type indicated by to_ct
+ * and uv to_usr. For strings this means it will do a string lookup for the
+ * enum type. It leaves the stack unchanged. Will throw an error if the type
+ * at idx can't be conerted.
+ */
+int32_t check_enum(lua_State* L, int idx, int to_usr, const struct ctype* to_ct)
+{
+    int32_t ret;
+
+    switch (lua_type(L, idx)) {
+    case LUA_TSTRING:
+        /* lookup string in to_usr to find value */
+        to_usr = lua_absindex(L, to_usr);
+        lua_pushvalue(L, idx);
+        lua_rawget(L, to_usr);
+
+        if (lua_isnil(L, -1)) {
+            goto err;
+        }
+
+        ret = (int32_t) lua_tointeger(L, -1);
+        lua_pop(L, 1);
+        return ret;
+
+    case LUA_TUSERDATA:
+        return check_int32(L, idx);
+
+    case LUA_TNIL:
+        return (int32_t) 0;
+
+    case LUA_TNUMBER:
+        return (int32_t) lua_tointeger(L, idx);
+
+    default:
+        goto err;
+    }
+
+err:
+    return type_error(L, idx, NULL, to_usr, to_ct);
+}
+
+/* to_pointer tries converts a value at idx to a pointer. It fills out ct and
+ * pushes the uv of the found type. It will throw a lua error if it can not
+ * convert the value to a pointer. */
+static void* check_pointer(lua_State* L, int idx, struct ctype* ct)
+{
+    void* p;
+    memset(ct, 0, sizeof(*ct));
+    idx = lua_absindex(L, idx);
+
+    switch (lua_type(L, idx)) {
+    case LUA_TNIL:
+        ct->type = VOID_TYPE;
+        ct->pointers = 1;
+        ct->is_null = 1;
+        lua_pushnil(L);
+        return NULL;
+
+    case LUA_TNUMBER:
+        ct->type = INTPTR_TYPE;
+        ct->is_unsigned = 1;
+        ct->pointers = 0;
+        lua_pushnil(L);
+        return (void*) (uintptr_t) lua_tonumber(L, idx); // TODO in Lua 5.3: maybe change to lua_tointeger
+
+    case LUA_TLIGHTUSERDATA:
+        ct->type = VOID_TYPE;
+        ct->pointers = 1;
+        lua_pushnil(L);
+        return lua_touserdata(L, idx);
+
+    case LUA_TSTRING:
+        ct->type = INT8_TYPE;
+        ct->pointers = 1;
+        ct->is_unsigned = IS_CHAR_UNSIGNED;
+        ct->is_array = 1;
+        ct->base_size = 1;
+        ct->const_mask = 2;
+        lua_pushnil(L);
+        return (void*) lua_tolstring(L, idx, &ct->array_size);
+
+    case LUA_TUSERDATA:
+        p = to_cdata(L, idx, ct);
+
+        if (ct->type == INVALID_TYPE) {
+            /* some other type of user data */
+            ct->type = VOID_TYPE;
+            ct->pointers = 1;
+            return userdata_toptr(L, idx);
+        } else if (ct->type == STRUCT_TYPE || ct->type == UNION_TYPE) {
+            return p;
+        } else {
+            return (void*) (intptr_t) check_intptr(L, idx, p, ct);
+        }
+        break;
+    }
+
+    type_error(L, idx, "pointer", 0, NULL);
+    return NULL;
+}
+
+static int is_void_ptr(const struct ctype* ct)
+{
+    return ct->type == VOID_TYPE
+        && ct->pointers == 1;
+}
+
+static int is_same_type(lua_State* L, int usr1, int usr2, const struct ctype* t1, const struct ctype* t2)
+{
+    if (t1->type != t2->type) {
+        return 0;
+    }
+
+#if LUA_VERSION_NUM == 501
+    if (lua_isnil(L, usr1) != lua_isnil(L, usr2)) {
+        int ret;
+        usr1 = lua_absindex(L, usr1);
+        usr2 = lua_absindex(L, usr2);
+        push_upval(L, &niluv_key);
+
+        ret = lua_rawequal(L, usr1, -1)
+            || lua_rawequal(L, usr2, -1);
+
+        lua_pop(L, 1);
+
+        if (ret) {
+            return 1;
+        }
+    }
+#endif
+
+    return lua_rawequal(L, usr1, usr2);
+}
+
+static void set_struct(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers);
+
+/* to_typed_pointer converts a value at idx to a type tt with target uv to_usr
+ * checking all types. May push a temporary value so that it can create
+ * structs on the fly. */
+void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* tt)
+{
+    struct ctype ft;
+    void* p;
+
+    to_usr = lua_absindex(L, to_usr);
+    idx = lua_absindex(L, idx);
+
+    if (tt->pointers == 1 && (tt->type == STRUCT_TYPE || tt->type == UNION_TYPE) && lua_type(L, idx) == LUA_TTABLE) {
+        /* need to construct a struct of the target type */
+        struct ctype ct = *tt;
+        ct.pointers = ct.is_array = 0;
+        p = push_cdata(L, to_usr, &ct);
+        set_struct(L, idx, p, to_usr, &ct, 1);
+        return p;
+    }
+
+    p = check_pointer(L, idx, &ft);
+
+    if (tt->pointers == 1 && ft.pointers == 0 && (ft.type == STRUCT_TYPE || ft.type == UNION_TYPE)) {
+        /* auto dereference structs */
+        ft.pointers = 1;
+        ft.const_mask <<= 1;
+    }
+
+    if (is_void_ptr(tt)) {
+        /* any pointer can convert to void* */
+        goto suc;
+
+    } else if (is_void_ptr(&ft) && (ft.pointers || ft.is_reference)) {
+        /* void* can convert to any pointer */
+        goto suc;
+
+    } else if (ft.is_null) {
+        /* NULL can convert to any pointer */
+        goto suc;
+
+    } else if (!is_same_type(L, to_usr, -1, tt, &ft)) {
+        /* the base type is different */
+        goto err;
+
+    } else if (tt->pointers != ft.pointers) {
+        goto err;
+
+    } else if (ft.const_mask & ~tt->const_mask) {
+        /* for every const in from it must be in to, there are further rules
+         * for const casting (see the c++ spec), but they are hard to test
+         * quickly */
+        goto err;
+    }
+
+suc:
+    return p;
+
+err:
+    type_error(L, idx, NULL, to_usr, tt);
+    return NULL;
+}
+
+/**
+ * gets the address of the wrapped C function for the lua function value at idx
+ * and returns 1 if it exists; otherwise returns 0 and nothing is pushed */
+static int get_cfunction_address(lua_State* L, int idx, cfunction* addr)
+{
+    int top, n;
+    cfunction* f;
+    if (!lua_isfunction(L, idx)) return 0;
+
+    top = lua_gettop(L);
+
+    // Get the last upvalue
+    n = 2;
+    while (lua_getupvalue(L, idx, n)) {
+        lua_pop(L, 1);
+        n++;
+    }
+
+    if (!lua_getupvalue(L, idx, n - 1))
+        return 0;
+
+    if (!lua_isuserdata(L, -1) || !lua_getmetatable(L, -1)) {
+        lua_pop(L, 1);
+        return 0;
+    }
+
+    push_upval(L, &callback_mt_key);
+    if (!lua_rawequal(L, -1, -2)) {
+        lua_pop(L, 3);
+        return 0;
+    }
+
+    /* stack is:
+     * userdata upval
+     * metatable
+     * callback_mt
+     */
+
+    f = lua_touserdata(L, -3);
+    *addr = f[1];
+    lua_pop(L, 3);
+    return 1;
+}
+
+/* to_cfunction converts a value at idx with usr table at to_usr and type tt
+ * into a function. Leaves the stack unchanged. */
+static cfunction check_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt, int check_pointers)
+{
+    void* p;
+    struct ctype ft;
+    cfunction f;
+    int top = lua_gettop(L);
+
+    idx = lua_absindex(L, idx);
+    to_usr = lua_absindex(L, to_usr);
+
+    switch (lua_type(L, idx)) {
+    case LUA_TFUNCTION:
+        if (get_cfunction_address(L, idx, &f)) {
+            return f;
+        }
+
+        /* Function cdatas are pinned and must be manually cleaned up by
+         * calling func:free(). */
+        push_upval(L, &callbacks_key);
+        f = compile_callback(L, idx, to_usr, tt);
+        lua_pushboolean(L, 1);
+        lua_rawset(L, -3);
+        lua_pop(L, 1); /* callbacks tbl */
+        return f;
+
+    case LUA_TNIL:
+        return NULL;
+
+    case LUA_TLIGHTUSERDATA:
+        if (check_pointers) {
+            goto err;
+        } else {
+            return (cfunction) lua_touserdata(L, idx);
+        }
+
+    case LUA_TUSERDATA:
+        p = to_cdata(L, idx, &ft);
+        assert(lua_gettop(L) == top + 1);
+
+        if (ft.type == INVALID_TYPE) {
+            if (check_pointers) {
+                goto err;
+            } else {
+                lua_pop(L, 1);
+                return (cfunction) lua_touserdata(L, idx);
+            }
+
+        } else if (ft.is_null) {
+            lua_pop(L, 1);
+            return NULL;
+
+        } else if (!check_pointers && (ft.pointers || ft.type == INTPTR_TYPE)) {
+            lua_pop(L, 1);
+            return (cfunction) *(void**) p;
+
+        } else if (ft.type != FUNCTION_PTR_TYPE) {
+            goto err;
+
+        } else if (!check_pointers) {
+            lua_pop(L, 1);
+            return *(cfunction*) p;
+
+        } else if (ft.calling_convention != tt->calling_convention) {
+            goto err;
+
+        } else if (!is_same_type(L, -1, to_usr, &ft, tt)) {
+            goto err;
+
+        } else {
+            lua_pop(L, 1);
+            return *(cfunction*) p;
+        }
+
+    default:
+        goto err;
+    }
+
+err:
+    type_error(L, idx, NULL, to_usr, tt);
+    return NULL;
+}
+
+/* to_type_cfunction converts a value at idx with uv at to_usr and type tt to
+ * a cfunction. Leaves the stack unchanged. */
+cfunction check_typed_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt)
+{ return check_cfunction(L, idx, to_usr, tt, 1); }
+
+static void set_value(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers);
+
+static void set_array(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers)
+{
+    size_t i, sz, esz;
+    struct ctype et;
+
+    idx = lua_absindex(L, idx);
+    to_usr = lua_absindex(L, to_usr);
+
+    switch (lua_type(L, idx)) {
+    case LUA_TSTRING:
+        if (tt->pointers == 1 && tt->type == INT8_TYPE) {
+            const char* str = lua_tolstring(L, idx, &sz);
+
+            if (!tt->is_variable_array && sz >= tt->array_size) {
+                memcpy(to, str, tt->array_size);
+            } else {
+                /* include nul terminator */
+                memcpy(to, str, sz+1);
+            }
+        } else {
+            goto err;
+        }
+        break;
+
+    case LUA_TTABLE:
+        et = *tt;
+        et.pointers--;
+        et.const_mask >>= 1;
+        et.is_array = 0;
+        esz = et.pointers ? sizeof(void*) : et.base_size;
+
+        lua_rawgeti(L, idx, 2);
+
+        if (tt->is_variable_array) {
+            /* we have no idea how big the array is, so set values based off
+             * how many items were given to us */
+            lua_pop(L, 1);
+            for (i = 0; i < lua_rawlen(L, idx); i++) {
+                lua_rawgeti(L, idx, (int) i + 1);
+                set_value(L, -1, (char*) to + esz * i, to_usr, &et, check_pointers);
+                lua_pop(L, 1);
+            }
+
+        } else if (lua_isnil(L, -1)) {
+            /* there is no second element, so we set the whole array to the
+             * first element (or nil - ie 0) if there is no first element) */
+            lua_pop(L, 1);
+            lua_rawgeti(L, idx, 1);
+
+            if (lua_isnil(L, -1)) {
+                memset(to, 0, ctype_size(L, tt));
+            } else {
+                /* if its still variable we have no idea how many values to set */
+                for (i = 0; i < tt->array_size; i++) {
+                    set_value(L, -1, (char*) to + esz * i, to_usr, &et, check_pointers);
+                }
+            }
+
+            lua_pop(L, 1);
+
+        } else {
+            /* there is a second element, so we set each element using the
+             * equiv index in the table initializer */
+            lua_pop(L, 1);
+            for (i = 0; i < tt->array_size; i++) {
+                lua_rawgeti(L, idx, (int) (i+1));
+
+                if (lua_isnil(L, -1)) {
+                    /* we've hit the end of the values provided in the
+                     * initializer, so memset the rest to zero */
+                    lua_pop(L, 1);
+                    memset((char*) to + esz * i, 0, (tt->array_size - i) * esz);
+                    break;
+
+                } else {
+                    set_value(L, -1, (char*) to + esz * i, to_usr, &et, check_pointers);
+                    lua_pop(L, 1);
+                }
+            }
+        }
+        break;
+
+    default:
+        goto err;
+    }
+
+    return;
+
+err:
+    type_error(L, idx, NULL, to_usr, tt);
+}
+
+/* pops the member key from the stack, leaves the member user value on the
+ * stack. Returns the member offset. Returns -ve if the member can not be
+ * found. */
+static ptrdiff_t get_member(lua_State* L, int usr, const struct ctype* ct, struct ctype* mt)
+{
+    ptrdiff_t off;
+    lua_rawget(L, usr);
+
+    if (lua_isnil(L, -1)) {
+        lua_pop(L, 1);
+        return -1;
+    }
+
+    *mt = *(const struct ctype*) lua_touserdata(L, -1);
+    lua_getuservalue(L, -1);
+    lua_replace(L, -2);
+
+    if (mt->is_variable_array && ct->variable_size_known) {
+        /* eg char mbr[?] */
+        size_t sz = (mt->pointers > 1) ? sizeof(void*) : mt->base_size;
+        assert(ct->is_variable_struct && mt->is_array);
+        mt->array_size = ct->variable_increment / sz;
+        mt->is_variable_array = 0;
+
+    } else if (mt->is_variable_struct && ct->variable_size_known) {
+        /* eg struct {char a; char b[?]} mbr; */
+        assert(ct->is_variable_struct);
+        mt->variable_size_known = 1;
+        mt->variable_increment = ct->variable_increment;
+    }
+
+    off = mt->offset;
+    mt->offset = 0;
+    return off;
+}
+
+static void set_struct(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers)
+{
+    int have_first = 0;
+    int have_other = 0;
+    struct ctype mt;
+    void* p;
+
+    to_usr = lua_absindex(L, to_usr);
+    idx = lua_absindex(L, idx);
+
+    switch (lua_type(L, idx)) {
+    case LUA_TTABLE:
+        /* match up to the members based off the table initializers key - this
+         * will match both numbered and named members in the user table
+         * we need a special case for when no entries in the initializer -
+         * zero initialize the c struct, and only one entry in the initializer
+         * - set all members to this value */
+        memset(to, 0, ctype_size(L, tt));
+        lua_pushnil(L);
+        while (lua_next(L, idx)) {
+            ptrdiff_t off;
+
+            if (!have_first && lua_tonumber(L, -2) == 1 && lua_tonumber(L, -1) != 0) {
+                have_first = 1;
+            } else if (!have_other && (lua_type(L, -2) != LUA_TNUMBER || lua_tonumber(L, -2) != 1)) {
+                have_other = 1;
+            }
+
+            lua_pushvalue(L, -2);
+            off = get_member(L, to_usr, tt, &mt);
+            assert(off >= 0);
+            set_value(L, -2, (char*) to + off, -1, &mt, check_pointers);
+
+            /* initializer value, mt usr */
+            lua_pop(L, 2);
+        }
+
+        /* if we only had a single non zero value then initialize all members to that value */
+        if (!have_other && have_first && tt->type != UNION_TYPE) {
+            size_t i, sz;
+            ptrdiff_t off;
+            lua_rawgeti(L, idx, 1);
+            sz = lua_rawlen(L, to_usr);
+
+            for (i = 2; i < sz; i++) {
+                lua_pushinteger(L, i);
+                off = get_member(L, to_usr, tt, &mt);
+                assert(off >= 0);
+                set_value(L, -2, (char*) to + off, -1, &mt, check_pointers);
+                lua_pop(L, 1); /* mt usr */
+            }
+
+            lua_pop(L, 1); /* initializer table */
+        }
+        break;
+
+    case LUA_TUSERDATA:
+        if (check_pointers) {
+            p = check_typed_pointer(L, idx, to_usr, tt);
+        } else {
+            struct ctype ct;
+            p = check_pointer(L, idx, &ct);
+        }
+        memcpy(to, p, tt->base_size);
+        lua_pop(L, 1);
+        break;
+
+    default:
+        goto err;
+    }
+
+    return;
+
+err:
+    type_error(L, idx, NULL, to_usr, tt);
+}
+
+static void set_value(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers)
+{
+    int top = lua_gettop(L);
+
+    if (tt->is_array) {
+        set_array(L, idx, to, to_usr, tt, check_pointers);
+
+    } else if (tt->pointers || tt->is_reference) {
+        union {
+            uint8_t c[sizeof(void*)];
+            void* p;
+        } u;
+
+        if (lua_istable(L, idx)) {
+            luaL_error(L, "Can't set a pointer member to a struct that's about to be freed");
+        }
+
+        if (check_pointers) {
+            u.p = check_typed_pointer(L, idx, to_usr, tt);
+        } else {
+            struct ctype ct;
+            u.p = check_pointer(L, idx, &ct);
+        }
+
+#ifndef ALLOW_MISALIGNED_ACCESS
+        if ((uintptr_t) to & PTR_ALIGN_MASK) {
+            memcpy(to, u.c, sizeof(void*));
+        } else
+#endif
+        {
+            *(void**) to = u.p;
+        }
+
+        lua_pop(L, 1);
+
+    } else if (tt->is_bitfield) {
+
+        uint64_t hi_mask = UINT64_C(0) - (UINT64_C(1) << (tt->bit_offset + tt->bit_size));
+        uint64_t low_mask = (UINT64_C(1) << tt->bit_offset) - UINT64_C(1);
+        uint64_t val = check_uint64(L, idx);
+        val &= (UINT64_C(1) << tt->bit_size) - 1;
+        val <<= tt->bit_offset;
+        *(uint64_t*) to = val | (*(uint64_t*) to & (hi_mask | low_mask));
+
+    } else if (tt->type == STRUCT_TYPE || tt->type == UNION_TYPE) {
+        set_struct(L, idx, to, to_usr, tt, check_pointers);
+
+    } else {
+
+#ifndef ALLOW_MISALIGNED_ACCESS
+        union {
+            uint8_t c[8];
+            _Bool b;
+            uint64_t u64;
+            float f;
+            double d;
+            cfunction func;
+        } misalign;
+
+        void* origto = to;
+
+        if ((uintptr_t) origto & (tt->base_size - 1)) {
+            to = misalign.c;
+        }
+#endif
+
+        switch (tt->type) {
+        case BOOL_TYPE:
+            *(_Bool*) to = (cast_int64(L, idx, !check_pointers) != 0);
+            break;
+        case INT8_TYPE:
+            if (tt->is_unsigned) {
+                *(uint8_t*) to = (uint8_t) cast_uint64(L, idx, !check_pointers);
+            } else {
+                *(int8_t*) to = (int8_t) cast_int64(L, idx, !check_pointers);
+            }
+            break;
+        case INT16_TYPE:
+            if (tt->is_unsigned) {
+                *(uint16_t*) to = (uint16_t) cast_uint64(L, idx, !check_pointers);
+            } else {
+                *(int16_t*) to = (int16_t) cast_int64(L, idx, !check_pointers);
+            }
+            break;
+        case INT32_TYPE:
+            if (tt->is_unsigned) {
+                *(uint32_t*) to = (uint32_t) cast_uint64(L, idx, !check_pointers);
+            } else {
+                *(int32_t*) to = (int32_t) cast_int64(L, idx, !check_pointers);
+            }
+            break;
+        case INT64_TYPE:
+            if (tt->is_unsigned) {
+                *(uint64_t*) to = cast_uint64(L, idx, !check_pointers);
+            } else {
+                *(int64_t*) to = cast_int64(L, idx, !check_pointers);
+            }
+            break;
+        case FLOAT_TYPE:
+            *(float*) to = (float) check_double(L, idx);
+            break;
+        case DOUBLE_TYPE:
+            *(double*) to = check_double(L, idx);
+            break;
+        case COMPLEX_FLOAT_TYPE:
+            *(complex_float*) to = check_complex_float(L, idx);
+            break;
+        case COMPLEX_DOUBLE_TYPE:
+            *(complex_double*) to = check_complex_double(L, idx);
+            break;
+        case INTPTR_TYPE:
+            *(uintptr_t*) to = check_uintptr(L, idx);
+            break;
+        case ENUM_TYPE:
+            *(int32_t*) to = check_enum(L, idx, to_usr, tt);
+            break;
+        case FUNCTION_PTR_TYPE:
+            *(cfunction*) to = check_cfunction(L, idx, to_usr, tt, check_pointers);
+            break;
+        default:
+            goto err;
+        }
+
+#ifndef ALLOW_MISALIGNED_ACCESS
+        if ((uintptr_t) origto & (tt->base_size - 1)) {
+            memcpy(origto, misalign.c, tt->base_size);
+        }
+#endif
+    }
+
+    assert(lua_gettop(L) == top);
+    return;
+err:
+    type_error(L, idx, NULL, to_usr, tt);
+}
+
+static int ffi_typeof(lua_State* L)
+{
+    struct ctype ct;
+    check_ctype(L, 1, &ct);
+    push_ctype(L, -1, &ct);
+    return 1;
+}
+
+static void setmintop(lua_State* L, int idx)
+{
+    if (lua_gettop(L) < idx) {
+        lua_settop(L, idx);
+    }
+}
+
+/* warning: in the case that it finds an array size, it removes that index */
+static void get_variable_array_size(lua_State* L, int idx, struct ctype* ct)
+{
+    /* we only care about the variable buisness for the variable array
+     * directly ie ffi.new('char[?]') or the struct that contains the variable
+     * array ffi.new('struct {char v[?]}'). A pointer to the struct doesn't
+     * care about the variable size (it treats it as a zero sized array). */
+
+    if (ct->is_variable_array) {
+        assert(ct->is_array);
+        ct->array_size = (size_t) luaL_checknumber(L, idx);
+        ct->is_variable_array = 0;
+        lua_remove(L, idx);
+
+    } else if (ct->is_variable_struct && !ct->variable_size_known) {
+        assert(ct->type == STRUCT_TYPE && !ct->is_array);
+        ct->variable_increment *= (size_t) luaL_checknumber(L, idx);
+        ct->variable_size_known = 1;
+        lua_remove(L, idx);
+    }
+}
+
+static int is_scalar(struct ctype* ct)
+{
+    int type = ct->type;
+    if (ct->pointers || ct->is_reference) {
+        return !ct->is_array;
+    }
+    return type != STRUCT_TYPE && type != UNION_TYPE && !IS_COMPLEX(type);
+}
+
+static int should_pack(lua_State *L, int ct_usr, struct ctype* ct, int idx)
+{
+    struct ctype argt;
+    int same;
+    ct_usr = lua_absindex(L, ct_usr);
+
+    if (IS_COMPLEX(ct->type)) {
+        return 0;
+    }
+
+    switch (lua_type(L, idx)) {
+    case LUA_TTABLE:
+        return 0;
+    case LUA_TSTRING:
+        return ct->type == STRUCT_TYPE;
+    case LUA_TUSERDATA:
+        // don't pack if the argument is a cdata with the same type
+        to_cdata(L, idx, &argt);
+        same = is_same_type(L, ct_usr, -1, ct, &argt);
+        lua_pop(L, 1);
+        return !same;
+    default:
+        return 1;
+    }
+}
+
+static int do_new(lua_State* L, int is_cast)
+{
+    int cargs, i, scalar;
+    void* p;
+    struct ctype ct;
+    int check_ptrs = !is_cast;
+
+    check_ctype(L, 1, &ct);
+
+    /* don't push a callback when we have a c function, as cb:set needs a
+     * compiled callback from a lua function to work */
+    if (!ct.pointers && ct.type == FUNCTION_PTR_TYPE && (lua_isnil(L, 2) || lua_isfunction(L, 2))) {
+        // Get the bound C function if this is a ffi lua function
+        cfunction func;
+        if (get_cfunction_address(L, 2, &func)) {
+            p = push_cdata(L, -1, &ct);
+            *(cfunction*) p = func;
+            return 1;
+        }
+
+        /* Function cdatas are pinned and must be manually cleaned up by
+         * calling func:free(). */
+        compile_callback(L, 2, -1, &ct);
+        push_upval(L, &callbacks_key);
+        lua_pushvalue(L, -2);
+        lua_pushboolean(L, 1);
+        lua_rawset(L, -3);
+        lua_pop(L, 1); /* callbacks tbl */
+        return 1;
+    }
+
+    /* this removes the vararg argument if its needed, and errors if its invalid */
+    if (!is_cast) {
+        get_variable_array_size(L, 2, &ct);
+    }
+
+    p = push_cdata(L, -1, &ct);
+
+    /* if the user mt has a __gc function then call ffi.gc on this value */
+    if (push_user_mt(L, -2, &ct)) {
+        push_upval(L, &gc_key);
+        lua_pushvalue(L, -3);
+
+        /* user_mt.__gc */
+        lua_pushliteral(L, "__gc");
+        lua_rawget(L, -4);
+
+        lua_rawset(L, -3); /* gc_upval[cdata] = user_mt.__gc */
+        lua_pop(L, 2); /* user_mt and gc_upval */
+    }
+
+    /* stack is:
+     * ctype arg
+     * ctor args ... 0+
+     * ctype usr
+     * cdata
+     */
+
+    cargs = lua_gettop(L) - 3;
+
+    if (cargs == 0) {
+        return 1;
+    }
+
+    scalar = is_scalar(&ct);
+    if (scalar && cargs > 1) {
+        return luaL_error(L, "too many initializers");
+    }
+
+    if (cargs > 1 || (!scalar && should_pack(L, -2, &ct, 2))) {
+        lua_createtable(L, cargs, 0);
+        lua_replace(L, 1);
+        for (i = 1; i <= cargs; i++) {
+            lua_pushvalue(L, i + 1);
+            lua_rawseti(L, 1, i);
+        }
+        assert(lua_gettop(L) == cargs + 3);
+        set_value(L, 1, p, -2, &ct, check_ptrs);
+        return 1;
+    }
+
+    set_value(L, 2, p, -2, &ct, check_ptrs);
+    return 1;
+}
+
+static int ffi_new(lua_State* L)
+{ return do_new(L, 0); }
+
+static int ffi_cast(lua_State* L)
+{ return do_new(L, 1); }
+
+static int ctype_new(lua_State* L)
+{ return do_new(L, 0); }
+
+static int ctype_call(lua_State* L)
+{
+    struct ctype ct;
+    int top = lua_gettop(L);
+
+    check_ctype(L, 1, &ct);
+
+    if (push_user_mt(L, -1, &ct)) {
+        lua_pushstring(L, "__new");
+        lua_rawget(L, -2);
+        if (!lua_isnil(L, -1)) {
+            lua_insert(L, 1); // function at bottom of stack under args
+            lua_pop(L, 2);
+            lua_call(L, top, 1);
+            return 1;
+        }
+        lua_pop(L, 2);
+    }
+    lua_pop(L, 1);
+
+    assert(lua_gettop(L) == top);
+    return do_new(L, 0);
+}
+
+static int ffi_sizeof(lua_State* L)
+{
+    struct ctype ct;
+    check_ctype(L, 1, &ct);
+    get_variable_array_size(L, 2, &ct);
+    lua_pushinteger(L, ctype_size(L, &ct));
+    return 1;
+}
+
+static int ffi_alignof(lua_State* L)
+{
+    struct ctype ct, mt;
+    lua_settop(L, 2);
+    check_ctype(L, 1, &ct);
+
+    /* if no member is specified then we return the alignment of the type */
+    if (lua_isnil(L, 2)) {
+        lua_pushinteger(L, ct.align_mask + 1);
+        return 1;
+    }
+
+    /* get the alignment of the member */
+    lua_pushvalue(L, 2);
+    if (get_member(L, -2, &ct, &mt) < 0) {
+        push_type_name(L, 3, &ct);
+        return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2));
+    }
+
+    lua_pushinteger(L, mt.align_mask + 1);
+    return 1;
+}
+
+static int ffi_offsetof(lua_State* L)
+{
+    ptrdiff_t off;
+    struct ctype ct, mt;
+    lua_settop(L, 2);
+    check_ctype(L, 1, &ct);
+
+    lua_pushvalue(L, 2);
+    off = get_member(L, -2, &ct, &mt); /* this replaces the member key at -1 with the mbr usr value */
+    if (off < 0) {
+        push_type_name(L, 3, &ct);
+        return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2));
+    }
+
+    lua_pushinteger(L, off);
+
+    if (!mt.is_bitfield) {
+        return 1;
+    }
+
+    lua_pushinteger(L, mt.bit_offset);
+    lua_pushinteger(L, mt.bit_size);
+    return 3;
+}
+
+static int ffi_istype(lua_State* L)
+{
+    struct ctype tt, ft;
+    check_ctype(L, 1, &tt);
+    to_cdata(L, 2, &ft);
+
+    if (ft.type == INVALID_TYPE) {
+        goto fail;
+    }
+
+    if (!is_same_type(L, 3, 4, &tt, &ft)) {
+        goto fail;
+    }
+
+    if (tt.pointers != ft.pointers) {
+        goto fail;
+    }
+
+    if (tt.is_array != ft.is_array) {
+        goto fail;
+    }
+
+    if (tt.is_array && tt.array_size != ft.array_size) {
+        goto fail;
+    }
+
+    if (tt.calling_convention != ft.calling_convention) {
+        goto fail;
+    }
+
+    lua_pushboolean(L, 1);
+    return 1;
+
+fail:
+    lua_pushboolean(L, 0);
+    return 1;
+}
+
+static int cdata_gc(lua_State* L)
+{
+    struct ctype ct;
+    check_cdata(L, 1, &ct);
+    lua_settop(L, 1);
+
+    /* call the gc func if there is any registered */
+    lua_pushvalue(L, 1);
+    lua_rawget(L, lua_upvalueindex(2));
+    if (!lua_isnil(L, -1)) {
+        lua_pushvalue(L, 1);
+        lua_pcall(L, 1, 0, 0);
+    }
+
+    /* unset the closure */
+    lua_pushvalue(L, 1);
+    lua_pushnil(L);
+    lua_rawset(L, lua_upvalueindex(1));
+
+    return 0;
+}
+
+static int callback_free(lua_State* L)
+{
+    cfunction* p = (cfunction*) lua_touserdata(L, 1);
+    // FIXME: temporarily disabled to prevent SIGTRAP on exit
+    // free_code(get_jit(L), L, *p);
+    return 0;
+}
+
+static int cdata_free(lua_State* L)
+{
+    struct ctype ct;
+    cfunction* p = (cfunction*) check_cdata(L, 1, &ct);
+    lua_settop(L, 1);
+
+    /* unset the closure */
+    lua_pushvalue(L, 1);
+    lua_pushnil(L);
+    lua_rawset(L, lua_upvalueindex(1));
+
+    if (ct.is_jitted) {
+        free_code(get_jit(L), L, *p);
+        *p = NULL;
+    }
+
+    return 0;
+}
+
+static int cdata_set(lua_State* L)
+{
+    struct ctype ct;
+    cfunction* p = (cfunction*) check_cdata(L, 1, &ct);
+    luaL_checktype(L, 2, LUA_TFUNCTION);
+
+    if (!ct.is_jitted) {
+        luaL_error(L, "can't set the function for a non-lua callback");
+    }
+
+    if (*p == NULL) {
+        luaL_error(L, "can't set the function for a free'd callback");
+    }
+
+    push_func_ref(L, *p);
+    lua_pushvalue(L, 2);
+    lua_rawseti(L, -2, CALLBACK_FUNC_USR_IDX);
+
+    /* remove the closure for this callback as it embeds the function pointer
+     * value */
+    lua_pushvalue(L, 1);
+    lua_pushboolean(L, 1);
+    lua_rawset(L, lua_upvalueindex(1));
+
+    return 0;
+}
+
+static int cdata_call(lua_State* L)
+{
+    struct ctype ct;
+    int top = lua_gettop(L);
+    cfunction* p = (cfunction*) check_cdata(L, 1, &ct);
+
+    if (push_user_mt(L, -1, &ct)) {
+        lua_pushliteral(L, "__call");
+        lua_rawget(L, -2);
+
+        if (!lua_isnil(L, -1)) {
+            lua_insert(L, 1);
+            lua_pop(L, 2); /* ct_usr, user_mt */
+            lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
+            return lua_gettop(L);
+        }
+    }
+    if (ct.pointers || ct.type != FUNCTION_PTR_TYPE) {
+        return luaL_error(L, "only function callbacks are callable");
+    }
+
+    lua_pushvalue(L, 1);
+    lua_rawget(L, lua_upvalueindex(1));
+
+    if (!lua_isfunction(L, -1)) {
+        lua_pop(L, 1);
+        compile_function(L, *p, -1, &ct);
+
+        assert(lua_gettop(L) == top + 2); /* uv, closure */
+
+        /* closures[func] = closure */
+        lua_pushvalue(L, 1);
+        lua_pushvalue(L, -2);
+        lua_rawset(L, lua_upvalueindex(1));
+
+        lua_replace(L, 1);
+    } else {
+        lua_replace(L, 1);
+    }
+
+    lua_pop(L, 1); /* uv */
+    assert(lua_gettop(L) == top);
+
+    lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
+    return lua_gettop(L);
+}
+
+static int user_mt_key;
+
+static int ffi_metatype(lua_State* L)
+{
+    struct ctype ct;
+    lua_settop(L, 2);
+
+    check_ctype(L, 1, &ct);
+    if (lua_type(L, 2) != LUA_TTABLE && lua_type(L, 2) != LUA_TNIL) {
+        return luaL_argerror(L, 2, "metatable must be a table or nil");
+    }
+
+    lua_pushlightuserdata(L, &user_mt_key);
+    lua_pushvalue(L, 2);
+    lua_rawset(L, 3); /* user[user_mt_key] = mt */
+
+    /* return the passed in ctype */
+    push_ctype(L, 3, &ct);
+    return 1;
+}
+
+/* push_user_mt returns 1 if the type has a user metatable and pushes it onto
+ * the stack, otherwise it returns 0 and pushes nothing */
+int push_user_mt(lua_State* L, int ct_usr, const struct ctype* ct)
+{
+    if (ct->type != STRUCT_TYPE && ct->type != UNION_TYPE && !IS_COMPLEX(ct->type)) {
+        return 0;
+    }
+    if (!lua_istable(L, ct_usr)) {
+        return 0;
+    }
+
+    ct_usr = lua_absindex(L, ct_usr);
+    lua_pushlightuserdata(L, &user_mt_key);
+    lua_rawget(L, ct_usr);
+
+    if (lua_isnil(L, -1)) {
+        lua_pop(L, 1);
+        return 0;
+    }
+    return 1;
+}
+
+static int ffi_gc(lua_State* L)
+{
+    struct ctype ct;
+    lua_settop(L, 2);
+    check_cdata(L, 1, &ct);
+
+    push_upval(L, &gc_key);
+    lua_pushvalue(L, 1);
+    lua_pushvalue(L, 2);
+    lua_rawset(L, -3);
+
+    /* return the cdata back */
+    lua_settop(L, 1);
+    return 1;
+}
+
+/* lookup_cdata_index returns the offset of the found type and user value on
+ * the stack if valid. Otherwise returns -ve and doesn't touch the stack.
+ */
+static ptrdiff_t lookup_cdata_index(lua_State* L, int idx, int ct_usr, struct ctype* ct)
+{
+    struct ctype mt;
+    ptrdiff_t off;
+    int type;
+
+    ct_usr = lua_absindex(L, ct_usr);
+    type = lua_type(L, idx);
+
+    switch (type) {
+    case LUA_TNUMBER:
+    case LUA_TUSERDATA:
+        /* possibilities are array, pointer */
+
+        if (!ct->pointers || is_void_ptr(ct)) {
+            return -1;
+        }
+
+        // unbox cdata
+        if (type == LUA_TUSERDATA) {
+            if (!cdata_tointeger(L, idx, &off)) {
+                return -1;
+            }
+        } else {
+            off = lua_tointeger(L, idx);
+        }
+
+        ct->is_array = 0;
+        ct->pointers--;
+        ct->const_mask >>= 1;
+        ct->is_reference = 0;
+
+        lua_pushvalue(L, ct_usr);
+
+        return (ct->pointers ? sizeof(void*) : ct->base_size) * off;
+
+    case LUA_TSTRING:
+        /* possibilities are struct/union, pointer to struct/union */
+
+        if ((ct->type != STRUCT_TYPE && ct->type != UNION_TYPE) || ct->is_array || ct->pointers > 1) {
+            return -1;
+        }
+
+        lua_pushvalue(L, idx);
+        off = get_member(L, ct_usr, ct, &mt);
+        if (off < 0) {
+            return -1;
+        }
+
+        *ct = mt;
+        return off;
+
+    default:
+        return -1;
+    }
+}
+
+static int cdata_newindex(lua_State* L)
+{
+    struct ctype tt;
+    char* to;
+    ptrdiff_t off;
+
+    lua_settop(L, 3);
+
+    to = (char*) check_cdata(L, 1, &tt);
+    off = lookup_cdata_index(L, 2, -1, &tt);
+
+    if (off < 0) {
+        if (!push_user_mt(L, -1, &tt)) {
+            goto err;
+        }
+
+        lua_pushliteral(L, "__newindex");
+        lua_rawget(L, -2);
+
+        if (lua_isnil(L, -1)) {
+            goto err;
+        }
+
+        lua_insert(L, 1);
+        lua_settop(L, 4);
+        lua_call(L, 3, LUA_MULTRET);
+        return lua_gettop(L);
+    }
+
+    if (tt.const_mask & 1) {
+        return luaL_error(L, "can't set const data");
+    }
+
+    set_value(L, 3, to + off, -1, &tt, 1);
+    return 0;
+
+err:
+    push_type_name(L, 4, &tt);
+    return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2));
+}
+
+static int cdata_index(lua_State* L)
+{
+    void* to;
+    struct ctype ct;
+    char* data;
+    ptrdiff_t off;
+
+    lua_settop(L, 2);
+    data = (char*) check_cdata(L, 1, &ct);
+    assert(lua_gettop(L) == 3);
+
+    if (!ct.pointers) {
+        switch (ct.type) {
+        case FUNCTION_PTR_TYPE:
+            /* Callbacks use the same metatable as standard cdata values, but have set
+             * and free members. So instead of mt.__index = mt, we do the equiv here. */
+            lua_getmetatable(L, 1);
+            lua_pushvalue(L, 2);
+            lua_rawget(L, -2);
+            return 1;
+
+            /* This provides the .re and .im virtual members */
+        case COMPLEX_DOUBLE_TYPE:
+        case COMPLEX_FLOAT_TYPE:
+            if (!lua_isstring(L, 2)) {
+                luaL_error(L, "invalid member for complex number");
+
+            } else if (strcmp(lua_tostring(L, 2), "re") == 0) {
+                lua_pushnumber(L, ct.type == COMPLEX_DOUBLE_TYPE ? creal(*(complex_double*) data) : crealf(*(complex_float*) data));
+
+            } else if (strcmp(lua_tostring(L, 2), "im") == 0) {
+                lua_pushnumber(L, ct.type == COMPLEX_DOUBLE_TYPE ? cimag(*(complex_double*) data) : cimagf(*(complex_float*) data));
+
+            } else {
+                luaL_error(L, "invalid member for complex number");
+            }
+            return 1;
+        }
+    }
+
+    off = lookup_cdata_index(L, 2, -1, &ct);
+
+    if (off < 0) {
+        assert(lua_gettop(L) == 3);
+        if (!push_user_mt(L, -1, &ct)) {
+            goto err;
+        }
+
+        lua_pushliteral(L, "__index");
+        lua_rawget(L, -2);
+
+        if (lua_isnil(L, -1)) {
+            goto err;
+        }
+
+        if (lua_istable(L, -1)) {
+            lua_pushvalue(L, 2);
+            lua_gettable(L, -2);
+            return 1;
+        }
+
+        lua_insert(L, 1);
+        lua_settop(L, 3);
+        lua_call(L, 2, LUA_MULTRET);
+        return lua_gettop(L);
+
+err:
+        push_type_name(L, 3, &ct);
+        return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2));
+    }
+
+    assert(lua_gettop(L) == 4); /* ct, key, ct_usr, mbr_usr */
+    data += off;
+
+    if (ct.is_array) {
+        /* push a reference to the array */
+        ct.is_reference = 1;
+        to = push_cdata(L, -1, &ct);
+        *(void**) to = data;
+        return 1;
+
+    } else if (ct.is_bitfield) {
+
+        if (ct.type == INT64_TYPE) {
+            struct ctype rt;
+            uint64_t val = *(uint64_t*) data;
+            val >>= ct.bit_offset;
+            val &= (UINT64_C(1) << ct.bit_size) - 1;
+
+            memset(&rt, 0, sizeof(rt));
+            rt.base_size = 8;
+            rt.type = INT64_TYPE;
+            rt.is_unsigned = 1;
+            rt.is_defined = 1;
+
+            to = push_cdata(L, 0, &rt);
+            *(uint64_t*) to = val;
+
+            return 1;
+
+        } else if (ct.type == BOOL_TYPE) {
+            uint64_t val = *(uint64_t*) data;
+            lua_pushboolean(L, (int) (val & (UINT64_C(1) << ct.bit_offset)));
+            return 1;
+
+        } else {
+            uint64_t val = *(uint64_t*) data;
+            val >>= ct.bit_offset;
+            val &= (UINT64_C(1) << ct.bit_size) - 1;
+            lua_pushinteger(L, val);
+            return 1;
+        }
+
+    } else if (ct.pointers) {
+#ifndef ALLOW_MISALIGNED_ACCESS
+        union {
+            uint8_t c[8];
+            void* p;
+        } misalignbuf;
+
+        if ((uintptr_t) data & PTR_ALIGN_MASK) {
+            memcpy(misalignbuf.c, data, sizeof(void*));
+            data = misalignbuf.c;
+        }
+#endif
+        to = push_cdata(L, -1, &ct);
+        *(void**) to = *(void**) data;
+        return 1;
+
+    } else if (ct.type == STRUCT_TYPE || ct.type == UNION_TYPE) {
+        /* push a reference to the member */
+        ct.is_reference = 1;
+        to = push_cdata(L, -1, &ct);
+        *(void**) to = data;
+        return 1;
+
+    } else if (ct.type == FUNCTION_PTR_TYPE) {
+        cfunction* pf = (cfunction*) push_cdata(L, -1, &ct);
+        *pf = *(cfunction*) data;
+        return 1;
+
+    } else {
+#ifndef ALLOW_MISALIGNED_ACCESS
+        union {
+            uint8_t c[8];
+            double d;
+            float f;
+            uint64_t u64;
+        } misalignbuf;
+
+        assert(ct.base_size <= 8);
+
+        if ((uintptr_t) data & (ct.base_size - 1)) {
+            memcpy(misalignbuf.c, data, ct.base_size);
+            data = misalignbuf.c;
+        }
+#endif
+
+        switch (ct.type) {
+        case BOOL_TYPE:
+            lua_pushboolean(L, *(_Bool*) data);
+            break;
+        case INT8_TYPE:
+            lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint8_t*) data : (lua_Integer) *(int8_t*) data);
+            break;
+        case INT16_TYPE:
+            lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint16_t*) data : (lua_Integer) *(int16_t*) data);
+            break;
+        case ENUM_TYPE:
+        case INT32_TYPE:
+            lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint32_t*) data : (lua_Integer) *(int32_t*) data);
+            break;
+        case INT64_TYPE:
+            to = push_cdata(L, -1, &ct);
+            *(int64_t*) to = *(int64_t*) data;
+            break;
+        case INTPTR_TYPE:
+            to = push_cdata(L, -1, &ct);
+            *(intptr_t*) to = *(intptr_t*) data;
+            break;
+        case FLOAT_TYPE:
+            lua_pushnumber(L, *(float*) data);
+            break;
+        case DOUBLE_TYPE:
+            lua_pushnumber(L, *(double*) data);
+            break;
+        case COMPLEX_DOUBLE_TYPE:
+            to = push_cdata(L, -1, &ct);
+            *(complex_double*) to = *(complex_double*) data;
+            break;
+        case COMPLEX_FLOAT_TYPE:
+            to = push_cdata(L, -1, &ct);
+            *(complex_float*) to = *(complex_float*) data;
+            break;
+        default:
+            luaL_error(L, "internal error: invalid member type");
+        }
+
+        return 1;
+    }
+}
+
+static complex_double check_complex(lua_State* L, int idx, void* p, struct ctype* ct)
+{
+    if (ct->type == INVALID_TYPE) {
+        double d = luaL_checknumber(L, idx);
+#ifdef HAVE_COMPLEX
+        return d;
+#else
+        complex_double c;
+        c.real = d;
+        c.imag = 0;
+        return c;
+#endif
+    } else if (ct->type == COMPLEX_DOUBLE_TYPE) {
+        return *(complex_double*) p;
+    } else if (ct->type == COMPLEX_FLOAT_TYPE) {
+        complex_float* f = (complex_float*) p;
+#ifdef HAVE_COMPLEX
+        return *f;
+#else
+        complex_double d;
+        d.real = f->real;
+        d.imag = f->imag;
+        return d;
+#endif
+    } else {
+        complex_double dummy;
+        type_error(L, idx, "complex", 0, NULL);
+        memset(&dummy, 0, sizeof(dummy));
+        return dummy;
+    }
+}
+
+static int rank(const struct ctype* ct)
+{
+    if (ct->pointers) {
+        return 5;
+    }
+
+    switch (ct->type) {
+    case COMPLEX_DOUBLE_TYPE:
+        return 7;
+    case COMPLEX_FLOAT_TYPE:
+        return 6;
+    case INTPTR_TYPE:
+        return sizeof(intptr_t) >= sizeof(int64_t) ? 4 : 1;
+    case INT64_TYPE:
+        return ct->is_unsigned ? 3 : 2;
+    case INT32_TYPE:
+    case INT16_TYPE:
+    case INT8_TYPE:
+        return 2;
+    default:
+        return 0;
+    }
+}
+
+static void push_complex(lua_State* L, complex_double res, int ct_usr, const struct ctype* ct)
+{
+    if (ct->type == COMPLEX_DOUBLE_TYPE) {
+        complex_double* p = (complex_double*) push_cdata(L, ct_usr, ct);
+        *p = res;
+    } else {
+        complex_float* p = (complex_float*) push_cdata(L, ct_usr, ct);
+#ifdef HAVE_COMPLEX
+        *p = (complex float) res;
+#else
+        p->real = (float) res.real;
+        p->imag = (float) res.imag;
+#endif
+    }
+}
+
+static void push_number(lua_State* L, int64_t val, int ct_usr, const struct ctype* ct)
+{
+    if ((ct->pointers || ct->type == INTPTR_TYPE) && sizeof(intptr_t) != sizeof(int64_t)) {
+        intptr_t* p = (intptr_t*) push_cdata(L, ct_usr, ct);
+        *p = val;
+    } else {
+        int64_t* p = (int64_t*) push_cdata(L, ct_usr, ct);
+        *p = val;
+    }
+}
+
+static int call_user_op(lua_State* L, const char* opfield, int idx, int ct_usr, const struct ctype* ct)
+{
+    idx = lua_absindex(L, idx);
+
+    if (push_user_mt(L, ct_usr, ct)) {
+        lua_pushstring(L, opfield);
+        lua_rawget(L, -2);
+        if (!lua_isnil(L, -1)) {
+            int top = lua_gettop(L);
+            lua_pushvalue(L, idx);
+            lua_call(L, 1, LUA_MULTRET);
+            return lua_gettop(L) - top + 1;
+        }
+      lua_pop(L, 2);
+    }
+    return -1;
+}
+
+static int cdata_unm(lua_State* L)
+{
+    struct ctype ct;
+    void* p;
+    int64_t val;
+    int ret;
+
+    lua_settop(L, 1);
+    p = to_cdata(L, 1, &ct);
+
+    ret = call_user_op(L, "__unm", 1, 2, &ct);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    val = check_intptr(L, 1, p, &ct);
+
+    if (ct.pointers) {
+        luaL_error(L, "can't negate a pointer value");
+    } else {
+        memset(&ct, 0, sizeof(ct));
+        ct.type = INT64_TYPE;
+        ct.base_size = 8;
+        ct.is_defined = 1;
+        push_number(L, -val, 0, &ct);
+    }
+
+    return 1;
+}
+
+/* returns -ve if no binop was called otherwise returns the number of return
+ * arguments */
+static int call_user_binop(lua_State* L, const char* opfield, int lidx, int lusr, const struct ctype* lt, int ridx, int rusr, const struct ctype* rt)
+{
+    lidx = lua_absindex(L, lidx);
+    ridx = lua_absindex(L, ridx);
+
+    if (push_user_mt(L, lusr, lt)) {
+        lua_pushstring(L, opfield);
+        lua_rawget(L, -2);
+
+        if (!lua_isnil(L, -1)) {
+            int top = lua_gettop(L);
+            lua_pushvalue(L, lidx);
+            lua_pushvalue(L, ridx);
+            lua_call(L, 2, LUA_MULTRET);
+            return lua_gettop(L) - top + 1;
+        }
+
+        lua_pop(L, 2); /* user_mt and user_mt.op */
+    }
+
+    if (push_user_mt(L, rusr, rt)) {
+        lua_pushstring(L, opfield);
+        lua_rawget(L, -2);
+
+        if (!lua_isnil(L, -1)) {
+            int top = lua_gettop(L);
+            lua_pushvalue(L, lidx);
+            lua_pushvalue(L, ridx);
+            lua_call(L, 2, LUA_MULTRET);
+            return lua_gettop(L) - top + 1;
+        }
+
+        lua_pop(L, 2); /* user_mt and user_mt.op */
+    }
+
+    return -1;
+}
+
+static int cdata_concat(lua_State* L)
+{
+    struct ctype lt, rt;
+    int ret;
+
+    lua_settop(L, 2);
+    to_cdata(L, 1, &lt);
+    to_cdata(L, 2, &rt);
+
+    ret = call_user_binop(L, "__concat", 1, 3, &lt, 2, 4, &rt);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    return luaL_error(L, "NYI");
+}
+
+static int cdata_len(lua_State* L)
+{
+    struct ctype ct;
+    int ret;
+
+    lua_settop(L, 1);
+    to_cdata(L, 1, &ct);
+
+    ret = call_user_op(L, "__len", 1, 2, &ct);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    push_type_name(L, 2, &ct);
+    return luaL_error(L, "type %s does not implement the __len metamethod", lua_tostring(L, -1));
+}
+
+static int cdata_pairs(lua_State* L)
+{
+    struct ctype ct;
+    int ret;
+
+    lua_settop(L, 1);
+    to_cdata(L, 1, &ct);
+
+    ret = call_user_op(L, "__pairs", 1, 2, &ct);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    push_type_name(L, 2, &ct);
+    return luaL_error(L, "type %s does not implement the __pairs metamethod", lua_tostring(L, -1));
+}
+
+static int cdata_ipairs(lua_State* L)
+{
+    struct ctype ct;
+    int ret;
+
+    lua_settop(L, 1);
+    to_cdata(L, 1, &ct);
+
+    ret = call_user_op(L, "__ipairs", 1, 2, &ct);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    push_type_name(L, 2, &ct);
+    return luaL_error(L, "type %s does not implement the __ipairs metamethod", lua_tostring(L, -1));
+}
+
+static int cdata_add(lua_State* L)
+{
+    struct ctype lt, rt, ct;
+    void *lp, *rp;
+    int ct_usr;
+    int ret;
+
+    lua_settop(L, 2);
+
+    lp = to_cdata(L, 1, &lt);
+    rp = to_cdata(L, 2, &rt);
+    assert(lua_gettop(L) == 4);
+
+    ret = call_user_binop(L, "__add", 1, 3, &lt, 2, 4, &rt);
+    if (ret >= 0) {
+        return ret;
+    }
+    assert(lua_gettop(L) == 4);
+
+    ct_usr = rank(&lt) > rank(&rt) ? 3 : 4;
+    ct = rank(&lt) > rank(&rt) ? lt : rt;
+
+    if (IS_COMPLEX(ct.type)) {
+        complex_double left, right, res;
+
+        left = check_complex(L, 1, lp, &lt);
+        right = check_complex(L, 2, rp, &rt);
+        assert(lua_gettop(L) == 4);
+
+#ifdef HAVE_COMPLEX
+        res = left + right;
+#else
+        res.real = left.real + right.real;
+        res.imag = left.imag + right.imag;
+#endif
+
+        push_complex(L, res, ct_usr, &ct);
+        return 1;
+
+    } else {
+        int64_t left = check_intptr(L, 1, lp, &lt);
+        int64_t right = check_intptr(L, 2, rp, &rt);
+        assert(lua_gettop(L) == 4);
+
+        /* note due to 2s complement it doesn't matter if we do the addition as int or uint,
+         * but the result needs to be uint64_t if either of the sources are */
+
+        if (lt.pointers && rt.pointers) {
+            luaL_error(L, "can't add two pointers");
+
+        } else if (lt.pointers) {
+            int64_t res = left + (lt.pointers > 1 ? sizeof(void*) : lt.base_size) * right;
+            lt.is_array = 0;
+            push_number(L, res, 3, &lt);
+
+        } else if (rt.pointers) {
+            int64_t res = right + (rt.pointers > 1 ? sizeof(void*) : rt.base_size) * left;
+            rt.is_array = 0;
+            push_number(L, res, 4, &rt);
+
+        } else {
+            push_number(L, left + right, ct_usr, &ct);
+        }
+
+        return 1;
+    }
+}
+
+static int cdata_sub(lua_State* L)
+{
+    struct ctype lt, rt, ct;
+    void *lp, *rp;
+    int ct_usr;
+    int ret;
+
+    lua_settop(L, 2);
+
+    lp = to_cdata(L, 1, &lt);
+    rp = to_cdata(L, 2, &rt);
+
+    ret = call_user_binop(L, "__sub", 1, 3, &lt, 2, 4, &rt);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    ct_usr = rank(&lt) > rank(&rt) ? 3 : 4;
+    ct = rank(&lt) > rank(&rt) ? lt : rt;
+
+    if (IS_COMPLEX(ct.type)) {
+        complex_double left, right, res;
+
+        left = check_complex(L, 1, lp, &lt);
+        right = check_complex(L, 2, rp, &rt);
+
+#ifdef HAVE_COMPLEX
+        res = left - right;
+#else
+        res.real = left.real - right.real;
+        res.imag = left.imag - right.imag;
+#endif
+
+        push_complex(L, res, ct_usr, &ct);
+        return 1;
+
+    } else {
+        int64_t left = check_intptr(L, 1, lp, &lt);
+        int64_t right = check_intptr(L, 2, rp, &rt);
+
+        if (rt.pointers) {
+            luaL_error(L, "NYI: can't subtract a pointer value");
+
+        } else if (lt.pointers) {
+            int64_t res = left - (lt.pointers > 1 ? sizeof(void*) : lt.base_size) * right;
+            lt.is_array = 0;
+            push_number(L, res, 3, &lt);
+
+        } else {
+            int64_t res = left - right;
+            push_number(L, res, ct_usr, &ct);
+        }
+
+        return 1;
+    }
+}
+
+/* TODO fix for unsigned */
+#define NUMBER_ONLY_BINOP(OPSTR, DO_NORMAL, DO_COMPLEX)                     \
+    struct ctype lt, rt, ct;                                                \
+    void *lp, *rp;                                                          \
+    int ct_usr;                                                             \
+    int ret;                                                                \
+                                                                            \
+    lua_settop(L, 2);                                                       \
+                                                                            \
+    lp = to_cdata(L, 1, &lt);                                               \
+    rp = to_cdata(L, 2, &rt);                                               \
+                                                                            \
+    ret = call_user_binop(L, OPSTR, 1, 3, &lt, 2, 4, &rt);                  \
+    if (ret >= 0) {                                                         \
+        return ret;                                                         \
+    }                                                                       \
+                                                                            \
+    ct_usr = rank(&lt) > rank(&rt) ? 3 : 4;                                 \
+    ct = rank(&lt) > rank(&rt) ? lt : rt;                                   \
+                                                                            \
+    if (IS_COMPLEX(ct.type)) {                                              \
+        complex_double res;                                                 \
+        complex_double left = check_complex(L, 1, lp, &lt);                 \
+        complex_double right = check_complex(L, 2, rp, &rt);                \
+                                                                            \
+        DO_COMPLEX(left, right, res);                                       \
+        push_complex(L, res, ct_usr, &ct);                                  \
+                                                                            \
+    } else if (lt.pointers || rt.pointers) {                                \
+        luaL_error(L, "can't operate on a pointer value");                  \
+                                                                            \
+    } else {                                                                \
+        int64_t res;                                                        \
+        int64_t left = check_intptr(L, 1, lp, &lt);                         \
+        int64_t right = check_intptr(L, 2, rp, &rt);                        \
+                                                                            \
+        DO_NORMAL(left, right, res);                                        \
+        push_number(L, res, ct_usr, &ct);                                   \
+    }                                                                       \
+                                                                            \
+    return 1
+
+#define MUL(l,r,s) s = l * r
+#define DIV(l,r,s) s = l / r
+#define MOD(l,r,s) s = l % r
+#define POW(l,r,s) s = pow(l, r)
+
+#ifdef HAVE_COMPLEX
+#define MULC(l,r,s) s = l * r
+#define DIVC(l,r,s) s = l / r
+#define MODC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex mod")
+#define POWC(l,r,s) s = cpow(l, r)
+#else
+#define MULC(l,r,s) s.real = l.real * r.real - l.imag * r.imag, s.imag = l.real * r.imag + l.imag * r.real
+#define DIVC(l,r,s) s.real = (l.real * r.real + l.imag * r.imag) / (r.real * r.real + r.imag * r.imag), \
+                    s.imag = (l.imag * r.real - l.real * r.imag) / (r.real * r.real + r.imag * r.imag)
+#define MODC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex mod")
+#define POWC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex pow")
+#endif
+
+static int cdata_mul(lua_State* L)
+{ NUMBER_ONLY_BINOP("__mul", MUL, MULC); }
+
+static int cdata_div(lua_State* L)
+{ NUMBER_ONLY_BINOP("__div", DIV, DIVC); }
+
+static int cdata_mod(lua_State* L)
+{ NUMBER_ONLY_BINOP("__mod", MOD, MODC); }
+
+static int cdata_pow(lua_State* L)
+{ NUMBER_ONLY_BINOP("__pow", POW, POWC); }
+
+#define COMPARE_BINOP(OPSTR, OP, OPC)                                       \
+    struct ctype lt, rt;                                                    \
+    void *lp, *rp;                                                          \
+    int ret, res;                                                           \
+                                                                            \
+    lua_settop(L, 2);                                                       \
+                                                                            \
+    lp = to_cdata(L, 1, &lt);                                               \
+    rp = to_cdata(L, 2, &rt);                                               \
+                                                                            \
+    ret = call_user_binop(L, OPSTR, 1, 3, &lt, 2, 4, &rt);                  \
+    if (ret >= 0) {                                                         \
+        return ret;                                                         \
+    }                                                                       \
+                                                                            \
+    if (IS_COMPLEX(lt.type) || IS_COMPLEX(rt.type)) {                       \
+        complex_double left = check_complex(L, 1, lp, &lt);                 \
+        complex_double right = check_complex(L, 2, rp, &rt);                \
+                                                                            \
+        res = OPC(left, right);                                             \
+                                                                            \
+        lua_pushboolean(L, res);                                            \
+                                                                            \
+    } else {                                                                \
+        int64_t left = check_intptr(L, 1, lp, &lt);                         \
+        int64_t right = check_intptr(L, 2, rp, &rt);                        \
+                                                                            \
+        if (lt.pointers && rt.pointers) {                                   \
+            if (is_void_ptr(&lt) || is_void_ptr(&rt) || is_same_type(L, 3, 4, &lt, &rt)) { \
+                res = OP((uint64_t) left, (uint64_t) right);                \
+            } else {                                                        \
+                goto err;                                                   \
+            }                                                               \
+                                                                            \
+        } else if (lt.is_null && rt.type == FUNCTION_PTR_TYPE) {            \
+            res = OP((uint64_t) left, (uint64_t) right);                    \
+                                                                            \
+        } else if (rt.is_null && lt.type == FUNCTION_PTR_TYPE) {            \
+            res = OP((uint64_t) left, (uint64_t) right);                    \
+                                                                            \
+        } else if (lt.pointers && rt.type == INTPTR_TYPE && rt.is_unsigned) {\
+            res = OP((uint64_t) left, (uint64_t) right);                    \
+                                                                            \
+        } else if (rt.pointers && lt.type == INTPTR_TYPE && lt.is_unsigned) {\
+            res = OP((uint64_t) left, (uint64_t) right);                    \
+                                                                            \
+        } else if (rt.pointers || lt.pointers) {                            \
+            goto err;                                                       \
+                                                                            \
+        } else if (lt.is_unsigned && rt.is_unsigned) {                      \
+            res = OP((uint64_t) left, (uint64_t) right);                    \
+                                                                            \
+        } else if (lt.is_unsigned) {                                        \
+            res = OP((int64_t) (uint64_t) left, right);                     \
+                                                                            \
+        } else if (rt.is_unsigned) {                                        \
+            res = OP(left, (int64_t) (uint64_t) right);                     \
+                                                                            \
+        } else {                                                            \
+            res = OP(left, right);                                          \
+        }                                                                   \
+                                                                            \
+        lua_pushboolean(L, res);                                            \
+    }                                                                       \
+    return 1
+
+#define EQ(l, r) (l) == (r)
+#define LT(l, r) (l) < (r)
+#define LE(l, r) (l) <= (r)
+
+#ifdef HAVE_COMPLEX
+#define EQC(l, r) (l) == (r)
+#else
+#define EQC(l, r) (l).real == (r).real && (l).imag == (r).imag
+#endif
+
+#define LEC(l, r) EQC(l, r), luaL_error(L, "complex numbers are non-orderable")
+#define LTC(l, r) EQC(l, r), luaL_error(L, "complex numbers are non-orderable")
+
+static int cdata_eq(lua_State* L)
+{
+    COMPARE_BINOP("__eq", EQ, EQC);
+err:
+    lua_pushboolean(L, 0);
+    return 1;
+}
+
+static int cdata_lt(lua_State* L)
+{
+    COMPARE_BINOP("__lt", LT, LTC);
+err:
+    lua_getuservalue(L, 1);
+    lua_getuservalue(L, 2);
+    push_type_name(L, -2, &lt);
+    push_type_name(L, -2, &lt);
+    return luaL_error(L, "trying to compare incompatible types %s and %s", lua_tostring(L, -2), lua_tostring(L, -1));
+}
+
+static int cdata_le(lua_State* L)
+{
+    COMPARE_BINOP("__le", LE, LEC);
+err:
+    lua_getuservalue(L, 1);
+    lua_getuservalue(L, 2);
+    push_type_name(L, -2, &lt);
+    push_type_name(L, -2, &lt);
+    return luaL_error(L, "trying to compare incompatible types %s and %s", lua_tostring(L, -2), lua_tostring(L, -1));
+}
+
+static const char* etype_tostring(int type)
+{
+    switch (type) {
+    case VOID_TYPE: return "void";
+    case DOUBLE_TYPE: return "double";
+    case FLOAT_TYPE: return "float";
+    case COMPLEX_DOUBLE_TYPE: return "complex double";
+    case COMPLEX_FLOAT_TYPE: return "complex float";
+    case BOOL_TYPE: return "bool";
+    case INT8_TYPE: return "int8";
+    case INT16_TYPE: return "int16";
+    case INT32_TYPE: return "int32";
+    case INT64_TYPE: return "int64";
+    case INTPTR_TYPE: return "intptr";
+    case ENUM_TYPE: return "enum";
+    case UNION_TYPE: return "union";
+    case STRUCT_TYPE: return "struct";
+    case FUNCTION_PTR_TYPE: return "function ptr";
+    case FUNCTION_TYPE: return "function";
+    default: return "invalid";
+    }
+}
+
+static void print_type(lua_State* L, const struct ctype* ct)
+{
+    lua_pushfstring(L, " sz %d %d %d align %d ptr %d %d %d type %s%s %d %d %d name %d call %d %d var %d %d %d bit %d %d %d %d jit %d",
+            /* sz */
+            ct->base_size,
+            ct->array_size,
+            ct->offset,
+            /* align */
+            ct->align_mask,
+            /* ptr */
+            ct->is_array,
+            ct->pointers,
+            ct->const_mask,
+            /* type */
+            ct->is_unsigned ? "u" : "",
+            etype_tostring(ct->type),
+            ct->is_reference,
+            ct->is_defined,
+            ct->is_null,
+            /* name */
+            ct->has_member_name,
+            /* call */
+            ct->calling_convention,
+            ct->has_var_arg,
+            /* var */
+            ct->is_variable_array,
+            ct->is_variable_struct,
+            ct->variable_size_known,
+            /* bit */
+            ct->is_bitfield,
+            ct->has_bitfield,
+            ct->bit_offset,
+            ct->bit_size,
+            /* jit */
+            ct->is_jitted);
+}
+
+static int ctype_tostring(lua_State* L)
+{
+    struct ctype ct;
+    assert(lua_type(L, 1) == LUA_TUSERDATA);
+    lua_settop(L, 1);
+    check_ctype(L, 1, &ct);
+    assert(lua_gettop(L) == 2);
+    push_type_name(L, -1, &ct);
+    lua_pushfstring(L, "ctype<%s>", lua_tostring(L, -1));
+
+    if (DEBUG_TOSTRING) {
+        print_type(L, &ct);
+        lua_concat(L, 2);
+    }
+
+    return 1;
+}
+
+static int cdata_tostring(lua_State* L)
+{
+    struct ctype ct;
+    char buf[64];
+    void* p;
+    int ret;
+
+    lua_settop(L, 1);
+    p = to_cdata(L, 1, &ct);
+
+    ret = call_user_op(L, "__tostring", 1, 2, &ct);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    if (ct.pointers > 0 || ct.is_reference || ct.type == STRUCT_TYPE || ct.type == UNION_TYPE) {
+        push_type_name(L, -1, &ct);
+        lua_pushfstring(L, "cdata<%s>: %p", lua_tostring(L, -1), p);
+
+        if (DEBUG_TOSTRING) {
+            print_type(L, &ct);
+            lua_concat(L, 2);
+        }
+
+        return 1;
+    }
+
+    switch (ct.type) {
+    case COMPLEX_DOUBLE_TYPE:
+        {
+            complex_double c = *(complex_double*) p;
+            lua_pushfstring(L, "%f+%fi", creal(c), cimag(c));
+        }
+        return 1;
+
+    case COMPLEX_FLOAT_TYPE:
+        {
+            complex_float c = *(complex_float*) p;
+            lua_pushfstring(L, "%f+%fi", crealf(c), cimagf(c));
+        }
+        return 1;
+
+    case FUNCTION_PTR_TYPE:
+        p = *(void**) p;
+        push_type_name(L, -1, &ct);
+        lua_pushfstring(L, "cdata<%s>: %p", lua_tostring(L, -1), *(void**) p);
+        return 1;
+
+    case INTPTR_TYPE:
+        lua_pushfstring(L, "%p", *(uintptr_t*) p);
+        return 1;
+
+    case INT64_TYPE:
+        sprintf(buf, ct.is_unsigned ? "%"PRIu64 : "%"PRId64, *(uint64_t*) p);
+        lua_pushstring(L, buf);
+        return 1;
+
+    default:
+        sprintf(buf, ct.is_unsigned ? "%"PRId64 : "%"PRId64, (int64_t) check_intptr(L, 1, p, &ct));
+        lua_pushstring(L, buf);
+        return 1;
+    }
+}
+
+static int ffi_errno(lua_State* L)
+{
+    struct jit* jit = get_jit(L);
+
+    if (!lua_isnoneornil(L, 1)) {
+        lua_pushinteger(L, jit->last_errno);
+        jit->last_errno = luaL_checknumber(L, 1);
+    } else {
+        lua_pushinteger(L, jit->last_errno);
+    }
+
+    return 1;
+}
+
+static int ffi_type(lua_State* L)
+{
+    if (lua_isuserdata(L, 1) && lua_getmetatable(L, 1)) {
+        if (equals_upval(L, -1, &cdata_mt_key) || equals_upval(L, -1, &ctype_mt_key)) {
+            lua_pushstring(L, "cdata");
+            return 1;
+        }
+        lua_pop(L, 1); /* mt */
+    }
+
+    /* call the old _G.type, we use an upvalue as _G.type is set
+     * to this function */
+    lua_pushvalue(L, lua_upvalueindex(1));
+    lua_insert(L, 1);
+    lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
+    return lua_gettop(L);
+}
+
+static int ffi_number(lua_State* L)
+{
+    struct ctype ct;
+    void* data = to_cdata(L, 1, &ct);
+
+    if (ct.type != INVALID_TYPE) {
+        lua_pushinteger(L, check_intptr(L, 1, data, &ct));
+        return 1;
+    } else {
+        /* call the old _G.tonumber, we use an upvalue as _G.tonumber is set
+         * to this function */
+        lua_pushvalue(L, lua_upvalueindex(1));
+        lua_insert(L, 1);
+        lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
+        return lua_gettop(L);
+    }
+}
+
+static int ffi_string(lua_State* L)
+{
+    struct ctype ct;
+    char* data;
+    lua_settop(L, 2);
+
+    data = (char*) check_cdata(L, 1, &ct);
+
+    if (is_void_ptr(&ct)) {
+        lua_pushlstring(L, data, (size_t) luaL_checknumber(L, 2));
+        return 1;
+
+    } else if (ct.type == INT8_TYPE && ct.pointers == 1) {
+        size_t sz;
+
+        if (lua_isuserdata(L, 2)) {
+            ptrdiff_t val;
+            if (!cdata_tointeger(L, 2, &val)) {
+                type_error(L, 2, "int", 0, NULL);
+            }
+            sz = (size_t) val;
+        } else if (!lua_isnil(L, 2)) {
+            sz = (size_t) luaL_checknumber(L, 2);
+
+        } else if (ct.is_array && !ct.is_variable_array) {
+            char* nul = memchr(data, '\0', ct.array_size);
+            sz = nul ? nul - data : ct.array_size;
+
+        } else {
+            sz = strlen(data);
+        }
+
+        lua_pushlstring(L, data, sz);
+        return 1;
+    }
+
+    return luaL_error(L, "unable to convert cdata to string");
+}
+
+static int ffi_copy(lua_State* L)
+{
+    struct ctype ft, tt;
+    char *to, *from;
+
+    setmintop(L, 3);
+    to = (char*) check_pointer(L, 1, &tt);
+    from = (char*) check_pointer(L, 2, &ft);
+
+    if (!lua_isnoneornil(L, 3)) {
+        memcpy(to, from, (size_t) luaL_checknumber(L, 3));
+
+    } else if (ft.type == INT8_TYPE && ft.pointers == 1) {
+        size_t sz = ft.is_array ? ft.array_size : strlen(from);
+        memcpy(to, from, sz);
+        to[sz] = '\0';
+    }
+
+    return 0;
+}
+
+static int ffi_fill(lua_State* L)
+{
+    struct ctype ct;
+    void* to;
+    size_t sz;
+    int val = 0;
+
+    setmintop(L, 3);
+    to = check_pointer(L, 1, &ct);
+    sz = (size_t) luaL_checknumber(L, 2);
+
+    if (!lua_isnoneornil(L, 3)) {
+        val = (int) luaL_checkinteger(L, 3);
+    }
+
+    memset(to, val, sz);
+    return 0;
+}
+
+static int ffi_abi(lua_State* L)
+{
+    luaL_checkstring(L, 1);
+    push_upval(L, &abi_key);
+    lua_pushvalue(L, 1);
+    lua_rawget(L, -2);
+    lua_pushboolean(L, lua_toboolean(L, -1));
+    return 1;
+}
+
+static int ffi_load(lua_State* L)
+{
+    const char* libname = luaL_checkstring(L, 1);
+    void** lib = (void**) lua_newuserdata(L, sizeof(void*));
+
+    *lib = LoadLibraryA(libname);
+
+#ifdef LIB_FORMAT_1
+    if (!*lib) {
+        libname = lua_pushfstring(L, LIB_FORMAT_1, lua_tostring(L, 1));
+        *lib = LoadLibraryA(libname);
+        lua_pop(L, 1);
+    }
+#endif
+
+#ifdef LIB_FORMAT_2
+    if (!*lib) {
+        libname = lua_pushfstring(L, LIB_FORMAT_2, lua_tostring(L, 1));
+        *lib = LoadLibraryA(libname);
+        lua_pop(L, 1);
+    }
+#endif
+
+    if (!*lib) {
+        return luaL_error(L, "could not load library %s", lua_tostring(L, 1));
+    }
+
+    lua_newtable(L);
+    lua_setuservalue(L, -2);
+
+    push_upval(L, &cmodule_mt_key);
+    lua_setmetatable(L, -2);
+    return 1;
+}
+
+static void* find_symbol(lua_State* L, int modidx, const char* asmname)
+{
+    size_t i;
+    void** libs;
+    size_t num;
+    void* sym = NULL;
+
+    libs = (void**) lua_touserdata(L, modidx);
+    num = lua_rawlen(L, modidx) / sizeof(void*);
+
+    for (i = 0; i < num && sym == NULL; i++) {
+        if (libs[i]) {
+            sym = GetProcAddressA(libs[i], asmname);
+        }
+    }
+
+    return sym;
+}
+
+/* pushes the user table */
+static void* lookup_global(lua_State* L, int modidx, int nameidx, const char** pname, struct ctype* ct)
+{
+    int top = lua_gettop(L);
+    void* sym;
+
+    modidx = lua_absindex(L, modidx);
+    nameidx = lua_absindex(L, nameidx);
+
+    *pname = luaL_checkstring(L, nameidx);
+
+    /* get the ctype */
+    push_upval(L, &functions_key);
+    lua_pushvalue(L, nameidx);
+    lua_rawget(L, -2);
+    if (lua_isnil(L, -1)) {
+        luaL_error(L, "missing declaration for function/global %s", *pname);
+        return NULL;
+    }
+
+    /* leave just the ct_usr on the stack */
+    *ct = *(const struct ctype*) lua_touserdata(L, -1);
+    lua_getuservalue(L, -1);
+    lua_replace(L, top + 1);
+    lua_pop(L, 1);
+
+    assert(lua_gettop(L) == top + 1);
+
+    /* get the assembly name */
+    push_upval(L, &asmname_key);
+    lua_pushvalue(L, nameidx);
+    lua_rawget(L, -2);
+    if (lua_isstring(L, -1)) {
+        *pname = lua_tostring(L, -1);
+    }
+    lua_pop(L, 2);
+
+    sym = find_symbol(L, modidx, *pname);
+
+    assert(lua_gettop(L) == top + 1);
+    return sym;
+}
+
+static int cmodule_index(lua_State* L)
+{
+    const char* asmname;
+    struct ctype ct;
+    void *sym;
+
+    lua_settop(L, 2);
+
+    /* see if we have already loaded the function */
+    lua_getuservalue(L, 1);
+    lua_pushvalue(L, 2);
+    lua_rawget(L, -2);
+    if (!lua_isnil(L, -1)) {
+        return 1;
+    }
+    lua_pop(L, 2);
+
+    /* check the constants table */
+    push_upval(L, &constants_key);
+    lua_pushvalue(L, 2);
+    lua_rawget(L, -2);
+    if (!lua_isnil(L, -1)) {
+        return 1;
+    }
+    lua_pop(L, 2);
+
+    /* lookup_global pushes the ct_usr */
+    sym = lookup_global(L, 1, 2, &asmname, &ct);
+
+#if defined _WIN32 && !defined _WIN64 && (defined __i386__ || defined _M_IX86)
+    if (!sym && ct.type == FUNCTION_TYPE) {
+        ct.calling_convention = STD_CALL;
+        lua_pushfstring(L, "_%s@%d", asmname, x86_return_size(L, -1, &ct));
+        sym = find_symbol(L, 1, lua_tostring(L, -1));
+        lua_pop(L, 1);
+    }
+
+    if (!sym && ct.type == FUNCTION_TYPE) {
+        ct.calling_convention = FAST_CALL;
+        lua_pushfstring(L, "@%s@%d", asmname, x86_return_size(L, -1, &ct));
+        sym = find_symbol(L, 1, lua_tostring(L, -1));
+        lua_pop(L, 1);
+    }
+#endif
+
+    if (!sym) {
+        return luaL_error(L, "failed to find function/global %s", asmname);
+    }
+
+    assert(lua_gettop(L) == 3); /* module, name, ct_usr */
+
+    if (ct.type == FUNCTION_TYPE) {
+        compile_function(L, (cfunction) sym, -1, &ct);
+        assert(lua_gettop(L) == 4); /* module, name, ct_usr, function */
+
+        /* set module usr value[luaname] = function to cache for next time */
+        lua_getuservalue(L, 1);
+        lua_pushvalue(L, 2);
+        lua_pushvalue(L, -3);
+        lua_rawset(L, -3);
+        lua_pop(L, 1); /* module uv */
+        return 1;
+    }
+
+    /* extern const char* foo; and extern const char foo[]; */
+    if (ct.pointers == 1 && ct.type == INT8_TYPE) {
+        char* str = (char*) sym;
+        if (!ct.is_array) {
+            str = *(char**) sym;
+        }
+        lua_pushstring(L, str);
+        return 1;
+    }
+
+    /* extern struct foo foo[], extern void* foo[]; and extern struct foo foo; */
+    if (ct.is_array || (!ct.pointers && (ct.type == UNION_TYPE || ct.type == STRUCT_TYPE))) {
+        void* p;
+        ct.is_reference = 1;
+        p = push_cdata(L, -1, &ct);
+        *(void**) p = sym;
+        return 1;
+    }
+
+    /* extern void* foo; and extern void (*foo)(); */
+    if (ct.pointers || ct.type == FUNCTION_PTR_TYPE) {
+        void* p = push_cdata(L, -1, &ct);
+        *(void**) p = *(void**) sym;
+        return 1;
+    }
+
+    switch (ct.type) {
+    case COMPLEX_DOUBLE_TYPE:
+    case COMPLEX_FLOAT_TYPE:
+    case INTPTR_TYPE:
+    case INT64_TYPE:
+        {
+            /* TODO: complex float/double need to be references if .re and
+             * .imag are setable */
+            void* p = push_cdata(L, -1, &ct);
+            memcpy(p, sym, ct.base_size);
+            return 1;
+        }
+
+    case DOUBLE_TYPE:
+        lua_pushnumber(L, *(double*) sym);
+        return 1;
+
+    case FLOAT_TYPE:
+        lua_pushnumber(L, *(float*) sym);
+        return 1;
+
+    case BOOL_TYPE:
+        lua_pushboolean(L, *(bool*) sym);
+        return 1;
+
+    case INT8_TYPE:
+        lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint8_t*) sym : (lua_Integer) *(int8_t*) sym);
+        return 1;
+
+    case INT16_TYPE:
+        lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint16_t*) sym : (lua_Integer) *(int16_t*) sym);
+        return 1;
+
+    case INT32_TYPE:
+    case ENUM_TYPE:
+        lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint32_t*) sym : (lua_Integer) *(int32_t*) sym);
+        return 1;
+    }
+
+    return luaL_error(L, "NYI - global value type");
+}
+
+static int cmodule_newindex(lua_State* L)
+{
+    const char* name;
+    void* sym;
+    struct ctype ct;
+
+    lua_settop(L, 3);
+
+    /* pushes the ct_usr */
+    sym = lookup_global(L, 1, 2, &name, &ct);
+    assert(lua_gettop(L) == 4); /* module, name, value, ct_usr */
+
+    if (sym == NULL) {
+        return luaL_error(L, "failed to find global %s", name);
+    }
+
+    if (ct.type == FUNCTION_TYPE || ct.is_array || (ct.const_mask & 1)) {
+        return luaL_error(L, "can not set global %s", name);
+    }
+
+    set_value(L, 3, sym, -1, &ct, 1);
+    return 0;
+}
+
+static int jit_gc(lua_State* L)
+{
+    size_t i;
+    struct jit* jit = get_jit(L);
+    dasm_free(jit);
+    for (i = 0; i < jit->pagenum; i++) {
+        FreePage(jit->pages[i], jit->pages[i]->size);
+    }
+    free(jit->pages);
+    free(jit->globals);
+    return 0;
+}
+
+static int ffi_debug(lua_State* L)
+{
+    lua_newtable(L);
+    push_upval(L, &ctype_mt_key);
+    lua_setfield(L, -2, "ctype_mt");
+    push_upval(L, &cdata_mt_key);
+    lua_setfield(L, -2, "cdata_mt");
+    push_upval(L, &cmodule_mt_key);
+    lua_setfield(L, -2, "cmodule_mt");
+    push_upval(L, &constants_key);
+    lua_setfield(L, -2, "constants");
+    push_upval(L, &types_key);
+    lua_setfield(L, -2, "types");
+    push_upval(L, &jit_key);
+    lua_setfield(L, -2, "jit");
+    push_upval(L, &gc_key);
+    lua_setfield(L, -2, "gc");
+    push_upval(L, &callbacks_key);
+    lua_setfield(L, -2, "callbacks");
+    push_upval(L, &functions_key);
+    lua_setfield(L, -2, "functions");
+    push_upval(L, &abi_key);
+    lua_setfield(L, -2, "abi");
+    push_upval(L, &next_unnamed_key);
+    lua_setfield(L, -2, "next_unnamed");
+    return 1;
+}
+
+static int do64(lua_State* L, int is_unsigned)
+{
+    lua_Number low, high;
+    struct ctype ct;
+    int64_t val;
+
+    lua_settop(L, 2);
+
+    if (!lua_isnil(L, 2)) {
+        high = luaL_checknumber(L, 1);
+        low = luaL_checknumber(L, 2);
+    } else {
+        high = 0;
+        low = luaL_checknumber(L, 1);
+    }
+
+    val = ((int64_t) (uint32_t) high << 32) | (int64_t) (uint32_t) low;
+
+    if (!is_unsigned && (high < 0 || low < 0)) {
+        val = -val;
+    }
+
+    memset(&ct, 0, sizeof(ct));
+    ct.type = INT64_TYPE;
+    ct.is_unsigned = is_unsigned;
+    ct.is_defined = 1;
+    ct.base_size = sizeof(int64_t);
+    push_number(L, (int64_t) val, 0, &ct);
+
+    return 1;
+}
+
+static int ffi_i64(lua_State* L)
+{ return do64(L, 0); }
+
+static int ffi_u64(lua_State* L)
+{ return do64(L, 1); }
+
+static const luaL_Reg cdata_mt[] = {
+    {"__gc", &cdata_gc},
+    {"__call", &cdata_call},
+    {"free", &cdata_free},
+    {"set", &cdata_set},
+    {"__index", &cdata_index},
+    {"__newindex", &cdata_newindex},
+    {"__add", &cdata_add},
+    {"__sub", &cdata_sub},
+    {"__mul", &cdata_mul},
+    {"__div", &cdata_div},
+    {"__mod", &cdata_mod},
+    {"__pow", &cdata_pow},
+    {"__unm", &cdata_unm},
+    {"__eq", &cdata_eq},
+    {"__lt", &cdata_lt},
+    {"__le", &cdata_le},
+    {"__tostring", &cdata_tostring},
+    {"__concat", &cdata_concat},
+    {"__len", &cdata_len},
+    {"__pairs", &cdata_pairs},
+    {"__ipairs", &cdata_ipairs},
+    {NULL, NULL}
+};
+
+static const luaL_Reg callback_mt[] = {
+    {"__gc", &callback_free},
+    {NULL, NULL}
+};
+
+static const luaL_Reg ctype_mt[] = {
+    {"__call", &ctype_call},
+    {"__new", &ctype_new},
+    {"__tostring", &ctype_tostring},
+    {NULL, NULL}
+};
+
+static const luaL_Reg cmodule_mt[] = {
+    {"__index", &cmodule_index},
+    {"__newindex", &cmodule_newindex},
+    {NULL, NULL}
+};
+
+static const luaL_Reg jit_mt[] = {
+    {"__gc", &jit_gc},
+    {NULL, NULL}
+};
+
+static const luaL_Reg ffi_reg[] = {
+    {"cdef", &ffi_cdef},
+    {"load", &ffi_load},
+    {"new", &ffi_new},
+    {"typeof", &ffi_typeof},
+    {"cast", &ffi_cast},
+    {"metatype", &ffi_metatype},
+    {"gc", &ffi_gc},
+    {"sizeof", &ffi_sizeof},
+    {"alignof", &ffi_alignof},
+    {"offsetof", &ffi_offsetof},
+    {"istype", &ffi_istype},
+    {"errno", &ffi_errno},
+    {"string", &ffi_string},
+    {"copy", &ffi_copy},
+    {"fill", &ffi_fill},
+    {"abi", &ffi_abi},
+    {"debug", &ffi_debug},
+    {"i64", &ffi_i64},
+    {"u64", &ffi_u64},
+    {NULL, NULL}
+};
+
+/* leaves the usr table on the stack */
+static void push_builtin(lua_State* L, struct ctype* ct, const char* name, int type, int size, int align, int is_unsigned)
+{
+    memset(ct, 0, sizeof(*ct));
+    ct->type = type;
+    ct->base_size = size;
+    ct->align_mask = align;
+    ct->is_defined = 1;
+    ct->is_unsigned = is_unsigned;
+
+    if (IS_COMPLEX(type)) {
+        lua_newtable(L);
+    } else {
+        lua_pushnil(L);
+    }
+
+    push_upval(L, &types_key);
+    push_ctype(L, -2, ct);
+    lua_setfield(L, -2, name);
+    lua_pop(L, 2); /* types, usr table */
+}
+
+static void push_builtin_undef(lua_State* L, struct ctype* ct, const char* name, int type)
+{
+    memset(ct, 0, sizeof(*ct));
+    ct->type = type;
+
+    push_upval(L, &types_key);
+    push_ctype(L, 0, ct);
+    lua_setfield(L, -2, name);
+    lua_pop(L, 1); /* types */
+}
+
+static void add_typedef(lua_State* L, const char* from, const char* to)
+{
+    struct ctype ct;
+    struct parser P;
+    P.line = 1;
+    P.align_mask = DEFAULT_ALIGN_MASK;
+    P.next = P.prev = from;
+
+    push_upval(L, &types_key);
+    parse_type(L, &P, &ct);
+    parse_argument(L, &P, -1, &ct, NULL, NULL);
+    push_ctype(L, -1, &ct);
+
+    /* stack is at +4: types, type usr, arg usr, ctype */
+
+    lua_setfield(L, -4, to);
+    lua_pop(L, 3); /* types, type usr, arg usr */
+}
+
+static int setup_upvals(lua_State* L)
+{
+    struct jit* jit = get_jit(L);
+
+    /* jit setup */
+    {
+        dasm_init(jit, 64);
+#ifdef _WIN32
+        {
+            SYSTEM_INFO si;
+            GetSystemInfo(&si);
+            jit->align_page_size = si.dwAllocationGranularity - 1;
+        }
+#else
+        jit->align_page_size = sysconf(_SC_PAGE_SIZE) - 1;
+#endif
+        jit->globals = (void**) malloc(64 * sizeof(void*));
+        dasm_setupglobal(jit, jit->globals, 64);
+        compile_globals(jit, L);
+    }
+
+    /* ffi.C */
+    {
+#ifdef _WIN32
+        size_t sz = sizeof(HMODULE) * 6;
+        HMODULE* libs = lua_newuserdata(L, sz);
+        memset(libs, 0, sz);
+
+        /* exe */
+        GetModuleHandle(NULL);
+        /* lua dll */
+#ifdef LUA_DLL_NAME
+#define STR2(tok) #tok
+#define STR(tok) STR2(tok)
+        libs[1] = LoadLibraryA(STR(LUA_DLL_NAME));
+#undef STR
+#undef STR2
+#endif
+
+        /* crt */
+#ifdef UNDER_CE
+        libs[2] = LoadLibraryA("coredll.dll");
+#else
+        GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (char*) &_fmode, &libs[2]);
+        libs[3] = LoadLibraryA("kernel32.dll");
+        libs[4] = LoadLibraryA("user32.dll");
+        libs[5] = LoadLibraryA("gdi32.dll");
+#endif
+
+        jit->lua_dll = libs[1];
+        jit->kernel32_dll = libs[3];
+
+#else /* !_WIN32 */
+        size_t sz = sizeof(void*) * 5;
+        void** libs = lua_newuserdata(L, sz);
+        memset(libs, 0, sz);
+
+        libs[0] = LoadLibraryA(NULL); /* exe */
+        libs[1] = LoadLibraryA("libc.so");
+#ifdef __GNUC__
+        libs[2] = LoadLibraryA("libgcc.so");
+#endif
+        libs[3] = LoadLibraryA("libm.so");
+        libs[4] = LoadLibraryA("libdl.so");
+#endif
+
+        lua_newtable(L);
+        lua_setuservalue(L, -2);
+
+        push_upval(L, &cmodule_mt_key);
+        lua_setmetatable(L, -2);
+
+        lua_setfield(L, 1, "C");
+    }
+
+    /* setup builtin types */
+    {
+        complex_double* pc;
+        struct {char ch; uint16_t v;} a16;
+        struct {char ch; uint32_t v;} a32;
+        struct {char ch; uint64_t v;} a64;
+        struct {char ch; float v;} af;
+        struct {char ch; double v;} ad;
+#ifdef HAVE_LONG_DOUBLE
+        struct {char ch; long double v;} ald;
+#endif
+        struct {char ch; uintptr_t v;} aptr;
+        struct ctype ct;
+        struct {char ch; complex_float v;} cf;
+        struct {char ch; complex_double v;} cd;
+#if defined HAVE_LONG_DOUBLE && defined HAVE_COMPLEX
+        struct {char ch; complex long double v;} cld;
+#endif
+
+        push_builtin(L, &ct, "void", VOID_TYPE, 0, 0, 0);
+        push_builtin(L, &ct, "bool", BOOL_TYPE, sizeof(_Bool), sizeof(_Bool) -1, 1);
+        push_builtin(L, &ct, "uint8_t", INT8_TYPE, sizeof(uint8_t), 0, 1);
+        push_builtin(L, &ct, "int8_t", INT8_TYPE, sizeof(int8_t), 0, 0);
+        push_builtin(L, &ct, "uint16_t", INT16_TYPE, sizeof(uint16_t), ALIGNOF(a16), 1);
+        push_builtin(L, &ct, "int16_t", INT16_TYPE, sizeof(int16_t), ALIGNOF(a16), 0);
+        push_builtin(L, &ct, "uint32_t", INT32_TYPE, sizeof(uint32_t), ALIGNOF(a32), 1);
+        push_builtin(L, &ct, "int32_t", INT32_TYPE, sizeof(int32_t), ALIGNOF(a32), 0);
+        push_builtin(L, &ct, "uint64_t", INT64_TYPE, sizeof(uint64_t), ALIGNOF(a64), 1);
+        push_builtin(L, &ct, "int64_t", INT64_TYPE, sizeof(int64_t), ALIGNOF(a64), 0);
+        push_builtin(L, &ct, "float", FLOAT_TYPE, sizeof(float), ALIGNOF(af), 0);
+        push_builtin(L, &ct, "double", DOUBLE_TYPE, sizeof(double), ALIGNOF(ad), 0);
+#ifdef HAVE_LONG_DOUBLE
+        push_builtin(L, &ct, "long double", LONG_DOUBLE_TYPE, sizeof(long double), ALIGNOF(ald), 0);
+#else
+        push_builtin_undef(L, &ct, "long double", LONG_DOUBLE_TYPE);
+#endif
+        push_builtin(L, &ct, "uintptr_t", INTPTR_TYPE, sizeof(uintptr_t), ALIGNOF(aptr), 1);
+        push_builtin(L, &ct, "intptr_t", INTPTR_TYPE, sizeof(uintptr_t), ALIGNOF(aptr), 0);
+        push_builtin(L, &ct, "complex float", COMPLEX_FLOAT_TYPE, sizeof(complex_float), ALIGNOF(cf), 0);
+        push_builtin(L, &ct, "complex double", COMPLEX_DOUBLE_TYPE, sizeof(complex_double), ALIGNOF(cd), 0);
+#if defined HAVE_LONG_DOUBLE && defined HAVE_COMPLEX
+        push_builtin(L, &ct, "complex long double", COMPLEX_LONG_DOUBLE_TYPE, sizeof(complex long double), ALIGNOF(cld), 0);
+#else
+        push_builtin_undef(L, &ct, "complex long double", COMPLEX_LONG_DOUBLE_TYPE);
+#endif
+
+        /* add NULL and i constants */
+        push_upval(L, &constants_key);
+
+        memset(&ct, 0, sizeof(ct));
+        ct.type = VOID_TYPE;
+        ct.is_defined = 1;
+        ct.pointers = 1;
+        ct.is_null = 1;
+
+        /* add ffi.C.NULL */
+        push_cdata(L, 0, &ct);
+        lua_setfield(L, -2, "NULL");
+
+        /* add ffi.NULL */
+        push_cdata(L, 0, &ct);
+        lua_setfield(L, 1, "NULL");
+
+        memset(&ct, 0, sizeof(ct));
+        ct.type = COMPLEX_DOUBLE_TYPE;
+        ct.is_defined = 1;
+        ct.base_size = sizeof(complex_double);
+        pc = (complex_double*) push_cdata(L, 0, &ct);
+#ifdef HAVE_COMPLEX
+        *pc = 1i;
+#else
+        pc->real = 0;
+        pc->imag = 1;
+#endif
+        lua_setfield(L, -2, "i");
+
+        lua_pop(L, 1); /* constants */
+    }
+
+    assert(lua_gettop(L) == 1);
+
+    /* setup builtin typedefs */
+    {
+        add_typedef(L, "bool", "_Bool");
+
+        if (sizeof(uint32_t) == sizeof(size_t)) {
+            add_typedef(L, "uint32_t", "size_t");
+            add_typedef(L, "int32_t", "ssize_t");
+        } else if (sizeof(uint64_t) == sizeof(size_t)) {
+            add_typedef(L, "uint64_t", "size_t");
+            add_typedef(L, "int64_t", "ssize_t");
+        }
+
+        if (sizeof(int32_t) == sizeof(intptr_t)) {
+            add_typedef(L, "int32_t", "intptr_t");
+            add_typedef(L, "int32_t", "ptrdiff_t");
+        } else if (sizeof(int64_t) == sizeof(intptr_t)) {
+            add_typedef(L, "int64_t", "intptr_t");
+            add_typedef(L, "int64_t", "ptrdiff_t");
+        }
+
+        if (sizeof(uint8_t) == sizeof(wchar_t)) {
+            add_typedef(L, "uint8_t", "wchar_t");
+        } else if (sizeof(uint16_t) == sizeof(wchar_t)) {
+            add_typedef(L, "uint16_t", "wchar_t");
+        } else if (sizeof(uint32_t) == sizeof(wchar_t)) {
+            add_typedef(L, "uint32_t", "wchar_t");
+        }
+
+        if (sizeof(va_list) == sizeof(char*)) {
+            add_typedef(L, "char*", "va_list");
+        } else {
+            struct {char ch; va_list v;} av;
+            lua_pushfstring(L, "struct {char data[%d] __attribute__((align(%d)));}", (int) sizeof(va_list), (int) ALIGNOF(av) + 1);
+            add_typedef(L, lua_tostring(L, -1), "va_list");
+            lua_pop(L, 1);
+        }
+
+        add_typedef(L, "va_list", "__builtin_va_list");
+        add_typedef(L, "va_list", "__gnuc_va_list");
+    }
+
+    assert(lua_gettop(L) == 1);
+
+    /* setup ABI params table */
+    push_upval(L, &abi_key);
+
+#if defined ARCH_X86 || defined ARCH_ARM
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -2, "32bit");
+#elif defined ARCH_X64 || defined ARCH_PPC64
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -2, "64bit");
+#else
+#error
+#endif
+
+#if defined ARCH_X86 || defined ARCH_X64 || defined ARCH_ARM || defined ARCH_PPC64
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -2, "le");
+#else
+#error
+#endif
+
+#if defined ARCH_X86 || defined ARCH_X64 || defined ARCH_PPC64
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -2, "fpu");
+#elif defined ARCH_ARM
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -2, "softfp");
+#else
+#error
+#endif
+    lua_pop(L, 1); /* abi tbl */
+
+
+    /* GC table - shouldn't pin cdata values */
+    push_upval(L, &gc_key);
+    lua_newtable(L);
+    lua_pushliteral(L, "k");
+    lua_setfield(L, -2, "__mode");
+    lua_setmetatable(L, -2);
+    lua_pop(L, 1); /* gc table */
+
+
+    /* ffi.os */
+#if defined OS_CE
+    lua_pushliteral(L, "WindowsCE");
+#elif defined OS_WIN
+    lua_pushliteral(L, "Windows");
+#elif defined OS_OSX
+    lua_pushliteral(L, "OSX");
+#elif defined OS_LINUX
+    lua_pushliteral(L, "Linux");
+#elif defined OS_BSD
+    lua_pushliteral(L, "BSD");
+#elif defined OS_POSIX
+    lua_pushliteral(L, "POSIX");
+#else
+    lua_pushliteral(L, "Other");
+#endif
+    lua_setfield(L, 1, "os");
+
+
+    /* ffi.arch */
+#if defined ARCH_X86
+    lua_pushliteral(L, "x86");
+#elif defined ARCH_X64
+    lua_pushliteral(L, "x64");
+#elif defined ARCH_ARM
+    lua_pushliteral(L, "arm");
+#elif defined ARCH_PPC64
+    lua_pushliteral(L, "ppc64");
+#else
+# error
+#endif
+    lua_setfield(L, 1, "arch");
+
+    assert(lua_gettop(L) == 1);
+
+    return 0;
+}
+
+static void setup_mt(lua_State* L, const luaL_Reg* mt, int upvals)
+{
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -upvals-2, "__metatable");
+    luaL_setfuncs(L, mt, upvals);
+}
+
+
+#if defined FFI_ENABLE_LUATEX_INTERFACE
+int luaopen_ffi(lua_State* L)
+{
+    lua_settop(L, 0);
+
+    lua_newtable(L);
+    set_upval(L, &niluv_key);
+
+    lua_newtable(L);
+    setup_mt(L, ctype_mt, 0);
+    set_upval(L, &ctype_mt_key);
+
+    lua_newtable(L);
+    set_upval(L, &callbacks_key);
+
+    lua_newtable(L);
+    set_upval(L, &gc_key);
+
+    lua_newtable(L);
+    push_upval(L, &callbacks_key);
+    push_upval(L, &gc_key);
+    setup_mt(L, cdata_mt, 2);
+    set_upval(L, &cdata_mt_key);
+
+    lua_newtable(L);
+    setup_mt(L, callback_mt, 0);
+    set_upval(L, &callback_mt_key);
+
+    lua_newtable(L);
+    setup_mt(L, cmodule_mt, 0);
+    set_upval(L, &cmodule_mt_key);
+
+    memset(lua_newuserdata(L, sizeof(struct jit)), 0, sizeof(struct jit));
+    lua_newtable(L);
+    setup_mt(L, jit_mt, 0);
+    lua_setmetatable(L, -2);
+    set_upval(L, &jit_key);
+
+    lua_newtable(L);
+    set_upval(L, &constants_key);
+
+    lua_newtable(L);
+    set_upval(L, &types_key);
+
+    lua_newtable(L);
+    set_upval(L, &functions_key);
+
+    lua_newtable(L);
+    set_upval(L, &asmname_key);
+
+    lua_newtable(L);
+    set_upval(L, &abi_key);
+
+    lua_pushinteger(L, 1);
+    set_upval(L, &next_unnamed_key);
+
+    assert(lua_gettop(L) == 0);
+
+    /* ffi table */
+    lua_newtable(L);
+    luaL_setfuncs(L, ffi_reg, 0);
+
+    /* setup_upvals(ffi tbl) */
+    lua_pushcfunction(L, &setup_upvals);
+    lua_pushvalue(L, 1);
+    lua_call(L, 1, 0);
+
+    assert(lua_gettop(L) == 1);
+
+    lua_getglobal(L, "tonumber");
+    lua_pushcclosure(L, &ffi_number, 1);
+    lua_pushvalue(L, -1);
+    lua_setglobal(L, "tonumber");
+    lua_setfield(L, -2, "number"); /* ffi.number */
+
+    lua_getglobal(L, "type");
+    lua_pushcclosure(L, &ffi_type, 1);
+    lua_pushvalue(L, -1);
+    lua_setglobal(L, "type");
+    lua_setfield(L, -2, "type"); /* ffi.type */
+    return 1;
+}
+#else
+/* This is  a stub for OS/ARCH that at this moment don't support ffi */
+int luaopen_ffi(lua_State *L)
+{
+  int k ; 
+
+  k = luaL_dostring(L, "local info = [[\n"
+"The ffi module is available for:\n"
+"\n" 
+"    archictures       : ARCH_X86 and ARCH_X64,\n"
+"    operating systems : OS_CE, OS_WIN, OS_LINUX, OS BD and OS_POSIX\n"
+"\n"
+"The ARM processor is currently not supported. There are subtle\n"
+"differences between this module and the one in luajitTeX \n"
+"and we hope to be in sync around TeXLive 2018.\n"
+"Different OS can have different interfaces,\n"
+"for instance OS_WIN has not 'complex.h'. If you want portable\n"
+"code, stick to the most common concepts.\n"
+"]]\n"
+"\n"
+"local function stub()\n"
+"    texio.write_nl(info)\n"
+"end\n"
+"\n"
+"return   {\n"
+"    fill      = stub,\n"
+"    cast      = stub,\n"
+"    offsetof  = stub,\n"
+"    copy      = stub,\n"
+"    string    = stub,\n"
+"    abi       = stub,\n"
+"    cdef      = stub,\n"
+"    typeof    = stub,\n"
+"    sizeof    = stub,\n"
+"    type      = stub,\n"
+"    number    = stub,\n"
+"    gc        = stub,\n"
+"    metatype  = stub,\n"
+"    errno     = stub,\n"
+"    debug     = stub,\n"
+"    os        = ''  ,\n"
+"    arch      = ''  ,\n"
+"    NULL      = nil ,\n"
+"    alignof   = stub,\n"
+"    new       = stub,\n"
+"    u64       = stub,\n"
+"    i64       = stub,\n"
+"    istype    = stub,\n"
+"    load      = stub,\n"
+"    C         = nil ,\n"
+"}");
+
+     return k==0 ? 1 : k;
+}
+#endif


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.c.orig
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.c.orig	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.c.orig	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,3552 @@
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+#include "ffi.h"
+#include <math.h>
+#include <inttypes.h>
+
+/* Set to 1 to get extra debugging on print */
+#define DEBUG_TOSTRING 0
+
+int jit_key;
+int ctype_mt_key;
+int cdata_mt_key;
+int callback_mt_key;
+int cmodule_mt_key;
+int constants_key;
+int types_key;
+int gc_key;
+int callbacks_key;
+int functions_key;
+int abi_key;
+int next_unnamed_key;
+int niluv_key;
+int asmname_key;
+
+void push_upval(lua_State* L, int* key)
+{
+    lua_pushlightuserdata(L, key);
+    lua_rawget(L, LUA_REGISTRYINDEX);
+}
+
+void set_upval(lua_State* L, int* key)
+{
+    lua_pushlightuserdata(L, key);
+    lua_insert(L, -2);
+    lua_rawset(L, LUA_REGISTRYINDEX);
+}
+
+int equals_upval(lua_State* L, int idx, int* key)
+{
+    int ret;
+    lua_pushvalue(L, idx);
+    push_upval(L, key);
+    ret = lua_rawequal(L, -2, -1);
+    lua_pop(L, 2);
+    return ret;
+}
+
+struct jit* get_jit(lua_State* L)
+{
+    struct jit* jit;
+    push_upval(L, &jit_key);
+    jit = (struct jit*) lua_touserdata(L, -1);
+    jit->L = L;
+    lua_pop(L, 1); /* still in registry */
+    return jit;
+}
+
+static int type_error(lua_State* L, int idx, const char* to_type, int to_usr, const struct ctype* to_ct)
+{
+    luaL_Buffer B;
+    struct ctype ft;
+
+    assert(to_type || (to_usr && to_ct));
+    if (to_usr) {
+        to_usr = lua_absindex(L, to_usr);
+    }
+
+    idx = lua_absindex(L, idx);
+
+    luaL_buffinit(L, &B);
+    to_cdata(L, idx, &ft);
+
+    if (ft.type != INVALID_TYPE) {
+        push_type_name(L, -1, &ft);
+        lua_pushfstring(L, "unable to convert argument %d from cdata<%s> to cdata<", idx, lua_tostring(L, -1));
+        lua_remove(L, -2);
+        luaL_addvalue(&B);
+    } else {
+        lua_pushfstring(L, "unable to convert argument %d from lua<%s> to cdata<", idx, luaL_typename(L, idx));
+        luaL_addvalue(&B);
+    }
+
+    if (to_ct) {
+        push_type_name(L, to_usr, to_ct);
+        luaL_addvalue(&B);
+    } else {
+        luaL_addstring(&B, to_type);
+    }
+
+    luaL_addchar(&B, '>');
+
+    luaL_pushresult(&B);
+    return lua_error(L);
+}
+
+static void* userdata_toptr(lua_State* L, int idx)
+{
+    void* ptr = lua_touserdata(L, idx);
+
+    // check for FILE*
+    lua_getmetatable(L, idx);
+    luaL_getmetatable(L, LUA_FILEHANDLE);
+    int isfile = lua_rawequal(L, -1, -2);
+    lua_pop(L, 2);
+
+    if (isfile) {
+#if LUA_VERSION_NUM == 501
+        FILE** stream = (FILE**) ptr;
+        return *stream;
+#else
+        luaL_Stream* stream = (luaL_Stream*) ptr;
+        return stream->f;
+#endif
+    }
+
+    return ptr;
+}
+
+static int cdata_tointeger(lua_State* L, int idx, ptrdiff_t* val)
+{
+    struct ctype ct;
+    void* addr = to_cdata(L, idx, &ct);
+    lua_pop(L, 1);
+
+    if (ct.pointers) {
+        return 0;
+    }
+
+    switch (ct.type) {
+    case INT8_TYPE:
+        *val = *(int8_t*)addr;
+        return 1;
+    case INT16_TYPE:
+        *val = *(int16_t*)addr;
+        return 1;
+    case INT32_TYPE:
+        *val = *(int32_t*)addr;
+        return 1;
+    case INT64_TYPE:
+        *val = *(int64_t*)addr;
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+static int64_t check_intptr(lua_State* L, int idx, void* p, struct ctype* ct)
+{
+    if (ct->type == INVALID_TYPE) {
+        int64_t ret;
+        memset(ct, 0, sizeof(*ct));
+        ct->base_size = 8;
+        ct->type = INT64_TYPE;
+        ct->is_defined = 1;
+        ret = luaL_checknumber(L, idx);
+        return ret;
+
+    } else if (ct->pointers) {
+        return (intptr_t) p;
+    }
+
+    switch (ct->type) {
+    case INTPTR_TYPE:
+    case FUNCTION_PTR_TYPE:
+        return *(intptr_t*) p;
+
+    case INT64_TYPE:
+        return *(int64_t*) p;
+
+    case INT32_TYPE:
+        return ct->is_unsigned ? (int64_t) *(uint32_t*) p : (int64_t) *(int32_t*) p;
+
+    case INT16_TYPE:
+        return ct->is_unsigned ? (int64_t) *(uint16_t*) p : (int64_t) *(int16_t*) p;
+
+    case INT8_TYPE:
+        return ct->is_unsigned ? (int64_t) *(uint8_t*) p : (int64_t) *(int8_t*) p;
+
+    default:
+        type_error(L, idx, "intptr_t", 0, NULL);
+        return 0;
+    }
+}
+
+static int get_cfunction_address(lua_State* L, int idx, cfunction* addr);
+
+#define TO_NUMBER(TYPE, ALLOW_POINTERS, LUA_TONUMBER)                       \
+    TYPE ret = 0;                                                           \
+    void* p;                                                                \
+    struct ctype ct;                                                        \
+    cfunction f;                                                            \
+                                                                            \
+    switch (lua_type(L, idx)) {                                             \
+    case LUA_TBOOLEAN:                                                      \
+        ret = (TYPE) lua_toboolean(L, idx);                                 \
+        break;                                                              \
+                                                                            \
+    case LUA_TNUMBER:                                                       \
+        ret = (TYPE) LUA_TONUMBER(L, idx);                                  \
+        break;                                                              \
+                                                                            \
+    case LUA_TSTRING:                                                       \
+        if (!ALLOW_POINTERS) {                                              \
+            type_error(L, idx, #TYPE, 0, NULL);                             \
+        }                                                                   \
+        ret = (TYPE) (intptr_t) lua_tostring(L, idx);                       \
+        break;                                                              \
+                                                                            \
+    case LUA_TLIGHTUSERDATA:                                                \
+        if (!ALLOW_POINTERS) {                                              \
+            type_error(L, idx, #TYPE, 0, NULL);                             \
+        }                                                                   \
+        ret = (TYPE) (intptr_t) lua_topointer(L, idx);                      \
+        break;                                                              \
+                                                                            \
+    case LUA_TFUNCTION:                                                     \
+        if (!ALLOW_POINTERS) {                                              \
+            type_error(L, idx, #TYPE, 0, NULL);                             \
+        }                                                                   \
+        if (!get_cfunction_address(L, idx, &f)) {                           \
+            type_error(L, idx, #TYPE, 0, NULL);                             \
+        }                                                                   \
+        ret = (TYPE) (intptr_t) f;                                          \
+        break;                                                              \
+                                                                            \
+    case LUA_TUSERDATA:                                                     \
+        p = to_cdata(L, idx, &ct);                                          \
+                                                                            \
+        if (ct.type == INVALID_TYPE) {                                      \
+            if (!ALLOW_POINTERS) {                                          \
+                type_error(L, idx, #TYPE, 0, NULL);                         \
+            }                                                               \
+            ret = (TYPE) (intptr_t) userdata_toptr(L, idx);                 \
+        } else if (ct.pointers || ct.type == STRUCT_TYPE || ct.type == UNION_TYPE) {\
+            if (!ALLOW_POINTERS) {                                          \
+                type_error(L, idx, #TYPE, 0, NULL);                         \
+            }                                                               \
+            ret = (TYPE) (intptr_t) p;                                      \
+        } else if (ct.type == COMPLEX_DOUBLE_TYPE) {                        \
+            ret = (TYPE) creal(*(complex_double*) p);                       \
+        } else if (ct.type == COMPLEX_FLOAT_TYPE) {                         \
+            ret = (TYPE) crealf(*(complex_float*) p);                       \
+        } else if (ct.type == DOUBLE_TYPE) {                                \
+            ret = (TYPE) *(double*) p;                                      \
+        } else if (ct.type == FLOAT_TYPE) {                                 \
+            ret = (TYPE) *(float*) p;                                       \
+        } else {                                                            \
+            ret = check_intptr(L, idx, p, &ct);                             \
+        }                                                                   \
+        lua_pop(L, 1);                                                      \
+        break;                                                              \
+                                                                            \
+    case LUA_TNIL:                                                          \
+        ret = (TYPE) 0;                                                     \
+        break;                                                              \
+                                                                            \
+    default:                                                                \
+        type_error(L, idx, #TYPE, 0, NULL);                                 \
+    }                                                                       \
+
+static int64_t cast_int64(lua_State* L, int idx, int is_cast)
+{ TO_NUMBER(int64_t, is_cast, lua_tointeger); return ret; }
+
+static uint64_t cast_uint64(lua_State* L, int idx, int is_cast)
+{ TO_NUMBER(uint64_t, is_cast, lua_tointeger); return ret; }
+
+int32_t check_int32(lua_State* L, int idx)
+{ return (int32_t) cast_int64(L, idx, 0); }
+
+uint32_t check_uint32(lua_State* L, int idx)
+{ return (uint32_t) cast_uint64(L, idx, 0); }
+
+int64_t check_int64(lua_State* L, int idx)
+{ return cast_int64(L, idx, 0); }
+
+uint64_t check_uint64(lua_State* L, int idx)
+{ return cast_uint64(L, idx, 0); }
+
+double check_double(lua_State* L, int idx)
+{ TO_NUMBER(double, 0, lua_tonumber); return ret; }
+
+float check_float(lua_State* L, int idx)
+{ TO_NUMBER(double, 0, lua_tonumber); return ret; }
+
+uintptr_t check_uintptr(lua_State* L, int idx)
+{ TO_NUMBER(uintptr_t, 1, lua_tointeger); return ret; }
+
+complex_double check_complex_double(lua_State* L, int idx)
+{
+    double real = 0, imag = 0;
+    void* p;
+    struct ctype ct;
+
+    switch (lua_type(L, idx)) {
+    case LUA_TNUMBER:
+        real = (double) lua_tonumber(L, idx);
+        break;
+    case LUA_TTABLE:
+        lua_rawgeti(L, idx, 1);
+        real = check_double(L, -1);
+        lua_pop(L, 1);
+
+        lua_rawgeti(L, idx, 2);
+        if (lua_isnil(L, -1)) {
+            imag = real;
+        }  else {
+            imag = check_double(L, -1);
+        }
+        lua_pop(L, 1);
+        break;
+    case LUA_TUSERDATA:
+        p = to_cdata(L, idx, &ct);
+        if (ct.type == COMPLEX_DOUBLE_TYPE) {
+            real = creal(*(complex_double*) p);
+            imag = cimag(*(complex_double*) p);
+        } else if (ct.type == COMPLEX_FLOAT_TYPE) {
+            real = crealf(*(complex_float*) p);
+            imag = cimagf(*(complex_float*) p);
+        } else if (ct.type == DOUBLE_TYPE) {
+            real = *(double*) p;
+        } else if (ct.type == FLOAT_TYPE) {
+            real = *(float*) p;
+        } else {
+            real = check_intptr(L, idx, p, &ct);
+        }
+        lua_pop(L, 1);
+        break;
+
+    default:
+        type_error(L, idx, "complex", 0, NULL);
+    }
+
+    return mk_complex_double(real, imag);
+}
+
+complex_float check_complex_float(lua_State* L, int idx)
+{
+    complex_double d = check_complex_double(L, idx);
+    return mk_complex_float(creal(d), cimag(d));
+}
+
+static size_t unpack_vararg(lua_State* L, int i, char* to)
+{
+    void* p;
+    struct ctype ct;
+
+    switch (lua_type(L, i)) {
+    case LUA_TBOOLEAN:
+        *(int*) to = lua_toboolean(L, i);
+        return sizeof(int);
+
+    case LUA_TNUMBER:
+        *(double*) to = lua_tonumber(L, i); // TODO in Lua 5.3: lua_tointeger sometimes should be here
+        return sizeof(double);
+
+    case LUA_TSTRING:
+        *(const char**) to = lua_tostring(L, i);
+        return sizeof(const char*);
+
+    case LUA_TLIGHTUSERDATA:
+        *(void**) to = lua_touserdata(L, i);
+        return sizeof(void*);
+
+    case LUA_TUSERDATA:
+        p = to_cdata(L, i, &ct);
+        lua_pop(L, 1);
+
+        if (ct.type == INVALID_TYPE) {
+            *(void**) to = userdata_toptr(L, i);
+            return sizeof(void*);
+
+        } else if (ct.pointers || ct.type == INTPTR_TYPE) {
+            *(void**) to = p;
+            return sizeof(void*);
+
+        } else if (ct.type == INT32_TYPE) {
+            *(int32_t*) to = *(int32_t*) p;
+            return sizeof(int32_t);
+
+        } else if (ct.type == INT64_TYPE) {
+            *(int64_t*) to = *(int64_t*) p;
+            return sizeof(int64_t);
+        }
+        goto err;
+
+    case LUA_TNIL:
+        *(void**) to = NULL;
+        return sizeof(void*);
+
+    default:
+        goto err;
+    }
+
+err:
+    return type_error(L, i, "vararg", 0, NULL);
+}
+
+void unpack_varargs_stack(lua_State* L, int first, int last, char* to)
+{
+    int i;
+
+    for (i = first; i <= last; i++) {
+        to += unpack_vararg(L, i, to);
+    }
+}
+
+void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_skip, int floats_to_skip, char* to)
+{
+    int i;
+
+    for (i = first; i <= last; i++) {
+        int type = lua_type(L, i);
+
+        if (type == LUA_TNUMBER && --floats_to_skip >= 0) {
+            continue;
+        } else if (type != LUA_TNUMBER && --ints_to_skip >= 0) {
+            continue;
+        }
+
+        to += unpack_vararg(L, i, to);
+    }
+}
+
+void unpack_varargs_float(lua_State* L, int first, int last, int max, char* to)
+{
+    int i;
+
+    for (i = first; i <= last && max > 0; i++) {
+        if (lua_type(L, i) == LUA_TNUMBER) {
+            unpack_vararg(L, i, to);
+            to += sizeof(double);
+            max--;
+        }
+    }
+}
+
+void unpack_varargs_int(lua_State* L, int first, int last, int max, char* to)
+{
+    int i;
+
+    for (i = first; i <= last && max > 0; i++) {
+        if (lua_type(L, i) != LUA_TNUMBER) {
+            unpack_vararg(L, i, to);
+            to += sizeof(void*);
+            max--;
+        }
+    }
+}
+
+void unpack_varargs_reg(lua_State* L, int first, int last, char* to)
+{
+    int i;
+
+    for (i = first; i <= last; i++) {
+        unpack_vararg(L, i, to);
+        to += sizeof(double);
+    }
+}
+
+/* to_enum tries to convert a value at idx to the enum type indicated by to_ct
+ * and uv to_usr. For strings this means it will do a string lookup for the
+ * enum type. It leaves the stack unchanged. Will throw an error if the type
+ * at idx can't be conerted.
+ */
+int32_t check_enum(lua_State* L, int idx, int to_usr, const struct ctype* to_ct)
+{
+    int32_t ret;
+
+    switch (lua_type(L, idx)) {
+    case LUA_TSTRING:
+        /* lookup string in to_usr to find value */
+        to_usr = lua_absindex(L, to_usr);
+        lua_pushvalue(L, idx);
+        lua_rawget(L, to_usr);
+
+        if (lua_isnil(L, -1)) {
+            goto err;
+        }
+
+        ret = (int32_t) lua_tointeger(L, -1);
+        lua_pop(L, 1);
+        return ret;
+
+    case LUA_TUSERDATA:
+        return check_int32(L, idx);
+
+    case LUA_TNIL:
+        return (int32_t) 0;
+
+    case LUA_TNUMBER:
+        return (int32_t) lua_tointeger(L, idx);
+
+    default:
+        goto err;
+    }
+
+err:
+    return type_error(L, idx, NULL, to_usr, to_ct);
+}
+
+/* to_pointer tries converts a value at idx to a pointer. It fills out ct and
+ * pushes the uv of the found type. It will throw a lua error if it can not
+ * convert the value to a pointer. */
+static void* check_pointer(lua_State* L, int idx, struct ctype* ct)
+{
+    void* p;
+    memset(ct, 0, sizeof(*ct));
+    idx = lua_absindex(L, idx);
+
+    switch (lua_type(L, idx)) {
+    case LUA_TNIL:
+        ct->type = VOID_TYPE;
+        ct->pointers = 1;
+        ct->is_null = 1;
+        lua_pushnil(L);
+        return NULL;
+
+    case LUA_TNUMBER:
+        ct->type = INTPTR_TYPE;
+        ct->is_unsigned = 1;
+        ct->pointers = 0;
+        lua_pushnil(L);
+        return (void*) (uintptr_t) lua_tonumber(L, idx); // TODO in Lua 5.3: maybe change to lua_tointeger
+
+    case LUA_TLIGHTUSERDATA:
+        ct->type = VOID_TYPE;
+        ct->pointers = 1;
+        lua_pushnil(L);
+        return lua_touserdata(L, idx);
+
+    case LUA_TSTRING:
+        ct->type = INT8_TYPE;
+        ct->pointers = 1;
+        ct->is_unsigned = IS_CHAR_UNSIGNED;
+        ct->is_array = 1;
+        ct->base_size = 1;
+        ct->const_mask = 2;
+        lua_pushnil(L);
+        return (void*) lua_tolstring(L, idx, &ct->array_size);
+
+    case LUA_TUSERDATA:
+        p = to_cdata(L, idx, ct);
+
+        if (ct->type == INVALID_TYPE) {
+            /* some other type of user data */
+            ct->type = VOID_TYPE;
+            ct->pointers = 1;
+            return userdata_toptr(L, idx);
+        } else if (ct->type == STRUCT_TYPE || ct->type == UNION_TYPE) {
+            return p;
+        } else {
+            return (void*) (intptr_t) check_intptr(L, idx, p, ct);
+        }
+        break;
+    }
+
+    type_error(L, idx, "pointer", 0, NULL);
+    return NULL;
+}
+
+static int is_void_ptr(const struct ctype* ct)
+{
+    return ct->type == VOID_TYPE
+        && ct->pointers == 1;
+}
+
+static int is_same_type(lua_State* L, int usr1, int usr2, const struct ctype* t1, const struct ctype* t2)
+{
+    if (t1->type != t2->type) {
+        return 0;
+    }
+
+#if LUA_VERSION_NUM == 501
+    if (lua_isnil(L, usr1) != lua_isnil(L, usr2)) {
+        int ret;
+        usr1 = lua_absindex(L, usr1);
+        usr2 = lua_absindex(L, usr2);
+        push_upval(L, &niluv_key);
+
+        ret = lua_rawequal(L, usr1, -1)
+            || lua_rawequal(L, usr2, -1);
+
+        lua_pop(L, 1);
+
+        if (ret) {
+            return 1;
+        }
+    }
+#endif
+
+    return lua_rawequal(L, usr1, usr2);
+}
+
+static void set_struct(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers);
+
+/* to_typed_pointer converts a value at idx to a type tt with target uv to_usr
+ * checking all types. May push a temporary value so that it can create
+ * structs on the fly. */
+void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* tt)
+{
+    struct ctype ft;
+    void* p;
+
+    to_usr = lua_absindex(L, to_usr);
+    idx = lua_absindex(L, idx);
+
+    if (tt->pointers == 1 && (tt->type == STRUCT_TYPE || tt->type == UNION_TYPE) && lua_type(L, idx) == LUA_TTABLE) {
+        /* need to construct a struct of the target type */
+        struct ctype ct = *tt;
+        ct.pointers = ct.is_array = 0;
+        p = push_cdata(L, to_usr, &ct);
+        set_struct(L, idx, p, to_usr, &ct, 1);
+        return p;
+    }
+
+    p = check_pointer(L, idx, &ft);
+
+    if (tt->pointers == 1 && ft.pointers == 0 && (ft.type == STRUCT_TYPE || ft.type == UNION_TYPE)) {
+        /* auto dereference structs */
+        ft.pointers = 1;
+        ft.const_mask <<= 1;
+    }
+
+    if (is_void_ptr(tt)) {
+        /* any pointer can convert to void* */
+        goto suc;
+
+    } else if (is_void_ptr(&ft) && (ft.pointers || ft.is_reference)) {
+        /* void* can convert to any pointer */
+        goto suc;
+
+    } else if (ft.is_null) {
+        /* NULL can convert to any pointer */
+        goto suc;
+
+    } else if (!is_same_type(L, to_usr, -1, tt, &ft)) {
+        /* the base type is different */
+        goto err;
+
+    } else if (tt->pointers != ft.pointers) {
+        goto err;
+
+    } else if (ft.const_mask & ~tt->const_mask) {
+        /* for every const in from it must be in to, there are further rules
+         * for const casting (see the c++ spec), but they are hard to test
+         * quickly */
+        goto err;
+    }
+
+suc:
+    return p;
+
+err:
+    type_error(L, idx, NULL, to_usr, tt);
+    return NULL;
+}
+
+/**
+ * gets the address of the wrapped C function for the lua function value at idx
+ * and returns 1 if it exists; otherwise returns 0 and nothing is pushed */
+static int get_cfunction_address(lua_State* L, int idx, cfunction* addr)
+{
+    if (!lua_isfunction(L, idx)) return 0;
+
+    int top = lua_gettop(L);
+
+    // Get the last upvalue
+    int n = 2;
+    while (lua_getupvalue(L, idx, n)) {
+        lua_pop(L, 1);
+        n++;
+    }
+
+    if (!lua_getupvalue(L, idx, n - 1))
+        return 0;
+
+    if (!lua_isuserdata(L, -1) || !lua_getmetatable(L, -1)) {
+        lua_pop(L, 1);
+        return 0;
+    }
+
+    push_upval(L, &callback_mt_key);
+    if (!lua_rawequal(L, -1, -2)) {
+        lua_pop(L, 3);
+        return 0;
+    }
+
+    /* stack is:
+     * userdata upval
+     * metatable
+     * callback_mt
+     */
+
+    cfunction* f = lua_touserdata(L, -3);
+    *addr = f[1];
+    lua_pop(L, 3);
+    return 1;
+}
+
+/* to_cfunction converts a value at idx with usr table at to_usr and type tt
+ * into a function. Leaves the stack unchanged. */
+static cfunction check_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt, int check_pointers)
+{
+    void* p;
+    struct ctype ft;
+    cfunction f;
+    int top = lua_gettop(L);
+
+    idx = lua_absindex(L, idx);
+    to_usr = lua_absindex(L, to_usr);
+
+    switch (lua_type(L, idx)) {
+    case LUA_TFUNCTION:
+        if (get_cfunction_address(L, idx, &f)) {
+            return f;
+        }
+
+        /* Function cdatas are pinned and must be manually cleaned up by
+         * calling func:free(). */
+        push_upval(L, &callbacks_key);
+        f = compile_callback(L, idx, to_usr, tt);
+        lua_pushboolean(L, 1);
+        lua_rawset(L, -3);
+        lua_pop(L, 1); /* callbacks tbl */
+        return f;
+
+    case LUA_TNIL:
+        return NULL;
+
+    case LUA_TLIGHTUSERDATA:
+        if (check_pointers) {
+            goto err;
+        } else {
+            return (cfunction) lua_touserdata(L, idx);
+        }
+
+    case LUA_TUSERDATA:
+        p = to_cdata(L, idx, &ft);
+        assert(lua_gettop(L) == top + 1);
+
+        if (ft.type == INVALID_TYPE) {
+            if (check_pointers) {
+                goto err;
+            } else {
+                lua_pop(L, 1);
+                return (cfunction) lua_touserdata(L, idx);
+            }
+
+        } else if (ft.is_null) {
+            lua_pop(L, 1);
+            return NULL;
+
+        } else if (!check_pointers && (ft.pointers || ft.type == INTPTR_TYPE)) {
+            lua_pop(L, 1);
+            return (cfunction) *(void**) p;
+
+        } else if (ft.type != FUNCTION_PTR_TYPE) {
+            goto err;
+
+        } else if (!check_pointers) {
+            lua_pop(L, 1);
+            return *(cfunction*) p;
+
+        } else if (ft.calling_convention != tt->calling_convention) {
+            goto err;
+
+        } else if (!is_same_type(L, -1, to_usr, &ft, tt)) {
+            goto err;
+
+        } else {
+            lua_pop(L, 1);
+            return *(cfunction*) p;
+        }
+
+    default:
+        goto err;
+    }
+
+err:
+    type_error(L, idx, NULL, to_usr, tt);
+    return NULL;
+}
+
+/* to_type_cfunction converts a value at idx with uv at to_usr and type tt to
+ * a cfunction. Leaves the stack unchanged. */
+cfunction check_typed_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt)
+{ return check_cfunction(L, idx, to_usr, tt, 1); }
+
+static void set_value(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers);
+
+static void set_array(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers)
+{
+    size_t i, sz, esz;
+    struct ctype et;
+
+    idx = lua_absindex(L, idx);
+    to_usr = lua_absindex(L, to_usr);
+
+    switch (lua_type(L, idx)) {
+    case LUA_TSTRING:
+        if (tt->pointers == 1 && tt->type == INT8_TYPE) {
+            const char* str = lua_tolstring(L, idx, &sz);
+
+            if (!tt->is_variable_array && sz >= tt->array_size) {
+                memcpy(to, str, tt->array_size);
+            } else {
+                /* include nul terminator */
+                memcpy(to, str, sz+1);
+            }
+        } else {
+            goto err;
+        }
+        break;
+
+    case LUA_TTABLE:
+        et = *tt;
+        et.pointers--;
+        et.const_mask >>= 1;
+        et.is_array = 0;
+        esz = et.pointers ? sizeof(void*) : et.base_size;
+
+        lua_rawgeti(L, idx, 2);
+
+        if (tt->is_variable_array) {
+            /* we have no idea how big the array is, so set values based off
+             * how many items were given to us */
+            lua_pop(L, 1);
+            for (i = 0; i < lua_rawlen(L, idx); i++) {
+                lua_rawgeti(L, idx, (int) i + 1);
+                set_value(L, -1, (char*) to + esz * i, to_usr, &et, check_pointers);
+                lua_pop(L, 1);
+            }
+
+        } else if (lua_isnil(L, -1)) {
+            /* there is no second element, so we set the whole array to the
+             * first element (or nil - ie 0) if there is no first element) */
+            lua_pop(L, 1);
+            lua_rawgeti(L, idx, 1);
+
+            if (lua_isnil(L, -1)) {
+                memset(to, 0, ctype_size(L, tt));
+            } else {
+                /* if its still variable we have no idea how many values to set */
+                for (i = 0; i < tt->array_size; i++) {
+                    set_value(L, -1, (char*) to + esz * i, to_usr, &et, check_pointers);
+                }
+            }
+
+            lua_pop(L, 1);
+
+        } else {
+            /* there is a second element, so we set each element using the
+             * equiv index in the table initializer */
+            lua_pop(L, 1);
+            for (i = 0; i < tt->array_size; i++) {
+                lua_rawgeti(L, idx, (int) (i+1));
+
+                if (lua_isnil(L, -1)) {
+                    /* we've hit the end of the values provided in the
+                     * initializer, so memset the rest to zero */
+                    lua_pop(L, 1);
+                    memset((char*) to + esz * i, 0, (tt->array_size - i) * esz);
+                    break;
+
+                } else {
+                    set_value(L, -1, (char*) to + esz * i, to_usr, &et, check_pointers);
+                    lua_pop(L, 1);
+                }
+            }
+        }
+        break;
+
+    default:
+        goto err;
+    }
+
+    return;
+
+err:
+    type_error(L, idx, NULL, to_usr, tt);
+}
+
+/* pops the member key from the stack, leaves the member user value on the
+ * stack. Returns the member offset. Returns -ve if the member can not be
+ * found. */
+static ptrdiff_t get_member(lua_State* L, int usr, const struct ctype* ct, struct ctype* mt)
+{
+    ptrdiff_t off;
+    lua_rawget(L, usr);
+
+    if (lua_isnil(L, -1)) {
+        lua_pop(L, 1);
+        return -1;
+    }
+
+    *mt = *(const struct ctype*) lua_touserdata(L, -1);
+    lua_getuservalue(L, -1);
+    lua_replace(L, -2);
+
+    if (mt->is_variable_array && ct->variable_size_known) {
+        /* eg char mbr[?] */
+        size_t sz = (mt->pointers > 1) ? sizeof(void*) : mt->base_size;
+        assert(ct->is_variable_struct && mt->is_array);
+        mt->array_size = ct->variable_increment / sz;
+        mt->is_variable_array = 0;
+
+    } else if (mt->is_variable_struct && ct->variable_size_known) {
+        /* eg struct {char a; char b[?]} mbr; */
+        assert(ct->is_variable_struct);
+        mt->variable_size_known = 1;
+        mt->variable_increment = ct->variable_increment;
+    }
+
+    off = mt->offset;
+    mt->offset = 0;
+    return off;
+}
+
+static void set_struct(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers)
+{
+    int have_first = 0;
+    int have_other = 0;
+    struct ctype mt;
+    void* p;
+
+    to_usr = lua_absindex(L, to_usr);
+    idx = lua_absindex(L, idx);
+
+    switch (lua_type(L, idx)) {
+    case LUA_TTABLE:
+        /* match up to the members based off the table initializers key - this
+         * will match both numbered and named members in the user table
+         * we need a special case for when no entries in the initializer -
+         * zero initialize the c struct, and only one entry in the initializer
+         * - set all members to this value */
+        memset(to, 0, ctype_size(L, tt));
+        lua_pushnil(L);
+        while (lua_next(L, idx)) {
+            ptrdiff_t off;
+
+            if (!have_first && lua_tonumber(L, -2) == 1 && lua_tonumber(L, -1) != 0) {
+                have_first = 1;
+            } else if (!have_other && (lua_type(L, -2) != LUA_TNUMBER || lua_tonumber(L, -2) != 1)) {
+                have_other = 1;
+            }
+
+            lua_pushvalue(L, -2);
+            off = get_member(L, to_usr, tt, &mt);
+            assert(off >= 0);
+            set_value(L, -2, (char*) to + off, -1, &mt, check_pointers);
+
+            /* initializer value, mt usr */
+            lua_pop(L, 2);
+        }
+
+        /* if we only had a single non zero value then initialize all members to that value */
+        if (!have_other && have_first && tt->type != UNION_TYPE) {
+            size_t i, sz;
+            ptrdiff_t off;
+            lua_rawgeti(L, idx, 1);
+            sz = lua_rawlen(L, to_usr);
+
+            for (i = 2; i < sz; i++) {
+                lua_pushinteger(L, i);
+                off = get_member(L, to_usr, tt, &mt);
+                assert(off >= 0);
+                set_value(L, -2, (char*) to + off, -1, &mt, check_pointers);
+                lua_pop(L, 1); /* mt usr */
+            }
+
+            lua_pop(L, 1); /* initializer table */
+        }
+        break;
+
+    case LUA_TUSERDATA:
+        if (check_pointers) {
+            p = check_typed_pointer(L, idx, to_usr, tt);
+        } else {
+            struct ctype ct;
+            p = check_pointer(L, idx, &ct);
+        }
+        memcpy(to, p, tt->base_size);
+        lua_pop(L, 1);
+        break;
+
+    default:
+        goto err;
+    }
+
+    return;
+
+err:
+    type_error(L, idx, NULL, to_usr, tt);
+}
+
+static void set_value(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers)
+{
+    int top = lua_gettop(L);
+
+    if (tt->is_array) {
+        set_array(L, idx, to, to_usr, tt, check_pointers);
+
+    } else if (tt->pointers || tt->is_reference) {
+        union {
+            uint8_t c[sizeof(void*)];
+            void* p;
+        } u;
+
+        if (lua_istable(L, idx)) {
+            luaL_error(L, "Can't set a pointer member to a struct that's about to be freed");
+        }
+
+        if (check_pointers) {
+            u.p = check_typed_pointer(L, idx, to_usr, tt);
+        } else {
+            struct ctype ct;
+            u.p = check_pointer(L, idx, &ct);
+        }
+
+#ifndef ALLOW_MISALIGNED_ACCESS
+        if ((uintptr_t) to & PTR_ALIGN_MASK) {
+            memcpy(to, u.c, sizeof(void*));
+        } else
+#endif
+        {
+            *(void**) to = u.p;
+        }
+
+        lua_pop(L, 1);
+
+    } else if (tt->is_bitfield) {
+
+        uint64_t hi_mask = UINT64_C(0) - (UINT64_C(1) << (tt->bit_offset + tt->bit_size));
+        uint64_t low_mask = (UINT64_C(1) << tt->bit_offset) - UINT64_C(1);
+        uint64_t val = check_uint64(L, idx);
+        val &= (UINT64_C(1) << tt->bit_size) - 1;
+        val <<= tt->bit_offset;
+        *(uint64_t*) to = val | (*(uint64_t*) to & (hi_mask | low_mask));
+
+    } else if (tt->type == STRUCT_TYPE || tt->type == UNION_TYPE) {
+        set_struct(L, idx, to, to_usr, tt, check_pointers);
+
+    } else {
+
+#ifndef ALLOW_MISALIGNED_ACCESS
+        union {
+            uint8_t c[8];
+            _Bool b;
+            uint64_t u64;
+            float f;
+            double d;
+            cfunction func;
+        } misalign;
+
+        void* origto = to;
+
+        if ((uintptr_t) origto & (tt->base_size - 1)) {
+            to = misalign.c;
+        }
+#endif
+
+        switch (tt->type) {
+        case BOOL_TYPE:
+            *(_Bool*) to = (cast_int64(L, idx, !check_pointers) != 0);
+            break;
+        case INT8_TYPE:
+            if (tt->is_unsigned) {
+                *(uint8_t*) to = (uint8_t) cast_uint64(L, idx, !check_pointers);
+            } else {
+                *(int8_t*) to = (int8_t) cast_int64(L, idx, !check_pointers);
+            }
+            break;
+        case INT16_TYPE:
+            if (tt->is_unsigned) {
+                *(uint16_t*) to = (uint16_t) cast_uint64(L, idx, !check_pointers);
+            } else {
+                *(int16_t*) to = (int16_t) cast_int64(L, idx, !check_pointers);
+            }
+            break;
+        case INT32_TYPE:
+            if (tt->is_unsigned) {
+                *(uint32_t*) to = (uint32_t) cast_uint64(L, idx, !check_pointers);
+            } else {
+                *(int32_t*) to = (int32_t) cast_int64(L, idx, !check_pointers);
+            }
+            break;
+        case INT64_TYPE:
+            if (tt->is_unsigned) {
+                *(uint64_t*) to = cast_uint64(L, idx, !check_pointers);
+            } else {
+                *(int64_t*) to = cast_int64(L, idx, !check_pointers);
+            }
+            break;
+        case FLOAT_TYPE:
+            *(float*) to = (float) check_double(L, idx);
+            break;
+        case DOUBLE_TYPE:
+            *(double*) to = check_double(L, idx);
+            break;
+        case COMPLEX_FLOAT_TYPE:
+            *(complex_float*) to = check_complex_float(L, idx);
+            break;
+        case COMPLEX_DOUBLE_TYPE:
+            *(complex_double*) to = check_complex_double(L, idx);
+            break;
+        case INTPTR_TYPE:
+            *(uintptr_t*) to = check_uintptr(L, idx);
+            break;
+        case ENUM_TYPE:
+            *(int32_t*) to = check_enum(L, idx, to_usr, tt);
+            break;
+        case FUNCTION_PTR_TYPE:
+            *(cfunction*) to = check_cfunction(L, idx, to_usr, tt, check_pointers);
+            break;
+        default:
+            goto err;
+        }
+
+#ifndef ALLOW_MISALIGNED_ACCESS
+        if ((uintptr_t) origto & (tt->base_size - 1)) {
+            memcpy(origto, misalign.c, tt->base_size);
+        }
+#endif
+    }
+
+    assert(lua_gettop(L) == top);
+    return;
+err:
+    type_error(L, idx, NULL, to_usr, tt);
+}
+
+static int ffi_typeof(lua_State* L)
+{
+    struct ctype ct;
+    check_ctype(L, 1, &ct);
+    push_ctype(L, -1, &ct);
+    return 1;
+}
+
+static void setmintop(lua_State* L, int idx)
+{
+    if (lua_gettop(L) < idx) {
+        lua_settop(L, idx);
+    }
+}
+
+/* warning: in the case that it finds an array size, it removes that index */
+static void get_variable_array_size(lua_State* L, int idx, struct ctype* ct)
+{
+    /* we only care about the variable buisness for the variable array
+     * directly ie ffi.new('char[?]') or the struct that contains the variable
+     * array ffi.new('struct {char v[?]}'). A pointer to the struct doesn't
+     * care about the variable size (it treats it as a zero sized array). */
+
+    if (ct->is_variable_array) {
+        assert(ct->is_array);
+        ct->array_size = (size_t) luaL_checknumber(L, idx);
+        ct->is_variable_array = 0;
+        lua_remove(L, idx);
+
+    } else if (ct->is_variable_struct && !ct->variable_size_known) {
+        assert(ct->type == STRUCT_TYPE && !ct->is_array);
+        ct->variable_increment *= (size_t) luaL_checknumber(L, idx);
+        ct->variable_size_known = 1;
+        lua_remove(L, idx);
+    }
+}
+
+static int is_scalar(struct ctype* ct)
+{
+    int type = ct->type;
+    if (ct->pointers || ct->is_reference) {
+        return !ct->is_array;
+    }
+    return type != STRUCT_TYPE && type != UNION_TYPE && !IS_COMPLEX(type);
+}
+
+static int should_pack(lua_State *L, int ct_usr, struct ctype* ct, int idx)
+{
+    struct ctype argt;
+    ct_usr = lua_absindex(L, ct_usr);
+
+    if (IS_COMPLEX(ct->type)) {
+        return 0;
+    }
+
+    switch (lua_type(L, idx)) {
+    case LUA_TTABLE:
+        return 0;
+    case LUA_TSTRING:
+        return ct->type == STRUCT_TYPE;
+    case LUA_TUSERDATA:
+        // don't pack if the argument is a cdata with the same type
+        to_cdata(L, idx, &argt);
+        int same = is_same_type(L, ct_usr, -1, ct, &argt);
+        lua_pop(L, 1);
+        return !same;
+    default:
+        return 1;
+    }
+}
+
+static int do_new(lua_State* L, int is_cast)
+{
+    int cargs, i;
+    void* p;
+    struct ctype ct;
+    int check_ptrs = !is_cast;
+
+    check_ctype(L, 1, &ct);
+
+    /* don't push a callback when we have a c function, as cb:set needs a
+     * compiled callback from a lua function to work */
+    if (!ct.pointers && ct.type == FUNCTION_PTR_TYPE && (lua_isnil(L, 2) || lua_isfunction(L, 2))) {
+        // Get the bound C function if this is a ffi lua function
+        cfunction func;
+        if (get_cfunction_address(L, 2, &func)) {
+            p = push_cdata(L, -1, &ct);
+            *(cfunction*) p = func;
+            return 1;
+        }
+
+        /* Function cdatas are pinned and must be manually cleaned up by
+         * calling func:free(). */
+        compile_callback(L, 2, -1, &ct);
+        push_upval(L, &callbacks_key);
+        lua_pushvalue(L, -2);
+        lua_pushboolean(L, 1);
+        lua_rawset(L, -3);
+        lua_pop(L, 1); /* callbacks tbl */
+        return 1;
+    }
+
+    /* this removes the vararg argument if its needed, and errors if its invalid */
+    if (!is_cast) {
+        get_variable_array_size(L, 2, &ct);
+    }
+
+    p = push_cdata(L, -1, &ct);
+
+    /* if the user mt has a __gc function then call ffi.gc on this value */
+    if (push_user_mt(L, -2, &ct)) {
+        push_upval(L, &gc_key);
+        lua_pushvalue(L, -3);
+
+        /* user_mt.__gc */
+        lua_pushliteral(L, "__gc");
+        lua_rawget(L, -4);
+
+        lua_rawset(L, -3); /* gc_upval[cdata] = user_mt.__gc */
+        lua_pop(L, 2); /* user_mt and gc_upval */
+    }
+
+    /* stack is:
+     * ctype arg
+     * ctor args ... 0+
+     * ctype usr
+     * cdata
+     */
+
+    cargs = lua_gettop(L) - 3;
+
+    if (cargs == 0) {
+        return 1;
+    }
+
+    int scalar = is_scalar(&ct);
+    if (scalar && cargs > 1) {
+        return luaL_error(L, "too many initializers");
+    }
+
+    if (cargs > 1 || (!scalar && should_pack(L, -2, &ct, 2))) {
+        lua_createtable(L, cargs, 0);
+        lua_replace(L, 1);
+        for (i = 1; i <= cargs; i++) {
+            lua_pushvalue(L, i + 1);
+            lua_rawseti(L, 1, i);
+        }
+        assert(lua_gettop(L) == cargs + 3);
+        set_value(L, 1, p, -2, &ct, check_ptrs);
+        return 1;
+    }
+
+    set_value(L, 2, p, -2, &ct, check_ptrs);
+    return 1;
+}
+
+static int ffi_new(lua_State* L)
+{ return do_new(L, 0); }
+
+static int ffi_cast(lua_State* L)
+{ return do_new(L, 1); }
+
+static int ctype_new(lua_State* L)
+{ return do_new(L, 0); }
+
+static int ctype_call(lua_State* L)
+{
+    struct ctype ct;
+    int top = lua_gettop(L);
+
+    check_ctype(L, 1, &ct);
+
+    if (push_user_mt(L, -1, &ct)) {
+        lua_pushstring(L, "__new");
+        lua_rawget(L, -2);
+        if (!lua_isnil(L, -1)) {
+            lua_insert(L, 1); // function at bottom of stack under args
+            lua_pop(L, 2);
+            lua_call(L, top, 1);
+            return 1;
+        }
+        lua_pop(L, 2);
+    }
+    lua_pop(L, 1);
+
+    assert(lua_gettop(L) == top);
+    return do_new(L, 0);
+}
+
+static int ffi_sizeof(lua_State* L)
+{
+    struct ctype ct;
+    check_ctype(L, 1, &ct);
+    get_variable_array_size(L, 2, &ct);
+    lua_pushinteger(L, ctype_size(L, &ct));
+    return 1;
+}
+
+static int ffi_alignof(lua_State* L)
+{
+    struct ctype ct, mt;
+    lua_settop(L, 2);
+    check_ctype(L, 1, &ct);
+
+    /* if no member is specified then we return the alignment of the type */
+    if (lua_isnil(L, 2)) {
+        lua_pushinteger(L, ct.align_mask + 1);
+        return 1;
+    }
+
+    /* get the alignment of the member */
+    lua_pushvalue(L, 2);
+    if (get_member(L, -2, &ct, &mt) < 0) {
+        push_type_name(L, 3, &ct);
+        return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2));
+    }
+
+    lua_pushinteger(L, mt.align_mask + 1);
+    return 1;
+}
+
+static int ffi_offsetof(lua_State* L)
+{
+    ptrdiff_t off;
+    struct ctype ct, mt;
+    lua_settop(L, 2);
+    check_ctype(L, 1, &ct);
+
+    lua_pushvalue(L, 2);
+    off = get_member(L, -2, &ct, &mt); /* this replaces the member key at -1 with the mbr usr value */
+    if (off < 0) {
+        push_type_name(L, 3, &ct);
+        return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2));
+    }
+
+    lua_pushinteger(L, off);
+
+    if (!mt.is_bitfield) {
+        return 1;
+    }
+
+    lua_pushinteger(L, mt.bit_offset);
+    lua_pushinteger(L, mt.bit_size);
+    return 3;
+}
+
+static int ffi_istype(lua_State* L)
+{
+    struct ctype tt, ft;
+    check_ctype(L, 1, &tt);
+    to_cdata(L, 2, &ft);
+
+    if (ft.type == INVALID_TYPE) {
+        goto fail;
+    }
+
+    if (!is_same_type(L, 3, 4, &tt, &ft)) {
+        goto fail;
+    }
+
+    if (tt.pointers != ft.pointers) {
+        goto fail;
+    }
+
+    if (tt.is_array != ft.is_array) {
+        goto fail;
+    }
+
+    if (tt.is_array && tt.array_size != ft.array_size) {
+        goto fail;
+    }
+
+    if (tt.calling_convention != ft.calling_convention) {
+        goto fail;
+    }
+
+    lua_pushboolean(L, 1);
+    return 1;
+
+fail:
+    lua_pushboolean(L, 0);
+    return 1;
+}
+
+static int cdata_gc(lua_State* L)
+{
+    struct ctype ct;
+    check_cdata(L, 1, &ct);
+    lua_settop(L, 1);
+
+    /* call the gc func if there is any registered */
+    lua_pushvalue(L, 1);
+    lua_rawget(L, lua_upvalueindex(2));
+    if (!lua_isnil(L, -1)) {
+        lua_pushvalue(L, 1);
+        lua_pcall(L, 1, 0, 0);
+    }
+
+    /* unset the closure */
+    lua_pushvalue(L, 1);
+    lua_pushnil(L);
+    lua_rawset(L, lua_upvalueindex(1));
+
+    return 0;
+}
+
+static int callback_free(lua_State* L)
+{
+    cfunction* p = (cfunction*) lua_touserdata(L, 1);
+    // FIXME: temporarily disabled to prevent SIGTRAP on exit
+    // free_code(get_jit(L), L, *p);
+    return 0;
+}
+
+static int cdata_free(lua_State* L)
+{
+    struct ctype ct;
+    cfunction* p = (cfunction*) check_cdata(L, 1, &ct);
+    lua_settop(L, 1);
+
+    /* unset the closure */
+    lua_pushvalue(L, 1);
+    lua_pushnil(L);
+    lua_rawset(L, lua_upvalueindex(1));
+
+    if (ct.is_jitted) {
+        free_code(get_jit(L), L, *p);
+        *p = NULL;
+    }
+
+    return 0;
+}
+
+static int cdata_set(lua_State* L)
+{
+    struct ctype ct;
+    cfunction* p = (cfunction*) check_cdata(L, 1, &ct);
+    luaL_checktype(L, 2, LUA_TFUNCTION);
+
+    if (!ct.is_jitted) {
+        luaL_error(L, "can't set the function for a non-lua callback");
+    }
+
+    if (*p == NULL) {
+        luaL_error(L, "can't set the function for a free'd callback");
+    }
+
+    push_func_ref(L, *p);
+    lua_pushvalue(L, 2);
+    lua_rawseti(L, -2, CALLBACK_FUNC_USR_IDX);
+
+    /* remove the closure for this callback as it embeds the function pointer
+     * value */
+    lua_pushvalue(L, 1);
+    lua_pushboolean(L, 1);
+    lua_rawset(L, lua_upvalueindex(1));
+
+    return 0;
+}
+
+static int cdata_call(lua_State* L)
+{
+    struct ctype ct;
+    int top = lua_gettop(L);
+    cfunction* p = (cfunction*) check_cdata(L, 1, &ct);
+
+    if (push_user_mt(L, -1, &ct)) {
+        lua_pushliteral(L, "__call");
+        lua_rawget(L, -2);
+
+        if (!lua_isnil(L, -1)) {
+            lua_insert(L, 1);
+            lua_pop(L, 2); /* ct_usr, user_mt */
+            lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
+            return lua_gettop(L);
+        }
+    }
+    if (ct.pointers || ct.type != FUNCTION_PTR_TYPE) {
+        return luaL_error(L, "only function callbacks are callable");
+    }
+
+    lua_pushvalue(L, 1);
+    lua_rawget(L, lua_upvalueindex(1));
+
+    if (!lua_isfunction(L, -1)) {
+        lua_pop(L, 1);
+        compile_function(L, *p, -1, &ct);
+
+        assert(lua_gettop(L) == top + 2); /* uv, closure */
+
+        /* closures[func] = closure */
+        lua_pushvalue(L, 1);
+        lua_pushvalue(L, -2);
+        lua_rawset(L, lua_upvalueindex(1));
+
+        lua_replace(L, 1);
+    } else {
+        lua_replace(L, 1);
+    }
+
+    lua_pop(L, 1); /* uv */
+    assert(lua_gettop(L) == top);
+
+    lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
+    return lua_gettop(L);
+}
+
+static int user_mt_key;
+
+static int ffi_metatype(lua_State* L)
+{
+    struct ctype ct;
+    lua_settop(L, 2);
+
+    check_ctype(L, 1, &ct);
+    if (lua_type(L, 2) != LUA_TTABLE && lua_type(L, 2) != LUA_TNIL) {
+        return luaL_argerror(L, 2, "metatable must be a table or nil");
+    }
+
+    lua_pushlightuserdata(L, &user_mt_key);
+    lua_pushvalue(L, 2);
+    lua_rawset(L, 3); /* user[user_mt_key] = mt */
+
+    /* return the passed in ctype */
+    push_ctype(L, 3, &ct);
+    return 1;
+}
+
+/* push_user_mt returns 1 if the type has a user metatable and pushes it onto
+ * the stack, otherwise it returns 0 and pushes nothing */
+int push_user_mt(lua_State* L, int ct_usr, const struct ctype* ct)
+{
+    if (ct->type != STRUCT_TYPE && ct->type != UNION_TYPE && !IS_COMPLEX(ct->type)) {
+        return 0;
+    }
+    if (!lua_istable(L, ct_usr)) {
+        return 0;
+    }
+
+    ct_usr = lua_absindex(L, ct_usr);
+    lua_pushlightuserdata(L, &user_mt_key);
+    lua_rawget(L, ct_usr);
+
+    if (lua_isnil(L, -1)) {
+        lua_pop(L, 1);
+        return 0;
+    }
+    return 1;
+}
+
+static int ffi_gc(lua_State* L)
+{
+    struct ctype ct;
+    lua_settop(L, 2);
+    check_cdata(L, 1, &ct);
+
+    push_upval(L, &gc_key);
+    lua_pushvalue(L, 1);
+    lua_pushvalue(L, 2);
+    lua_rawset(L, -3);
+
+    /* return the cdata back */
+    lua_settop(L, 1);
+    return 1;
+}
+
+/* lookup_cdata_index returns the offset of the found type and user value on
+ * the stack if valid. Otherwise returns -ve and doesn't touch the stack.
+ */
+static ptrdiff_t lookup_cdata_index(lua_State* L, int idx, int ct_usr, struct ctype* ct)
+{
+    struct ctype mt;
+    ptrdiff_t off;
+
+    ct_usr = lua_absindex(L, ct_usr);
+    int type = lua_type(L, idx);
+
+    switch (type) {
+    case LUA_TNUMBER:
+    case LUA_TUSERDATA:
+        /* possibilities are array, pointer */
+
+        if (!ct->pointers || is_void_ptr(ct)) {
+            return -1;
+        }
+
+        // unbox cdata
+        if (type == LUA_TUSERDATA) {
+            if (!cdata_tointeger(L, idx, &off)) {
+                return -1;
+            }
+        } else {
+            off = lua_tointeger(L, idx);
+        }
+
+        ct->is_array = 0;
+        ct->pointers--;
+        ct->const_mask >>= 1;
+        ct->is_reference = 0;
+
+        lua_pushvalue(L, ct_usr);
+
+        return (ct->pointers ? sizeof(void*) : ct->base_size) * off;
+
+    case LUA_TSTRING:
+        /* possibilities are struct/union, pointer to struct/union */
+
+        if ((ct->type != STRUCT_TYPE && ct->type != UNION_TYPE) || ct->is_array || ct->pointers > 1) {
+            return -1;
+        }
+
+        lua_pushvalue(L, idx);
+        off = get_member(L, ct_usr, ct, &mt);
+        if (off < 0) {
+            return -1;
+        }
+
+        *ct = mt;
+        return off;
+
+    default:
+        return -1;
+    }
+}
+
+static int cdata_newindex(lua_State* L)
+{
+    struct ctype tt;
+    char* to;
+    ptrdiff_t off;
+
+    lua_settop(L, 3);
+
+    to = (char*) check_cdata(L, 1, &tt);
+    off = lookup_cdata_index(L, 2, -1, &tt);
+
+    if (off < 0) {
+        if (!push_user_mt(L, -1, &tt)) {
+            goto err;
+        }
+
+        lua_pushliteral(L, "__newindex");
+        lua_rawget(L, -2);
+
+        if (lua_isnil(L, -1)) {
+            goto err;
+        }
+
+        lua_insert(L, 1);
+        lua_settop(L, 4);
+        lua_call(L, 3, LUA_MULTRET);
+        return lua_gettop(L);
+    }
+
+    if (tt.const_mask & 1) {
+        return luaL_error(L, "can't set const data");
+    }
+
+    set_value(L, 3, to + off, -1, &tt, 1);
+    return 0;
+
+err:
+    push_type_name(L, 4, &tt);
+    return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2));
+}
+
+static int cdata_index(lua_State* L)
+{
+    void* to;
+    struct ctype ct;
+    char* data;
+    ptrdiff_t off;
+
+    lua_settop(L, 2);
+    data = (char*) check_cdata(L, 1, &ct);
+    assert(lua_gettop(L) == 3);
+
+    if (!ct.pointers) {
+        switch (ct.type) {
+        case FUNCTION_PTR_TYPE:
+            /* Callbacks use the same metatable as standard cdata values, but have set
+             * and free members. So instead of mt.__index = mt, we do the equiv here. */
+            lua_getmetatable(L, 1);
+            lua_pushvalue(L, 2);
+            lua_rawget(L, -2);
+            return 1;
+
+            /* This provides the .re and .im virtual members */
+        case COMPLEX_DOUBLE_TYPE:
+        case COMPLEX_FLOAT_TYPE:
+            if (!lua_isstring(L, 2)) {
+                luaL_error(L, "invalid member for complex number");
+
+            } else if (strcmp(lua_tostring(L, 2), "re") == 0) {
+                lua_pushnumber(L, ct.type == COMPLEX_DOUBLE_TYPE ? creal(*(complex_double*) data) : crealf(*(complex_float*) data));
+
+            } else if (strcmp(lua_tostring(L, 2), "im") == 0) {
+                lua_pushnumber(L, ct.type == COMPLEX_DOUBLE_TYPE ? cimag(*(complex_double*) data) : cimagf(*(complex_float*) data));
+
+            } else {
+                luaL_error(L, "invalid member for complex number");
+            }
+            return 1;
+        }
+    }
+
+    off = lookup_cdata_index(L, 2, -1, &ct);
+
+    if (off < 0) {
+        assert(lua_gettop(L) == 3);
+        if (!push_user_mt(L, -1, &ct)) {
+            goto err;
+        }
+
+        lua_pushliteral(L, "__index");
+        lua_rawget(L, -2);
+
+        if (lua_isnil(L, -1)) {
+            goto err;
+        }
+
+        if (lua_istable(L, -1)) {
+            lua_pushvalue(L, 2);
+            lua_gettable(L, -2);
+            return 1;
+        }
+
+        lua_insert(L, 1);
+        lua_settop(L, 3);
+        lua_call(L, 2, LUA_MULTRET);
+        return lua_gettop(L);
+
+err:
+        push_type_name(L, 3, &ct);
+        return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2));
+    }
+
+    assert(lua_gettop(L) == 4); /* ct, key, ct_usr, mbr_usr */
+    data += off;
+
+    if (ct.is_array) {
+        /* push a reference to the array */
+        ct.is_reference = 1;
+        to = push_cdata(L, -1, &ct);
+        *(void**) to = data;
+        return 1;
+
+    } else if (ct.is_bitfield) {
+
+        if (ct.type == INT64_TYPE) {
+            struct ctype rt;
+            uint64_t val = *(uint64_t*) data;
+            val >>= ct.bit_offset;
+            val &= (UINT64_C(1) << ct.bit_size) - 1;
+
+            memset(&rt, 0, sizeof(rt));
+            rt.base_size = 8;
+            rt.type = INT64_TYPE;
+            rt.is_unsigned = 1;
+            rt.is_defined = 1;
+
+            to = push_cdata(L, 0, &rt);
+            *(uint64_t*) to = val;
+
+            return 1;
+
+        } else if (ct.type == BOOL_TYPE) {
+            uint64_t val = *(uint64_t*) data;
+            lua_pushboolean(L, (int) (val & (UINT64_C(1) << ct.bit_offset)));
+            return 1;
+
+        } else {
+            uint64_t val = *(uint64_t*) data;
+            val >>= ct.bit_offset;
+            val &= (UINT64_C(1) << ct.bit_size) - 1;
+            lua_pushinteger(L, val);
+            return 1;
+        }
+
+    } else if (ct.pointers) {
+#ifndef ALLOW_MISALIGNED_ACCESS
+        union {
+            uint8_t c[8];
+            void* p;
+        } misalignbuf;
+
+        if ((uintptr_t) data & PTR_ALIGN_MASK) {
+            memcpy(misalignbuf.c, data, sizeof(void*));
+            data = misalignbuf.c;
+        }
+#endif
+        to = push_cdata(L, -1, &ct);
+        *(void**) to = *(void**) data;
+        return 1;
+
+    } else if (ct.type == STRUCT_TYPE || ct.type == UNION_TYPE) {
+        /* push a reference to the member */
+        ct.is_reference = 1;
+        to = push_cdata(L, -1, &ct);
+        *(void**) to = data;
+        return 1;
+
+    } else if (ct.type == FUNCTION_PTR_TYPE) {
+        cfunction* pf = (cfunction*) push_cdata(L, -1, &ct);
+        *pf = *(cfunction*) data;
+        return 1;
+
+    } else {
+#ifndef ALLOW_MISALIGNED_ACCESS
+        union {
+            uint8_t c[8];
+            double d;
+            float f;
+            uint64_t u64;
+        } misalignbuf;
+
+        assert(ct.base_size <= 8);
+
+        if ((uintptr_t) data & (ct.base_size - 1)) {
+            memcpy(misalignbuf.c, data, ct.base_size);
+            data = misalignbuf.c;
+        }
+#endif
+
+        switch (ct.type) {
+        case BOOL_TYPE:
+            lua_pushboolean(L, *(_Bool*) data);
+            break;
+        case INT8_TYPE:
+            lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint8_t*) data : (lua_Integer) *(int8_t*) data);
+            break;
+        case INT16_TYPE:
+            lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint16_t*) data : (lua_Integer) *(int16_t*) data);
+            break;
+        case ENUM_TYPE:
+        case INT32_TYPE:
+            lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint32_t*) data : (lua_Integer) *(int32_t*) data);
+            break;
+        case INT64_TYPE:
+            to = push_cdata(L, -1, &ct);
+            *(int64_t*) to = *(int64_t*) data;
+            break;
+        case INTPTR_TYPE:
+            to = push_cdata(L, -1, &ct);
+            *(intptr_t*) to = *(intptr_t*) data;
+            break;
+        case FLOAT_TYPE:
+            lua_pushnumber(L, *(float*) data);
+            break;
+        case DOUBLE_TYPE:
+            lua_pushnumber(L, *(double*) data);
+            break;
+        case COMPLEX_DOUBLE_TYPE:
+            to = push_cdata(L, -1, &ct);
+            *(complex_double*) to = *(complex_double*) data;
+            break;
+        case COMPLEX_FLOAT_TYPE:
+            to = push_cdata(L, -1, &ct);
+            *(complex_float*) to = *(complex_float*) data;
+            break;
+        default:
+            luaL_error(L, "internal error: invalid member type");
+        }
+
+        return 1;
+    }
+}
+
+static complex_double check_complex(lua_State* L, int idx, void* p, struct ctype* ct)
+{
+    if (ct->type == INVALID_TYPE) {
+        double d = luaL_checknumber(L, idx);
+#ifdef HAVE_COMPLEX
+        return d;
+#else
+        complex_double c;
+        c.real = d;
+        c.imag = 0;
+        return c;
+#endif
+    } else if (ct->type == COMPLEX_DOUBLE_TYPE) {
+        return *(complex_double*) p;
+    } else if (ct->type == COMPLEX_FLOAT_TYPE) {
+        complex_float* f = (complex_float*) p;
+#ifdef HAVE_COMPLEX
+        return *f;
+#else
+        complex_double d;
+        d.real = f->real;
+        d.imag = f->imag;
+        return d;
+#endif
+    } else {
+        complex_double dummy;
+        type_error(L, idx, "complex", 0, NULL);
+        memset(&dummy, 0, sizeof(dummy));
+        return dummy;
+    }
+}
+
+static int rank(const struct ctype* ct)
+{
+    if (ct->pointers) {
+        return 5;
+    }
+
+    switch (ct->type) {
+    case COMPLEX_DOUBLE_TYPE:
+        return 7;
+    case COMPLEX_FLOAT_TYPE:
+        return 6;
+    case INTPTR_TYPE:
+        return sizeof(intptr_t) >= sizeof(int64_t) ? 4 : 1;
+    case INT64_TYPE:
+        return ct->is_unsigned ? 3 : 2;
+    case INT32_TYPE:
+    case INT16_TYPE:
+    case INT8_TYPE:
+        return 2;
+    default:
+        return 0;
+    }
+}
+
+static void push_complex(lua_State* L, complex_double res, int ct_usr, const struct ctype* ct)
+{
+    if (ct->type == COMPLEX_DOUBLE_TYPE) {
+        complex_double* p = (complex_double*) push_cdata(L, ct_usr, ct);
+        *p = res;
+    } else {
+        complex_float* p = (complex_float*) push_cdata(L, ct_usr, ct);
+#ifdef HAVE_COMPLEX
+        *p = (complex float) res;
+#else
+        p->real = (float) res.real;
+        p->imag = (float) res.imag;
+#endif
+    }
+}
+
+static void push_number(lua_State* L, int64_t val, int ct_usr, const struct ctype* ct)
+{
+    if ((ct->pointers || ct->type == INTPTR_TYPE) && sizeof(intptr_t) != sizeof(int64_t)) {
+        intptr_t* p = (intptr_t*) push_cdata(L, ct_usr, ct);
+        *p = val;
+    } else {
+        int64_t* p = (int64_t*) push_cdata(L, ct_usr, ct);
+        *p = val;
+    }
+}
+
+static int call_user_op(lua_State* L, const char* opfield, int idx, int ct_usr, const struct ctype* ct)
+{
+    idx = lua_absindex(L, idx);
+
+    if (push_user_mt(L, ct_usr, ct)) {
+        lua_pushstring(L, opfield);
+        lua_rawget(L, -2);
+        if (!lua_isnil(L, -1)) {
+            int top = lua_gettop(L);
+            lua_pushvalue(L, idx);
+            lua_call(L, 1, LUA_MULTRET);
+            return lua_gettop(L) - top + 1;
+        }
+      lua_pop(L, 2);
+    }
+    return -1;
+}
+
+static int cdata_unm(lua_State* L)
+{
+    struct ctype ct;
+    void* p;
+    int64_t val;
+    int ret;
+
+    lua_settop(L, 1);
+    p = to_cdata(L, 1, &ct);
+
+    ret = call_user_op(L, "__unm", 1, 2, &ct);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    val = check_intptr(L, 1, p, &ct);
+
+    if (ct.pointers) {
+        luaL_error(L, "can't negate a pointer value");
+    } else {
+        memset(&ct, 0, sizeof(ct));
+        ct.type = INT64_TYPE;
+        ct.base_size = 8;
+        ct.is_defined = 1;
+        push_number(L, -val, 0, &ct);
+    }
+
+    return 1;
+}
+
+/* returns -ve if no binop was called otherwise returns the number of return
+ * arguments */
+static int call_user_binop(lua_State* L, const char* opfield, int lidx, int lusr, const struct ctype* lt, int ridx, int rusr, const struct ctype* rt)
+{
+    lidx = lua_absindex(L, lidx);
+    ridx = lua_absindex(L, ridx);
+
+    if (push_user_mt(L, lusr, lt)) {
+        lua_pushstring(L, opfield);
+        lua_rawget(L, -2);
+
+        if (!lua_isnil(L, -1)) {
+            int top = lua_gettop(L);
+            lua_pushvalue(L, lidx);
+            lua_pushvalue(L, ridx);
+            lua_call(L, 2, LUA_MULTRET);
+            return lua_gettop(L) - top + 1;
+        }
+
+        lua_pop(L, 2); /* user_mt and user_mt.op */
+    }
+
+    if (push_user_mt(L, rusr, rt)) {
+        lua_pushstring(L, opfield);
+        lua_rawget(L, -2);
+
+        if (!lua_isnil(L, -1)) {
+            int top = lua_gettop(L);
+            lua_pushvalue(L, lidx);
+            lua_pushvalue(L, ridx);
+            lua_call(L, 2, LUA_MULTRET);
+            return lua_gettop(L) - top + 1;
+        }
+
+        lua_pop(L, 2); /* user_mt and user_mt.op */
+    }
+
+    return -1;
+}
+
+static int cdata_concat(lua_State* L)
+{
+    struct ctype lt, rt;
+    int ret;
+
+    lua_settop(L, 2);
+    to_cdata(L, 1, &lt);
+    to_cdata(L, 2, &rt);
+
+    ret = call_user_binop(L, "__concat", 1, 3, &lt, 2, 4, &rt);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    return luaL_error(L, "NYI");
+}
+
+static int cdata_len(lua_State* L)
+{
+    struct ctype ct;
+    int ret;
+
+    lua_settop(L, 1);
+    to_cdata(L, 1, &ct);
+
+    ret = call_user_op(L, "__len", 1, 2, &ct);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    push_type_name(L, 2, &ct);
+    return luaL_error(L, "type %s does not implement the __len metamethod", lua_tostring(L, -1));
+}
+
+static int cdata_pairs(lua_State* L)
+{
+    struct ctype ct;
+    int ret;
+
+    lua_settop(L, 1);
+    to_cdata(L, 1, &ct);
+
+    ret = call_user_op(L, "__pairs", 1, 2, &ct);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    push_type_name(L, 2, &ct);
+    return luaL_error(L, "type %s does not implement the __pairs metamethod", lua_tostring(L, -1));
+}
+
+static int cdata_ipairs(lua_State* L)
+{
+    struct ctype ct;
+    int ret;
+
+    lua_settop(L, 1);
+    to_cdata(L, 1, &ct);
+
+    ret = call_user_op(L, "__ipairs", 1, 2, &ct);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    push_type_name(L, 2, &ct);
+    return luaL_error(L, "type %s does not implement the __ipairs metamethod", lua_tostring(L, -1));
+}
+
+static int cdata_add(lua_State* L)
+{
+    struct ctype lt, rt, ct;
+    void *lp, *rp;
+    int ct_usr;
+    int ret;
+
+    lua_settop(L, 2);
+
+    lp = to_cdata(L, 1, &lt);
+    rp = to_cdata(L, 2, &rt);
+    assert(lua_gettop(L) == 4);
+
+    ret = call_user_binop(L, "__add", 1, 3, &lt, 2, 4, &rt);
+    if (ret >= 0) {
+        return ret;
+    }
+    assert(lua_gettop(L) == 4);
+
+    ct_usr = rank(&lt) > rank(&rt) ? 3 : 4;
+    ct = rank(&lt) > rank(&rt) ? lt : rt;
+
+    if (IS_COMPLEX(ct.type)) {
+        complex_double left, right, res;
+
+        left = check_complex(L, 1, lp, &lt);
+        right = check_complex(L, 2, rp, &rt);
+        assert(lua_gettop(L) == 4);
+
+#ifdef HAVE_COMPLEX
+        res = left + right;
+#else
+        res.real = left.real + right.real;
+        res.imag = left.imag + right.imag;
+#endif
+
+        push_complex(L, res, ct_usr, &ct);
+        return 1;
+
+    } else {
+        int64_t left = check_intptr(L, 1, lp, &lt);
+        int64_t right = check_intptr(L, 2, rp, &rt);
+        assert(lua_gettop(L) == 4);
+
+        /* note due to 2s complement it doesn't matter if we do the addition as int or uint,
+         * but the result needs to be uint64_t if either of the sources are */
+
+        if (lt.pointers && rt.pointers) {
+            luaL_error(L, "can't add two pointers");
+
+        } else if (lt.pointers) {
+            int64_t res = left + (lt.pointers > 1 ? sizeof(void*) : lt.base_size) * right;
+            lt.is_array = 0;
+            push_number(L, res, 3, &lt);
+
+        } else if (rt.pointers) {
+            int64_t res = right + (rt.pointers > 1 ? sizeof(void*) : rt.base_size) * left;
+            rt.is_array = 0;
+            push_number(L, res, 4, &rt);
+
+        } else {
+            push_number(L, left + right, ct_usr, &ct);
+        }
+
+        return 1;
+    }
+}
+
+static int cdata_sub(lua_State* L)
+{
+    struct ctype lt, rt, ct;
+    void *lp, *rp;
+    int ct_usr;
+    int ret;
+
+    lua_settop(L, 2);
+
+    lp = to_cdata(L, 1, &lt);
+    rp = to_cdata(L, 2, &rt);
+
+    ret = call_user_binop(L, "__sub", 1, 3, &lt, 2, 4, &rt);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    ct_usr = rank(&lt) > rank(&rt) ? 3 : 4;
+    ct = rank(&lt) > rank(&rt) ? lt : rt;
+
+    if (IS_COMPLEX(ct.type)) {
+        complex_double left, right, res;
+
+        left = check_complex(L, 1, lp, &lt);
+        right = check_complex(L, 2, rp, &rt);
+
+#ifdef HAVE_COMPLEX
+        res = left - right;
+#else
+        res.real = left.real - right.real;
+        res.imag = left.imag - right.imag;
+#endif
+
+        push_complex(L, res, ct_usr, &ct);
+        return 1;
+
+    } else {
+        int64_t left = check_intptr(L, 1, lp, &lt);
+        int64_t right = check_intptr(L, 2, rp, &rt);
+
+        if (rt.pointers) {
+            luaL_error(L, "NYI: can't subtract a pointer value");
+
+        } else if (lt.pointers) {
+            int64_t res = left - (lt.pointers > 1 ? sizeof(void*) : lt.base_size) * right;
+            lt.is_array = 0;
+            push_number(L, res, 3, &lt);
+
+        } else {
+            int64_t res = left - right;
+            push_number(L, res, ct_usr, &ct);
+        }
+
+        return 1;
+    }
+}
+
+/* TODO fix for unsigned */
+#define NUMBER_ONLY_BINOP(OPSTR, DO_NORMAL, DO_COMPLEX)                     \
+    struct ctype lt, rt, ct;                                                \
+    void *lp, *rp;                                                          \
+    int ct_usr;                                                             \
+    int ret;                                                                \
+                                                                            \
+    lua_settop(L, 2);                                                       \
+                                                                            \
+    lp = to_cdata(L, 1, &lt);                                               \
+    rp = to_cdata(L, 2, &rt);                                               \
+                                                                            \
+    ret = call_user_binop(L, OPSTR, 1, 3, &lt, 2, 4, &rt);                  \
+    if (ret >= 0) {                                                         \
+        return ret;                                                         \
+    }                                                                       \
+                                                                            \
+    ct_usr = rank(&lt) > rank(&rt) ? 3 : 4;                                 \
+    ct = rank(&lt) > rank(&rt) ? lt : rt;                                   \
+                                                                            \
+    if (IS_COMPLEX(ct.type)) {                                              \
+        complex_double res;                                                 \
+        complex_double left = check_complex(L, 1, lp, &lt);                 \
+        complex_double right = check_complex(L, 2, rp, &rt);                \
+                                                                            \
+        DO_COMPLEX(left, right, res);                                       \
+        push_complex(L, res, ct_usr, &ct);                                  \
+                                                                            \
+    } else if (lt.pointers || rt.pointers) {                                \
+        luaL_error(L, "can't operate on a pointer value");                  \
+                                                                            \
+    } else {                                                                \
+        int64_t res;                                                        \
+        int64_t left = check_intptr(L, 1, lp, &lt);                         \
+        int64_t right = check_intptr(L, 2, rp, &rt);                        \
+                                                                            \
+        DO_NORMAL(left, right, res);                                        \
+        push_number(L, res, ct_usr, &ct);                                   \
+    }                                                                       \
+                                                                            \
+    return 1
+
+#define MUL(l,r,s) s = l * r
+#define DIV(l,r,s) s = l / r
+#define MOD(l,r,s) s = l % r
+#define POW(l,r,s) s = pow(l, r)
+
+#ifdef HAVE_COMPLEX
+#define MULC(l,r,s) s = l * r
+#define DIVC(l,r,s) s = l / r
+#define MODC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex mod")
+#define POWC(l,r,s) s = cpow(l, r)
+#else
+#define MULC(l,r,s) s.real = l.real * r.real - l.imag * r.imag, s.imag = l.real * r.imag + l.imag * r.real
+#define DIVC(l,r,s) s.real = (l.real * r.real + l.imag * r.imag) / (r.real * r.real + r.imag * r.imag), \
+                    s.imag = (l.imag * r.real - l.real * r.imag) / (r.real * r.real + r.imag * r.imag)
+#define MODC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex mod")
+#define POWC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex pow")
+#endif
+
+static int cdata_mul(lua_State* L)
+{ NUMBER_ONLY_BINOP("__mul", MUL, MULC); }
+
+static int cdata_div(lua_State* L)
+{ NUMBER_ONLY_BINOP("__div", DIV, DIVC); }
+
+static int cdata_mod(lua_State* L)
+{ NUMBER_ONLY_BINOP("__mod", MOD, MODC); }
+
+static int cdata_pow(lua_State* L)
+{ NUMBER_ONLY_BINOP("__pow", POW, POWC); }
+
+#define COMPARE_BINOP(OPSTR, OP, OPC)                                       \
+    struct ctype lt, rt;                                                    \
+    void *lp, *rp;                                                          \
+    int ret, res;                                                           \
+                                                                            \
+    lua_settop(L, 2);                                                       \
+                                                                            \
+    lp = to_cdata(L, 1, &lt);                                               \
+    rp = to_cdata(L, 2, &rt);                                               \
+                                                                            \
+    ret = call_user_binop(L, OPSTR, 1, 3, &lt, 2, 4, &rt);                  \
+    if (ret >= 0) {                                                         \
+        return ret;                                                         \
+    }                                                                       \
+                                                                            \
+    if (IS_COMPLEX(lt.type) || IS_COMPLEX(rt.type)) {                       \
+        complex_double left = check_complex(L, 1, lp, &lt);                 \
+        complex_double right = check_complex(L, 2, rp, &rt);                \
+                                                                            \
+        res = OPC(left, right);                                             \
+                                                                            \
+        lua_pushboolean(L, res);                                            \
+                                                                            \
+    } else {                                                                \
+        int64_t left = check_intptr(L, 1, lp, &lt);                         \
+        int64_t right = check_intptr(L, 2, rp, &rt);                        \
+                                                                            \
+        if (lt.pointers && rt.pointers) {                                   \
+            if (is_void_ptr(&lt) || is_void_ptr(&rt) || is_same_type(L, 3, 4, &lt, &rt)) { \
+                res = OP((uint64_t) left, (uint64_t) right);                \
+            } else {                                                        \
+                goto err;                                                   \
+            }                                                               \
+                                                                            \
+        } else if (lt.is_null && rt.type == FUNCTION_PTR_TYPE) {            \
+            res = OP((uint64_t) left, (uint64_t) right);                    \
+                                                                            \
+        } else if (rt.is_null && lt.type == FUNCTION_PTR_TYPE) {            \
+            res = OP((uint64_t) left, (uint64_t) right);                    \
+                                                                            \
+        } else if (lt.pointers && rt.type == INTPTR_TYPE && rt.is_unsigned) {\
+            res = OP((uint64_t) left, (uint64_t) right);                    \
+                                                                            \
+        } else if (rt.pointers && lt.type == INTPTR_TYPE && lt.is_unsigned) {\
+            res = OP((uint64_t) left, (uint64_t) right);                    \
+                                                                            \
+        } else if (rt.pointers || lt.pointers) {                            \
+            goto err;                                                       \
+                                                                            \
+        } else if (lt.is_unsigned && rt.is_unsigned) {                      \
+            res = OP((uint64_t) left, (uint64_t) right);                    \
+                                                                            \
+        } else if (lt.is_unsigned) {                                        \
+            res = OP((int64_t) (uint64_t) left, right);                     \
+                                                                            \
+        } else if (rt.is_unsigned) {                                        \
+            res = OP(left, (int64_t) (uint64_t) right);                     \
+                                                                            \
+        } else {                                                            \
+            res = OP(left, right);                                          \
+        }                                                                   \
+                                                                            \
+        lua_pushboolean(L, res);                                            \
+    }                                                                       \
+    return 1
+
+#define EQ(l, r) (l) == (r)
+#define LT(l, r) (l) < (r)
+#define LE(l, r) (l) <= (r)
+
+#ifdef HAVE_COMPLEX
+#define EQC(l, r) (l) == (r)
+#else
+#define EQC(l, r) (l).real == (r).real && (l).imag == (r).imag
+#endif
+
+#define LEC(l, r) EQC(l, r), luaL_error(L, "complex numbers are non-orderable")
+#define LTC(l, r) EQC(l, r), luaL_error(L, "complex numbers are non-orderable")
+
+static int cdata_eq(lua_State* L)
+{
+    COMPARE_BINOP("__eq", EQ, EQC);
+err:
+    lua_pushboolean(L, 0);
+    return 1;
+}
+
+static int cdata_lt(lua_State* L)
+{
+    COMPARE_BINOP("__lt", LT, LTC);
+err:
+    lua_getuservalue(L, 1);
+    lua_getuservalue(L, 2);
+    push_type_name(L, -2, &lt);
+    push_type_name(L, -2, &lt);
+    return luaL_error(L, "trying to compare incompatible types %s and %s", lua_tostring(L, -2), lua_tostring(L, -1));
+}
+
+static int cdata_le(lua_State* L)
+{
+    COMPARE_BINOP("__le", LE, LEC);
+err:
+    lua_getuservalue(L, 1);
+    lua_getuservalue(L, 2);
+    push_type_name(L, -2, &lt);
+    push_type_name(L, -2, &lt);
+    return luaL_error(L, "trying to compare incompatible types %s and %s", lua_tostring(L, -2), lua_tostring(L, -1));
+}
+
+static const char* etype_tostring(int type)
+{
+    switch (type) {
+    case VOID_TYPE: return "void";
+    case DOUBLE_TYPE: return "double";
+    case FLOAT_TYPE: return "float";
+    case COMPLEX_DOUBLE_TYPE: return "complex double";
+    case COMPLEX_FLOAT_TYPE: return "complex float";
+    case BOOL_TYPE: return "bool";
+    case INT8_TYPE: return "int8";
+    case INT16_TYPE: return "int16";
+    case INT32_TYPE: return "int32";
+    case INT64_TYPE: return "int64";
+    case INTPTR_TYPE: return "intptr";
+    case ENUM_TYPE: return "enum";
+    case UNION_TYPE: return "union";
+    case STRUCT_TYPE: return "struct";
+    case FUNCTION_PTR_TYPE: return "function ptr";
+    case FUNCTION_TYPE: return "function";
+    default: return "invalid";
+    }
+}
+
+static void print_type(lua_State* L, const struct ctype* ct)
+{
+    lua_pushfstring(L, " sz %d %d %d align %d ptr %d %d %d type %s%s %d %d %d name %d call %d %d var %d %d %d bit %d %d %d %d jit %d",
+            /* sz */
+            ct->base_size,
+            ct->array_size,
+            ct->offset,
+            /* align */
+            ct->align_mask,
+            /* ptr */
+            ct->is_array,
+            ct->pointers,
+            ct->const_mask,
+            /* type */
+            ct->is_unsigned ? "u" : "",
+            etype_tostring(ct->type),
+            ct->is_reference,
+            ct->is_defined,
+            ct->is_null,
+            /* name */
+            ct->has_member_name,
+            /* call */
+            ct->calling_convention,
+            ct->has_var_arg,
+            /* var */
+            ct->is_variable_array,
+            ct->is_variable_struct,
+            ct->variable_size_known,
+            /* bit */
+            ct->is_bitfield,
+            ct->has_bitfield,
+            ct->bit_offset,
+            ct->bit_size,
+            /* jit */
+            ct->is_jitted);
+}
+
+static int ctype_tostring(lua_State* L)
+{
+    struct ctype ct;
+    assert(lua_type(L, 1) == LUA_TUSERDATA);
+    lua_settop(L, 1);
+    check_ctype(L, 1, &ct);
+    assert(lua_gettop(L) == 2);
+    push_type_name(L, -1, &ct);
+    lua_pushfstring(L, "ctype<%s>", lua_tostring(L, -1));
+
+    if (DEBUG_TOSTRING) {
+        print_type(L, &ct);
+        lua_concat(L, 2);
+    }
+
+    return 1;
+}
+
+static int cdata_tostring(lua_State* L)
+{
+    struct ctype ct;
+    char buf[64];
+    void* p;
+    int ret;
+
+    lua_settop(L, 1);
+    p = to_cdata(L, 1, &ct);
+
+    ret = call_user_op(L, "__tostring", 1, 2, &ct);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    if (ct.pointers > 0 || ct.is_reference || ct.type == STRUCT_TYPE || ct.type == UNION_TYPE) {
+        push_type_name(L, -1, &ct);
+        lua_pushfstring(L, "cdata<%s>: %p", lua_tostring(L, -1), p);
+
+        if (DEBUG_TOSTRING) {
+            print_type(L, &ct);
+            lua_concat(L, 2);
+        }
+
+        return 1;
+    }
+
+    switch (ct.type) {
+    case COMPLEX_DOUBLE_TYPE:
+        {
+            complex_double c = *(complex_double*) p;
+            lua_pushfstring(L, "%f+%fi", creal(c), cimag(c));
+        }
+        return 1;
+
+    case COMPLEX_FLOAT_TYPE:
+        {
+            complex_float c = *(complex_float*) p;
+            lua_pushfstring(L, "%f+%fi", crealf(c), cimagf(c));
+        }
+        return 1;
+
+    case FUNCTION_PTR_TYPE:
+        p = *(void**) p;
+        push_type_name(L, -1, &ct);
+        lua_pushfstring(L, "cdata<%s>: %p", lua_tostring(L, -1), *(void**) p);
+        return 1;
+
+    case INTPTR_TYPE:
+        lua_pushfstring(L, "%p", *(uintptr_t*) p);
+        return 1;
+
+    case INT64_TYPE:
+        sprintf(buf, ct.is_unsigned ? "%"PRIu64 : "%"PRId64, *(uint64_t*) p);
+        lua_pushstring(L, buf);
+        return 1;
+
+    default:
+        sprintf(buf, ct.is_unsigned ? "%"PRId64 : "%"PRId64, (int64_t) check_intptr(L, 1, p, &ct));
+        lua_pushstring(L, buf);
+        return 1;
+    }
+}
+
+static int ffi_errno(lua_State* L)
+{
+    struct jit* jit = get_jit(L);
+
+    if (!lua_isnoneornil(L, 1)) {
+        lua_pushinteger(L, jit->last_errno);
+        jit->last_errno = luaL_checknumber(L, 1);
+    } else {
+        lua_pushinteger(L, jit->last_errno);
+    }
+
+    return 1;
+}
+
+static int ffi_type(lua_State* L)
+{
+    if (lua_isuserdata(L, 1) && lua_getmetatable(L, 1)) {
+        if (equals_upval(L, -1, &cdata_mt_key) || equals_upval(L, -1, &ctype_mt_key)) {
+            lua_pushstring(L, "cdata");
+            return 1;
+        }
+        lua_pop(L, 1); /* mt */
+    }
+
+    /* call the old _G.type, we use an upvalue as _G.type is set
+     * to this function */
+    lua_pushvalue(L, lua_upvalueindex(1));
+    lua_insert(L, 1);
+    lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
+    return lua_gettop(L);
+}
+
+static int ffi_number(lua_State* L)
+{
+    struct ctype ct;
+    void* data = to_cdata(L, 1, &ct);
+
+    if (ct.type != INVALID_TYPE) {
+        lua_pushinteger(L, check_intptr(L, 1, data, &ct));
+        return 1;
+    } else {
+        /* call the old _G.tonumber, we use an upvalue as _G.tonumber is set
+         * to this function */
+        lua_pushvalue(L, lua_upvalueindex(1));
+        lua_insert(L, 1);
+        lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
+        return lua_gettop(L);
+    }
+}
+
+static int ffi_string(lua_State* L)
+{
+    struct ctype ct;
+    char* data;
+    lua_settop(L, 2);
+
+    data = (char*) check_cdata(L, 1, &ct);
+
+    if (is_void_ptr(&ct)) {
+        lua_pushlstring(L, data, (size_t) luaL_checknumber(L, 2));
+        return 1;
+
+    } else if (ct.type == INT8_TYPE && ct.pointers == 1) {
+        size_t sz;
+
+        if (lua_isuserdata(L, 2)) {
+            ptrdiff_t val;
+            if (!cdata_tointeger(L, 2, &val)) {
+                type_error(L, 2, "int", 0, NULL);
+            }
+            sz = (size_t) val;
+        } else if (!lua_isnil(L, 2)) {
+            sz = (size_t) luaL_checknumber(L, 2);
+
+        } else if (ct.is_array && !ct.is_variable_array) {
+            char* nul = memchr(data, '\0', ct.array_size);
+            sz = nul ? nul - data : ct.array_size;
+
+        } else {
+            sz = strlen(data);
+        }
+
+        lua_pushlstring(L, data, sz);
+        return 1;
+    }
+
+    return luaL_error(L, "unable to convert cdata to string");
+}
+
+static int ffi_copy(lua_State* L)
+{
+    struct ctype ft, tt;
+    char *to, *from;
+
+    setmintop(L, 3);
+    to = (char*) check_pointer(L, 1, &tt);
+    from = (char*) check_pointer(L, 2, &ft);
+
+    if (!lua_isnoneornil(L, 3)) {
+        memcpy(to, from, (size_t) luaL_checknumber(L, 3));
+
+    } else if (ft.type == INT8_TYPE && ft.pointers == 1) {
+        size_t sz = ft.is_array ? ft.array_size : strlen(from);
+        memcpy(to, from, sz);
+        to[sz] = '\0';
+    }
+
+    return 0;
+}
+
+static int ffi_fill(lua_State* L)
+{
+    struct ctype ct;
+    void* to;
+    size_t sz;
+    int val = 0;
+
+    setmintop(L, 3);
+    to = check_pointer(L, 1, &ct);
+    sz = (size_t) luaL_checknumber(L, 2);
+
+    if (!lua_isnoneornil(L, 3)) {
+        val = (int) luaL_checkinteger(L, 3);
+    }
+
+    memset(to, val, sz);
+    return 0;
+}
+
+static int ffi_abi(lua_State* L)
+{
+    luaL_checkstring(L, 1);
+    push_upval(L, &abi_key);
+    lua_pushvalue(L, 1);
+    lua_rawget(L, -2);
+    lua_pushboolean(L, lua_toboolean(L, -1));
+    return 1;
+}
+
+static int ffi_load(lua_State* L)
+{
+    const char* libname = luaL_checkstring(L, 1);
+    void** lib = (void**) lua_newuserdata(L, sizeof(void*));
+
+    *lib = LoadLibraryA(libname);
+
+#ifdef LIB_FORMAT_1
+    if (!*lib) {
+        libname = lua_pushfstring(L, LIB_FORMAT_1, lua_tostring(L, 1));
+        *lib = LoadLibraryA(libname);
+        lua_pop(L, 1);
+    }
+#endif
+
+#ifdef LIB_FORMAT_2
+    if (!*lib) {
+        libname = lua_pushfstring(L, LIB_FORMAT_2, lua_tostring(L, 1));
+        *lib = LoadLibraryA(libname);
+        lua_pop(L, 1);
+    }
+#endif
+
+    if (!*lib) {
+        return luaL_error(L, "could not load library %s", lua_tostring(L, 1));
+    }
+
+    lua_newtable(L);
+    lua_setuservalue(L, -2);
+
+    push_upval(L, &cmodule_mt_key);
+    lua_setmetatable(L, -2);
+    return 1;
+}
+
+static void* find_symbol(lua_State* L, int modidx, const char* asmname)
+{
+    size_t i;
+    void** libs;
+    size_t num;
+    void* sym = NULL;
+
+    libs = (void**) lua_touserdata(L, modidx);
+    num = lua_rawlen(L, modidx) / sizeof(void*);
+
+    for (i = 0; i < num && sym == NULL; i++) {
+        if (libs[i]) {
+            sym = GetProcAddressA(libs[i], asmname);
+        }
+    }
+
+    return sym;
+}
+
+/* pushes the user table */
+static void* lookup_global(lua_State* L, int modidx, int nameidx, const char** pname, struct ctype* ct)
+{
+    int top = lua_gettop(L);
+    void* sym;
+
+    modidx = lua_absindex(L, modidx);
+    nameidx = lua_absindex(L, nameidx);
+
+    *pname = luaL_checkstring(L, nameidx);
+
+    /* get the ctype */
+    push_upval(L, &functions_key);
+    lua_pushvalue(L, nameidx);
+    lua_rawget(L, -2);
+    if (lua_isnil(L, -1)) {
+        luaL_error(L, "missing declaration for function/global %s", *pname);
+        return NULL;
+    }
+
+    /* leave just the ct_usr on the stack */
+    *ct = *(const struct ctype*) lua_touserdata(L, -1);
+    lua_getuservalue(L, -1);
+    lua_replace(L, top + 1);
+    lua_pop(L, 1);
+
+    assert(lua_gettop(L) == top + 1);
+
+    /* get the assembly name */
+    push_upval(L, &asmname_key);
+    lua_pushvalue(L, nameidx);
+    lua_rawget(L, -2);
+    if (lua_isstring(L, -1)) {
+        *pname = lua_tostring(L, -1);
+    }
+    lua_pop(L, 2);
+
+    sym = find_symbol(L, modidx, *pname);
+
+    assert(lua_gettop(L) == top + 1);
+    return sym;
+}
+
+static int cmodule_index(lua_State* L)
+{
+    const char* asmname;
+    struct ctype ct;
+    void *sym;
+
+    lua_settop(L, 2);
+
+    /* see if we have already loaded the function */
+    lua_getuservalue(L, 1);
+    lua_pushvalue(L, 2);
+    lua_rawget(L, -2);
+    if (!lua_isnil(L, -1)) {
+        return 1;
+    }
+    lua_pop(L, 2);
+
+    /* check the constants table */
+    push_upval(L, &constants_key);
+    lua_pushvalue(L, 2);
+    lua_rawget(L, -2);
+    if (!lua_isnil(L, -1)) {
+        return 1;
+    }
+    lua_pop(L, 2);
+
+    /* lookup_global pushes the ct_usr */
+    sym = lookup_global(L, 1, 2, &asmname, &ct);
+
+#if defined _WIN32 && !defined _WIN64 && (defined __i386__ || defined _M_IX86)
+    if (!sym && ct.type == FUNCTION_TYPE) {
+        ct.calling_convention = STD_CALL;
+        lua_pushfstring(L, "_%s@%d", asmname, x86_return_size(L, -1, &ct));
+        sym = find_symbol(L, 1, lua_tostring(L, -1));
+        lua_pop(L, 1);
+    }
+
+    if (!sym && ct.type == FUNCTION_TYPE) {
+        ct.calling_convention = FAST_CALL;
+        lua_pushfstring(L, "@%s@%d", asmname, x86_return_size(L, -1, &ct));
+        sym = find_symbol(L, 1, lua_tostring(L, -1));
+        lua_pop(L, 1);
+    }
+#endif
+
+    if (!sym) {
+        return luaL_error(L, "failed to find function/global %s", asmname);
+    }
+
+    assert(lua_gettop(L) == 3); /* module, name, ct_usr */
+
+    if (ct.type == FUNCTION_TYPE) {
+        compile_function(L, (cfunction) sym, -1, &ct);
+        assert(lua_gettop(L) == 4); /* module, name, ct_usr, function */
+
+        /* set module usr value[luaname] = function to cache for next time */
+        lua_getuservalue(L, 1);
+        lua_pushvalue(L, 2);
+        lua_pushvalue(L, -3);
+        lua_rawset(L, -3);
+        lua_pop(L, 1); /* module uv */
+        return 1;
+    }
+
+    /* extern const char* foo; and extern const char foo[]; */
+    if (ct.pointers == 1 && ct.type == INT8_TYPE) {
+        char* str = (char*) sym;
+        if (!ct.is_array) {
+            str = *(char**) sym;
+        }
+        lua_pushstring(L, str);
+        return 1;
+    }
+
+    /* extern struct foo foo[], extern void* foo[]; and extern struct foo foo; */
+    if (ct.is_array || (!ct.pointers && (ct.type == UNION_TYPE || ct.type == STRUCT_TYPE))) {
+        void* p;
+        ct.is_reference = 1;
+        p = push_cdata(L, -1, &ct);
+        *(void**) p = sym;
+        return 1;
+    }
+
+    /* extern void* foo; and extern void (*foo)(); */
+    if (ct.pointers || ct.type == FUNCTION_PTR_TYPE) {
+        void* p = push_cdata(L, -1, &ct);
+        *(void**) p = *(void**) sym;
+        return 1;
+    }
+
+    switch (ct.type) {
+    case COMPLEX_DOUBLE_TYPE:
+    case COMPLEX_FLOAT_TYPE:
+    case INTPTR_TYPE:
+    case INT64_TYPE:
+        {
+            /* TODO: complex float/double need to be references if .re and
+             * .imag are setable */
+            void* p = push_cdata(L, -1, &ct);
+            memcpy(p, sym, ct.base_size);
+            return 1;
+        }
+
+    case DOUBLE_TYPE:
+        lua_pushnumber(L, *(double*) sym);
+        return 1;
+
+    case FLOAT_TYPE:
+        lua_pushnumber(L, *(float*) sym);
+        return 1;
+
+    case BOOL_TYPE:
+        lua_pushboolean(L, *(bool*) sym);
+        return 1;
+
+    case INT8_TYPE:
+        lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint8_t*) sym : (lua_Integer) *(int8_t*) sym);
+        return 1;
+
+    case INT16_TYPE:
+        lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint16_t*) sym : (lua_Integer) *(int16_t*) sym);
+        return 1;
+
+    case INT32_TYPE:
+    case ENUM_TYPE:
+        lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint32_t*) sym : (lua_Integer) *(int32_t*) sym);
+        return 1;
+    }
+
+    return luaL_error(L, "NYI - global value type");
+}
+
+static int cmodule_newindex(lua_State* L)
+{
+    const char* name;
+    void* sym;
+    struct ctype ct;
+
+    lua_settop(L, 3);
+
+    /* pushes the ct_usr */
+    sym = lookup_global(L, 1, 2, &name, &ct);
+    assert(lua_gettop(L) == 4); /* module, name, value, ct_usr */
+
+    if (sym == NULL) {
+        return luaL_error(L, "failed to find global %s", name);
+    }
+
+    if (ct.type == FUNCTION_TYPE || ct.is_array || (ct.const_mask & 1)) {
+        return luaL_error(L, "can not set global %s", name);
+    }
+
+    set_value(L, 3, sym, -1, &ct, 1);
+    return 0;
+}
+
+static int jit_gc(lua_State* L)
+{
+    size_t i;
+    struct jit* jit = get_jit(L);
+    dasm_free(jit);
+    for (i = 0; i < jit->pagenum; i++) {
+        FreePage(jit->pages[i], jit->pages[i]->size);
+    }
+    free(jit->pages);
+    free(jit->globals);
+    return 0;
+}
+
+static int ffi_debug(lua_State* L)
+{
+    lua_newtable(L);
+    push_upval(L, &ctype_mt_key);
+    lua_setfield(L, -2, "ctype_mt");
+    push_upval(L, &cdata_mt_key);
+    lua_setfield(L, -2, "cdata_mt");
+    push_upval(L, &cmodule_mt_key);
+    lua_setfield(L, -2, "cmodule_mt");
+    push_upval(L, &constants_key);
+    lua_setfield(L, -2, "constants");
+    push_upval(L, &types_key);
+    lua_setfield(L, -2, "types");
+    push_upval(L, &jit_key);
+    lua_setfield(L, -2, "jit");
+    push_upval(L, &gc_key);
+    lua_setfield(L, -2, "gc");
+    push_upval(L, &callbacks_key);
+    lua_setfield(L, -2, "callbacks");
+    push_upval(L, &functions_key);
+    lua_setfield(L, -2, "functions");
+    push_upval(L, &abi_key);
+    lua_setfield(L, -2, "abi");
+    push_upval(L, &next_unnamed_key);
+    lua_setfield(L, -2, "next_unnamed");
+    return 1;
+}
+
+static int do64(lua_State* L, int is_unsigned)
+{
+    lua_Number low, high;
+    struct ctype ct;
+    int64_t val;
+
+    lua_settop(L, 2);
+
+    if (!lua_isnil(L, 2)) {
+        high = luaL_checknumber(L, 1);
+        low = luaL_checknumber(L, 2);
+    } else {
+        high = 0;
+        low = luaL_checknumber(L, 1);
+    }
+
+    val = ((int64_t) (uint32_t) high << 32) | (int64_t) (uint32_t) low;
+
+    if (!is_unsigned && (high < 0 || low < 0)) {
+        val = -val;
+    }
+
+    memset(&ct, 0, sizeof(ct));
+    ct.type = INT64_TYPE;
+    ct.is_unsigned = is_unsigned;
+    ct.is_defined = 1;
+    ct.base_size = sizeof(int64_t);
+    push_number(L, (int64_t) val, 0, &ct);
+
+    return 1;
+}
+
+static int ffi_i64(lua_State* L)
+{ return do64(L, 0); }
+
+static int ffi_u64(lua_State* L)
+{ return do64(L, 1); }
+
+static const luaL_Reg cdata_mt[] = {
+    {"__gc", &cdata_gc},
+    {"__call", &cdata_call},
+    {"free", &cdata_free},
+    {"set", &cdata_set},
+    {"__index", &cdata_index},
+    {"__newindex", &cdata_newindex},
+    {"__add", &cdata_add},
+    {"__sub", &cdata_sub},
+    {"__mul", &cdata_mul},
+    {"__div", &cdata_div},
+    {"__mod", &cdata_mod},
+    {"__pow", &cdata_pow},
+    {"__unm", &cdata_unm},
+    {"__eq", &cdata_eq},
+    {"__lt", &cdata_lt},
+    {"__le", &cdata_le},
+    {"__tostring", &cdata_tostring},
+    {"__concat", &cdata_concat},
+    {"__len", &cdata_len},
+    {"__pairs", &cdata_pairs},
+    {"__ipairs", &cdata_ipairs},
+    {NULL, NULL}
+};
+
+static const luaL_Reg callback_mt[] = {
+    {"__gc", &callback_free},
+    {NULL, NULL}
+};
+
+static const luaL_Reg ctype_mt[] = {
+    {"__call", &ctype_call},
+    {"__new", &ctype_new},
+    {"__tostring", &ctype_tostring},
+    {NULL, NULL}
+};
+
+static const luaL_Reg cmodule_mt[] = {
+    {"__index", &cmodule_index},
+    {"__newindex", &cmodule_newindex},
+    {NULL, NULL}
+};
+
+static const luaL_Reg jit_mt[] = {
+    {"__gc", &jit_gc},
+    {NULL, NULL}
+};
+
+static const luaL_Reg ffi_reg[] = {
+    {"cdef", &ffi_cdef},
+    {"load", &ffi_load},
+    {"new", &ffi_new},
+    {"typeof", &ffi_typeof},
+    {"cast", &ffi_cast},
+    {"metatype", &ffi_metatype},
+    {"gc", &ffi_gc},
+    {"sizeof", &ffi_sizeof},
+    {"alignof", &ffi_alignof},
+    {"offsetof", &ffi_offsetof},
+    {"istype", &ffi_istype},
+    {"errno", &ffi_errno},
+    {"string", &ffi_string},
+    {"copy", &ffi_copy},
+    {"fill", &ffi_fill},
+    {"abi", &ffi_abi},
+    {"debug", &ffi_debug},
+    {"i64", &ffi_i64},
+    {"u64", &ffi_u64},
+    {NULL, NULL}
+};
+
+/* leaves the usr table on the stack */
+static void push_builtin(lua_State* L, struct ctype* ct, const char* name, int type, int size, int align, int is_unsigned)
+{
+    memset(ct, 0, sizeof(*ct));
+    ct->type = type;
+    ct->base_size = size;
+    ct->align_mask = align;
+    ct->is_defined = 1;
+    ct->is_unsigned = is_unsigned;
+
+    if (IS_COMPLEX(type)) {
+        lua_newtable(L);
+    } else {
+        lua_pushnil(L);
+    }
+
+    push_upval(L, &types_key);
+    push_ctype(L, -2, ct);
+    lua_setfield(L, -2, name);
+    lua_pop(L, 2); /* types, usr table */
+}
+
+static void push_builtin_undef(lua_State* L, struct ctype* ct, const char* name, int type)
+{
+    memset(ct, 0, sizeof(*ct));
+    ct->type = type;
+
+    push_upval(L, &types_key);
+    push_ctype(L, 0, ct);
+    lua_setfield(L, -2, name);
+    lua_pop(L, 1); /* types */
+}
+
+static void add_typedef(lua_State* L, const char* from, const char* to)
+{
+    struct ctype ct;
+    struct parser P;
+    P.line = 1;
+    P.align_mask = DEFAULT_ALIGN_MASK;
+    P.next = P.prev = from;
+
+    push_upval(L, &types_key);
+    parse_type(L, &P, &ct);
+    parse_argument(L, &P, -1, &ct, NULL, NULL);
+    push_ctype(L, -1, &ct);
+
+    /* stack is at +4: types, type usr, arg usr, ctype */
+
+    lua_setfield(L, -4, to);
+    lua_pop(L, 3); /* types, type usr, arg usr */
+}
+
+static int setup_upvals(lua_State* L)
+{
+    struct jit* jit = get_jit(L);
+
+    /* jit setup */
+    {
+        dasm_init(jit, 64);
+#ifdef _WIN32
+        {
+            SYSTEM_INFO si;
+            GetSystemInfo(&si);
+            jit->align_page_size = si.dwAllocationGranularity - 1;
+        }
+#else
+        jit->align_page_size = sysconf(_SC_PAGE_SIZE) - 1;
+#endif
+        jit->globals = (void**) malloc(64 * sizeof(void*));
+        dasm_setupglobal(jit, jit->globals, 64);
+        compile_globals(jit, L);
+    }
+
+    /* ffi.C */
+    {
+#ifdef _WIN32
+        size_t sz = sizeof(HMODULE) * 6;
+        HMODULE* libs = lua_newuserdata(L, sz);
+        memset(libs, 0, sz);
+
+        /* exe */
+        GetModuleHandle(NULL);
+        /* lua dll */
+#ifdef LUA_DLL_NAME
+#define STR2(tok) #tok
+#define STR(tok) STR2(tok)
+        libs[1] = LoadLibraryA(STR(LUA_DLL_NAME));
+#undef STR
+#undef STR2
+#endif
+
+        /* crt */
+#ifdef UNDER_CE
+        libs[2] = LoadLibraryA("coredll.dll");
+#else
+        GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (char*) &_fmode, &libs[2]);
+        libs[3] = LoadLibraryA("kernel32.dll");
+        libs[4] = LoadLibraryA("user32.dll");
+        libs[5] = LoadLibraryA("gdi32.dll");
+#endif
+
+        jit->lua_dll = libs[1];
+        jit->kernel32_dll = libs[3];
+
+#else /* !_WIN32 */
+        size_t sz = sizeof(void*) * 5;
+        void** libs = lua_newuserdata(L, sz);
+        memset(libs, 0, sz);
+
+        libs[0] = LoadLibraryA(NULL); /* exe */
+        libs[1] = LoadLibraryA("libc.so");
+#ifdef __GNUC__
+        libs[2] = LoadLibraryA("libgcc.so");
+#endif
+        libs[3] = LoadLibraryA("libm.so");
+        libs[4] = LoadLibraryA("libdl.so");
+#endif
+
+        lua_newtable(L);
+        lua_setuservalue(L, -2);
+
+        push_upval(L, &cmodule_mt_key);
+        lua_setmetatable(L, -2);
+
+        lua_setfield(L, 1, "C");
+    }
+
+    /* setup builtin types */
+    {
+        complex_double* pc;
+        struct {char ch; uint16_t v;} a16;
+        struct {char ch; uint32_t v;} a32;
+        struct {char ch; uint64_t v;} a64;
+        struct {char ch; float v;} af;
+        struct {char ch; double v;} ad;
+#ifdef HAVE_LONG_DOUBLE
+        struct {char ch; long double v;} ald;
+#endif
+        struct {char ch; uintptr_t v;} aptr;
+        struct ctype ct;
+        struct {char ch; complex_float v;} cf;
+        struct {char ch; complex_double v;} cd;
+#if defined HAVE_LONG_DOUBLE && defined HAVE_COMPLEX
+        struct {char ch; complex long double v;} cld;
+#endif
+
+        push_builtin(L, &ct, "void", VOID_TYPE, 0, 0, 0);
+        push_builtin(L, &ct, "bool", BOOL_TYPE, sizeof(_Bool), sizeof(_Bool) -1, 1);
+        push_builtin(L, &ct, "uint8_t", INT8_TYPE, sizeof(uint8_t), 0, 1);
+        push_builtin(L, &ct, "int8_t", INT8_TYPE, sizeof(int8_t), 0, 0);
+        push_builtin(L, &ct, "uint16_t", INT16_TYPE, sizeof(uint16_t), ALIGNOF(a16), 1);
+        push_builtin(L, &ct, "int16_t", INT16_TYPE, sizeof(int16_t), ALIGNOF(a16), 0);
+        push_builtin(L, &ct, "uint32_t", INT32_TYPE, sizeof(uint32_t), ALIGNOF(a32), 1);
+        push_builtin(L, &ct, "int32_t", INT32_TYPE, sizeof(int32_t), ALIGNOF(a32), 0);
+        push_builtin(L, &ct, "uint64_t", INT64_TYPE, sizeof(uint64_t), ALIGNOF(a64), 1);
+        push_builtin(L, &ct, "int64_t", INT64_TYPE, sizeof(int64_t), ALIGNOF(a64), 0);
+        push_builtin(L, &ct, "float", FLOAT_TYPE, sizeof(float), ALIGNOF(af), 0);
+        push_builtin(L, &ct, "double", DOUBLE_TYPE, sizeof(double), ALIGNOF(ad), 0);
+#ifdef HAVE_LONG_DOUBLE
+        push_builtin(L, &ct, "long double", LONG_DOUBLE_TYPE, sizeof(long double), ALIGNOF(ald), 0);
+#else
+        push_builtin_undef(L, &ct, "long double", LONG_DOUBLE_TYPE);
+#endif
+        push_builtin(L, &ct, "uintptr_t", INTPTR_TYPE, sizeof(uintptr_t), ALIGNOF(aptr), 1);
+        push_builtin(L, &ct, "intptr_t", INTPTR_TYPE, sizeof(uintptr_t), ALIGNOF(aptr), 0);
+        push_builtin(L, &ct, "complex float", COMPLEX_FLOAT_TYPE, sizeof(complex_float), ALIGNOF(cf), 0);
+        push_builtin(L, &ct, "complex double", COMPLEX_DOUBLE_TYPE, sizeof(complex_double), ALIGNOF(cd), 0);
+#if defined HAVE_LONG_DOUBLE && defined HAVE_COMPLEX
+        push_builtin(L, &ct, "complex long double", COMPLEX_LONG_DOUBLE_TYPE, sizeof(complex long double), ALIGNOF(cld), 0);
+#else
+        push_builtin_undef(L, &ct, "complex long double", COMPLEX_LONG_DOUBLE_TYPE);
+#endif
+
+        /* add NULL and i constants */
+        push_upval(L, &constants_key);
+
+        memset(&ct, 0, sizeof(ct));
+        ct.type = VOID_TYPE;
+        ct.is_defined = 1;
+        ct.pointers = 1;
+        ct.is_null = 1;
+
+        /* add ffi.C.NULL */
+        push_cdata(L, 0, &ct);
+        lua_setfield(L, -2, "NULL");
+
+        /* add ffi.NULL */
+        push_cdata(L, 0, &ct);
+        lua_setfield(L, 1, "NULL");
+
+        memset(&ct, 0, sizeof(ct));
+        ct.type = COMPLEX_DOUBLE_TYPE;
+        ct.is_defined = 1;
+        ct.base_size = sizeof(complex_double);
+        pc = (complex_double*) push_cdata(L, 0, &ct);
+#ifdef HAVE_COMPLEX
+        *pc = 1i;
+#else
+        pc->real = 0;
+        pc->imag = 1;
+#endif
+        lua_setfield(L, -2, "i");
+
+        lua_pop(L, 1); /* constants */
+    }
+
+    assert(lua_gettop(L) == 1);
+
+    /* setup builtin typedefs */
+    {
+        add_typedef(L, "bool", "_Bool");
+
+        if (sizeof(uint32_t) == sizeof(size_t)) {
+            add_typedef(L, "uint32_t", "size_t");
+            add_typedef(L, "int32_t", "ssize_t");
+        } else if (sizeof(uint64_t) == sizeof(size_t)) {
+            add_typedef(L, "uint64_t", "size_t");
+            add_typedef(L, "int64_t", "ssize_t");
+        }
+
+        if (sizeof(int32_t) == sizeof(intptr_t)) {
+            add_typedef(L, "int32_t", "intptr_t");
+            add_typedef(L, "int32_t", "ptrdiff_t");
+        } else if (sizeof(int64_t) == sizeof(intptr_t)) {
+            add_typedef(L, "int64_t", "intptr_t");
+            add_typedef(L, "int64_t", "ptrdiff_t");
+        }
+
+        if (sizeof(uint8_t) == sizeof(wchar_t)) {
+            add_typedef(L, "uint8_t", "wchar_t");
+        } else if (sizeof(uint16_t) == sizeof(wchar_t)) {
+            add_typedef(L, "uint16_t", "wchar_t");
+        } else if (sizeof(uint32_t) == sizeof(wchar_t)) {
+            add_typedef(L, "uint32_t", "wchar_t");
+        }
+
+        if (sizeof(va_list) == sizeof(char*)) {
+            add_typedef(L, "char*", "va_list");
+        } else {
+            struct {char ch; va_list v;} av;
+            lua_pushfstring(L, "struct {char data[%d] __attribute__((align(%d)));}", (int) sizeof(va_list), (int) ALIGNOF(av) + 1);
+            add_typedef(L, lua_tostring(L, -1), "va_list");
+            lua_pop(L, 1);
+        }
+
+        add_typedef(L, "va_list", "__builtin_va_list");
+        add_typedef(L, "va_list", "__gnuc_va_list");
+    }
+
+    assert(lua_gettop(L) == 1);
+
+    /* setup ABI params table */
+    push_upval(L, &abi_key);
+
+#if defined ARCH_X86 || defined ARCH_ARM
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -2, "32bit");
+#elif defined ARCH_X64 || defined ARCH_PPC64
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -2, "64bit");
+#else
+#error
+#endif
+
+#if defined ARCH_X86 || defined ARCH_X64 || defined ARCH_ARM || defined ARCH_PPC64
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -2, "le");
+#else
+#error
+#endif
+
+#if defined ARCH_X86 || defined ARCH_X64 || defined ARCH_PPC64
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -2, "fpu");
+#elif defined ARCH_ARM
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -2, "softfp");
+#else
+#error
+#endif
+    lua_pop(L, 1); /* abi tbl */
+
+
+    /* GC table - shouldn't pin cdata values */
+    push_upval(L, &gc_key);
+    lua_newtable(L);
+    lua_pushliteral(L, "k");
+    lua_setfield(L, -2, "__mode");
+    lua_setmetatable(L, -2);
+    lua_pop(L, 1); /* gc table */
+
+
+    /* ffi.os */
+#if defined OS_CE
+    lua_pushliteral(L, "WindowsCE");
+#elif defined OS_WIN
+    lua_pushliteral(L, "Windows");
+#elif defined OS_OSX
+    lua_pushliteral(L, "OSX");
+#elif defined OS_LINUX
+    lua_pushliteral(L, "Linux");
+#elif defined OS_BSD
+    lua_pushliteral(L, "BSD");
+#elif defined OS_POSIX
+    lua_pushliteral(L, "POSIX");
+#else
+    lua_pushliteral(L, "Other");
+#endif
+    lua_setfield(L, 1, "os");
+
+
+    /* ffi.arch */
+#if defined ARCH_X86
+    lua_pushliteral(L, "x86");
+#elif defined ARCH_X64
+    lua_pushliteral(L, "x64");
+#elif defined ARCH_ARM
+    lua_pushliteral(L, "arm");
+#elif defined ARCH_PPC64
+    lua_pushliteral(L, "ppc64");
+#else
+# error
+#endif
+    lua_setfield(L, 1, "arch");
+
+    assert(lua_gettop(L) == 1);
+
+    return 0;
+}
+
+static void setup_mt(lua_State* L, const luaL_Reg* mt, int upvals)
+{
+    lua_pushboolean(L, 1);
+    lua_setfield(L, -upvals-2, "__metatable");
+    luaL_setfuncs(L, mt, upvals);
+}
+
+int luaopen_ffi(lua_State* L)
+{
+    lua_settop(L, 0);
+
+    lua_newtable(L);
+    set_upval(L, &niluv_key);
+
+    lua_newtable(L);
+    setup_mt(L, ctype_mt, 0);
+    set_upval(L, &ctype_mt_key);
+
+    lua_newtable(L);
+    set_upval(L, &callbacks_key);
+
+    lua_newtable(L);
+    set_upval(L, &gc_key);
+
+    lua_newtable(L);
+    push_upval(L, &callbacks_key);
+    push_upval(L, &gc_key);
+    setup_mt(L, cdata_mt, 2);
+    set_upval(L, &cdata_mt_key);
+
+    lua_newtable(L);
+    setup_mt(L, callback_mt, 0);
+    set_upval(L, &callback_mt_key);
+
+    lua_newtable(L);
+    setup_mt(L, cmodule_mt, 0);
+    set_upval(L, &cmodule_mt_key);
+
+    memset(lua_newuserdata(L, sizeof(struct jit)), 0, sizeof(struct jit));
+    lua_newtable(L);
+    setup_mt(L, jit_mt, 0);
+    lua_setmetatable(L, -2);
+    set_upval(L, &jit_key);
+
+    lua_newtable(L);
+    set_upval(L, &constants_key);
+
+    lua_newtable(L);
+    set_upval(L, &types_key);
+
+    lua_newtable(L);
+    set_upval(L, &functions_key);
+
+    lua_newtable(L);
+    set_upval(L, &asmname_key);
+
+    lua_newtable(L);
+    set_upval(L, &abi_key);
+
+    lua_pushinteger(L, 1);
+    set_upval(L, &next_unnamed_key);
+
+    assert(lua_gettop(L) == 0);
+
+    /* ffi table */
+    lua_newtable(L);
+    luaL_setfuncs(L, ffi_reg, 0);
+
+    /* setup_upvals(ffi tbl) */
+    lua_pushcfunction(L, &setup_upvals);
+    lua_pushvalue(L, 1);
+    lua_call(L, 1, 0);
+
+    assert(lua_gettop(L) == 1);
+
+    lua_getglobal(L, "tonumber");
+    lua_pushcclosure(L, &ffi_number, 1);
+    lua_pushvalue(L, -1);
+    lua_setglobal(L, "tonumber");
+    lua_setfield(L, -2, "number"); /* ffi.number */
+
+    lua_getglobal(L, "type");
+    lua_pushcclosure(L, &ffi_type, 1);
+    lua_pushvalue(L, -1);
+    lua_setglobal(L, "type");
+    lua_setfield(L, -2, "type"); /* ffi.type */
+    return 1;
+}

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,466 @@
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#pragma once
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C" {
+# include <lua.h>
+# include <lauxlib.h>
+# include <lualib.h>
+}
+# define EXTERN_C extern "C"
+#else
+# include <lua.h>
+# include <lauxlib.h>
+# include <lualib.h>
+# define EXTERN_C extern
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <errno.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <sys/mman.h>
+#endif
+
+#ifdef _WIN32
+/* We should include something equivalent to */
+/* complex.h                                 */
+#else
+#include <complex.h>
+#define HAVE_COMPLEX
+#define HAVE_LONG_DOUBLE
+#endif
+
+#ifndef NDEBUG
+#define DASM_CHECKS
+#endif
+
+struct jit;
+#define Dst_DECL	struct jit* Dst
+#define Dst_REF		(Dst->ctx)
+#define DASM_EXTERN(a,b,c,d) get_extern(a,b,c,d)
+
+#include "dynasm/dasm_proto.h"
+
+#if defined LUA_FFI_BUILD_AS_DLL
+# define EXPORT __declspec(dllexport)
+#elif defined __GNUC__
+# define EXPORT __attribute__((visibility("default")))
+#else
+# define EXPORT
+#endif
+
+EXTERN_C EXPORT int luaopen_ffi(lua_State* L);
+
+static int lua_absindex2(lua_State* L, int idx) {
+    return (LUA_REGISTRYINDEX <= idx && idx < 0)
+         ? lua_gettop(L) + idx + 1
+         : idx;
+}
+/* use our own version of lua_absindex such that lua_absindex(L, 0) == 0 */
+#define lua_absindex(L, idx) lua_absindex2(L, idx)
+
+#if LUA_VERSION_NUM == 501
+static void lua_callk(lua_State *L, int nargs, int nresults, int ctx, lua_CFunction k)
+{
+    lua_call(L, nargs, nresults);
+}
+/*
+** set functions from list 'l' into table at top - 'nup'; each
+** function gets the 'nup' elements at the top as upvalues.
+** Returns with only the table at the stack.
+*/
+static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
+  luaL_checkstack(L, nup, "too many upvalues");
+  for (; l && l->name; l++) {  /* fill the table with given functions */
+    int i;
+    for (i = 0; i < nup; i++)  /* copy upvalues to the top */
+      lua_pushvalue(L, -nup);
+    lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
+    lua_setfield(L, -(nup + 2), l->name);
+  }
+  lua_pop(L, nup);  /* remove upvalues */
+}
+#define lua_setuservalue lua_setfenv
+#define lua_getuservalue lua_getfenv
+#define lua_rawlen lua_objlen
+static char* luaL_prepbuffsize(luaL_Buffer* B, size_t sz) {
+    if (sz > LUAL_BUFFERSIZE) {
+        luaL_error(B->L, "string too long");
+    }
+    return luaL_prepbuffer(B);
+}
+#elif LUA_VERSION_NUM == 503
+static void (lua_remove)(lua_State *L, int idx) {
+    lua_remove(L, idx);
+}
+#endif
+
+/* architectures */
+#if defined _WIN32 && defined UNDER_CE
+# define OS_CE
+#elif defined _WIN32
+# define OS_WIN
+#elif defined __APPLE__ && defined __MACH__
+# define OS_OSX
+#elif defined __linux__
+# define OS_LINUX
+#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
+# define OS_BSD
+#elif defined unix || defined __unix__ || defined __unix || defined _POSIX_VERSION || defined _XOPEN_VERSION
+# define OS_POSIX
+#endif
+
+/* architecture */
+#if defined __i386__ || defined _M_IX86
+# define ARCH_X86
+#elif defined __amd64__ || defined _M_X64
+# define ARCH_X64
+#elif defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __aarch64__
+# define ARCH_ARM
+#elif defined __powerpc64__
+# define ARCH_PPC64
+#else
+# error
+#endif
+
+
+/* See ffi.c: replace luaopen_ffi with a stub    */
+/* if FFI_ENABLE_LUATEX_INTERFACE is not defined */
+#if (defined ARCH_X86 || defined ARCH_X64) && (defined OS_CE || defined OS_WIN || defined OS_LINUX || defined OS_BSD || defined OS_POSIX)
+#define FFI_ENABLE_LUATEX_INTERFACE
+#endif 
+
+#ifdef _WIN32
+
+#   ifdef UNDER_CE
+        static void* DoLoadLibraryA(const char* name) {
+          wchar_t buf[MAX_PATH];
+          int sz = MultiByteToWideChar(CP_UTF8, 0, name, -1, buf, 512);
+          if (sz > 0) {
+            buf[sz] = 0;
+            return LoadLibraryW(buf);
+          } else {
+            return NULL;
+          }
+        }
+#       define LoadLibraryA DoLoadLibraryA
+#   else
+#       define GetProcAddressA GetProcAddress
+#   endif
+
+#   define LIB_FORMAT_1 "%s.dll"
+#   define AllocPage(size) VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)
+#   define FreePage(data, size) VirtualFree(data, 0, MEM_RELEASE)
+#   define EnableExecute(data, size) do {DWORD old; VirtualProtect(data, size, PAGE_EXECUTE, &old); FlushInstructionCache(GetCurrentProcess(), data, size);} while (0)
+#   define EnableWrite(data, size) do {DWORD old; VirtualProtect(data, size, PAGE_READWRITE, &old);} while (0)
+
+#else
+#ifdef OS_OSX
+#   define LIB_FORMAT_1 "%s.dylib"
+#   define LIB_FORMAT_2 "lib%s.dylib"
+#else
+#   define LIB_FORMAT_1 "%s.so"
+#   define LIB_FORMAT_2 "lib%s.so"
+#endif
+#   define LoadLibraryA(name) dlopen(name, RTLD_LAZY | RTLD_GLOBAL)
+#   define GetProcAddressA(lib, name) dlsym(lib, name)
+#   define AllocPage(size) mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0)
+#   define FreePage(data, size) munmap(data, size)
+#   define EnableExecute(data, size) mprotect(data, size, PROT_READ|PROT_EXEC)
+#   define EnableWrite(data, size) mprotect(data, size, PROT_READ|PROT_WRITE)
+#endif
+
+#if defined ARCH_X86 || defined ARCH_X64
+#define ALLOW_MISALIGNED_ACCESS
+#endif
+
+struct token;
+
+struct parser {
+    int line;
+    const char* next;
+    const char* prev;
+    unsigned align_mask;
+};
+
+struct page {
+    size_t size;
+    size_t off;
+    size_t freed;
+};
+
+struct jit {
+    lua_State* L;
+    int32_t last_errno;
+    dasm_State* ctx;
+    size_t pagenum;
+    struct page** pages;
+    size_t align_page_size;
+    void** globals;
+    int function_extern;
+    void* lua_dll;
+    void* kernel32_dll;
+};
+
+#define ALIGN_DOWN(PTR, MASK) \
+  (((uintptr_t) (PTR)) & (~ ((uintptr_t) (MASK)) ))
+#define ALIGN_UP(PTR, MASK) \
+  (( ((uintptr_t) (PTR)) + ((uintptr_t) (MASK)) ) & (~ ((uintptr_t) (MASK)) ))
+
+/* struct cdata/struct ctype */
+
+#define PTR_ALIGN_MASK (sizeof(void*) - 1)
+#define FUNCTION_ALIGN_MASK (sizeof(void (*)()) - 1)
+#define DEFAULT_ALIGN_MASK 7
+
+#ifdef OS_OSX
+/* TODO: figure out why the alignof trick doesn't work on OS X */
+#define ALIGNED_DEFAULT 7
+#elif defined __GNUC__
+#define ALIGNED_DEFAULT (__alignof__(void* __attribute__((aligned))) - 1)
+#else
+#define ALIGNED_DEFAULT PTR_ALIGN_MASK
+#endif
+
+extern int jit_key;
+extern int ctype_mt_key;
+extern int cdata_mt_key;
+extern int cmodule_mt_key;
+extern int callback_mt_key;
+extern int constants_key;
+extern int types_key;
+extern int gc_key;
+extern int callbacks_key;
+extern int functions_key;
+extern int abi_key;
+extern int next_unnamed_key;
+extern int niluv_key;
+extern int asmname_key;
+
+int equals_upval(lua_State* L, int idx, int* key);
+void push_upval(lua_State* L, int* key);
+void set_upval(lua_State* L, int* key);
+struct jit* get_jit(lua_State* L);
+
+/* both ctype and cdata are stored as userdatas
+ *
+ * usr value is a table shared between the related subtypes which has:
+ * name -> member ctype (for structs and unions)
+ * +ves -> member ctype - in memory order (for structs)
+ * +ves -> argument ctype (for function prototypes)
+ * 0 -> return ctype (for function prototypes)
+ * light userdata -> misc
+ */
+
+enum {
+    C_CALL,
+    STD_CALL,
+    FAST_CALL,
+};
+
+enum {
+    INVALID_TYPE,
+    VOID_TYPE,
+    FLOAT_TYPE,
+    DOUBLE_TYPE,
+    LONG_DOUBLE_TYPE,
+    COMPLEX_FLOAT_TYPE,
+    COMPLEX_DOUBLE_TYPE,
+    COMPLEX_LONG_DOUBLE_TYPE,
+    BOOL_TYPE,
+    INT8_TYPE,
+    INT16_TYPE,
+    INT32_TYPE,
+    INT64_TYPE,
+    INTPTR_TYPE,
+    ENUM_TYPE,
+    UNION_TYPE,
+    STRUCT_TYPE,
+    FUNCTION_TYPE,
+    FUNCTION_PTR_TYPE,
+};
+
+#define IS_CHAR_UNSIGNED (((char) -1) > 0)
+#define IS_COMPLEX(type) ((type) == COMPLEX_FLOAT_TYPE || (type) == COMPLEX_DOUBLE_TYPE)
+
+#define POINTER_BITS 2
+#define POINTER_MAX ((1 << POINTER_BITS) - 1)
+
+#define ALIGNOF(S) ((int) ((char*) &S.v - (char*) &S - 1))
+
+/* Note: if adding a new member that is associated with a struct/union
+ * definition then it needs to be copied over in ctype.c:set_defined for when
+ * we create types based off of the declaration alone.
+ *
+ * Since this is used as a header for every ctype and cdata, and we create a
+ * ton of them on the stack, we try and minimise its size.
+ */
+struct ctype {
+    size_t base_size; /* size of the base type in bytes */
+
+    union {
+        /* valid if is_bitfield */
+        struct {
+            /* size of bitfield in bits */
+            unsigned bit_size : 7;
+            /* offset within the current byte between 0-63 */
+            unsigned bit_offset : 6;
+        };
+        /* Valid if is_array */
+        size_t array_size;
+        /* Valid for is_variable_struct or is_variable_array. If
+         * variable_size_known (only used for is_variable_struct) then this is
+         * the total increment otherwise this is the per element increment.
+         */
+        size_t variable_increment;
+    };
+    size_t offset;
+    unsigned align_mask : 4; /* as (align bytes - 1) eg 7 gives 8 byte alignment */
+    unsigned pointers : POINTER_BITS; /* number of dereferences to get to the base type including +1 for arrays */
+    unsigned const_mask : POINTER_MAX + 1; /* const pointer mask, LSB is current pointer, +1 for the whether the base type is const */
+    unsigned type : 5; /* value given by type enum above */
+    unsigned is_reference : 1;
+    unsigned is_array : 1;
+    unsigned is_defined : 1;
+    unsigned is_null : 1;
+    unsigned has_member_name : 1;
+    unsigned calling_convention : 2;
+    unsigned has_var_arg : 1;
+    unsigned is_variable_array : 1; /* set for variable array types where we don't know the variable size yet */
+    unsigned is_variable_struct : 1;
+    unsigned variable_size_known : 1; /* used for variable structs after we know the variable size */
+    unsigned is_bitfield : 1;
+    unsigned has_bitfield : 1;
+    unsigned is_jitted : 1;
+    unsigned is_packed : 1;
+    unsigned is_unsigned : 1;
+};
+
+#ifdef _MSC_VER
+__declspec(align(16))
+#endif
+struct cdata {
+    const struct ctype type
+#ifdef __GNUC__
+      __attribute__ ((aligned(16)))
+#endif
+      ;
+};
+
+typedef void (*cfunction)(void);
+
+#ifdef HAVE_COMPLEX
+typedef double complex complex_double;
+typedef float complex complex_float;
+static complex_double mk_complex_double(double real, double imag) {
+    return real + imag * 1i;
+}
+static complex_double mk_complex_float(double real, double imag) {
+    return real + imag * 1i;
+}
+#else
+typedef struct {
+    double real, imag;
+} complex_double;
+
+typedef struct {
+    float real, imag;
+} complex_float;
+
+static complex_double mk_complex_double(double real, double imag) {
+    complex_double ret = { real, imag };
+    return ret;
+}
+static complex_float mk_complex_float(double real, double imag) {
+    complex_float ret = { real, imag };
+    return ret;
+}
+static double creal(complex_double c) {
+    return c.real;
+}
+static float crealf(complex_float c) {
+    return c.real;
+}
+
+static double cimag(complex_double c) {
+    return c.imag;
+}
+static float cimagf(complex_float c) {
+    return c.imag;
+}
+#endif
+
+#define CALLBACK_FUNC_USR_IDX 1
+
+void set_defined(lua_State* L, int ct_usr, struct ctype* ct);
+struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct);
+void* push_cdata(lua_State* L, int ct_usr, const struct ctype* ct); /* called from asm */
+void push_callback(lua_State* L, cfunction luafunc, cfunction cfunc);
+void check_ctype(lua_State* L, int idx, struct ctype* ct);
+void* to_cdata(lua_State* L, int idx, struct ctype* ct);
+void* check_cdata(lua_State* L, int idx, struct ctype* ct);
+size_t ctype_size(lua_State* L, const struct ctype* ct);
+
+int parse_type(lua_State* L, struct parser* P, struct ctype* type);
+void parse_argument(lua_State* L, struct parser* P, int ct_usr, struct ctype* type, struct token* name, struct parser* asmname);
+void push_type_name(lua_State* L, int usr, const struct ctype* ct);
+
+int push_user_mt(lua_State* L, int ct_usr, const struct ctype* ct);
+
+int ffi_cdef(lua_State* L);
+
+void push_func_ref(lua_State* L, cfunction func);
+void free_code(struct jit* jit, lua_State* L, cfunction func);
+int x86_return_size(lua_State* L, int usr, const struct ctype* ct);
+void compile_function(lua_State* L, cfunction f, int ct_usr, const struct ctype* ct);
+cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct);
+void compile_globals(struct jit* jit, lua_State* L);
+int get_extern(struct jit* jit, uint8_t* addr, int idx, int type);
+
+/* WARNING: assembly needs to be updated for prototype changes of these functions */
+int check_bool(lua_State* L, int idx);
+double check_double(lua_State* L, int idx);
+double check_complex_imag(lua_State* L, int idx);
+float check_float(lua_State* L, int idx);
+uint64_t check_uint64(lua_State* L, int idx);
+int64_t check_int64(lua_State* L, int idx);
+int32_t check_int32(lua_State* L, int idx);
+uint32_t check_uint32(lua_State* L, int idx);
+uintptr_t check_uintptr(lua_State* L, int idx);
+int32_t check_enum(lua_State* L, int idx, int to_usr, const struct ctype* tt);
+/* these two will always push a value so that we can create structs/functions on the fly */
+void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* tt);
+cfunction check_typed_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt);
+complex_double check_complex_double(lua_State* L, int idx);
+complex_float check_complex_float(lua_State* L, int idx);
+
+void unpack_varargs_stack(lua_State* L, int first, int last, char* to);
+void unpack_varargs_reg(lua_State* L, int first, int last, char* to);
+
+void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_skip, int floats_to_skip, char* to);
+void unpack_varargs_float(lua_State* L, int first, int last, int max, char* to);
+void unpack_varargs_int(lua_State* L, int first, int last, int max, char* to);
+
+
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.h.orig
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.h.orig	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/ffi.h.orig	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,455 @@
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#pragma once
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C" {
+# include <lua.h>
+# include <lauxlib.h>
+# include <lualib.h>
+}
+# define EXTERN_C extern "C"
+#else
+# include <lua.h>
+# include <lauxlib.h>
+# include <lualib.h>
+# define EXTERN_C extern
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <errno.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <sys/mman.h>
+#endif
+
+#include <complex.h>
+#define HAVE_COMPLEX
+#define HAVE_LONG_DOUBLE
+
+#ifndef NDEBUG
+#define DASM_CHECKS
+#endif
+
+struct jit;
+#define Dst_DECL	struct jit* Dst
+#define Dst_REF		(Dst->ctx)
+#define DASM_EXTERN(a,b,c,d) get_extern(a,b,c,d)
+
+#include "dynasm/dasm_proto.h"
+
+#if defined LUA_FFI_BUILD_AS_DLL
+# define EXPORT __declspec(dllexport)
+#elif defined __GNUC__
+# define EXPORT __attribute__((visibility("default")))
+#else
+# define EXPORT
+#endif
+
+EXTERN_C EXPORT int luaopen_ffi(lua_State* L);
+
+static int lua_absindex2(lua_State* L, int idx) {
+    return (LUA_REGISTRYINDEX <= idx && idx < 0)
+         ? lua_gettop(L) + idx + 1
+         : idx;
+}
+/* use our own version of lua_absindex such that lua_absindex(L, 0) == 0 */
+#define lua_absindex(L, idx) lua_absindex2(L, idx)
+
+#if LUA_VERSION_NUM == 501
+static void lua_callk(lua_State *L, int nargs, int nresults, int ctx, lua_CFunction k)
+{
+    lua_call(L, nargs, nresults);
+}
+/*
+** set functions from list 'l' into table at top - 'nup'; each
+** function gets the 'nup' elements at the top as upvalues.
+** Returns with only the table at the stack.
+*/
+static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
+  luaL_checkstack(L, nup, "too many upvalues");
+  for (; l && l->name; l++) {  /* fill the table with given functions */
+    int i;
+    for (i = 0; i < nup; i++)  /* copy upvalues to the top */
+      lua_pushvalue(L, -nup);
+    lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
+    lua_setfield(L, -(nup + 2), l->name);
+  }
+  lua_pop(L, nup);  /* remove upvalues */
+}
+#define lua_setuservalue lua_setfenv
+#define lua_getuservalue lua_getfenv
+#define lua_rawlen lua_objlen
+static char* luaL_prepbuffsize(luaL_Buffer* B, size_t sz) {
+    if (sz > LUAL_BUFFERSIZE) {
+        luaL_error(B->L, "string too long");
+    }
+    return luaL_prepbuffer(B);
+}
+#elif LUA_VERSION_NUM == 503
+static void (lua_remove)(lua_State *L, int idx) {
+    lua_remove(L, idx);
+}
+#endif
+
+/* architectures */
+#if defined _WIN32 && defined UNDER_CE
+# define OS_CE
+#elif defined _WIN32
+# define OS_WIN
+#elif defined __APPLE__ && defined __MACH__
+# define OS_OSX
+#elif defined __linux__
+# define OS_LINUX
+#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
+# define OS_BSD
+#elif defined unix || defined __unix__ || defined __unix || defined _POSIX_VERSION || defined _XOPEN_VERSION
+# define OS_POSIX
+#endif
+
+/* architecture */
+#if defined __i386__ || defined _M_IX86
+# define ARCH_X86
+#elif defined __amd64__ || defined _M_X64
+# define ARCH_X64
+#elif defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __aarch64__
+# define ARCH_ARM
+#elif defined __powerpc64__
+# define ARCH_PPC64
+#else
+# error
+#endif
+
+
+#ifdef _WIN32
+
+#   ifdef UNDER_CE
+        static void* DoLoadLibraryA(const char* name) {
+          wchar_t buf[MAX_PATH];
+          int sz = MultiByteToWideChar(CP_UTF8, 0, name, -1, buf, 512);
+          if (sz > 0) {
+            buf[sz] = 0;
+            return LoadLibraryW(buf);
+          } else {
+            return NULL;
+          }
+        }
+#       define LoadLibraryA DoLoadLibraryA
+#   else
+#       define GetProcAddressA GetProcAddress
+#   endif
+
+#   define LIB_FORMAT_1 "%s.dll"
+#   define AllocPage(size) VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)
+#   define FreePage(data, size) VirtualFree(data, 0, MEM_RELEASE)
+#   define EnableExecute(data, size) do {DWORD old; VirtualProtect(data, size, PAGE_EXECUTE, &old); FlushInstructionCache(GetCurrentProcess(), data, size);} while (0)
+#   define EnableWrite(data, size) do {DWORD old; VirtualProtect(data, size, PAGE_READWRITE, &old);} while (0)
+
+#else
+#ifdef OS_OSX
+#   define LIB_FORMAT_1 "%s.dylib"
+#   define LIB_FORMAT_2 "lib%s.dylib"
+#else
+#   define LIB_FORMAT_1 "%s.so"
+#   define LIB_FORMAT_2 "lib%s.so"
+#endif
+#   define LoadLibraryA(name) dlopen(name, RTLD_LAZY | RTLD_GLOBAL)
+#   define GetProcAddressA(lib, name) dlsym(lib, name)
+#   define AllocPage(size) mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0)
+#   define FreePage(data, size) munmap(data, size)
+#   define EnableExecute(data, size) mprotect(data, size, PROT_READ|PROT_EXEC)
+#   define EnableWrite(data, size) mprotect(data, size, PROT_READ|PROT_WRITE)
+#endif
+
+#if defined ARCH_X86 || defined ARCH_X64
+#define ALLOW_MISALIGNED_ACCESS
+#endif
+
+struct token;
+
+struct parser {
+    int line;
+    const char* next;
+    const char* prev;
+    unsigned align_mask;
+};
+
+struct page {
+    size_t size;
+    size_t off;
+    size_t freed;
+};
+
+struct jit {
+    lua_State* L;
+    int32_t last_errno;
+    dasm_State* ctx;
+    size_t pagenum;
+    struct page** pages;
+    size_t align_page_size;
+    void** globals;
+    int function_extern;
+    void* lua_dll;
+    void* kernel32_dll;
+};
+
+#define ALIGN_DOWN(PTR, MASK) \
+  (((uintptr_t) (PTR)) & (~ ((uintptr_t) (MASK)) ))
+#define ALIGN_UP(PTR, MASK) \
+  (( ((uintptr_t) (PTR)) + ((uintptr_t) (MASK)) ) & (~ ((uintptr_t) (MASK)) ))
+
+/* struct cdata/struct ctype */
+
+#define PTR_ALIGN_MASK (sizeof(void*) - 1)
+#define FUNCTION_ALIGN_MASK (sizeof(void (*)()) - 1)
+#define DEFAULT_ALIGN_MASK 7
+
+#ifdef OS_OSX
+/* TODO: figure out why the alignof trick doesn't work on OS X */
+#define ALIGNED_DEFAULT 7
+#elif defined __GNUC__
+#define ALIGNED_DEFAULT (__alignof__(void* __attribute__((aligned))) - 1)
+#else
+#define ALIGNED_DEFAULT PTR_ALIGN_MASK
+#endif
+
+extern int jit_key;
+extern int ctype_mt_key;
+extern int cdata_mt_key;
+extern int cmodule_mt_key;
+extern int callback_mt_key;
+extern int constants_key;
+extern int types_key;
+extern int gc_key;
+extern int callbacks_key;
+extern int functions_key;
+extern int abi_key;
+extern int next_unnamed_key;
+extern int niluv_key;
+extern int asmname_key;
+
+int equals_upval(lua_State* L, int idx, int* key);
+void push_upval(lua_State* L, int* key);
+void set_upval(lua_State* L, int* key);
+struct jit* get_jit(lua_State* L);
+
+/* both ctype and cdata are stored as userdatas
+ *
+ * usr value is a table shared between the related subtypes which has:
+ * name -> member ctype (for structs and unions)
+ * +ves -> member ctype - in memory order (for structs)
+ * +ves -> argument ctype (for function prototypes)
+ * 0 -> return ctype (for function prototypes)
+ * light userdata -> misc
+ */
+
+enum {
+    C_CALL,
+    STD_CALL,
+    FAST_CALL,
+};
+
+enum {
+    INVALID_TYPE,
+    VOID_TYPE,
+    FLOAT_TYPE,
+    DOUBLE_TYPE,
+    LONG_DOUBLE_TYPE,
+    COMPLEX_FLOAT_TYPE,
+    COMPLEX_DOUBLE_TYPE,
+    COMPLEX_LONG_DOUBLE_TYPE,
+    BOOL_TYPE,
+    INT8_TYPE,
+    INT16_TYPE,
+    INT32_TYPE,
+    INT64_TYPE,
+    INTPTR_TYPE,
+    ENUM_TYPE,
+    UNION_TYPE,
+    STRUCT_TYPE,
+    FUNCTION_TYPE,
+    FUNCTION_PTR_TYPE,
+};
+
+#define IS_CHAR_UNSIGNED (((char) -1) > 0)
+#define IS_COMPLEX(type) ((type) == COMPLEX_FLOAT_TYPE || (type) == COMPLEX_DOUBLE_TYPE)
+
+#define POINTER_BITS 2
+#define POINTER_MAX ((1 << POINTER_BITS) - 1)
+
+#define ALIGNOF(S) ((int) ((char*) &S.v - (char*) &S - 1))
+
+/* Note: if adding a new member that is associated with a struct/union
+ * definition then it needs to be copied over in ctype.c:set_defined for when
+ * we create types based off of the declaration alone.
+ *
+ * Since this is used as a header for every ctype and cdata, and we create a
+ * ton of them on the stack, we try and minimise its size.
+ */
+struct ctype {
+    size_t base_size; /* size of the base type in bytes */
+
+    union {
+        /* valid if is_bitfield */
+        struct {
+            /* size of bitfield in bits */
+            unsigned bit_size : 7;
+            /* offset within the current byte between 0-63 */
+            unsigned bit_offset : 6;
+        };
+        /* Valid if is_array */
+        size_t array_size;
+        /* Valid for is_variable_struct or is_variable_array. If
+         * variable_size_known (only used for is_variable_struct) then this is
+         * the total increment otherwise this is the per element increment.
+         */
+        size_t variable_increment;
+    };
+    size_t offset;
+    unsigned align_mask : 4; /* as (align bytes - 1) eg 7 gives 8 byte alignment */
+    unsigned pointers : POINTER_BITS; /* number of dereferences to get to the base type including +1 for arrays */
+    unsigned const_mask : POINTER_MAX + 1; /* const pointer mask, LSB is current pointer, +1 for the whether the base type is const */
+    unsigned type : 5; /* value given by type enum above */
+    unsigned is_reference : 1;
+    unsigned is_array : 1;
+    unsigned is_defined : 1;
+    unsigned is_null : 1;
+    unsigned has_member_name : 1;
+    unsigned calling_convention : 2;
+    unsigned has_var_arg : 1;
+    unsigned is_variable_array : 1; /* set for variable array types where we don't know the variable size yet */
+    unsigned is_variable_struct : 1;
+    unsigned variable_size_known : 1; /* used for variable structs after we know the variable size */
+    unsigned is_bitfield : 1;
+    unsigned has_bitfield : 1;
+    unsigned is_jitted : 1;
+    unsigned is_packed : 1;
+    unsigned is_unsigned : 1;
+};
+
+#ifdef _MSC_VER
+__declspec(align(16))
+#endif
+struct cdata {
+    const struct ctype type
+#ifdef __GNUC__
+      __attribute__ ((aligned(16)))
+#endif
+      ;
+};
+
+typedef void (*cfunction)(void);
+
+#ifdef HAVE_COMPLEX
+typedef double complex complex_double;
+typedef float complex complex_float;
+static complex_double mk_complex_double(double real, double imag) {
+    return real + imag * 1i;
+}
+static complex_double mk_complex_float(double real, double imag) {
+    return real + imag * 1i;
+}
+#else
+typedef struct {
+    double real, imag;
+} complex_double;
+
+typedef struct {
+    float real, imag;
+} complex_float;
+
+static complex_double mk_complex_double(double real, double imag) {
+    complex_double ret = { real, imag };
+    return ret;
+}
+static complex_float mk_complex_float(double real, double imag) {
+    complex_float ret = { real, imag };
+    return ret;
+}
+static double creal(complex_double c) {
+    return c.real;
+}
+static float crealf(complex_float c) {
+    return c.real;
+}
+
+static double cimag(complex_double c) {
+    return c.imag;
+}
+static float cimagf(complex_float c) {
+    return c.imag;
+}
+#endif
+
+#define CALLBACK_FUNC_USR_IDX 1
+
+void set_defined(lua_State* L, int ct_usr, struct ctype* ct);
+struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct);
+void* push_cdata(lua_State* L, int ct_usr, const struct ctype* ct); /* called from asm */
+void push_callback(lua_State* L, cfunction luafunc, cfunction cfunc);
+void check_ctype(lua_State* L, int idx, struct ctype* ct);
+void* to_cdata(lua_State* L, int idx, struct ctype* ct);
+void* check_cdata(lua_State* L, int idx, struct ctype* ct);
+size_t ctype_size(lua_State* L, const struct ctype* ct);
+
+int parse_type(lua_State* L, struct parser* P, struct ctype* type);
+void parse_argument(lua_State* L, struct parser* P, int ct_usr, struct ctype* type, struct token* name, struct parser* asmname);
+void push_type_name(lua_State* L, int usr, const struct ctype* ct);
+
+int push_user_mt(lua_State* L, int ct_usr, const struct ctype* ct);
+
+int ffi_cdef(lua_State* L);
+
+void push_func_ref(lua_State* L, cfunction func);
+void free_code(struct jit* jit, lua_State* L, cfunction func);
+int x86_return_size(lua_State* L, int usr, const struct ctype* ct);
+void compile_function(lua_State* L, cfunction f, int ct_usr, const struct ctype* ct);
+cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct);
+void compile_globals(struct jit* jit, lua_State* L);
+int get_extern(struct jit* jit, uint8_t* addr, int idx, int type);
+
+/* WARNING: assembly needs to be updated for prototype changes of these functions */
+int check_bool(lua_State* L, int idx);
+double check_double(lua_State* L, int idx);
+double check_complex_imag(lua_State* L, int idx);
+float check_float(lua_State* L, int idx);
+uint64_t check_uint64(lua_State* L, int idx);
+int64_t check_int64(lua_State* L, int idx);
+int32_t check_int32(lua_State* L, int idx);
+uint32_t check_uint32(lua_State* L, int idx);
+uintptr_t check_uintptr(lua_State* L, int idx);
+int32_t check_enum(lua_State* L, int idx, int to_usr, const struct ctype* tt);
+/* these two will always push a value so that we can create structs/functions on the fly */
+void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* tt);
+cfunction check_typed_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt);
+complex_double check_complex_double(lua_State* L, int idx);
+complex_float check_complex_float(lua_State* L, int idx);
+
+void unpack_varargs_stack(lua_State* L, int first, int last, char* to);
+void unpack_varargs_reg(lua_State* L, int first, int last, char* to);
+
+void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_skip, int floats_to_skip, char* to);
+void unpack_varargs_float(lua_State* L, int first, int last, int max, char* to);
+void unpack_varargs_int(lua_State* L, int first, int last, int max, char* to);
+
+
+

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/generate_call_h.bat
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/generate_call_h.bat	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/generate_call_h.bat	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,4 @@
+lua.exe dynasm\dynasm.lua -LNE -D X32WIN -o call_x86.h call_x86.dasc
+lua.exe dynasm\dynasm.lua -LNE -D X64 -o call_x64.h call_x86.dasc
+lua.exe dynasm\dynasm.lua -LNE -D X64 -D X64WIN -o call_x64win.h call_x86.dasc
+lua.exe dynasm\dynasm.lua -LNE -o call_arm.h call_arm.dasc

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/luaffi-scm-1.rockspec
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/luaffi-scm-1.rockspec	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/luaffi-scm-1.rockspec	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,34 @@
+package = "luaffi"
+version = "scm-1"
+
+source = {
+   url = "git://github.com/facebook/luaffifb.git",
+}
+
+description = {
+   summary = "FFI library for calling C functions from lua",
+   detailed = [[
+   ]],
+   homepage = "https://github.com/facebook/luaffifb",
+   license = "BSD"
+}
+
+dependencies = {
+   "lua >= 5.1",
+}
+
+build = {
+   type = "builtin",
+   modules = {
+      ['ffi'] = {
+         incdirs = {
+            "dynasm"
+         },
+         sources = {
+            "call.c", "ctype.c", "ffi.c", "parser.c",
+         }
+      },
+      ['ffi.libtest'] = 'test.c',
+      ['ffi.test'] = 'test.lua',
+   }
+}

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/inttypes.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/inttypes.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/inttypes.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,31 @@
+#pragma once
+
+/* Signed integers */
+#define PRId8   "d"
+#define PRId16  "d"
+#define PRId32  "d"
+#define PRId64  "I64d"
+#define PRIi8   "i"
+#define PRIi16  "i"
+#define PRIi32  "i"
+#define PRIi64  "I64i"
+
+/* Unsigned integers */
+#define PRIo8   "o"
+#define PRIo16  "o"
+#define PRIo32  "o"
+#define PRIo64  "I64o"
+#define PRIu8   "u"
+#define PRIu16  "u"
+#define PRIu32  "u"
+#define PRIu64  "I64u"
+#define PRIx8   "x"
+#define PRIx16  "x"
+#define PRIx32  "x"
+#define PRIx64  "I64x"
+#define PRIX8   "X"
+#define PRIX16  "X"
+#define PRIX32  "X"
+#define PRIX64  "I64X"
+#define PRIxPTR PRIx32
+#define PRIXPTR PRIX32


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/inttypes.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/stdbool.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/stdbool.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/stdbool.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,42 @@
+/* vim: ts=4 sw=4 sts=4 et
+ *
+ * Copyright (c) 2009 James R. McKaskill
+ *
+ * This software is licensed under the stock MIT license:
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+#pragma once
+
+
+#if defined __cplusplus
+typedef bool _Bool;
+
+#else
+#pragma warning(disable:4244) /* conversion from int to _Bool */
+typedef unsigned char _Bool;
+#define bool _Bool
+#define true 1
+#define false 0
+#define __bool_true_false_are_defined 1
+
+#endif


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/stdbool.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/stdint.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/stdint.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/stdint.h	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,174 @@
+//  boost cstdint.hpp header file  ------------------------------------------//
+
+//  (C) Copyright Beman Dawes 1999. 
+//  (C) Copyright Jens Mauer 2001  
+//  (C) Copyright John Maddock 2001 
+//  Distributed under the Boost
+//  Software License, Version 1.0. (See accompanying file
+//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org/libs/integer for documentation.
+
+//  Revision History
+//   31 Oct 01  use BOOST_HAS_LONG_LONG to check for "long long" (Jens M.)
+//   16 Apr 01  check LONGLONG_MAX when looking for "long long" (Jens Maurer)
+//   23 Jan 01  prefer "long" over "int" for int32_t and intmax_t (Jens Maurer)
+//   12 Nov 00  Merged <boost/stdint.h> (Jens Maurer)
+//   23 Sep 00  Added INTXX_C macro support (John Maddock).
+//   22 Sep 00  Better 64-bit support (John Maddock)
+//   29 Jun 00  Reimplement to avoid including stdint.h within namespace boost
+//    8 Aug 99  Initial version (Beman Dawes)
+
+
+#ifndef STDINT_H
+#define STDINT_H
+
+#ifndef UNDER_CE
+#include <crtdefs.h>
+#endif
+
+#include <limits.h>
+
+//  These are fairly safe guesses for some 16-bit, and most 32-bit and 64-bit
+//  platforms.  For other systems, they will have to be hand tailored.
+//
+//  Because the fast types are assumed to be the same as the undecorated types,
+//  it may be possible to hand tailor a more efficient implementation.  Such
+//  an optimization may be illusionary; on the Intel x86-family 386 on, for
+//  example, byte arithmetic and load/stores are as fast as "int" sized ones.
+
+//  8-bit types  ------------------------------------------------------------//
+
+# if UCHAR_MAX == 0xff
+     typedef signed char     int8_t;
+     typedef signed char     int_least8_t;
+     typedef signed char     int_fast8_t;
+     typedef unsigned char   uint8_t;
+     typedef unsigned char   uint_least8_t;
+     typedef unsigned char   uint_fast8_t;
+# else
+#    error defaults not correct; you must hand modify boost/cstdint.hpp
+# endif
+
+//  16-bit types  -----------------------------------------------------------//
+
+# if USHRT_MAX == 0xffff
+#  if defined(__crayx1)
+     // The Cray X1 has a 16-bit short, however it is not recommend
+     // for use in performance critical code.
+     typedef short           int16_t;
+     typedef short           int_least16_t;
+     typedef int             int_fast16_t;
+     typedef unsigned short  uint16_t;
+     typedef unsigned short  uint_least16_t;
+     typedef unsigned int    uint_fast16_t;
+#  else
+     typedef short           int16_t;
+     typedef short           int_least16_t;
+     typedef short           int_fast16_t;
+     typedef unsigned short  uint16_t;
+     typedef unsigned short  uint_least16_t;
+     typedef unsigned short  uint_fast16_t;
+#  endif
+# elif (USHRT_MAX == 0xffffffff) && defined(CRAY)
+     // no 16-bit types on Cray:
+     typedef short           int_least16_t;
+     typedef short           int_fast16_t;
+     typedef unsigned short  uint_least16_t;
+     typedef unsigned short  uint_fast16_t;
+# else
+#    error defaults not correct; you must hand modify boost/cstdint.hpp
+# endif
+
+//  32-bit types  -----------------------------------------------------------//
+
+# if ULONG_MAX == 0xffffffff
+     typedef long            int32_t;
+     typedef long            int_least32_t;
+     typedef long            int_fast32_t;
+     typedef unsigned long   uint32_t;
+     typedef unsigned long   uint_least32_t;
+     typedef unsigned long   uint_fast32_t;
+# elif UINT_MAX == 0xffffffff
+     typedef int             int32_t;
+     typedef int             int_least32_t;
+     typedef int             int_fast32_t;
+     typedef unsigned int    uint32_t;
+     typedef unsigned int    uint_least32_t;
+     typedef unsigned int    uint_fast32_t;
+# else
+#    error defaults not correct; you must hand modify boost/cstdint.hpp
+# endif
+
+//  64-bit types + intmax_t and uintmax_t  ----------------------------------//
+
+     //
+     // we have Borland/Intel/Microsoft __int64:
+     //
+     typedef __int64             intmax_t;
+     typedef unsigned __int64    uintmax_t;
+     typedef __int64             int64_t;
+     typedef __int64             int_least64_t;
+     typedef __int64             int_fast64_t;
+     typedef unsigned __int64    uint64_t;
+     typedef unsigned __int64    uint_least64_t;
+     typedef unsigned __int64    uint_fast64_t;
+
+
+
+/****************************************************
+
+Macro definition section:
+
+Define various INTXX_C macros only if
+__STDC_CONSTANT_MACROS is defined.
+
+Undefine the macros if __STDC_CONSTANT_MACROS is
+not defined and the macros are (cf <cassert>).
+
+Added 23rd September 2000 (John Maddock).
+Modified 11th September 2001 to be excluded when
+BOOST_HAS_STDINT_H is defined (John Maddock).
+
+******************************************************/
+
+#if defined(__STDC_CONSTANT_MACROS) || !defined(__cplusplus)
+//
+// Borland/Intel/Microsoft compilers have width specific suffixes:
+//
+#  define INT8_C(value)     value##i8
+#  define INT16_C(value)    value##i16
+#  define INT32_C(value)    value##i32
+#  define INT64_C(value)    value##i64
+#  define UINT8_C(value)    value##ui8
+#  define UINT16_C(value)   value##ui16
+#  define UINT32_C(value)   value##ui32
+#  define UINT64_C(value)   value##ui64
+#  define INTMAX_C(value)   value##i64
+#  define UINTMAX_C(value)  value##ui64
+
+#endif // __STDC_CONSTANT_MACROS_DEFINED etc.
+
+#if defined(__STDC_LIMIT_MACROS) || !defined(__cplusplus)
+#  define INT8_MIN          INT8_C(-127)-1
+#  define INT8_MAX          INT8_C(127)
+#  define INT16_MIN         INT16_C(-32767)-1
+#  define INT16_MAX         INT16_C(32767)
+#  define INT32_MIN         INT32_C(-2147483647)-1
+#  define INT32_MAX         INT32_C(2147483647)
+#  define INT64_MAX         INT64_C(9223372036854775807)
+#  define UINT8_MAX         UINT8_C(255)
+#  define UINT16_MAX        UINT16_C(65535)
+#  define UINT32_MAX        UINT32_C(4294967295)
+#  define UINT64_MAX        UINT64_C(18446744073709551615)
+#endif
+
+#ifdef UNDER_CE
+typedef unsigned long uintptr_t;
+typedef long intptr_t;
+#endif
+
+
+
+#endif // BOOST_CSTDINT_HPP
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/msvc/stdint.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/msvcbuild.bat
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/msvcbuild.bat	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/msvcbuild.bat	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,76 @@
+ at if not defined INCLUDE goto :FAIL
+
+ at setlocal
+
+ at if "%1"=="debug-5.1" goto :DEBUG_5_1
+
+rem These should not have quotes
+ at set LUA_INCLUDE=Z:\c\lua-5.2.0\src
+ at set LUA_LIB=Z:\c\lua-5.2.0\lua5.2.lib
+ at set LUA_EXE=Z:\c\lua-5.2.0\lua.exe
+rem This the name of the dll that can be handed to LoadLibrary. This should not have a path.
+ at set LUA_DLL=lua5.2.dll
+ at goto :DEBUG
+
+:DEBUG_5_1
+ at set LUA_INCLUDE=Z:\c\lua-5.1.4\src
+ at set LUA_LIB=Z:\c\lua-5.1.4\lua5.1.lib
+ at set LUA_EXE=Z:\c\lua-5.1.4\lua.exe
+ at set LUA_DLL=lua5.1.dll
+
+:DEBUG
+ at set DO_CL=cl.exe /nologo /c /MDd /FC /Zi /Od /W3 /WX /D_CRT_SECURE_NO_DEPRECATE /DLUA_FFI_BUILD_AS_DLL /I"msvc"
+ at set DO_LINK=link /nologo /debug
+ at set DO_MT=mt /nologo
+
+ at if "%1"=="debug" goto :COMPILE
+ at if "%1"=="debug-5.1" goto :COMPILE
+ at if "%1"=="test" goto :COMPILE
+ at if "%1"=="clean" goto :CLEAN
+ at if "%1"=="release" goto :RELEASE
+ at if "%1"=="test-release" goto :RELEASE
+
+:RELEASE
+ at set DO_CL=cl.exe /nologo /c /MD /Ox /W3 /Zi /WX /D_CRT_SECURE_NO_DEPRECATE /DLUA_FFI_BUILD_AS_DLL /I"msvc"
+ at set DO_LINK=link.exe /nologo /debug
+ at set DO_MT=mt.exe /nologo
+ at goto :COMPILE
+
+:COMPILE
+"%LUA_EXE%" dynasm\dynasm.lua -LNE -D X32WIN -o call_x86.h call_x86.dasc
+"%LUA_EXE%" dynasm\dynasm.lua -LNE -D X64 -o call_x64.h call_x86.dasc
+"%LUA_EXE%" dynasm\dynasm.lua -LNE -D X64 -D X64WIN -o call_x64win.h call_x86.dasc
+"%LUA_EXE%" dynasm\dynasm.lua -LNE -o call_arm.h call_arm.dasc
+%DO_CL% /I"." /I"%LUA_INCLUDE%" /DLUA_DLL_NAME="%LUA_DLL%" call.c ctype.c ffi.c parser.c
+%DO_LINK% /DLL /OUT:ffi.dll "%LUA_LIB%" *.obj
+if exist ffi.dll.manifest^
+    %DO_MT% -manifest ffi.dll.manifest -outputresource:"ffi.dll;2"
+
+%DO_CL% /Gd test.c /Fo"test_cdecl.obj"
+%DO_CL% /Gz test.c /Fo"test_stdcall.obj"
+%DO_CL% /Gr test.c /Fo"test_fastcall.obj"
+%DO_LINK% /DLL /OUT:test_cdecl.dll test_cdecl.obj
+%DO_LINK% /DLL /OUT:test_stdcall.dll test_stdcall.obj
+%DO_LINK% /DLL /OUT:test_fastcall.dll test_fastcall.obj
+if exist test_cdecl.dll.manifest^
+    %DO_MT% -manifest test_cdecl.dll.manifest -outputresource:"test_cdecl.dll;2"
+if exist test_stdcall.dll.manifest^
+    %DO_MT% -manifest test_stdcall.dll.manifest -outputresource:"test_stdcall.dll;2"
+if exist test_fastcall.dll.manifest^
+    %DO_MT% -manifest test_fastcall.dll.manifest -outputresource:"test_fastcall.dll;2"
+
+ at if "%1"=="test" "%LUA_EXE%" test.lua
+ at if "%1"=="test-5.2" "%LUA_EXE%" test.lua
+ at if "%1"=="test-release" "%LUA_EXE%" test.lua
+ at goto :CLEAN_OBJ
+
+:CLEAN
+del *.dll
+:CLEAN_OBJ
+del *.obj *.manifest
+ at goto :END
+
+:FAIL
+ at echo You must open a "Visual Studio .NET Command Prompt" to run this script
+:END
+

Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/parser.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/parser.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/parser.c	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,2618 @@
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+#include "ffi.h"
+
+#define IS_CONST(tok) (IS_LITERAL(tok, "const") || IS_LITERAL(tok, "__const") || IS_LITERAL(tok, "__const__"))
+#define IS_VOLATILE(tok) (IS_LITERAL(tok, "volatile") || IS_LITERAL(tok, "__volatile") || IS_LITERAL(tok, "__volatile__"))
+#define IS_RESTRICT(tok) (IS_LITERAL(tok, "restrict") || IS_LITERAL(tok, "__restrict") || IS_LITERAL(tok, "__restrict__"))
+#define IS_INLINE(tok) (IS_LITERAL(tok, "inline") || IS_LITERAL(tok, "__inline") || IS_LITERAL(tok, "__inline__"))
+
+enum etoken {
+    TOK_NIL,
+    TOK_NUMBER,
+    TOK_STRING,
+    TOK_TOKEN,
+
+    /* the order of these values must match the token strings in lex.c */
+
+    TOK_3_BEGIN,
+    TOK_VA_ARG,
+
+    TOK_2_BEGIN,
+    TOK_LEFT_SHIFT, TOK_RIGHT_SHIFT, TOK_LOGICAL_AND, TOK_LOGICAL_OR, TOK_LESS_EQUAL,
+    TOK_GREATER_EQUAL, TOK_EQUAL, TOK_NOT_EQUAL,
+
+    TOK_1_BEGIN,
+    TOK_OPEN_CURLY, TOK_CLOSE_CURLY, TOK_SEMICOLON, TOK_COMMA, TOK_COLON,
+    TOK_ASSIGN, TOK_OPEN_PAREN, TOK_CLOSE_PAREN, TOK_OPEN_SQUARE, TOK_CLOSE_SQUARE,
+    TOK_DOT, TOK_AMPERSAND, TOK_LOGICAL_NOT, TOK_BITWISE_NOT, TOK_MINUS,
+    TOK_PLUS, TOK_STAR, TOK_DIVIDE, TOK_MODULUS, TOK_LESS,
+    TOK_GREATER, TOK_BITWISE_XOR, TOK_BITWISE_OR, TOK_QUESTION, TOK_POUND,
+
+    TOK_REFERENCE = TOK_AMPERSAND,
+    TOK_MULTIPLY = TOK_STAR,
+    TOK_BITWISE_AND = TOK_AMPERSAND,
+};
+
+struct token {
+    enum etoken type;
+    int64_t integer;
+    const char* str;
+    size_t size;
+};
+
+#define IS_LITERAL(TOK, STR) \
+  (((TOK).size == sizeof(STR) - 1) && 0 == memcmp((TOK).str, STR, sizeof(STR) - 1))
+
+/* the order of tokens _must_ match the order of the enum etoken enum */
+
+static char tok3[][4] = {
+    "...", /* unused ">>=", "<<=", */
+};
+
+static char tok2[][3] = {
+    "<<", ">>", "&&", "||", "<=",
+    ">=", "==", "!=",
+    /* unused "+=", "-=", "*=", "/=", "%=", "&=", "^=", "|=", "++", "--", "->", "::", */
+};
+
+static char tok1[] = {
+    '{', '}', ';', ',', ':',
+    '=', '(', ')', '[', ']',
+    '.', '&', '!', '~', '-',
+    '+', '*', '/', '%', '<',
+    '>', '^', '|', '?', '#'
+};
+
+static int next_token(lua_State* L, struct parser* P, struct token* tok)
+{
+    size_t i;
+    const char* s = P->next;
+
+    /* UTF8 BOM */
+    if (s[0] == '\xEF' && s[1] == '\xBB' && s[2] == '\xBF') {
+        s += 3;
+    }
+
+    /* consume whitespace and comments */
+    for (;;) {
+        /* consume whitespace */
+        while(*s == '\t' || *s == '\n' || *s == ' ' || *s == '\v' || *s == '\r') {
+            if (*s == '\n') {
+                P->line++;
+            }
+            s++;
+        }
+
+        /* consume comments */
+        if (*s == '/' && *(s+1) == '/') {
+
+            s = strchr(s, '\n');
+            if (!s) {
+                luaL_error(L, "non-terminated comment");
+            }
+
+        } else if (*s == '/' && *(s+1) == '*') {
+            s += 2;
+
+            for (;;) {
+                if (s[0] == '\0') {
+                    luaL_error(L, "non-terminated comment");
+                } else if (s[0] == '*' && s[1] == '/') {
+                    s += 2;
+                    break;
+                } else if (s[0] == '\n') {
+                    P->line++;
+                }
+                s++;
+            }
+
+        } else if (*s == '\0') {
+            tok->type = TOK_NIL;
+            return 0;
+
+        } else {
+            break;
+        }
+    }
+
+    P->prev = s;
+
+    for (i = 0; i < sizeof(tok3) / sizeof(tok3[0]); i++) {
+        if (s[0] == tok3[i][0] && s[1] == tok3[i][1] && s[2] == tok3[i][2]) {
+            tok->type = (enum etoken) (TOK_3_BEGIN + 1 + i);
+            P->next = s + 3;
+            goto end;
+        }
+    }
+
+    for (i = 0; i < sizeof(tok2) / sizeof(tok2[0]); i++) {
+        if (s[0] == tok2[i][0] && s[1] == tok2[i][1]) {
+            tok->type = (enum etoken) (TOK_2_BEGIN + 1 + i);
+            P->next = s + 2;
+            goto end;
+        }
+    }
+
+    for (i = 0; i < sizeof(tok1) / sizeof(tok1[0]); i++) {
+        if (s[0] == tok1[i]) {
+            tok->type = (enum etoken) (TOK_1_BEGIN + 1 + i);
+            P->next = s + 1;
+            goto end;
+        }
+    }
+
+    if (*s == '.' || *s == '-' || ('0' <= *s && *s <= '9')) {
+        /* number */
+        tok->type = TOK_NUMBER;
+
+        /* split out the negative case so we get the full range of bits for
+         * unsigned (eg to support 0xFFFFFFFF where sizeof(long) == 4)
+         */
+        if (*s == '-') {
+            tok->integer = strtol(s, (char**) &s, 0);
+        } else {
+            tok->integer = strtoul(s, (char**) &s, 0);
+        }
+
+        while (*s == 'u' || *s == 'U' || *s == 'l' || *s == 'L') {
+            s++;
+        }
+
+        P->next = s;
+        goto end;
+
+    } else if (*s == '\'' || *s == '\"') {
+        /* "..." or '...' */
+        char quote = *s;
+        s++; /* jump over " */
+
+        tok->type = TOK_STRING;
+        tok->str = s;
+
+        while (*s != quote) {
+
+            if (*s == '\0' || (*s == '\\' && *(s+1) == '\0')) {
+                return luaL_error(L, "string not finished");
+            }
+
+            if (*s == '\\') {
+                s++;
+            }
+
+            s++;
+        }
+
+        tok->size = s - tok->str;
+        s++; /* jump over " */
+        P->next = s;
+        goto end;
+
+    } else if (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z') || *s == '_') {
+        /* tokens */
+        tok->type = TOK_TOKEN;
+        tok->str = s;
+
+        while (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z') || *s == '_' || ('0' <= *s && *s <= '9')) {
+            s++;
+        }
+
+        tok->size = s - tok->str;
+        P->next = s;
+        goto end;
+
+    } else {
+        return luaL_error(L, "invalid character %d", P->line);
+    }
+
+end:
+    /*fprintf(stderr, "token %d %d %.*s %.10s\n", tok->type, (int) tok->size, (tok->type == TOK_TOKEN || tok->type == TOK_STRING) ? (int) tok->size : 0, tok->str, P->next);*/
+    return 1;
+}
+
+#define require_token(L, P, tok) require_token_line(L, P, tok, __FILE__, __LINE__)
+
+static void require_token_line(lua_State* L, struct parser* P, struct token* tok, const char* file, int line)
+{
+    if (!next_token(L, P, tok)) {
+        luaL_error(L, "unexpected end on line %s:%d", file, line);
+    }
+}
+
+static void check_token(lua_State* L, struct parser* P, int type, const char* str, const char* err, ...)
+{
+    struct token tok;
+    if (!next_token(L, P, &tok) || tok.type != type || (tok.type == TOK_TOKEN && (tok.size != strlen(str) || memcmp(tok.str, str, tok.size) != 0))) {
+        va_list ap;
+        va_start(ap, err);
+        lua_pushvfstring(L, err, ap);
+        lua_error(L);
+    }
+}
+
+static void put_back(struct parser* P)
+{ P->next = P->prev; }
+
+
+int64_t calculate_constant(lua_State* L, struct parser* P);
+
+static int g_name_key;
+static int g_front_name_key;
+static int g_back_name_key;
+
+#ifndef max
+#define max(a,b) ((a) < (b) ? (b) : (a))
+#endif
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+enum test {TEST};
+
+/* Parses an enum definition from after the open curly through to the close
+ * curly. Expects the user table to be on the top of the stack
+ */
+static int parse_enum(lua_State* L, struct parser* P, struct ctype* type)
+{
+    struct token tok;
+    int value = -1;
+    int ct_usr = lua_gettop(L);
+
+    for (;;) {
+        require_token(L, P, &tok);
+
+        assert(lua_gettop(L) == ct_usr);
+
+        if (tok.type == TOK_CLOSE_CURLY) {
+            break;
+        } else if (tok.type != TOK_TOKEN) {
+            return luaL_error(L, "unexpected token in enum at line %d", P->line);
+        }
+
+        lua_pushlstring(L, tok.str, tok.size);
+
+        require_token(L, P, &tok);
+
+        if (tok.type == TOK_COMMA || tok.type == TOK_CLOSE_CURLY) {
+            /* we have an auto calculated enum value */
+            value++;
+        } else if (tok.type == TOK_ASSIGN) {
+            /* we have an explicit enum value */
+            value = (int) calculate_constant(L, P);
+            require_token(L, P, &tok);
+        } else {
+            return luaL_error(L, "unexpected token in enum at line %d", P->line);
+        }
+
+        assert(lua_gettop(L) == ct_usr + 1);
+
+        /* add the enum value to the constants table */
+        push_upval(L, &constants_key);
+        lua_pushvalue(L, -2);
+        lua_pushinteger(L, value);
+        lua_rawset(L, -3);
+        lua_pop(L, 1);
+
+        assert(lua_gettop(L) == ct_usr + 1);
+
+        /* add the enum value to the enum usr value table */
+        lua_pushinteger(L, value);
+        lua_rawset(L, ct_usr);
+
+        if (tok.type == TOK_CLOSE_CURLY) {
+            break;
+        } else if (tok.type != TOK_COMMA) {
+            return luaL_error(L, "unexpected token in enum at line %d", P->line);
+        }
+    }
+
+    type->base_size = sizeof(enum test);
+    type->align_mask = sizeof(enum test) - 1;
+
+    assert(lua_gettop(L) == ct_usr);
+    return 0;
+}
+
+static void calculate_member_position(lua_State* L, struct parser* P, struct ctype* ct, struct ctype* mt, int* pbit_offset, int* pbitfield_type)
+{
+    int bit_offset = *pbit_offset;
+
+    if (ct->type == UNION_TYPE) {
+        size_t msize;
+
+        if (mt->is_variable_struct || mt->is_variable_array) {
+            luaL_error(L, "NYI: variable sized members in unions");
+            return;
+
+        } else if (mt->is_bitfield) {
+            msize = (mt->align_mask + 1);
+#ifdef _WIN32
+            /* MSVC has a bug where it doesn't update the alignment of
+             * a union for bitfield members. */
+            mt->align_mask = 0;
+#endif
+
+        } else if (mt->is_array) {
+            msize = mt->array_size * (mt->pointers > 1 ? sizeof(void*) : mt->base_size);
+
+        } else {
+            msize = mt->pointers ? sizeof(void*) : mt->base_size;
+        }
+
+        ct->base_size = max(ct->base_size, msize);
+
+    } else if (mt->is_bitfield) {
+        if (mt->has_member_name && mt->bit_size == 0) {
+            luaL_error(L, "zero length bitfields must be unnamed on line %d", P->line);
+        }
+
+#if defined _WIN32
+        /* MSVC uses a seperate storage unit for each size. This is aligned
+         * before the first bitfield. :0 finishes up the storage unit using
+         * the greater alignment of the storage unit or the type used with the
+         * :0. This is equivalent to the :0 always creating a new storage
+         * unit, but not necesserily using it yet.
+         */
+
+        if (*pbitfield_type == -1 && mt->bit_size == 0) {
+            /* :0 not after a bitfield are ignored */
+            return;
+        }
+
+        {
+            int different_storage = mt->align_mask != *pbitfield_type;
+            int no_room_left = bit_offset + mt->bit_size > (mt->align_mask + 1) * CHAR_BIT;
+
+            if (different_storage || no_room_left || !mt->bit_size) {
+                ct->base_size += (bit_offset + CHAR_BIT - 1) / CHAR_BIT;
+                bit_offset = 0;
+                if (*pbitfield_type >= 0) {
+                    ct->base_size = ALIGN_UP(ct->base_size, *pbitfield_type);
+                }
+                ct->base_size = ALIGN_UP(ct->base_size, mt->align_mask);
+            }
+        }
+
+        mt->bit_offset = bit_offset;
+        mt->offset = ct->base_size;
+
+        *pbitfield_type = mt->align_mask;
+        bit_offset += mt->bit_size;
+
+// #elif defined OS_OSX
+//         /* OSX doesn't use containers and bitfields are not aligned. So
+//          * bitfields never add any padding, except for :0 which still forces
+//          * an alignment based off the type used with the :0 */
+//         if (mt->bit_size) {
+//             mt->offset = ct->base_size;
+//             mt->bit_offset = bit_offset;
+//             bit_offset += mt->bit_size;
+//             ct->base_size += bit_offset / CHAR_BIT;
+//             bit_offset = bit_offset % CHAR_BIT;
+//         } else {
+//             ct->base_size += (bit_offset + CHAR_BIT - 1) / CHAR_BIT;
+//             ct->base_size = ALIGN_UP(ct->base_size, mt->align_mask);
+//             bit_offset = 0;
+//         }
+
+//         if (!mt->has_member_name) {
+//             /* unnamed bitfields don't update the struct alignment */
+//             mt->align_mask = 0;
+//         }
+
+#elif defined __GNUC__
+        /* GCC tries to pack bitfields in as close as much as possible, but
+         * still making sure that they don't cross alignment boundaries.
+         * :0 forces an alignment based off the type used with the :0
+         */
+
+        int bits_used = (ct->base_size - ALIGN_DOWN(ct->base_size, mt->align_mask)) * CHAR_BIT + bit_offset;
+        int need_to_realign = bits_used + mt->bit_size > mt->base_size * CHAR_BIT;
+
+        if (!mt->is_packed && (!mt->bit_size || need_to_realign)) {
+            ct->base_size += (bit_offset + CHAR_BIT - 1) / CHAR_BIT;
+            ct->base_size = ALIGN_UP(ct->base_size, mt->align_mask);
+            bit_offset = 0;
+        }
+
+        mt->bit_offset = bit_offset;
+        mt->offset = ct->base_size;
+
+        bit_offset += mt->bit_size;
+        ct->base_size += bit_offset / CHAR_BIT;
+        bit_offset = bit_offset % CHAR_BIT;
+
+        /* unnamed bitfields don't update the struct alignment */
+        if (!mt->has_member_name) {
+            mt->align_mask = 0;
+        }
+#else
+#error
+#endif
+
+    } else {
+        /* finish up the current bitfield storage unit */
+        ct->base_size += (bit_offset + CHAR_BIT - 1) / CHAR_BIT;
+        bit_offset = 0;
+
+        if (*pbitfield_type >= 0) {
+            ct->base_size = ALIGN_UP(ct->base_size, *pbitfield_type);
+        }
+
+        *pbitfield_type = -1;
+
+        ct->base_size = ALIGN_UP(ct->base_size, mt->align_mask);
+        mt->offset = ct->base_size;
+
+        if (mt->is_variable_array) {
+            ct->is_variable_struct = 1;
+            ct->variable_increment = mt->pointers > 1 ? sizeof(void*) : mt->base_size;
+
+        } else if (mt->is_variable_struct) {
+            assert(!mt->variable_size_known && !mt->is_array && !mt->pointers);
+            ct->base_size += mt->base_size;
+            ct->is_variable_struct = 1;
+            ct->variable_increment = mt->variable_increment;
+
+        } else if (mt->is_array) {
+            ct->base_size += mt->array_size * (mt->pointers > 1 ? sizeof(void*) : mt->base_size);
+
+        } else {
+            ct->base_size += mt->pointers ? sizeof(void*) : mt->base_size;
+        }
+    }
+
+    /* increase the outer struct/union alignment if needed */
+    if (mt->align_mask > (int) ct->align_mask) {
+        ct->align_mask = mt->align_mask;
+    }
+
+    if (mt->has_bitfield || mt->is_bitfield) {
+        ct->has_bitfield = 1;
+    }
+
+    *pbit_offset = bit_offset;
+}
+
+static int copy_submembers(lua_State* L, int to_usr, int from_usr, const struct ctype* ft, int* midx)
+{
+    struct ctype ct;
+    int i, sublen;
+
+    from_usr = lua_absindex(L, from_usr);
+    to_usr = lua_absindex(L, to_usr);
+
+    /* integer keys */
+    sublen = (int) lua_rawlen(L, from_usr);
+    for (i = 1; i <= sublen; i++) {
+        lua_rawgeti(L, from_usr, i);
+
+        ct = *(const struct ctype*) lua_touserdata(L, -1);
+        ct.offset += ft->offset;
+        lua_getuservalue(L, -1);
+
+        push_ctype(L, -1, &ct);
+        lua_rawseti(L, to_usr, (*midx)++);
+
+        lua_pop(L, 2); /* ctype, user value */
+    }
+
+    /* string keys */
+    lua_pushnil(L);
+    while (lua_next(L, from_usr)) {
+        if (lua_type(L, -2) == LUA_TSTRING) {
+            struct ctype ct = *(const struct ctype*) lua_touserdata(L, -1);
+            ct.offset += ft->offset;
+            lua_getuservalue(L, -1);
+
+            /* uservalue[sub_mname] = new_sub_mtype */
+            lua_pushvalue(L, -3);
+            push_ctype(L, -2, &ct);
+            lua_rawset(L, to_usr);
+
+            lua_pop(L, 1); /* remove submember user value */
+        }
+        lua_pop(L, 1);
+    }
+
+    return 0;
+}
+
+static int add_member(lua_State* L, int ct_usr, int mname, int mbr_usr, const struct ctype* mt, int* midx)
+{
+    ct_usr = lua_absindex(L, ct_usr);
+    mname = lua_absindex(L, mname);
+
+    push_ctype(L, mbr_usr, mt);
+
+    /* usrvalue[mbr index] = pushed mtype */
+    lua_pushvalue(L, -1);
+    lua_rawseti(L, ct_usr, (*midx)++);
+
+    /* set usrvalue[mname] = pushed mtype */
+    lua_pushvalue(L, mname);
+    lua_pushvalue(L, -2);
+    lua_rawset(L, ct_usr);
+
+    /* set usrvalue[mtype] = mname */
+    lua_pushvalue(L, -1);
+    lua_pushvalue(L, mname);
+    lua_rawset(L, ct_usr);
+
+    lua_pop(L, 1);
+
+    return 0;
+}
+
+/* Parses a struct from after the open curly through to the close curly.
+ */
+static int parse_struct(lua_State* L, struct parser* P, int tmp_usr, const struct ctype* ct)
+{
+    struct token tok;
+    int midx = 1;
+    int top = lua_gettop(L);
+
+    tmp_usr = lua_absindex(L, tmp_usr);
+
+    /* parse members */
+    for (;;) {
+        struct ctype mbase;
+
+        assert(lua_gettop(L) == top);
+
+        /* see if we're at the end of the struct */
+        require_token(L, P, &tok);
+        if (tok.type == TOK_CLOSE_CURLY) {
+            break;
+        } else if (ct->is_variable_struct) {
+            return luaL_error(L, "can't have members after a variable sized member on line %d", P->line);
+        } else {
+            put_back(P);
+        }
+
+        /* members are of the form
+         * <base type> <arg>, <arg>, <arg>;
+         * eg struct foo bar, *bar2[2];
+         * mbase is 'struct foo'
+         * mtype is '' then '*[2]'
+         * mname is 'bar' then 'bar2'
+         */
+
+        parse_type(L, P, &mbase);
+
+        for (;;) {
+            struct token mname;
+            struct ctype mt = mbase;
+
+            memset(&mname, 0, sizeof(mname));
+
+            if (ct->is_variable_struct) {
+                return luaL_error(L, "can't have members after a variable sized member on line %d", P->line);
+            }
+
+            assert(lua_gettop(L) == top + 1);
+            parse_argument(L, P, -1, &mt, &mname, NULL);
+            assert(lua_gettop(L) == top + 2);
+
+            if (!mt.is_defined && (mt.pointers - mt.is_array) == 0) {
+                return luaL_error(L, "member type is undefined on line %d", P->line);
+            }
+
+            if (mt.type == VOID_TYPE && (mt.pointers - mt.is_array) == 0) {
+                return luaL_error(L, "member type can not be void on line %d", P->line);
+            }
+
+            mt.has_member_name = (mname.size > 0);
+            lua_pushlstring(L, mname.str, mname.size);
+
+            add_member(L, tmp_usr, -1, -2, &mt, &midx);
+
+            /* pop the usr value from push_argument and the member name */
+            lua_pop(L, 2);
+            assert(lua_gettop(L) == top + 1);
+
+            require_token(L, P, &tok);
+            if (tok.type == TOK_SEMICOLON) {
+                break;
+            } else if (tok.type != TOK_COMMA) {
+                luaL_error(L, "unexpected token in struct definition on line %d", P->line);
+            }
+        }
+
+        /* pop the usr value from push_type */
+        lua_pop(L, 1);
+    }
+
+    assert(lua_gettop(L) == top);
+    return 0;
+}
+
+static int calculate_struct_offsets(lua_State* L, struct parser* P, int ct_usr, struct ctype* ct, int tmp_usr)
+{
+    int i;
+    int midx = 1;
+    int sz = (int) lua_rawlen(L, tmp_usr);
+    int bit_offset = 0;
+    int bitfield_type = -1;
+
+    ct_usr = lua_absindex(L, ct_usr);
+    tmp_usr = lua_absindex(L, tmp_usr);
+
+    for (i = 1; i <= sz; i++) {
+        struct ctype mt;
+
+        /* get the member type */
+        lua_rawgeti(L, tmp_usr, i);
+        mt = *(const struct ctype*) lua_touserdata(L, -1);
+
+        /* get the member user table */
+        lua_getuservalue(L, -1);
+
+        /* get the member name */
+        lua_pushvalue(L, -2);
+        lua_rawget(L, tmp_usr);
+
+        calculate_member_position(L, P, ct, &mt, &bit_offset, &bitfield_type);
+
+        if (mt.has_member_name) {
+            assert(!lua_isnil(L, -1));
+            add_member(L, ct_usr, -1, -2, &mt, &midx);
+
+        } else if (mt.type == STRUCT_TYPE || mt.type == UNION_TYPE) {
+            /* With an unnamed member we copy all of the submembers into our
+             * usr value adjusting the offset as necessary. Note ctypes are
+             * immutable so need to push a new ctype to update the offset.
+             */
+            copy_submembers(L, ct_usr, -2, &mt, &midx);
+
+        } else {
+            /* We ignore unnamed members that aren't structs or unions. These
+             * are there just to change the padding */
+        }
+
+        lua_pop(L, 3);
+    }
+
+    /* finish up the current bitfield storage unit */
+    ct->base_size += (bit_offset + CHAR_BIT - 1) / CHAR_BIT;
+
+    /* only void is allowed 0 size */
+    if (ct->base_size == 0) {
+        ct->base_size = 1;
+    }
+
+    ct->base_size = ALIGN_UP(ct->base_size, ct->align_mask);
+    return 0;
+}
+
+/* copy over attributes that could be specified before the typedef eg
+ * __attribute__(packed) const type_t */
+static void instantiate_typedef(struct parser* P, struct ctype* tt, const struct ctype* ft)
+{
+    struct ctype pt = *tt;
+    *tt = *ft;
+
+    tt->const_mask |= pt.const_mask;
+    tt->is_packed = pt.is_packed;
+
+    if (tt->is_packed) {
+        tt->align_mask = 0;
+    } else {
+        /* Instantiate the typedef in the current packing. This may be
+         * further updated if a pointer is added or another alignment
+         * attribute is applied. If pt.align_mask is already non-zero than an
+         * increased alignment via __declspec(aligned(#)) has been set. */
+        tt->align_mask = max(min(P->align_mask, tt->align_mask), pt.align_mask);
+    }
+}
+
+/* this parses a struct or union starting with the optional
+ * name before the opening brace
+ * leaves the type usr value on the stack
+ */
+static int parse_record(lua_State* L, struct parser* P, struct ctype* ct)
+{
+    struct token tok;
+    int top = lua_gettop(L);
+
+    require_token(L, P, &tok);
+
+    /* name is optional */
+    if (tok.type == TOK_TOKEN) {
+        /* declaration */
+        lua_pushlstring(L, tok.str, tok.size);
+
+        assert(lua_gettop(L) == top+1);
+
+        /* lookup the name to see if we've seen this type before */
+        push_upval(L, &types_key);
+        lua_pushvalue(L, -2);
+        lua_rawget(L, top+2);
+
+        assert(lua_gettop(L) == top+3);
+
+        if (lua_isnil(L, -1)) {
+            lua_pop(L, 1); /* pop the nil usr value */
+            lua_newtable(L); /* the new usr table */
+
+            /* stack layout is:
+             * top+1: record name
+             * top+2: types table
+             * top+3: new usr table
+             */
+
+            lua_pushlightuserdata(L, &g_name_key);
+            lua_pushvalue(L, top+1);
+            lua_rawset(L, top+3); /* usr[name_key] = name */
+
+            lua_pushvalue(L, top+1);
+            push_ctype(L, top+3, ct);
+            lua_rawset(L, top+2); /* types[name] = new_ctype */
+
+        } else {
+            /* get the exsting declared type */
+            const struct ctype* prevt = (const struct ctype*) lua_touserdata(L, top+3);
+
+            if (prevt->type != ct->type) {
+                lua_getuservalue(L, top+3);
+                push_type_name(L, -1, ct);
+                push_type_name(L, top+3, prevt);
+                luaL_error(L, "type '%s' previously declared as '%s'", lua_tostring(L, -2), lua_tostring(L, -1));
+            }
+
+            instantiate_typedef(P, ct, prevt);
+
+            /* replace the ctype with its usr value */
+            lua_getuservalue(L, -1);
+            lua_replace(L, -2);
+        }
+
+        /* remove the extra name and types table */
+        lua_replace(L, -3);
+        lua_pop(L, 1);
+
+        assert(lua_gettop(L) == top + 1 && lua_istable(L, -1));
+
+        /* if a name is given then we may be at the end of the string
+         * eg for ffi.new('struct foo')
+         */
+        if (!next_token(L, P, &tok)) {
+            return 0;
+        }
+
+    } else {
+        /* create a new unnamed record */
+        int num;
+
+        /* get the next unnamed number */
+        push_upval(L, &next_unnamed_key);
+        num = lua_tointeger(L, -1);
+        lua_pop(L, 1);
+
+        /* increment the unnamed upval */
+        lua_pushinteger(L, num + 1);
+        set_upval(L, &next_unnamed_key);
+
+        lua_newtable(L); /* the new usr table - leave on stack */
+
+        /* usr[name_key] = num */
+        lua_pushlightuserdata(L, &g_name_key);
+        lua_pushfstring(L, "%d", num);
+        lua_rawset(L, -3);
+    }
+
+    if (tok.type != TOK_OPEN_CURLY) {
+        /* this may just be a declaration or use of the type as an argument or
+         * member */
+        put_back(P);
+        return 0;
+    }
+
+    if (ct->is_defined) {
+        return luaL_error(L, "redefinition in line %d", P->line);
+    }
+
+    assert(lua_gettop(L) == top + 1 && lua_istable(L, -1));
+
+    if (ct->type == ENUM_TYPE) {
+        parse_enum(L, P, ct);
+    } else {
+        /* we do a two stage parse, where we parse the content first and build up
+         * the temp user table. We then iterate over that to calculate the offsets
+         * and fill out ct_usr. This is so we can handle out of order members
+         * (eg vtable) and attributes specified at the end of the struct.
+         */
+        lua_newtable(L);
+        parse_struct(L, P, -1, ct);
+        calculate_struct_offsets(L, P, -2, ct, -1);
+        assert(lua_gettop(L) == top + 2 && lua_istable(L, -1));
+        lua_pop(L, 1);
+    }
+
+    assert(lua_gettop(L) == top + 1 && lua_istable(L, -1));
+    set_defined(L, -1, ct);
+    assert(lua_gettop(L) == top + 1);
+    return 0;
+}
+
+/* parses single or multi work built in types, and pushes it onto the stack */
+static int parse_type_name(lua_State* L, struct parser* P)
+{
+    struct token tok;
+    int flags = 0;
+
+    enum {
+        UNSIGNED = 0x01,
+        SIGNED = 0x02,
+        LONG = 0x04,
+        SHORT = 0x08,
+        INT = 0x10,
+        CHAR = 0x20,
+        LONG_LONG = 0x40,
+        INT8 = 0x80,
+        INT16 = 0x100,
+        INT32 = 0x200,
+        INT64 = 0x400,
+        DOUBLE = 0x800,
+        FLOAT = 0x1000,
+        COMPLEX = 0x2000,
+    };
+
+    require_token(L, P, &tok);
+
+    /* we have to manually decode the builtin types since they can take up
+     * more then one token
+     */
+    for (;;) {
+        if (tok.type != TOK_TOKEN) {
+            break;
+        } else if (IS_LITERAL(tok, "unsigned")) {
+            flags |= UNSIGNED;
+        } else if (IS_LITERAL(tok, "signed")) {
+            flags |= SIGNED;
+        } else if (IS_LITERAL(tok, "short")) {
+            flags |= SHORT;
+        } else if (IS_LITERAL(tok, "char")) {
+            flags |= CHAR;
+        } else if (IS_LITERAL(tok, "long")) {
+            flags |= (flags & LONG) ? LONG_LONG : LONG;
+        } else if (IS_LITERAL(tok, "int")) {
+            flags |= INT;
+        } else if (IS_LITERAL(tok, "__int8")) {
+            flags |= INT8;
+        } else if (IS_LITERAL(tok, "__int16")) {
+            flags |= INT16;
+        } else if (IS_LITERAL(tok, "__int32")) {
+            flags |= INT32;
+        } else if (IS_LITERAL(tok, "__int64")) {
+            flags |= INT64;
+        } else if (IS_LITERAL(tok, "double")) {
+            flags |= DOUBLE;
+        } else if (IS_LITERAL(tok, "float")) {
+            flags |= FLOAT;
+        } else if (IS_LITERAL(tok, "complex") || IS_LITERAL(tok, "_Complex")) {
+            flags |= COMPLEX;
+        } else if (IS_LITERAL(tok, "register")) {
+            /* ignore */
+        } else {
+            break;
+        }
+
+        if (!next_token(L, P, &tok)) {
+            break;
+        }
+    }
+
+    if (flags) {
+        put_back(P);
+    }
+
+    if (flags & CHAR) {
+        if (flags & SIGNED) {
+            lua_pushliteral(L, "int8_t");
+        } else if (flags & UNSIGNED) {
+            lua_pushliteral(L, "uint8_t");
+        } else {
+            lua_pushstring(L, (((char) -1) > 0) ? "uint8_t" : "int8_t");
+        }
+
+    } else if (flags & INT8) {
+        lua_pushstring(L, (flags & UNSIGNED) ? "uint8_t" : "int8_t");
+    } else if (flags & INT16) {
+        lua_pushstring(L, (flags & UNSIGNED) ? "uint16_t" : "int16_t");
+    } else if (flags & INT32) {
+        lua_pushstring(L, (flags & UNSIGNED) ? "uint32_t" : "int32_t");
+    } else if (flags & (INT64 | LONG_LONG)) {
+        lua_pushstring(L, (flags & UNSIGNED) ? "uint64_t" : "int64_t");
+
+    } else if (flags & COMPLEX) {
+        if (flags & LONG) {
+            lua_pushliteral(L, "complex long double");
+        } else if (flags & FLOAT) {
+            lua_pushliteral(L, "complex float");
+        } else {
+            lua_pushliteral(L, "complex double");
+        }
+
+    } else if (flags & DOUBLE) {
+        if (flags & LONG) {
+            lua_pushliteral(L, "long double");
+        } else {
+            lua_pushliteral(L, "double");
+        }
+
+    } else if (flags & FLOAT) {
+        lua_pushliteral(L, "float");
+
+    } else if (flags & SHORT) {
+#define SHORT_TYPE(u) (sizeof(short) == sizeof(int64_t) ? u "int64_t" : sizeof(short) == sizeof(int32_t) ? u "int32_t" : u "int16_t")
+        if (flags & UNSIGNED) {
+            lua_pushstring(L, SHORT_TYPE("u"));
+        } else {
+            lua_pushstring(L, SHORT_TYPE(""));
+        }
+#undef SHORT_TYPE
+
+    } else if (flags & LONG) {
+#define LONG_TYPE(u) (sizeof(long) == sizeof(int64_t) ? u "int64_t" : u "int32_t")
+        if (flags & UNSIGNED) {
+            lua_pushstring(L, LONG_TYPE("u"));
+        } else {
+            lua_pushstring(L, LONG_TYPE(""));
+        }
+#undef LONG_TYPE
+
+    } else if (flags) {
+#define INT_TYPE(u) (sizeof(int) == sizeof(int64_t) ? u "int64_t" : sizeof(int) == sizeof(int32_t) ? u "int32_t" : u "int16_t")
+        if (flags & UNSIGNED) {
+            lua_pushstring(L, INT_TYPE("u"));
+        } else {
+            lua_pushstring(L, INT_TYPE(""));
+        }
+#undef INT_TYPE
+
+    } else {
+        lua_pushlstring(L, tok.str, tok.size);
+    }
+
+    return 0;
+}
+
+/* parse_attribute parses a token to see if it is an attribute. It may then
+ * parse some following tokens to decode the attribute setting the appropriate
+ * fields in ct. It will return 1 if the token was used (and possibly some
+ * more following it) or 0 if not. If the token was used, the next token must
+ * be retrieved using next_token/require_token.
+ */
+static int parse_attribute(lua_State* L, struct parser* P, struct token* tok, struct ctype* ct, struct parser* asmname)
+{
+    if (tok->type != TOK_TOKEN) {
+        return 0;
+
+    } else if (asmname && (IS_LITERAL(*tok, "__asm__") || IS_LITERAL(*tok, "__asm"))) {
+        check_token(L, P, TOK_OPEN_PAREN, NULL, "unexpected token after __asm__ on line %d", P->line);
+        *asmname = *P;
+
+        require_token(L, P, tok);
+        while (tok->type == TOK_STRING) {
+            require_token(L, P, tok);
+        }
+
+        if (tok->type != TOK_CLOSE_PAREN) {
+            luaL_error(L, "unexpected token after __asm__ on line %d", P->line);
+        }
+        return 1;
+
+    } else if (IS_LITERAL(*tok, "__attribute__") || IS_LITERAL(*tok, "__declspec")) {
+        int parens = 1;
+        check_token(L, P, TOK_OPEN_PAREN, NULL, "expected parenthesis after __attribute__ or __declspec on line %d", P->line);
+
+        for (;;) {
+            require_token(L, P, tok);
+            if (tok->type == TOK_OPEN_PAREN) {
+                parens++;
+            } else if (tok->type == TOK_CLOSE_PAREN) {
+                if (--parens == 0) {
+                    break;
+                }
+
+            } else if (tok->type != TOK_TOKEN) {
+                /* ignore unknown symbols within parentheses */
+
+            } else if (IS_LITERAL(*tok, "align") || IS_LITERAL(*tok, "aligned") || IS_LITERAL(*tok, "__aligned__")) {
+                unsigned align = 0;
+                require_token(L, P, tok);
+
+                switch (tok->type) {
+                case TOK_CLOSE_PAREN:
+                    align = ALIGNED_DEFAULT;
+                    put_back(P);
+                    break;
+
+                case TOK_OPEN_PAREN:
+                    require_token(L, P, tok);
+
+                    if (tok->type != TOK_NUMBER) {
+                        luaL_error(L, "expected align(#) on line %d", P->line);
+                    }
+
+                    switch (tok->integer) {
+                    case 1: align = 0; break;
+                    case 2: align = 1; break;
+                    case 4: align = 3; break;
+                    case 8: align = 7; break;
+                    case 16: align = 15; break;
+                    default:
+                        luaL_error(L, "unsupported align size on line %d", P->line);
+                    }
+
+                    check_token(L, P, TOK_CLOSE_PAREN, NULL, "expected align(#) on line %d", P->line);
+                    break;
+
+                default:
+                    luaL_error(L, "expected align(#) on line %d", P->line);
+                }
+
+                /* __attribute__(aligned(#)) is only supposed to increase alignment */
+                ct->align_mask = max(align, ct->align_mask);
+
+            } else if (IS_LITERAL(*tok, "packed") || IS_LITERAL(*tok, "__packed__")) {
+                ct->align_mask = 0;
+                ct->is_packed = 1;
+
+            } else if (IS_LITERAL(*tok, "mode") || IS_LITERAL(*tok, "__mode__")) {
+
+                check_token(L, P, TOK_OPEN_PAREN, NULL, "expected mode(MODE) on line %d", P->line);
+
+                require_token(L, P, tok);
+                if (tok->type != TOK_TOKEN) {
+                    luaL_error(L, "expected mode(MODE) on line %d", P->line);
+                }
+
+                if (ct->type == FLOAT_TYPE || ct->type == DOUBLE_TYPE) {
+                    struct {char ch; float v;} af;
+                    struct {char ch; double v;} ad;
+
+                    if (IS_LITERAL(*tok, "SF") || IS_LITERAL(*tok, "__SF__")) {
+                        ct->type = FLOAT_TYPE;
+                        ct->base_size = sizeof(float);
+                        ct->align_mask = ALIGNOF(af);
+
+                    } else if (IS_LITERAL(*tok, "DF") || IS_LITERAL(*tok, "__DF__")) {
+                        ct->type = DOUBLE_TYPE;
+                        ct->base_size = sizeof(double);
+                        ct->align_mask = ALIGNOF(ad);
+
+                    } else {
+                        luaL_error(L, "unexpected mode on line %d", P->line);
+                    }
+
+                } else {
+                    struct {char ch; uint16_t v;} a16;
+                    struct {char ch; uint32_t v;} a32;
+                    struct {char ch; uint64_t v;} a64;
+
+                    if (IS_LITERAL(*tok, "QI") || IS_LITERAL(*tok, "__QI__")
+                            || IS_LITERAL(*tok, "byte") || IS_LITERAL(*tok, "__byte__")
+                            ) {
+                        ct->type = INT8_TYPE;
+                        ct->base_size = sizeof(uint8_t);
+                        ct->align_mask = 0;
+
+                    } else if (IS_LITERAL(*tok, "HI") || IS_LITERAL(*tok, "__HI__")) {
+                        ct->type = INT16_TYPE;
+                        ct->base_size = sizeof(uint16_t);
+                        ct->align_mask = ALIGNOF(a16);
+
+                    } else if (IS_LITERAL(*tok, "SI") || IS_LITERAL(*tok, "__SI__")
+#if defined ARCH_X86 || defined ARCH_ARM
+                            || IS_LITERAL(*tok, "word") || IS_LITERAL(*tok, "__word__")
+                            || IS_LITERAL(*tok, "pointer") || IS_LITERAL(*tok, "__pointer__")
+#endif
+                            ) {
+                        ct->type = INT32_TYPE;
+                        ct->base_size = sizeof(uint32_t);
+                        ct->align_mask = ALIGNOF(a32);
+
+                    } else if (IS_LITERAL(*tok, "DI") || IS_LITERAL(*tok, "__DI__")
+#if defined ARCH_X64 || defined ARCH_PPC64
+                            || IS_LITERAL(*tok, "word") || IS_LITERAL(*tok, "__word__")
+                            || IS_LITERAL(*tok, "pointer") || IS_LITERAL(*tok, "__pointer__")
+#endif
+                            ) {
+                        ct->type = INT64_TYPE;
+                        ct->base_size = sizeof(uint64_t);
+                        ct->align_mask = ALIGNOF(a64);
+
+                    } else {
+                        luaL_error(L, "unexpected mode on line %d", P->line);
+                    }
+                }
+
+                check_token(L, P, TOK_CLOSE_PAREN, NULL, "expected mode(MODE) on line %d", P->line);
+
+            } else if (IS_LITERAL(*tok, "cdecl") || IS_LITERAL(*tok, "__cdecl__")) {
+                ct->calling_convention = C_CALL;
+
+            } else if (IS_LITERAL(*tok, "fastcall") || IS_LITERAL(*tok, "__fastcall__")) {
+                ct->calling_convention = FAST_CALL;
+
+            } else if (IS_LITERAL(*tok, "stdcall") || IS_LITERAL(*tok, "__stdcall__")) {
+                ct->calling_convention = STD_CALL;
+            }
+            /* ignore unknown tokens within parentheses */
+        }
+        return 1;
+
+    } else if (IS_LITERAL(*tok, "__cdecl")) {
+        ct->calling_convention = C_CALL;
+        return 1;
+
+    } else if (IS_LITERAL(*tok, "__fastcall")) {
+        ct->calling_convention = FAST_CALL;
+        return 1;
+
+    } else if (IS_LITERAL(*tok, "__stdcall")) {
+        ct->calling_convention = STD_CALL;
+        return 1;
+
+    } else if (IS_LITERAL(*tok, "__extension__") || IS_LITERAL(*tok, "extern")) {
+        /* ignore */
+        return 1;
+
+    } else {
+        return 0;
+    }
+}
+
+/* parses out the base type of a type expression in a function declaration,
+ * struct definition, typedef etc
+ *
+ * leaves the usr value of the type on the stack
+ */
+int parse_type(lua_State* L, struct parser* P, struct ctype* ct)
+{
+    struct token tok;
+    int top = lua_gettop(L);
+
+    memset(ct, 0, sizeof(*ct));
+
+    require_token(L, P, &tok);
+
+    /* get const/volatile before the base type */
+    for (;;) {
+        if (tok.type != TOK_TOKEN) {
+            return luaL_error(L, "unexpected value before type name on line %d", P->line);
+
+        } else if (IS_CONST(tok)) {
+            ct->const_mask = 1;
+            require_token(L, P, &tok);
+
+        } else if (IS_VOLATILE(tok) ||
+                   IS_RESTRICT(tok) ||
+                   IS_LITERAL(tok, "static") ||
+                   IS_INLINE(tok)) {
+            /* ignored for now */
+            require_token(L, P, &tok);
+        } else if (parse_attribute(L, P, &tok, ct, NULL)) {
+            /* get function attributes before the return type */
+            require_token(L, P, &tok);
+
+        } else {
+            break;
+        }
+    }
+
+    /* get base type */
+    if (tok.type != TOK_TOKEN) {
+        return luaL_error(L, "unexpected value before type name on line %d", P->line);
+
+    } else if (IS_LITERAL(tok, "struct")) {
+        ct->type = STRUCT_TYPE;
+        parse_record(L, P, ct);
+
+    } else if (IS_LITERAL(tok, "union")) {
+        ct->type = UNION_TYPE;
+        parse_record(L, P, ct);
+
+    } else if (IS_LITERAL(tok, "enum")) {
+        ct->type = ENUM_TYPE;
+        parse_record(L, P, ct);
+
+    } else {
+        put_back(P);
+
+        /* lookup type */
+        push_upval(L, &types_key);
+        parse_type_name(L, P);
+        lua_rawget(L, -2);
+        lua_remove(L, -2);
+
+        if (lua_isnil(L, -1)) {
+            lua_pushlstring(L, tok.str, tok.size);
+            return luaL_error(L, "unknown type %s on line %d", lua_tostring(L, -1), P->line);
+        }
+
+        instantiate_typedef(P, ct, (const struct ctype*) lua_touserdata(L, -1));
+
+        /* we only want the usr tbl from the ctype in the types tbl */
+        lua_getuservalue(L, -1);
+        lua_replace(L, -2);
+    }
+
+    while (next_token(L, P, &tok)) {
+        if (tok.type != TOK_TOKEN) {
+            put_back(P);
+            break;
+
+        } else if (IS_CONST(tok) || IS_VOLATILE(tok)) {
+            /* ignore for now */
+
+        } else {
+            put_back(P);
+            break;
+        }
+    }
+
+    assert(lua_gettop(L) == top + 1 && (lua_istable(L, -1) || lua_isnil(L, -1)));
+    return 0;
+}
+
+enum name_type {
+    BOTH,
+    FRONT,
+    BACK,
+};
+
+static void append_type_name(luaL_Buffer* B, int usr, const struct ctype* ct, enum name_type type)
+{
+    size_t i;
+    lua_State* L = B->L;
+
+    usr = lua_absindex(L, usr);
+
+    if (type == FRONT || type == BOTH) {
+        if (ct->type != FUNCTION_PTR_TYPE && (ct->const_mask & (1 << ct->pointers))) {
+            luaL_addstring(B, "const ");
+        }
+
+        if (ct->is_unsigned) {
+            luaL_addstring(B, "unsigned ");
+        }
+
+        switch (ct->type) {
+        case ENUM_TYPE:
+            luaL_addstring(B, "enum ");
+            goto get_name;
+
+        case STRUCT_TYPE:
+            luaL_addstring(B, "struct ");
+            goto get_name;
+
+        case UNION_TYPE:
+            luaL_addstring(B, "union ");
+            goto get_name;
+
+        get_name:
+            lua_pushlightuserdata(L, &g_name_key);
+            lua_rawget(L, usr);
+            luaL_addvalue(B);
+            break;
+
+        case FUNCTION_TYPE:
+        case FUNCTION_PTR_TYPE:
+            lua_pushlightuserdata(L, &g_front_name_key);
+            lua_rawget(L, usr);
+            luaL_addvalue(B);
+            break;
+
+        case VOID_TYPE:
+            luaL_addstring(B, "void");
+            break;
+        case BOOL_TYPE:
+            luaL_addstring(B, "bool");
+            break;
+        case DOUBLE_TYPE:
+            luaL_addstring(B, "double");
+            break;
+        case LONG_DOUBLE_TYPE:
+            luaL_addstring(B, "long double");
+            break;
+        case FLOAT_TYPE:
+            luaL_addstring(B, "float");
+            break;
+        case COMPLEX_LONG_DOUBLE_TYPE:
+            luaL_addstring(B, "long complex double");
+            break;
+        case COMPLEX_DOUBLE_TYPE:
+            luaL_addstring(B, "complex double");
+            break;
+        case COMPLEX_FLOAT_TYPE:
+            luaL_addstring(B, "complex float");
+            break;
+        case INT8_TYPE:
+            luaL_addstring(B, "char");
+            break;
+        case INT16_TYPE:
+            luaL_addstring(B, "short");
+            break;
+        case INT32_TYPE:
+            luaL_addstring(B, "int");
+            break;
+        case INT64_TYPE:
+            luaL_addstring(B, "long long");
+            break;
+
+        case INTPTR_TYPE:
+            if (sizeof(intptr_t) == sizeof(int32_t)) {
+                luaL_addstring(B, "long");
+            } else if (sizeof(intptr_t) == sizeof(int64_t)) {
+                luaL_addstring(B, "long long");
+            } else {
+                luaL_error(L, "internal error - bad type");
+            }
+            break;
+
+        default:
+            luaL_error(L, "internal error - bad type %d", ct->type);
+        }
+
+        for (i = 0; i < ct->pointers - ct->is_array; i++) {
+            luaL_addchar(B, '*');
+            if (ct->const_mask & (1 << (ct->pointers - i - 1))) {
+                luaL_addstring(B, " const");
+            }
+        }
+    }
+
+    if (type == BOTH || type == BACK) {
+        if (ct->is_reference) {
+            luaL_addstring(B, " &");
+        }
+
+        if (ct->is_variable_array && !ct->variable_size_known) {
+            luaL_addstring(B, "[?]");
+        } else if (ct->is_array) {
+            lua_pushfstring(L, "[%d]", (int) ct->array_size);
+            luaL_addvalue(B);
+        }
+
+        if (ct->type == FUNCTION_PTR_TYPE || ct->type == FUNCTION_TYPE) {
+            lua_pushlightuserdata(L, &g_back_name_key);
+            lua_rawget(L, usr);
+            luaL_addvalue(B);
+        }
+
+        if (ct->is_bitfield) {
+            lua_pushfstring(L, " : %d", (int) ct->bit_size);
+            luaL_addvalue(B);
+        }
+    }
+}
+
+void push_type_name(lua_State* L, int usr, const struct ctype* ct)
+{
+    luaL_Buffer B;
+    usr = lua_absindex(L, usr);
+    luaL_buffinit(L, &B);
+    append_type_name(&B, usr, ct, BOTH);
+    luaL_pushresult(&B);
+}
+
+static void push_function_type_strings(lua_State* L, int usr, const struct ctype* ct)
+{
+    size_t i, args;
+    luaL_Buffer B;
+    int top = lua_gettop(L);
+    const struct ctype* ret_ct;
+
+    int arg_ct = top+3;
+    int arg_usr = top+4;
+    int ret_usr = top+6;
+
+    usr = lua_absindex(L, usr);
+
+    /* return type */
+    lua_settop(L, top+4); /* room for two returns and two temp positions */
+    lua_rawgeti(L, usr, 0);
+    lua_getuservalue(L, -1);
+    ret_ct = (const struct ctype*) lua_touserdata(L, -2);
+
+    luaL_buffinit(L, &B);
+    append_type_name(&B, ret_usr, ret_ct, FRONT);
+
+    if (ret_ct->type != FUNCTION_TYPE && ret_ct->type != FUNCTION_PTR_TYPE) {
+        luaL_addchar(&B, ' ');
+    }
+
+    switch (ct->calling_convention) {
+    case STD_CALL:
+        luaL_addstring(&B, "(__stdcall *");
+        break;
+    case FAST_CALL:
+        luaL_addstring(&B, "(__fastcall *");
+        break;
+    case C_CALL:
+        luaL_addstring(&B, "(*");
+        break;
+    default:
+        luaL_error(L, "internal error - unknown calling convention");
+    }
+
+    luaL_pushresult(&B);
+    lua_replace(L, top+1);
+
+    luaL_buffinit(L, &B);
+    luaL_addstring(&B, ")(");
+
+    /* arguments */
+    args = lua_rawlen(L, usr);
+    for (i = 1; i <= args; i++) {
+        if (i > 1) {
+            luaL_addstring(&B, ", ");
+        }
+
+        /* note push the arg and user value below the indexes used by the buffer
+         * and use indexes relative to top to avoid problems due to the buffer
+         * system pushing a variable number of arguments onto the stack */
+        lua_rawgeti(L, usr, (int) i);
+        lua_replace(L, arg_ct);
+        lua_getuservalue(L, arg_ct);
+        lua_replace(L, arg_usr);
+        append_type_name(&B, arg_usr, (const struct ctype*) lua_touserdata(L, arg_ct), BOTH);
+    }
+
+    luaL_addstring(&B, ")");
+    append_type_name(&B, ret_usr, ret_ct, BACK);
+    luaL_pushresult(&B);
+    lua_replace(L, top+2);
+
+    lua_settop(L, top+2);
+    assert(lua_isstring(L, top+1) && lua_isstring(L, top+2));
+}
+
+/* parses from after the opening paranthesis to after the closing parenthesis */
+static void parse_function_arguments(lua_State* L, struct parser* P, int ct_usr, struct ctype* ct)
+{
+    struct token tok;
+    int args = 0;
+    int top = lua_gettop(L);
+
+    ct_usr = lua_absindex(L, ct_usr);
+
+    for (;;) {
+        require_token(L, P, &tok);
+
+        if (tok.type == TOK_CLOSE_PAREN) {
+            break;
+        }
+
+        if (args) {
+            if (tok.type != TOK_COMMA) {
+                luaL_error(L, "unexpected token in function argument %d on line %d", args, P->line);
+            }
+
+            require_token(L, P, &tok);
+        }
+
+        if (tok.type == TOK_VA_ARG) {
+            ct->has_var_arg = true;
+            check_token(L, P, TOK_CLOSE_PAREN, "", "unexpected token after ... in function on line %d", P->line);
+            break;
+
+        } else if (tok.type == TOK_TOKEN) {
+            struct ctype at;
+
+            put_back(P);
+            parse_type(L, P, &at);
+            parse_argument(L, P, -1, &at, NULL, NULL);
+
+            assert(lua_gettop(L) == top + 2);
+
+            /* array arguments are just treated as their base pointer type */
+            at.is_array = 0;
+
+            /* check for the c style int func(void) and error on other uses of arguments of type void */
+            if (at.type == VOID_TYPE && at.pointers == 0) {
+                if (args) {
+                    luaL_error(L, "can't have argument of type void on line %d", P->line);
+                }
+
+                check_token(L, P, TOK_CLOSE_PAREN, "", "unexpected void in function on line %d", P->line);
+                lua_pop(L, 2);
+                break;
+            }
+
+            push_ctype(L, -1, &at);
+            lua_rawseti(L, ct_usr, ++args);
+
+            lua_pop(L, 2); /* parse_type and parse_argument at_usr */
+
+        } else {
+            luaL_error(L, "unexpected token in function argument %d on line %d", args+1, P->line);
+        }
+    }
+
+    assert(lua_gettop(L) == top);
+}
+
+static int max_bitfield_size(int type)
+{
+    switch (type) {
+    case BOOL_TYPE:
+        return 1;
+    case INT8_TYPE:
+        return 8;
+    case INT16_TYPE:
+        return 16;
+    case INT32_TYPE:
+    case ENUM_TYPE:
+        return 32;
+    case INT64_TYPE:
+        return 64;
+    default:
+        return -1;
+    }
+}
+
+static struct ctype* parse_argument2(lua_State* L, struct parser* P, int ct_usr, struct ctype* ct, struct token* name, struct parser* asmname);
+
+/* parses from after the first ( in a function declaration or function pointer
+ * can be one of:
+ * void foo(...) before ...
+ * void (foo)(...) before foo
+ * void (* <>)(...) before <> which is the inner type
+ */
+static struct ctype* parse_function(lua_State* L, struct parser* P, int ct_usr, struct ctype* ct, struct token* name, struct parser* asmname)
+{
+    /* We have a function pointer or a function. The usr table will
+     * get replaced by the canonical one (if there is one) in
+     * find_canonical_usr after all the arguments and returns have
+     * been parsed. */
+    struct token tok;
+    int top = lua_gettop(L);
+    struct ctype* ret;
+
+    lua_newtable(L);
+    ret = push_ctype(L, ct_usr, ct);
+    lua_rawseti(L, -2, 0);
+    ct_usr = lua_gettop(L);
+
+    memset(ct, 0, sizeof(*ct));
+    ct->base_size = sizeof(void (*)());
+    ct->align_mask = min(FUNCTION_ALIGN_MASK, P->align_mask);
+    ct->type = FUNCTION_TYPE;
+    ct->is_defined = 1;
+
+    if (name->type == TOK_NIL) {
+        for (;;) {
+            require_token(L, P, &tok);
+
+            if (tok.type == TOK_STAR) {
+
+                if (ct->type == FUNCTION_TYPE) {
+                    ct->type = FUNCTION_PTR_TYPE;
+                } else if (ct->pointers == POINTER_MAX) {
+                    luaL_error(L, "maximum number of pointer derefs reached - use a struct to break up the pointers on line %d", P->line);
+                } else {
+                    ct->pointers++;
+                    ct->const_mask <<= 1;
+                }
+
+            } else if (parse_attribute(L, P, &tok, ct, asmname)) {
+                /* parse_attribute sets the appropriate fields */
+
+            } else {
+                /* call parse_argument to handle the inner contents
+                 * e.g. the <> in "void (* <>) (...)". Note that the
+                 * inner contents can itself be a function, a function
+                 * ptr, array, etc (e.g. "void (*signal(int sig, void
+                 * (*func)(int)))(int)" ).
+                 */
+                put_back(P);
+                ct = parse_argument2(L, P, ct_usr, ct, name, asmname);
+                break;
+            }
+        }
+
+        check_token(L, P, TOK_CLOSE_PAREN, NULL, "unexpected token in function on line %d", P->line);
+        check_token(L, P, TOK_OPEN_PAREN, NULL, "unexpected token in function on line %d", P->line);
+    }
+
+    parse_function_arguments(L, P, ct_usr, ct);
+
+    /* if we have an inner function then set the outer function ptr as its
+     * return type and return the inner function
+     * e.g. for void (* <signal(int, void (*)(int))> )(int) inner is
+     * surrounded by <>, return type is void (*)(int)
+     */
+    if (lua_gettop(L) == ct_usr+1) {
+        lua_replace(L, ct_usr);
+    }
+
+    assert(lua_gettop(L) == top + 1 && lua_istable(L, -1));
+    return ret;
+}
+
+static struct ctype* parse_argument2(lua_State* L, struct parser* P, int ct_usr, struct ctype* ct, struct token* name, struct parser* asmname)
+{
+    struct token tok;
+    int top = lua_gettop(L);
+    int ft_usr = 0;
+
+    luaL_checkstack(L, 10, "function too complex");
+    ct_usr = lua_absindex(L, ct_usr);
+
+    for (;;) {
+        if (!next_token(L, P, &tok)) {
+            /* we've reached the end of the string */
+            break;
+
+        } else if (tok.type == TOK_STAR) {
+            if (ct->pointers == POINTER_MAX) {
+                luaL_error(L, "maximum number of pointer derefs reached - use a struct to break up the pointers on line %d", P->line);
+            }
+
+            ct->pointers++;
+            ct->const_mask <<= 1;
+
+            /* __declspec(align(#)) may come before the type in a member */
+            if (!ct->is_packed) {
+                ct->align_mask = max(min(PTR_ALIGN_MASK, P->align_mask), ct->align_mask);
+            }
+
+        } else if (tok.type == TOK_REFERENCE) {
+            ct->is_reference = 1;
+
+        } else if (parse_attribute(L, P, &tok, ct, asmname)) {
+            /* parse attribute has filled out appropriate fields in type */
+
+        } else if (tok.type == TOK_OPEN_PAREN) {
+            ct = parse_function(L, P, ct_usr, ct, name, asmname);
+            ft_usr = lua_gettop(L);
+
+        } else if (tok.type == TOK_OPEN_SQUARE) {
+            /* array */
+            if (ct->pointers == POINTER_MAX) {
+                luaL_error(L, "maximum number of pointer derefs reached - use a struct to break up the pointers");
+            }
+            ct->is_array = 1;
+            ct->pointers++;
+            ct->const_mask <<= 1;
+            require_token(L, P, &tok);
+
+            if (ct->pointers == 1 && !ct->is_defined) {
+                luaL_error(L, "array of undefined type on line %d", P->line);
+            }
+
+            if (ct->is_variable_struct || ct->is_variable_array) {
+                luaL_error(L, "can't have an array of a variably sized type on line %d", P->line);
+            }
+
+            if (tok.type == TOK_QUESTION) {
+                ct->is_variable_array = 1;
+                ct->variable_increment = (ct->pointers > 1) ? sizeof(void*) : ct->base_size;
+                check_token(L, P, TOK_CLOSE_SQUARE, "", "invalid character in array on line %d", P->line);
+
+            } else if (tok.type == TOK_CLOSE_SQUARE) {
+                ct->array_size = 0;
+
+            } else if (tok.type == TOK_TOKEN && IS_RESTRICT(tok)) {
+                /* odd gcc extension foo[__restrict] for arguments */
+                ct->array_size = 0;
+                check_token(L, P, TOK_CLOSE_SQUARE, "", "invalid character in array on line %d", P->line);
+
+            } else {
+                int64_t asize;
+                put_back(P);
+                asize = calculate_constant(L, P);
+                if (asize < 0) {
+                    luaL_error(L, "array size can not be negative on line %d", P->line);
+                }
+                ct->array_size = (size_t) asize;
+                check_token(L, P, TOK_CLOSE_SQUARE, "", "invalid character in array on line %d", P->line);
+            }
+
+        } else if (tok.type == TOK_COLON) {
+            int64_t bsize = calculate_constant(L, P);
+
+            if (ct->pointers || bsize < 0 || bsize > max_bitfield_size(ct->type)) {
+                luaL_error(L, "invalid bitfield on line %d", P->line);
+            }
+
+            ct->is_bitfield = 1;
+            ct->bit_size = (unsigned) bsize;
+
+        } else if (tok.type != TOK_TOKEN) {
+            /* we've reached the end of the declaration */
+            put_back(P);
+            break;
+
+        } else if (IS_CONST(tok)) {
+            ct->const_mask |= 1;
+
+        } else if (IS_VOLATILE(tok) || IS_RESTRICT(tok)) {
+            /* ignored for now */
+
+        } else {
+            *name = tok;
+        }
+    }
+
+    assert((ft_usr == 0 && lua_gettop(L) == top) || (lua_gettop(L) == top + 1 && ft_usr == top + 1 && (lua_istable(L, -1) || lua_isnil(L, -1))));
+    return ct;
+}
+
+static void find_canonical_usr(lua_State* L, int ct_usr, const struct ctype *ct)
+{
+    struct ctype rt;
+    int top = lua_gettop(L);
+    int types;
+
+    if (ct->type != FUNCTION_PTR_TYPE && ct->type != FUNCTION_TYPE) {
+        return;
+    }
+
+    luaL_checkstack(L, 10, "function too complex");
+    ct_usr = lua_absindex(L, ct_usr);
+
+    /* check to see if we already have the canonical usr table */
+    lua_pushlightuserdata(L, &g_name_key);
+    lua_rawget(L, ct_usr);
+    if (!lua_isnil(L, -1)) {
+        lua_pop(L, 1);
+        assert(top == lua_gettop(L));
+        return;
+    }
+    lua_pop(L, 1);
+
+    assert(top == lua_gettop(L));
+
+    /* first canonize the return type */
+    lua_rawgeti(L, ct_usr, 0);
+    rt = *(struct ctype*) lua_touserdata(L, -1);
+    lua_getuservalue(L, -1);
+    find_canonical_usr(L, -1, &rt);
+    push_ctype(L, -1, &rt);
+    lua_rawseti(L, ct_usr, 0);
+    lua_pop(L, 2); /* return ctype and usr */
+
+    assert(top == lua_gettop(L));
+
+    /* look up the type string in the types table */
+    push_upval(L, &types_key);
+    types = lua_gettop(L);
+
+    push_function_type_strings(L, ct_usr, ct);
+    lua_pushvalue(L, -2);
+    lua_pushvalue(L, -2);
+    lua_concat(L, 2);
+
+    lua_pushvalue(L, -1);
+    lua_rawget(L, types);
+
+    assert(lua_gettop(L) == types + 4 && types == top + 1);
+    /* stack: types, front, back, both, looked up value */
+
+    if (lua_isnil(L, -1)) {
+        lua_pop(L, 1);
+
+        lua_pushlightuserdata(L, &g_front_name_key);
+        lua_pushvalue(L, -4);
+        lua_rawset(L, ct_usr);
+
+        lua_pushlightuserdata(L, &g_back_name_key);
+        lua_pushvalue(L, -3);
+        lua_rawset(L, ct_usr);
+
+        lua_pushlightuserdata(L, &g_name_key);
+        lua_pushvalue(L, -2);
+        lua_rawset(L, ct_usr);
+
+        lua_pushvalue(L, -1);
+        push_ctype(L, ct_usr, ct);
+        lua_rawset(L, types);
+    } else {
+        lua_getuservalue(L, -1);
+        lua_replace(L, ct_usr);
+        lua_pop(L, 1);
+    }
+
+    lua_pop(L, 4);
+    assert(top == lua_gettop(L) && types == top + 1);
+}
+
+
+/* parses after the main base type of a typedef, function argument or
+ * struct/union member
+ * eg for const void* bar[3] the base type is void with the subtype so far of
+ * const, this parses the "* bar[3]" and updates the type argument
+ *
+ * ct_usr and type must be as filled out by parse_type
+ *
+ * pushes the updated user value on the top of the stack
+ */
+void parse_argument(lua_State* L, struct parser* P, int ct_usr, struct ctype* ct, struct token* pname, struct parser* asmname)
+{
+    struct token tok, name;
+    int top = lua_gettop(L);
+
+    memset(&name, 0, sizeof(name));
+    parse_argument2(L, P, ct_usr, ct, &name, asmname);
+
+    for (;;) {
+        if (!next_token(L, P, &tok)) {
+            break;
+        } else if (parse_attribute(L, P, &tok, ct, asmname)) {
+            /* parse_attribute sets the appropriate fields */
+        } else {
+            put_back(P);
+            break;
+        }
+    }
+
+    if (lua_gettop(L) == top) {
+        lua_pushvalue(L, ct_usr);
+    }
+
+    find_canonical_usr(L, -1, ct);
+
+    if (pname) {
+        *pname = name;
+    }
+}
+
+static void parse_typedef(lua_State* L, struct parser* P)
+{
+    struct token tok;
+    struct ctype base_type;
+    int top = lua_gettop(L);
+
+    parse_type(L, P, &base_type);
+
+    for (;;) {
+        struct ctype arg_type = base_type;
+        struct token name;
+
+        memset(&name, 0, sizeof(name));
+
+        assert(lua_gettop(L) == top + 1);
+        parse_argument(L, P, -1, &arg_type, &name, NULL);
+        assert(lua_gettop(L) == top + 2);
+
+        if (!name.size) {
+            luaL_error(L, "Can't have a typedef without a name on line %d", P->line);
+        } else if (arg_type.is_variable_array) {
+            luaL_error(L, "Can't typedef a variable length array on line %d", P->line);
+        }
+
+        push_upval(L, &types_key);
+        lua_pushlstring(L, name.str, name.size);
+        push_ctype(L, -3, &arg_type);
+        lua_rawset(L, -3);
+        lua_pop(L, 2); /* types and parse_argument usr tbl */
+
+        require_token(L, P, &tok);
+
+        if (tok.type == TOK_SEMICOLON) {
+            break;
+        } else if (tok.type != TOK_COMMA) {
+            luaL_error(L, "Unexpected character in typedef on line %d", P->line);
+        }
+    }
+
+    lua_pop(L, 1); /* parse_type usr tbl */
+    assert(lua_gettop(L) == top);
+}
+
+static bool is_hex(char ch)
+{ return ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F'); }
+
+static bool is_digit(char ch)
+{ return '0' <= ch && ch <= '9'; }
+
+static int from_hex(char ch)
+{
+    if (ch >= 'a') {
+        return ch - 'a' + 10;
+    } else if (ch >= 'A') {
+        return ch - 'A' + 10;
+    } else {
+        return ch - '0';
+    }
+}
+
+static void push_strings(lua_State* L, struct parser* P)
+{
+    luaL_Buffer B;
+    luaL_buffinit(L, &B);
+
+    for (;;) {
+        const char *p, *e;
+        char *t, *s;
+        struct token tok;
+
+        require_token(L, P, &tok);
+        if (tok.type != TOK_STRING) {
+            break;
+        }
+
+        p = tok.str;
+        e = p + tok.size;
+
+        t = luaL_prepbuffsize(&B, tok.size);
+        s = t;
+
+        while (p < e) {
+            if (*p == '\\') {
+                if (++p == e) {
+                    luaL_error(L, "parse error in string");
+                }
+                switch (*p) {
+                case '\\': *(t++) = '\\'; p++; break;
+                case '\"': *(t++) = '\"'; p++; break;
+                case '\'': *(t++) = '\''; p++; break;
+                case 'n': *(t++) = '\n'; p++; break;
+                case 'r': *(t++) = '\r'; p++; break;
+                case 'b': *(t++) = '\b'; p++; break;
+                case 't': *(t++) = '\t'; p++; break;
+                case 'f': *(t++) = '\f'; p++; break;
+                case 'a': *(t++) = '\a'; p++; break;
+                case 'v': *(t++) = '\v'; p++; break;
+                case 'e': *(t++) = 0x1B; p++; break;
+                case 'x':
+                    {
+                        uint8_t u;
+                        p++;
+                        if (p + 2 > e || !is_hex(p[0]) || !is_hex(p[1])) {
+                            luaL_error(L, "parse error in string");
+                        }
+                        u = (from_hex(p[0]) << 4) | from_hex(p[1]);
+                        *(t++) = *(char*) &u;
+                        p += 2;
+                        break;
+                    }
+                default:
+                    {
+                        uint8_t u;
+                        const char* e2 = min(p + 3, e);
+                        if (!is_digit(*p)) {
+                            luaL_error(L, "parse error in string");
+                        }
+                        u = *p - '0';
+                        p++;
+                        while (is_digit(*p) && p < e2) {
+                            u = 10*u + *p-'0';
+                            p++;
+                        }
+                        *(t++) = *(char*) &u;
+                        break;
+                    }
+                }
+            } else {
+                *(t++) = *(p++);
+            }
+        }
+
+        luaL_addsize(&B, t-s);
+    }
+
+    luaL_pushresult(&B);
+}
+
+static void parse_constant_assignemnt(lua_State* L,
+                                      struct parser* P,
+                                      const struct ctype* type,
+                                      const struct token* name)
+{
+    int64_t val = calculate_constant(L, P);
+
+    check_token(L, P, TOK_SEMICOLON, "", "expected ; after constant definition on line %d", P->line);
+
+    push_upval(L, &constants_key);
+    lua_pushlstring(L, name->str, name->size);
+
+    switch (type->type) {
+        case INT8_TYPE:
+        case INT16_TYPE:
+        case INT32_TYPE:
+            if (type->is_unsigned)
+                lua_pushinteger(L, (unsigned int) val);
+            else
+                lua_pushinteger(L, (int) val);
+            break;
+
+        default:
+            luaL_error(L, "expected a valid 8-, 16-, or 32-bit signed or unsigned integer type after 'static const' on line %d", P->line);
+    }
+
+    lua_rawset(L, -3);
+    lua_pop(L, 2); /*constants and type*/
+}
+
+#define END 0
+#define PRAGMA_POP 1
+
+static int parse_root(lua_State* L, struct parser* P)
+{
+    int top = lua_gettop(L);
+    struct token tok;
+
+    while (next_token(L, P, &tok)) {
+        /* we can have:
+         * struct definition
+         * enum definition
+         * union definition
+         * struct/enum/union declaration
+         * typedef
+         * function declaration
+         * pragma pack
+         */
+
+        assert(lua_gettop(L) == top);
+
+        if (tok.type == TOK_SEMICOLON) {
+            /* empty semicolon in root continue on */
+
+        } else if (tok.type == TOK_POUND) {
+
+            check_token(L, P, TOK_TOKEN, "pragma", "unexpected pre processor directive on line %d", P->line);
+            check_token(L, P, TOK_TOKEN, "pack", "unexpected pre processor directive on line %d", P->line);
+            check_token(L, P, TOK_OPEN_PAREN, "", "invalid pack directive on line %d", P->line);
+
+            require_token(L, P, &tok);
+
+            if (tok.type == TOK_NUMBER) {
+                if (tok.integer != 1 && tok.integer != 2 && tok.integer != 4 && tok.integer != 8 && tok.integer != 16) {
+                    luaL_error(L, "pack directive with invalid pack size on line %d", P->line);
+                }
+
+                P->align_mask = (unsigned) (tok.integer - 1);
+                check_token(L, P, TOK_CLOSE_PAREN, "", "invalid pack directive on line %d", P->line);
+
+            } else if (tok.type == TOK_TOKEN && IS_LITERAL(tok, "push")) {
+                int line = P->line;
+                unsigned previous_alignment = P->align_mask;
+
+                check_token(L, P, TOK_CLOSE_PAREN, "", "invalid pack directive on line %d", P->line);
+
+                if (parse_root(L, P) != PRAGMA_POP) {
+                    luaL_error(L, "reached end of string without a pragma pop to match the push on line %d", line);
+                }
+
+                P->align_mask = previous_alignment;
+
+            } else if (tok.type == TOK_TOKEN && IS_LITERAL(tok, "pop")) {
+                check_token(L, P, TOK_CLOSE_PAREN, "", "invalid pack directive on line %d", P->line);
+                return PRAGMA_POP;
+
+            } else {
+                luaL_error(L, "invalid pack directive on line %d", P->line);
+            }
+
+
+        } else if (tok.type != TOK_TOKEN) {
+            return luaL_error(L, "unexpected character on line %d", P->line);
+
+        } else if (IS_LITERAL(tok, "__extension__")) {
+            /* ignore */
+            continue;
+
+        } else if (IS_LITERAL(tok, "extern")) {
+            /* ignore extern as data and functions can only be extern */
+            continue;
+
+        } else if (IS_LITERAL(tok, "typedef")) {
+            parse_typedef(L, P);
+
+        } else {
+            /* type declaration, type definition, or function declaration */
+            struct ctype type;
+            struct token name;
+            struct parser asmname;
+
+            memset(&name, 0, sizeof(name));
+            memset(&asmname, 0, sizeof(asmname));
+
+            put_back(P);
+            parse_type(L, P, &type);
+
+            for (;;) {
+                parse_argument(L, P, -1, &type, &name, &asmname);
+
+                if (name.size) {
+                    /* global/function declaration */
+
+                    /* set asmname_tbl[name] = asmname */
+                    if (asmname.next) {
+                        push_upval(L, &asmname_key);
+                        lua_pushlstring(L, name.str, name.size);
+                        push_strings(L, &asmname);
+                        lua_rawset(L, -3);
+                        lua_pop(L, 1); /* asmname upval */
+                    }
+
+                    push_upval(L, &functions_key);
+                    lua_pushlstring(L, name.str, name.size);
+                    push_ctype(L, -3, &type);
+                    lua_rawset(L, -3);
+                    lua_pop(L, 1); /* functions upval */
+                } else {
+                    /* type declaration/definition - already been processed */
+                }
+
+                lua_pop(L, 1);
+
+                if (!next_token(L, P, &tok)) {
+                    break;
+                }
+
+                if (tok.type == TOK_COMMA) {
+                    continue;
+                }
+
+                if (tok.type == TOK_OPEN_CURLY) {
+                    int line = P->line;
+                    int remaining = 1;
+                    while (remaining > 0 && next_token(L, P, &tok)) {
+                        if (tok.type == TOK_CLOSE_CURLY) {
+                            remaining--;
+                        } else if (tok.type == TOK_OPEN_CURLY) {
+                            remaining++;
+                        }
+                    }
+                    if (remaining > 0) {
+                        luaL_error(L, "missing closing bracket for line %d", line);
+                    }
+                } else if (tok.type == TOK_ASSIGN) {
+                    parse_constant_assignemnt(L, P, &type, &name);
+                } else if (tok.type != TOK_SEMICOLON) {
+                    luaL_error(L, "missing semicolon on line %d", P->line);
+                }
+                break;
+            }
+
+            lua_pop(L, 1);
+        }
+    }
+
+    return END;
+}
+
+int ffi_cdef(lua_State* L)
+{
+    struct parser P;
+
+    P.line = 1;
+    P.prev = P.next = luaL_checkstring(L, 1);
+    P.align_mask = DEFAULT_ALIGN_MASK;
+
+    if (parse_root(L, &P) == PRAGMA_POP) {
+        luaL_error(L, "pragma pop without an associated push on line %d", P.line);
+    }
+
+    return 0;
+}
+
+/* calculate_constant handles operator precedence by having a number of
+ * recursive commands each of which computes the result at that level of
+ * precedence and above. calculate_constant1 is the highest precedence
+ */
+
+static int64_t string_to_int(const char* str, size_t size)
+{
+    const char* end = str + size;
+    char c = *str++;
+    if (str < end)
+    {
+        if (c == '\\') {
+            c = *str++;
+            switch (c) {
+            case '\'': c = '\''; break;
+            case '\"': c = '\"'; break;
+            case '\?': c = '\?'; break;
+            case '\\': c = '\\'; break;
+            case 'a': c = '\a'; break;
+            case 'b': c = '\b'; break;
+            case 'f': c = '\f'; break;
+            case 'n': c = '\n'; break;
+            case 'r': c = '\r'; break;
+            case 't': c = '\t'; break;
+            case 'v': c = '\v'; break;
+            case 'e': c = 27; break;
+            case 'x':
+                c = 0;
+                while (str < end) {
+                    char d = *str++;
+                    c *= 16;
+                    if (d >= '0' && d <= '9') c += (d - '0');
+                    else c += (d - 'a' + 10);
+                }
+                break;
+            default:
+                c = c - '0';
+                while (str < end) {
+                    char d = *str++;
+                    c = c*8 + (d - '0');
+                }
+                break;
+            }
+        }
+    }
+    return c;
+}
+
+static int try_cast(lua_State* L)
+{
+    struct parser* P = (struct parser*) lua_touserdata(L, 1);
+    struct ctype ct;
+    struct token name, tok;
+    memset(&name, 0, sizeof(name));
+
+    parse_type(L, P, &ct);
+    parse_argument(L, P, -1, &ct, &name, NULL);
+
+    require_token(L, P, &tok);
+    if (tok.type != TOK_CLOSE_PAREN || name.size) {
+        return luaL_error(L, "invalid cast");
+    }
+
+    if (ct.pointers/* || ct.type != INT32_TYPE*/) {
+        return luaL_error(L, "unsupported cast on line %d", P->line);
+    }
+
+    return 0;
+}
+
+static int64_t calculate_constant2(lua_State* L, struct parser* P, struct token* tok);
+
+/* () */
+static int64_t calculate_constant1(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t ret;
+
+    if (tok->type == TOK_NUMBER) {
+        ret = tok->integer;
+        next_token(L, P, tok);
+        return ret;
+
+    } else if (tok->type == TOK_TOKEN) {
+        /* look up name in constants table */
+        push_upval(L, &constants_key);
+        lua_pushlstring(L, tok->str, tok->size);
+        lua_rawget(L, -2);
+        lua_remove(L, -2); /* constants table */
+
+        if (!lua_isnumber(L, -1)) {
+            lua_pushlstring(L, tok->str, tok->size);
+            luaL_error(L, "use of undefined constant %s on line %d", lua_tostring(L, -1), P->line);
+        }
+
+        ret = (int64_t) lua_tonumber(L, -1);
+        lua_pop(L, 1);
+        next_token(L, P, tok);
+        return ret;
+
+    } else if (tok->type == TOK_OPEN_PAREN) {
+        struct parser before_cast = *P;
+        int top = lua_gettop(L);
+
+        /* see if this is a numeric cast, which we ignore */
+        lua_pushcfunction(L, &try_cast);
+        lua_pushlightuserdata(L, P);
+        if (!lua_pcall(L, 1, 0, 0)) {
+            next_token(L, P, tok);
+            return calculate_constant2(L, P, tok);
+        }
+        lua_settop(L, top);
+
+        *P = before_cast;
+        ret = calculate_constant(L, P);
+
+        require_token(L, P, tok);
+        if (tok->type != TOK_CLOSE_PAREN) {
+            luaL_error(L, "error whilst parsing constant at line %d", P->line);
+        }
+
+        next_token(L, P, tok);
+        return ret;
+
+    } else if (tok->type == TOK_STRING) {
+        ret = string_to_int(tok->str, tok->size);
+
+        next_token(L, P, tok);
+        return ret;
+
+    } else {
+        return luaL_error(L, "unexpected token whilst parsing constant at line %d", P->line);
+    }
+}
+
+/* ! and ~, unary + and -, and sizeof */
+static int64_t calculate_constant2(lua_State* L, struct parser* P, struct token* tok)
+{
+    if (tok->type == TOK_LOGICAL_NOT) {
+        require_token(L, P, tok);
+        return !calculate_constant2(L, P, tok);
+
+    } else if (tok->type == TOK_BITWISE_NOT) {
+        require_token(L, P, tok);
+        return ~calculate_constant2(L, P, tok);
+
+    } else if (tok->type == TOK_PLUS) {
+        require_token(L, P, tok);
+        return calculate_constant2(L, P, tok);
+
+    } else if (tok->type == TOK_MINUS) {
+        require_token(L, P, tok);
+        return -calculate_constant2(L, P, tok);
+
+    } else if (tok->type == TOK_TOKEN &&
+            (IS_LITERAL(*tok, "sizeof")
+             || IS_LITERAL(*tok, "alignof")
+             || IS_LITERAL(*tok, "__alignof__")
+             || IS_LITERAL(*tok, "__alignof"))) {
+
+        bool issize = IS_LITERAL(*tok, "sizeof");
+        struct ctype type;
+
+        require_token(L, P, tok);
+        if (tok->type != TOK_OPEN_PAREN) {
+            luaL_error(L, "invalid sizeof at line %d", P->line);
+        }
+
+        parse_type(L, P, &type);
+        parse_argument(L, P, -1, &type, NULL, NULL);
+        lua_pop(L, 2);
+
+        require_token(L, P, tok);
+        if (tok->type != TOK_CLOSE_PAREN) {
+            luaL_error(L, "invalid sizeof at line %d", P->line);
+        }
+
+        next_token(L, P, tok);
+
+        return issize ? ctype_size(L, &type) : type.align_mask + 1;
+
+    } else {
+        return calculate_constant1(L, P, tok);
+    }
+}
+
+/* binary * / and % (left associative) */
+static int64_t calculate_constant3(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant2(L, P, tok);
+
+    for (;;) {
+        if (tok->type == TOK_MULTIPLY) {
+            require_token(L, P, tok);
+            left *= calculate_constant2(L, P, tok);
+
+        } else if (tok->type == TOK_DIVIDE) {
+            require_token(L, P, tok);
+            left /= calculate_constant2(L, P, tok);
+
+        } else if (tok->type == TOK_MODULUS) {
+            require_token(L, P, tok);
+            left %= calculate_constant2(L, P, tok);
+
+        } else {
+            return left;
+        }
+    }
+}
+
+/* binary + and - (left associative) */
+static int64_t calculate_constant4(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant3(L, P, tok);
+
+    for (;;) {
+        if (tok->type == TOK_PLUS) {
+            require_token(L, P, tok);
+            left += calculate_constant3(L, P, tok);
+
+        } else if (tok->type == TOK_MINUS) {
+            require_token(L, P, tok);
+            left -= calculate_constant3(L, P, tok);
+
+        } else {
+            return left;
+        }
+    }
+}
+
+/* binary << and >> (left associative) */
+static int64_t calculate_constant5(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant4(L, P, tok);
+
+    for (;;) {
+        if (tok->type == TOK_LEFT_SHIFT) {
+            require_token(L, P, tok);
+            left <<= calculate_constant4(L, P, tok);
+
+        } else if (tok->type == TOK_RIGHT_SHIFT) {
+            require_token(L, P, tok);
+            left >>= calculate_constant4(L, P, tok);
+
+        } else {
+            return left;
+        }
+    }
+}
+
+/* binary <, <=, >, and >= (left associative) */
+static int64_t calculate_constant6(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant5(L, P, tok);
+
+    for (;;) {
+        if (tok->type == TOK_LESS) {
+            require_token(L, P, tok);
+            left = (left < calculate_constant5(L, P, tok));
+
+        } else if (tok->type == TOK_LESS_EQUAL) {
+            require_token(L, P, tok);
+            left = (left <= calculate_constant5(L, P, tok));
+
+        } else if (tok->type == TOK_GREATER) {
+            require_token(L, P, tok);
+            left = (left > calculate_constant5(L, P, tok));
+
+        } else if (tok->type == TOK_GREATER_EQUAL) {
+            require_token(L, P, tok);
+            left = (left >= calculate_constant5(L, P, tok));
+
+        } else {
+            return left;
+        }
+    }
+}
+
+/* binary ==, != (left associative) */
+static int64_t calculate_constant7(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant6(L, P, tok);
+
+    for (;;) {
+        if (tok->type == TOK_EQUAL) {
+            require_token(L, P, tok);
+            left = (left == calculate_constant6(L, P, tok));
+
+        } else if (tok->type == TOK_NOT_EQUAL) {
+            require_token(L, P, tok);
+            left = (left != calculate_constant6(L, P, tok));
+
+        } else {
+            return left;
+        }
+    }
+}
+
+/* binary & (left associative) */
+static int64_t calculate_constant8(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant7(L, P, tok);
+
+    for (;;) {
+        if (tok->type == TOK_BITWISE_AND) {
+            require_token(L, P, tok);
+            left = (left & calculate_constant7(L, P, tok));
+
+        } else {
+            return left;
+        }
+    }
+}
+
+/* binary ^ (left associative) */
+static int64_t calculate_constant9(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant8(L, P, tok);
+
+    for (;;) {
+        if (tok->type == TOK_BITWISE_XOR) {
+            require_token(L, P, tok);
+            left = (left ^ calculate_constant8(L, P, tok));
+
+        } else {
+            return left;
+        }
+    }
+}
+
+/* binary | (left associative) */
+static int64_t calculate_constant10(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant9(L, P, tok);
+
+    for (;;) {
+        if (tok->type == TOK_BITWISE_OR) {
+            require_token(L, P, tok);
+            left = (left | calculate_constant9(L, P, tok));
+
+        } else {
+            return left;
+        }
+    }
+}
+
+/* binary && (left associative) */
+static int64_t calculate_constant11(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant10(L, P, tok);
+
+    for (;;) {
+        if (tok->type == TOK_LOGICAL_AND) {
+            require_token(L, P, tok);
+            left = (left && calculate_constant10(L, P, tok));
+
+        } else {
+            return left;
+        }
+    }
+}
+
+/* binary || (left associative) */
+static int64_t calculate_constant12(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant11(L, P, tok);
+
+    for (;;) {
+        if (tok->type == TOK_LOGICAL_OR) {
+            require_token(L, P, tok);
+            left = (left || calculate_constant11(L, P, tok));
+
+        } else {
+            return left;
+        }
+    }
+}
+
+/* ternary ?: (right associative) */
+static int64_t calculate_constant13(lua_State* L, struct parser* P, struct token* tok)
+{
+    int64_t left = calculate_constant12(L, P, tok);
+
+    if (tok->type == TOK_QUESTION) {
+        int64_t middle, right;
+        require_token(L, P, tok);
+        middle = calculate_constant13(L, P, tok);
+        if (tok->type != TOK_COLON) {
+            luaL_error(L, "invalid ternery (? :) in constant on line %d", P->line);
+        }
+        require_token(L, P, tok);
+        right = calculate_constant13(L, P, tok);
+        return left ? middle : right;
+
+    } else {
+        return left;
+    }
+}
+
+int64_t calculate_constant(lua_State* L, struct parser* P)
+{
+    struct token tok;
+    int64_t ret;
+    require_token(L, P, &tok);
+    ret = calculate_constant13(L, P, &tok);
+
+    if (tok.type != TOK_NIL) {
+        put_back(P);
+    }
+
+    return ret;
+}
+
+
+
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/parser.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/test.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/test.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/test.c	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,720 @@
+/* vim: ts=4 sw=4 sts=4 et tw=78
+ * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+ * Portions copyright (c) 2011 James R. McKaskill.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <errno.h>
+#endif
+
+#include <complex.h>
+#define HAVE_COMPLEX
+
+#ifdef __cplusplus
+# define EXTERN_C extern "C"
+#else
+# define EXTERN_C extern
+#endif
+
+#ifdef _WIN32
+#define EXPORT EXTERN_C __declspec(dllexport)
+#elif defined __GNUC__
+#define EXPORT EXTERN_C __attribute__((visibility("default")))
+#else
+#define EXPORT EXTERN_C
+#endif
+
+enum e8 {
+    FOO8,
+    BAR8,
+};
+enum e16 {
+    FOO16 = 1 << 8,
+    BAR16,
+    BIG16 = 1 << 14,
+};
+enum e32 {
+    FOO32 = 1 << 16,
+    BAR32,
+    BIG32 = 1 << 30,
+};
+
+EXPORT bool have_complex();
+
+bool have_complex()
+{
+#ifdef HAVE_COMPLEX
+    return 1;
+#else
+    return 0;
+#endif
+}
+
+EXPORT bool is_msvc;
+
+bool is_msvc =
+#ifdef _MSC_VER
+    1;
+#else
+    0;
+#endif
+
+EXPORT int test_pow(int v);
+int test_pow(int v)
+{ return v * v; }
+
+#define ADD(TYPE, NAME) \
+    EXPORT TYPE NAME(TYPE a, TYPE b); \
+    TYPE NAME(TYPE a, TYPE b) { return a + b; }
+
+ADD(int8_t, add_i8)
+ADD(uint8_t, add_u8)
+ADD(int16_t, add_i16)
+ADD(uint16_t, add_u16)
+ADD(int32_t, add_i32)
+ADD(uint32_t, add_u32)
+ADD(int64_t, add_i64)
+ADD(uint64_t, add_u64)
+ADD(double, add_d)
+ADD(float, add_f)
+#ifdef HAVE_COMPLEX
+ADD(double complex, add_dc)
+ADD(float complex, add_fc)
+#endif
+
+EXPORT enum e8 inc_e8(enum e8 v);
+EXPORT enum e16 inc_e16(enum e16 v);
+EXPORT enum e32 inc_e32(enum e32 v);
+enum e8 inc_e8(enum e8 v) {return v+1;}
+enum e16 inc_e16(enum e16 v) {return v+1;}
+enum e32 inc_e32(enum e32 v) {return v+1;}
+
+EXPORT _Bool not_b(_Bool v);
+EXPORT _Bool not_b2(_Bool v);
+
+_Bool not_b(_Bool v) {return !v;}
+_Bool not_b2(_Bool v) {return !v;}
+
+#define PRINT(TYPE, NAME, FORMAT) \
+    EXPORT int NAME(char* buf, TYPE val); \
+    int NAME(char* buf, TYPE val) {return sprintf(buf, "%" FORMAT, val);}
+
+PRINT(int8_t, print_i8, PRId8)
+PRINT(uint8_t, print_u8, PRIu8)
+PRINT(int16_t, print_i16, PRId16)
+PRINT(uint16_t, print_u16, PRIu16)
+PRINT(int32_t, print_i32, PRId32)
+PRINT(uint32_t, print_u32, PRIu32)
+PRINT(int64_t, print_i64, PRId64)
+PRINT(uint64_t, print_u64, PRIu64)
+PRINT(double, print_d, "g")
+PRINT(float, print_f, "g")
+PRINT(const char*, print_s, "s")
+PRINT(void*, print_p, "p")
+PRINT(enum e8, print_e8, "d")
+PRINT(enum e16, print_e16, "d")
+PRINT(enum e32, print_e32, "d")
+
+#ifdef HAVE_COMPLEX
+EXPORT int print_dc(char* buf, double complex val);
+EXPORT int print_fc(char* buf, float complex val);
+int print_dc(char* buf, double complex val) {return sprintf(buf, "%g+%gi", creal(val), cimag(val));}
+int print_fc(char* buf, float complex val) {return sprintf(buf, "%g+%gi", creal(val), cimag(val));}
+#endif
+
+EXPORT int print_b(char* buf, _Bool val);
+EXPORT int print_b2(char* buf, _Bool val);
+int print_b(char* buf, _Bool val) {return sprintf(buf, "%s", val ? "true" : "false");}
+int print_b2(char* buf, _Bool val) {return sprintf(buf, "%s", val ? "true" : "false");}
+
+EXPORT bool (*ret_fp(bool (*val)(bool)))(bool);
+bool (*ret_fp(bool (*val)(bool)))(bool)
+{return val;}
+
+#define OFFSETOF(STRUCT, MEMBER) ((int) ((char*) &STRUCT.MEMBER - (char*) &S - 1))
+
+#define ALIGN_UP(VALUE, ALIGNMENT, SUFFIX) \
+    struct align_##ALIGNMENT##_##SUFFIX {   \
+        char pad;                   \
+        VALUE;                       \
+    };                              \
+    EXPORT int print_align_##ALIGNMENT##_##SUFFIX(char* buf, struct align_##ALIGNMENT##_##SUFFIX* p);   \
+    int print_align_##ALIGNMENT##_##SUFFIX(char* buf, struct align_##ALIGNMENT##_##SUFFIX* p) { \
+        struct {char ch; struct align_##ALIGNMENT##_##SUFFIX v;} s; \
+        int off = sprintf(buf, "size %d offset %d align %d value ", \
+                (int) sizeof(s.v), \
+                (int) (((char*) &p->v) - (char*) p), \
+                (int) (((char*) &s.v) - (char*) &s)); \
+        return print_##SUFFIX(buf+off, p->v); \
+    }
+
+#ifdef HAVE_COMPLEX
+#define COMPLEX_ALIGN(ALIGNMENT, ATTR) \
+    ALIGN_UP(ATTR(double complex), ALIGNMENT, dc) \
+    ALIGN_UP(ATTR(float complex), ALIGNMENT, fc)
+#else
+#define COMPLEX_ALIGN(ALIGNMENT, ATTR)
+#endif
+
+/* MSVC doesn't support __declspec(aligned(#)) on enums see C4329 */
+#define ENUM_ALIGN2(ALIGNMENT, ATTR) \
+    ALIGN_UP(ATTR(enum e8), ALIGNMENT, e8)        \
+    ALIGN_UP(ATTR(enum e16), ALIGNMENT, e16)      \
+    ALIGN_UP(ATTR(enum e32), ALIGNMENT, e32)      \
+
+#ifdef _MSC_VER
+#define ENUM_ALIGN(ALIGNMENT, ATTR)
+#else
+#define ENUM_ALIGN(ALIGNMENT, ATTR) ENUM_ALIGN2(ALIGNMENT, ATTR)
+#endif
+
+#define ALIGN2(ALIGNMENT, ATTR)                   \
+    ALIGN_UP(ATTR(uint16_t), ALIGNMENT, u16)      \
+    ALIGN_UP(ATTR(uint32_t), ALIGNMENT, u32)      \
+    ALIGN_UP(ATTR(uint64_t), ALIGNMENT, u64)      \
+    ALIGN_UP(ATTR(float), ALIGNMENT, f)           \
+    ALIGN_UP(ATTR(double), ALIGNMENT, d)          \
+    ALIGN_UP(ATTR(const char*), ALIGNMENT, s)     \
+    ALIGN_UP(ATTR(void*), ALIGNMENT, p)           \
+    ALIGN_UP(ATTR(_Bool), ALIGNMENT, b)           \
+    ALIGN_UP(ATTR(_Bool), ALIGNMENT, b2)          \
+    ENUM_ALIGN(ALIGNMENT, ATTR)                   \
+    COMPLEX_ALIGN(ALIGNMENT, ATTR)
+
+#define NO_ATTR(TYPE) TYPE v
+
+#ifdef _MSC_VER
+#define ALIGN_NO_ATTR(ALIGNMENT) \
+    ALIGN2(ALIGNMENT, NO_ATTR) \
+    ENUM_ALIGN2(ALIGNMENT, NO_ATTR)
+#else
+#define ALIGN_NO_ATTR(ALIGNMENT) \
+    ALIGN2(ALIGNMENT, NO_ATTR)
+#endif
+
+ALIGN_NO_ATTR(0)
+
+#pragma pack(push)
+#pragma pack(1)
+ALIGN_NO_ATTR(1)
+#pragma pack(2)
+ALIGN_NO_ATTR(2)
+#pragma pack(4)
+ALIGN_NO_ATTR(4)
+#pragma pack(8)
+ALIGN_NO_ATTR(8)
+#pragma pack(16)
+ALIGN_NO_ATTR(16)
+#pragma pack(pop)
+
+#ifdef _MSC_VER
+#define ATTR_(TYPE, ALIGN) __declspec(align(ALIGN)) TYPE v
+#else
+#define ATTR_(TYPE, ALIGN) TYPE v __attribute__((aligned(ALIGN)))
+#endif
+
+#define ATTR1(TYPE) ATTR_(TYPE, 1)
+#define ATTR2(TYPE) ATTR_(TYPE, 2)
+#define ATTR4(TYPE) ATTR_(TYPE, 4)
+#define ATTR8(TYPE) ATTR_(TYPE, 8)
+#define ATTR16(TYPE) ATTR_(TYPE, 16)
+
+#define ATTR_DEF(TYPE) TYPE v __attribute__((aligned))
+
+ALIGN2(attr_1, ATTR1)
+ALIGN2(attr_2, ATTR2)
+ALIGN2(attr_4, ATTR4)
+ALIGN2(attr_8, ATTR8)
+ALIGN2(attr_16, ATTR16)
+
+#ifndef _MSC_VER
+ALIGN2(attr_def, ATTR_DEF)
+#endif
+
+#ifdef _MSC_VER
+#define alignof(type) __alignof(type)
+#else
+#define alignof(type) __alignof__(type)
+#endif
+
+EXPORT int max_alignment();
+
+int max_alignment()
+{ return alignof(struct align_attr_16_p); }
+
+/* bit_fields1.cpp */
+/* compile with: /LD */
+struct Date {
+   unsigned short nWeekDay  : 3;    /* 0..7   (3 bits) */
+   unsigned short nMonthDay : 6;    /* 0..31  (6 bits) */
+   unsigned short nMonth    : 5;    /* 0..12  (5 bits) */
+   unsigned short nYear     : 8;    /* 0..100 (8 bits) */
+};
+
+EXPORT int print_date(size_t* sz, size_t* align, char* buf, struct Date* d);
+
+int print_date(size_t* sz, size_t* align, char* buf, struct Date* d) {
+    *sz = sizeof(struct Date);
+    *align = alignof(struct Date);
+    return sprintf(buf, "%d %d %d %d", d->nWeekDay, d->nMonthDay, d->nMonth, d->nYear);
+}
+
+/* bit_fields2.cpp */
+/* compile with: /LD */
+struct Date2 {
+   unsigned nWeekDay  : 3;    /* 0..7   (3 bits) */
+   unsigned nMonthDay : 6;    /* 0..31  (6 bits) */
+   unsigned           : 0;    /* Force alignment to next boundary. */
+   unsigned nMonth    : 5;    /* 0..12  (5 bits) */
+   unsigned nYear     : 8;    /* 0..100 (8 bits) */
+};
+
+EXPORT int print_date2(size_t* sz, size_t* align, char* buf, struct Date2* d);
+
+int print_date2(size_t* sz, size_t* align, char* buf, struct Date2* d) {
+    *sz = sizeof(struct Date2);
+    *align = alignof(struct Date2);
+    return sprintf(buf, "%d %d %d %d", d->nWeekDay, d->nMonthDay, d->nMonth, d->nYear);
+}
+
+// Examples from SysV X86 ABI
+struct sysv1 {
+    int     j:5;
+    int     k:6;
+    int     m:7;
+};
+
+EXPORT int print_sysv1(size_t* sz, size_t* align, char* buf, struct sysv1* s);
+
+int print_sysv1(size_t* sz, size_t* align, char* buf, struct sysv1* s) {
+    *sz = sizeof(struct sysv1);
+    *align = alignof(struct sysv1);
+    return sprintf(buf, "%d %d %d", s->j, s->k, s->m);
+}
+
+struct sysv2 {
+    short   s:9;
+    int     j:9;
+    char    c;
+    short   t:9;
+    short   u:9;
+    char    d;
+};
+
+EXPORT int print_sysv2(size_t* sz, size_t* align, char* buf, struct sysv2* s);
+
+int print_sysv2(size_t* sz, size_t* align, char* buf, struct sysv2* s) {
+    *sz = sizeof(struct sysv2);
+    *align = alignof(struct sysv2);
+    return sprintf(buf, "%d %d %d %d %d %d", s->s, s->j, s->c, s->t, s->u, s->d);
+}
+
+struct sysv3 {
+    char    c;
+    short   s:8;
+};
+
+EXPORT int print_sysv3(size_t* sz, size_t* align, char* buf, struct sysv3* s);
+
+int print_sysv3(size_t* sz, size_t* align, char* buf, struct sysv3* s) {
+    *sz = sizeof(struct sysv3);
+    *align = alignof(struct sysv3);
+    return sprintf(buf, "%d %d", s->c, s->s);
+}
+
+union sysv4 {
+    char    c;
+    short   s:8;
+};
+
+EXPORT int print_sysv4(size_t* sz, size_t* align, char* buf, union sysv4* s);
+
+int print_sysv4(size_t* sz, size_t* align, char* buf, union sysv4* s) {
+    *sz = sizeof(union sysv4);
+    *align = alignof(union sysv4);
+    return sprintf(buf, "%d", s->s);
+}
+
+struct sysv5 {
+    char    c;
+    int     :0;
+    char    d;
+    short   :9;
+    char    e;
+    char    :0;
+};
+
+EXPORT int print_sysv5(size_t* sz, size_t* align, char* buf, struct sysv5* s);
+
+int print_sysv5(size_t* sz, size_t* align, char* buf, struct sysv5* s) {
+    *sz = sizeof(struct sysv5);
+    *align = alignof(struct sysv5);
+    return sprintf(buf, "%d %d %d", s->c, s->d, s->e);
+}
+
+struct sysv6 {
+    char    c;
+    int     :0;
+    char    d;
+    int     :9;
+    char    e;
+};
+
+EXPORT int print_sysv6(size_t* sz, size_t* align, char* buf, struct sysv6* s);
+
+int print_sysv6(size_t* sz, size_t* align, char* buf, struct sysv6* s) {
+    *sz = sizeof(struct sysv6);
+    *align = alignof(struct sysv6);
+    return sprintf(buf, "%d %d %d", s->c, s->d, s->e);
+}
+
+struct sysv7 {
+    int     j:9;
+    short   s:9;
+    char    c;
+    short   t:9;
+    short   u:9;
+};
+
+EXPORT int print_sysv7(size_t* sz, size_t* align, char* buf, struct sysv7* s);
+
+int print_sysv7(size_t* sz, size_t* align, char* buf, struct sysv7* s) {
+    *sz = sizeof(struct sysv7);
+    *align = alignof(struct sysv7);
+    return sprintf(buf, "%d %d %d %d %d", s->j, s->s, s->c, s->t, s->u);
+}
+
+/* Now some targeting bitfield tests */
+
+/* Bitfield alignment */
+#define BITALIGN(TNUM,BNUM) \
+    struct ba_##TNUM##_##BNUM { \
+        char a; \
+        uint##TNUM##_t b : BNUM; \
+    }; \
+    EXPORT int print_ba_##TNUM##_##BNUM(size_t* sz, size_t* align, char* buf, struct ba_##TNUM##_##BNUM* s); \
+    int print_ba_##TNUM##_##BNUM(size_t* sz, size_t* align, char* buf, struct ba_##TNUM##_##BNUM* s) { \
+        *sz = sizeof(struct ba_##TNUM##_##BNUM); \
+        *align = alignof(struct ba_##TNUM##_##BNUM); \
+        return sprintf(buf, "%d %d", (int) s->a, (int) s->b); \
+    }
+
+BITALIGN(8,7)
+BITALIGN(16,7)
+BITALIGN(16,15)
+BITALIGN(32,7)
+BITALIGN(32,15)
+BITALIGN(32,31)
+BITALIGN(64,7)
+BITALIGN(64,15)
+BITALIGN(64,31)
+BITALIGN(64,63)
+
+/* Do unsigned and signed coallesce */
+#define BITCOALESCE(NUM) \
+    struct bc##NUM { \
+        uint##NUM##_t a : 3; \
+        int##NUM##_t b : 3; \
+    }; \
+    EXPORT int print_bc##NUM(size_t* sz, size_t* align, char* buf, struct bc##NUM* s); \
+    int print_bc##NUM(size_t* sz, size_t* align, char* buf, struct bc##NUM* s) { \
+        *sz = sizeof(struct bc##NUM); \
+        *align = alignof(struct bc##NUM); \
+        return sprintf(buf, "%d %d", (int) s->a, (int) s->b); \
+    }
+
+BITCOALESCE(8)
+BITCOALESCE(16)
+BITCOALESCE(32)
+BITCOALESCE(64)
+
+// Do different sizes coallesce
+struct bdsz {
+    uint8_t a : 3;
+    uint16_t b : 3;
+    uint32_t c : 3;
+    uint64_t d : 3;
+};
+
+EXPORT int print_bdsz(size_t* sz, size_t* align, char* buf, struct bdsz* s);
+int print_bdsz(size_t* sz, size_t* align, char* buf, struct bdsz* s) {
+    *sz = sizeof(struct bdsz);
+    *align = alignof(struct bdsz);
+    return sprintf(buf, "%d %d %d %d", (int) s->a, (int) s->b, (int) s->c, (int) s->d);
+}
+
+// Does coallesence upgrade the storage unit
+struct bcup {
+    uint8_t a : 7;
+    uint16_t b : 9;
+    uint32_t c : 17;
+    uint64_t d : 33;
+};
+
+EXPORT int print_bcup(size_t* sz, size_t* align, char* buf, struct bcup* s);
+int print_bcup(size_t* sz, size_t* align, char* buf, struct bcup* s) {
+    *sz = sizeof(struct bcup);
+    *align = alignof(struct bcup);
+    return sprintf(buf, "%d %d %d %"PRIu64, (int) s->a, (int) s->b, (int) s->c, (uint64_t) s->d);
+}
+
+// Is unaligned access allowed
+struct buna {
+    uint32_t a : 31;
+    uint32_t b : 31;
+};
+
+EXPORT int print_buna(size_t* sz, size_t* align, char* buf, struct buna* s);
+int print_buna(size_t* sz, size_t* align, char* buf, struct buna* s) {
+    *sz = sizeof(struct buna);
+    *align = alignof(struct buna);
+    return sprintf(buf, "%d %d", (int) s->a, (int) s->b);
+}
+
+/* What does a lone :0 do */
+#define BITLONEZERO(NUM) \
+    struct blz##NUM { \
+        uint##NUM##_t a; \
+        uint##NUM##_t :0; \
+        uint##NUM##_t b; \
+    }; \
+    EXPORT int print_##blz##NUM(size_t* sz, size_t* align, char* buf, struct blz##NUM* s); \
+    int print_blz##NUM(size_t* sz, size_t* align, char* buf, struct blz##NUM* s) { \
+        *sz = sizeof(struct blz##NUM); \
+        *align = alignof(struct blz##NUM); \
+        return sprintf(buf, "%d %d", (int) s->a, (int) s->b); \
+    }
+
+BITLONEZERO(8)
+BITLONEZERO(16)
+BITLONEZERO(32)
+BITLONEZERO(64)
+
+/* What does a :0 or unnamed :# of the same or different type do */
+#define BITZERO(NUM, ZNUM, BNUM) \
+    struct bz_##NUM##_##ZNUM##_##BNUM { \
+        uint8_t a; \
+        uint##NUM##_t b : 3; \
+        uint##ZNUM##_t :BNUM; \
+        uint##NUM##_t c : 3; \
+    }; \
+    EXPORT int print_bz_##NUM##_##ZNUM##_##BNUM(size_t* sz, size_t* align, char* buf, struct bz_##NUM##_##ZNUM##_##BNUM* s); \
+    int print_bz_##NUM##_##ZNUM##_##BNUM(size_t* sz, size_t* align, char* buf, struct bz_##NUM##_##ZNUM##_##BNUM* s) { \
+        *sz = sizeof(struct bz_##NUM##_##ZNUM##_##BNUM); \
+        *align = alignof(struct bz_##NUM##_##ZNUM##_##BNUM); \
+        return sprintf(buf, "%d %d %d", (int) s->a, (int) s->b, (int) s->c); \
+    }
+
+BITZERO(8,8,0)
+BITZERO(8,8,7)
+BITZERO(8,16,0)
+BITZERO(8,16,7)
+BITZERO(8,16,15)
+BITZERO(8,32,0)
+BITZERO(8,32,7)
+BITZERO(8,32,15)
+BITZERO(8,32,31)
+BITZERO(8,64,0)
+BITZERO(8,64,7)
+BITZERO(8,64,15)
+BITZERO(8,64,31)
+BITZERO(8,64,63)
+BITZERO(16,8,0)
+BITZERO(16,8,7)
+BITZERO(16,16,0)
+BITZERO(16,16,7)
+BITZERO(16,16,15)
+BITZERO(16,32,0)
+BITZERO(16,32,7)
+BITZERO(16,32,15)
+BITZERO(16,32,31)
+BITZERO(16,64,0)
+BITZERO(16,64,7)
+BITZERO(16,64,15)
+BITZERO(16,64,31)
+BITZERO(16,64,63)
+BITZERO(32,8,0)
+BITZERO(32,8,7)
+BITZERO(32,16,0)
+BITZERO(32,16,7)
+BITZERO(32,16,15)
+BITZERO(32,32,0)
+BITZERO(32,32,7)
+BITZERO(32,32,15)
+BITZERO(32,32,31)
+BITZERO(32,64,0)
+BITZERO(32,64,7)
+BITZERO(32,64,15)
+BITZERO(32,64,31)
+BITZERO(32,64,63)
+BITZERO(64,8,0)
+BITZERO(64,8,7)
+BITZERO(64,16,0)
+BITZERO(64,16,7)
+BITZERO(64,16,15)
+BITZERO(64,32,0)
+BITZERO(64,32,7)
+BITZERO(64,32,15)
+BITZERO(64,32,31)
+BITZERO(64,64,0)
+BITZERO(64,64,7)
+BITZERO(64,64,15)
+BITZERO(64,64,31)
+BITZERO(64,64,63)
+
+#define CALL(TYPE, SUFFIX) \
+    EXPORT TYPE call_##SUFFIX(TYPE (*func)(TYPE), TYPE arg); \
+    TYPE call_##SUFFIX(TYPE (*func)(TYPE), TYPE arg) { \
+        return func(arg); \
+    }
+
+CALL(int, i)
+CALL(float, f)
+CALL(double, d)
+CALL(const char*, s)
+CALL(_Bool, b)
+CALL(enum e8, e8)
+CALL(enum e16, e16)
+CALL(enum e32, e32)
+#ifdef HAVE_COMPLEX
+CALL(double complex, dc)
+CALL(float complex, fc)
+#endif
+
+struct fptr {
+#ifdef _MSC_VER
+    int (__cdecl *p)(int);
+#else
+    int (*p)(int);
+#endif
+};
+
+EXPORT int call_fptr(struct fptr* s, int val);
+
+int call_fptr(struct fptr* s, int val) {
+    return (s->p)(val);
+}
+
+EXPORT bool g_b;
+EXPORT int8_t g_i8;
+EXPORT int16_t g_i16;
+EXPORT int32_t g_i32;
+EXPORT int64_t g_i64;
+EXPORT uint8_t g_u8;
+EXPORT uint16_t g_u16;
+EXPORT uint32_t g_u32;
+EXPORT uint64_t g_u64;
+EXPORT float g_f;
+EXPORT double g_d;
+#ifdef HAVE_COMPLEX
+EXPORT double complex g_dc;
+EXPORT float complex g_fc;
+#endif
+EXPORT bool (*g_fp)(bool);
+EXPORT const char g_s[];
+EXPORT const char* g_sp;
+EXPORT void* g_p;
+EXPORT enum e8 g_e8;
+EXPORT enum e16 g_e16;
+EXPORT enum e32 g_e32;
+EXPORT struct Date g_date;
+
+bool g_b = true;
+int8_t g_i8 = -8;
+int16_t g_i16 = -16;
+int32_t g_i32 = -32;
+int64_t g_i64 = -64;
+uint8_t g_u8 = 8;
+uint16_t g_u16 = 16;
+uint32_t g_u32 = 32;
+uint64_t g_u64 = 64;
+float g_f = 3;
+double g_d = 5;
+#ifdef HAVE_COMPLEX
+double complex g_dc = 7+8i;
+float complex g_fc = 6+9i;
+#endif
+bool (*g_fp)(bool) = &not_b;
+void* g_p = (void*) &not_b;
+const char g_s[] = "g_s";
+const char* g_sp = "g_sp";
+enum e8 g_e8 = FOO8;
+enum e16 g_e16 = FOO16;
+enum e32 g_e32 = FOO32;
+struct Date g_date = {1,2,3,4};
+
+EXPORT void set_errno(int val);
+EXPORT int get_errno(void);
+
+void set_errno(int val) {
+#ifdef _WIN32
+    SetLastError(val);
+#else
+    errno = val;
+#endif
+}
+
+int get_errno(void) {
+#ifdef _WIN32
+    return GetLastError();
+#else
+    return errno;
+#endif
+}
+
+EXPORT int va_list_size, va_list_align;
+int va_list_size = sizeof(va_list);
+int va_list_align = alignof(va_list);
+
+
+EXPORT char buf[512];
+char buf[512];
+
+EXPORT void test_call_echo(char* c);
+void test_call_echo(char* c)
+{
+    sprintf(buf, "%s", c);
+}
+
+EXPORT void test_call_pppppii(void* a, void* b, void* c, void* d, void* e, int f, int g);
+void test_call_pppppii(void* a, void* b, void* c, void* d, void* e, int f, int g)
+{
+    sprintf(buf, "%p %p %p %p %p %d %d", a, b, c, d, e, f, g);
+}
+
+EXPORT void test_call_pppppiiiiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, int i4, int i5, int i6);
+void test_call_pppppiiiiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, int i4, int i5, int i6)
+{
+    sprintf(buf, "%p %p %p %p %p %d %d %d %d %d %d", p1, p2, p3, p4, p5, i1, i2, i3, i4, i5, i6);
+}
+
+EXPORT void test_call_pppppffffff(void* p1, void* p2, void* p3, void* p4, void* p5, float f1, float f2, float f3, float f4, float f5, float f6);
+void test_call_pppppffffff(void* p1, void* p2, void* p3, void* p4, void* p5, float f1, float f2, float f3, float f4, float f5, float f6)
+{
+    sprintf(buf, "%p %p %p %p %p %0.1f %0.1f %0.1f %0.1f %0.1f %0.1f", p1, p2, p3, p4, p5, f1, f2, f3, f4, f5, f6);
+}
+
+EXPORT void test_call_pppppiifiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, float f3, int i4, int i5, int i6);
+void test_call_pppppiifiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, float f3, int i4, int i5, int i6)
+{
+    sprintf(buf, "%p %p %p %p %p %d %d %0.1f %d %d %d", p1, p2, p3, p4, p5, i1, i2, f3, i4, i5, i6);
+}
+
+EXPORT void test_call_pppppiiifii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, float f4, int i5, int i6);
+void test_call_pppppiiifii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, float f4, int i5, int i6)
+{
+    sprintf(buf, "%p %p %p %p %p %d %d %d %0.1f %d %d", p1, p2, p3, p4, p5, i1, i2, i3, f4, i5, i6);
+}
+


Property changes on: trunk/Build/source/texk/web2c/luatexdir/luaffi/test.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/luatexdir/luaffi/test.lua
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaffi/test.lua	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaffi/test.lua	2017-02-09 22:44:03 UTC (rev 43177)
@@ -0,0 +1,1003 @@
+-- vim: ts=4 sw=4 sts=4 et tw=78
+-- Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+-- Portions copyright (c) 2011 James R. McKaskill.
+--
+-- This source code is licensed under the BSD-style license found in the
+-- LICENSE file in the root directory of this source tree. An additional grant
+-- of patent rights can be found in the PATENTS file in the same directory.
+--
+io.stdout:setvbuf('no')
+local ffi = require 'ffi'
+local dlls = {}
+
+local function loadlib(lib)
+    for pattern in package.cpath:gmatch('[^;]+') do
+        local path = pattern:gsub('?', lib)
+        local ok, lib = pcall(ffi.load, path)
+        if ok then
+            return lib
+        end
+    end
+    error("Unable to load", lib)
+end
+
+if _VERSION == 'Lua 5.1' then
+    dlls.__cdecl = loadlib('ffi/libtest')
+else
+    dlls.__cdecl = ffi.load(package.searchpath('ffi.libtest', package.cpath))
+end
+
+if ffi.arch == 'x86' and ffi.os == 'Windows' then
+    dlls.__stdcall = ffi.load('test_stdcall')
+    dlls.__fastcall = ffi.load('test_fastcall')
+end
+
+local function check(a, b, msg)
+    if a ~= b then
+        print('check', a, b)
+    end
+    return _G.assert(a == b, msg)
+end
+
+print('Running test')
+
+ffi.cdef [[
+enum e8 {
+    FOO8,
+    BAR8,
+};
+enum e16 {
+    FOO16 = 1 << 8,
+    BAR16,
+    BIG16 = 1 << 14,
+};
+enum e32 {
+    FOO32 = 1 << 16,
+    BAR32,
+    BIG32 = 1 << 30,
+};
+int max_alignment();
+bool is_msvc, is_msvc2 __asm__("is_msvc");
+bool have_complex(void);
+bool have_complex2() __asm__("have" /*foo*/ "\x5F" "complex"); // 5F is _
+
+int8_t add_i8(int8_t a, int8_t b);
+uint8_t add_u8(uint8_t a, uint8_t b);
+int16_t add_i16(int16_t a, int16_t b);
+uint16_t add_i16(uint16_t a, uint16_t b);
+int32_t add_i32(int32_t a, int32_t b);
+uint32_t add_u32(uint32_t a, uint32_t b);
+int64_t add_i64(int64_t a, int64_t b);
+uint64_t add_u64(uint64_t a, uint64_t b);
+double add_d(double a, double b);
+float add_f(float a, float b);
+double complex add_dc(double complex a, double complex b);
+float complex add_fc(float complex a, float complex b);
+enum e8 inc_e8(enum e8);
+enum e16 inc_e16(enum e16);
+enum e32 inc_e32(enum e32);
+bool not_b(bool v);
+_Bool not_b2(_Bool v);
+typedef bool (*fp)(bool);
+fp ret_fp(fp v);
+bool (*ret_fp2(bool (*)(bool)))(bool) __asm("ret_fp");
+
+int print_i8(char* buf, int8_t val);
+int print_u8(char* buf, uint8_t val);
+int print_i16(char* buf, int16_t val);
+int print_u16(char* buf, uint16_t val);
+int print_i32(char* buf, int32_t val);
+int print_u32(char* buf, uint32_t val);
+int print_i64(char* buf, int64_t val);
+int print_u64(char* buf, uint64_t val);
+int print_s(char* buf, const char* val);
+int print_b(char* buf, bool val);
+int print_b2(char* buf, _Bool val);
+int print_d(char* buf, double val);
+int print_f(char* buf, float val);
+int print_p(char* buf, void* val);
+int print_dc(char* buf, double complex val);
+int print_fc(char* buf, float complex val);
+int print_e8(char* buf, enum e8 val);
+int print_e16(char* buf, enum e16 val);
+int print_e32(char* buf, enum e32 val);
+int sprintf(char* buf, const char* format, ...);
+
+// Examples from MSDN
+
+// bit_fields1.cpp
+// compile with: /LD
+struct Date {
+   unsigned short nWeekDay  : 3;    // 0..7   (3 bits)
+   unsigned short nMonthDay : 6;    // 0..31  (6 bits)
+   unsigned short nMonth    : 5;    // 0..12  (5 bits)
+   unsigned short nYear     : 8;    // 0..100 (8 bits)
+};
+
+// bit_fields2.cpp
+// compile with: /LD
+struct Date2 {
+   unsigned nWeekDay  : 3;    // 0..7   (3 bits)
+   unsigned nMonthDay : 6;    // 0..31  (6 bits)
+   unsigned           : 0;    // Force alignment to next boundary.
+   unsigned nMonth    : 5;    // 0..12  (5 bits)
+   unsigned nYear     : 8;    // 0..100 (8 bits)
+};
+
+// For checking the alignment of short bitfields
+struct Date3 {
+   char pad;
+   unsigned short nWeekDay  : 3;    // 0..7   (3 bits)
+   unsigned short nMonthDay : 6;    // 0..31  (6 bits)
+   unsigned short nMonth    : 5;    // 0..12  (5 bits)
+   unsigned short nYear     : 8;    // 0..100 (8 bits)
+};
+
+// For checking the alignment and container of int64 bitfields
+struct bit64 {
+    char pad;
+    uint64_t a : 15;
+    uint64_t b : 14;
+    uint64_t c : 13;
+    uint64_t d : 12;
+};
+
+// Examples from SysV X86 ABI
+struct sysv1 {
+    int     j:5;
+    int     k:6;
+    int     m:7;
+};
+
+struct sysv2 {
+    short   s:9;
+    int     j:9;
+    char    c;
+    short   t:9;
+    short   u:9;
+    char    d;
+};
+
+struct sysv3 {
+    char    c;
+    short   s:8;
+};
+
+union sysv4 {
+    char    c;
+    short   s:8;
+};
+
+struct sysv5 {
+    char    c;
+    int     :0;
+    char    d;
+    short   :9;
+    char    e;
+    char    :0;
+};
+
+struct sysv6 {
+    char    c;
+    int     :0;
+    char    d;
+    int     :9;
+    char    e;
+};
+
+struct sysv7 {
+    int     j:9;
+    short   s:9;
+    char    c;
+    short   t:9;
+    short   u:9;
+};
+
+int print_date(size_t* sz, size_t* align, char* buf, struct Date* s);
+int print_date2(size_t* sz, size_t* align, char* buf, struct Date2* s);
+int print_date3(size_t* sz, size_t* align, char* buf, struct Date3* d);
+int print_bit64(size_t* sz, size_t* align, char* buf, struct bit64* d);
+int print_sysv1(size_t* sz, size_t* align, char* buf, struct sysv1* s);
+int print_sysv2(size_t* sz, size_t* align, char* buf, struct sysv2* s);
+int print_sysv3(size_t* sz, size_t* align, char* buf, struct sysv3* s);
+int print_sysv4(size_t* sz, size_t* align, char* buf, union sysv4* s);
+int print_sysv5(size_t* sz, size_t* align, char* buf, struct sysv5* s);
+int print_sysv6(size_t* sz, size_t* align, char* buf, struct sysv6* s);
+int print_sysv7(size_t* sz, size_t* align, char* buf, struct sysv7* s);
+
+struct fptr {
+    int (__cdecl *p)(int);
+};
+int call_fptr(struct fptr* s, int val);
+
+bool g_b;
+int8_t g_i8;
+int16_t g_i16;
+int32_t g_i32;
+int64_t g_i64;
+uint8_t g_u8;
+uint16_t g_u16;
+uint32_t g_u32;
+uint64_t g_u64;
+float g_f;
+double g_d;
+double complex g_dc;
+float complex g_fc;
+bool (*g_fp)(bool);
+const char g_s[];
+const char* g_sp;
+void* g_p;
+enum e8 g_e8;
+enum e16 g_e16;
+enum e32 g_e32;
+struct Date g_date;
+
+void set_errno(int val);
+int get_errno(void);
+]]
+
+local align = [[
+struct align_ALIGN_SUFFIX {
+    char pad;
+    TYPE v;
+};
+
+int print_align_ALIGN_SUFFIX(char* buf, struct align_ALIGN_SUFFIX* p);
+]]
+
+local palign = [[
+#pragma pack(push)
+#pragma pack(ALIGN)
+]] .. align .. [[
+#pragma pack(pop)
+]]
+
+local bitfields = [[
+struct bcTNUM {
+    uintTNUM_t a : 3;
+    intTNUM_t b : 3;
+};
+struct blzTNUM {
+    uintTNUM_t a;
+    uintTNUM_t :0;
+    uintTNUM_t b;
+};
+int print_bcTNUM(size_t* sz, size_t* align, char* buf, struct bcTNUM* s);
+int print_blzTNUM(size_t* sz, size_t* align, char* buf, struct blzTNUM* s);
+]]
+
+local bitalign = [[
+struct ba_TNUM_BNUM {
+    char a;
+    uintTNUM_t b : BNUM;
+};
+struct bu_TNUM_BNUM {
+    char a;
+    uintTNUM_t :BNUM;
+    char b;
+};
+int print_ba_TNUM_BNUM(size_t* sz, size_t* align, char* buf, struct ba_TNUM_BNUM* s);
+]]
+
+local bitzero = [[
+struct bz_TNUM_ZNUM_BNUM {
+    uint8_t a;
+    uintTNUM_t b : 3;
+    uintZNUM_t :BNUM;
+    uintTNUM_t c : 3;
+};
+int print_bz_TNUM_ZNUM_BNUM(size_t* sz, size_t* align, char* buf, struct bz_TNUM_ZNUM_BNUM* s);
+]]
+
+local i = ffi.C.i
+local test_values = {
+    ['void*'] = ffi.new('char[3]'),
+    ['const char*'] = 'foo',
+    float = 3.4,
+    double = 5.6,
+    uint16_t = 65000,
+    uint32_t = ffi.new('uint32_t', 700000056),
+    uint64_t = 12345678901234,
+    bool = true,
+    _Bool = false,
+    ['float complex'] = 3.1+4.2*i,
+    ['double complex'] = 5.1+6.2*i,
+    ['enum e8'] = ffi.C.FOO8,
+    ['enum e16'] = ffi.C.FOO16,
+    ['enum e32'] = ffi.C.FOO32,
+}
+
+local types = {
+    b = 'bool',
+    b2 = '_Bool',
+    d = 'double',
+    f = 'float',
+    u64 = 'uint64_t',
+    u32 = 'uint32_t',
+    u16 = 'uint16_t',
+    s = 'const char*',
+    p = 'void*',
+    e8 = 'enum e8',
+    e16 = 'enum e16',
+    e32 = 'enum e32',
+}
+
+local buf = ffi.new('char[256]')
+
+local function checkbuf(type, ret, msg)
+    local str = tostring(test_values[type]):gsub('^cdata%b<>: ', '')
+    check(ffi.string(buf), str, msg)
+    check(ret, #str, msg)
+end
+
+local function checkalign(type, v, ret)
+    --print(v)
+    local str = tostring(test_values[type]):gsub('^cdata%b<>: ', '')
+    check(ffi.string(buf), ('size %d offset %d align %d value %s'):format(ffi.sizeof(v), ffi.offsetof(v, 'v'), ffi.alignof(v, 'v'), str))
+    check(ret, #str)
+end
+
+local u64 = ffi.typeof('uint64_t')
+local i64 = ffi.typeof('int64_t')
+
+local first = true
+
+for convention,c in pairs(dlls) do
+    check(c.add_i8(1,1), 2)
+    check(c.add_i8(256,1), 1)
+    check(c.add_i8(127,1), -128)
+    check(c.add_i8(-120,120), 0)
+    check(c.add_u8(255,1), 0)
+    check(c.add_u8(120,120), 240)
+    check(c.add_i16(2000,4000), 6000)
+    check(c.add_d(20, 12), 32)
+    check(c.add_f(40, 32), 72)
+    check(c.not_b(true), false)
+    check(c.not_b2(false), true)
+    check(c.inc_e8(c.FOO8), c.BAR8)
+    check(c.inc_e8('FOO8'), c.BAR8)
+    check(c.inc_e16(c.FOO16), c.BAR16)
+    check(c.inc_e32(c.FOO32), c.BAR32)
+    check(c.ret_fp(c.g_fp), c.g_fp)
+    check(c.ret_fp2(c.g_fp), c.g_fp)
+
+    if c.have_complex() then
+        check(c.add_dc(3+4*i, 4+5*i), 7+9*i)
+        check(c.add_fc(2+4*i, 6+8*i), 8+12*i)
+        types.dc = 'double complex'
+        types.fc = 'float complex'
+    else
+        types.dc = nil
+        types.fc = nil
+    end
+    check((3+4*i).re, 3)
+    check((3+4*i).im, 4)
+    check(ffi.new('complex float', 2+8*i).re, 2)
+    check(ffi.new('complex float', 5+6*i).im, 6)
+
+    check(c.have_complex(), c.have_complex2())
+    check(c.is_msvc, c.is_msvc2)
+
+    check(c.g_b, true)
+    check(c.g_i8, -8)
+    check(c.g_i16, -16)
+    check(c.g_i32, -32)
+    check(c.g_i64, i64(-64))
+    check(c.g_u8, 8)
+    check(c.g_u16, 16)
+    check(c.g_u32, 32)
+    check(c.g_u64, u64(64))
+    check(c.g_f, 3)
+    check(c.g_d, 5)
+    if c.have_complex() then
+        check(c.g_dc, 7 + 8*i)
+        check(c.g_fc, 6 + 9*i)
+    end
+    check(ffi.cast('void*', c.g_fp), c.g_p)
+    check(c.g_s, 'g_s')
+    check(c.g_sp, 'g_sp')
+    check(c.g_e8, c.FOO8)
+    check(c.g_e16, c.FOO16)
+    check(c.g_e32, c.FOO32)
+    check(c.g_date.nWeekDay, 1)
+    check(c.g_date.nMonthDay, 2)
+    check(c.g_date.nMonth, 3)
+    check(c.g_date.nYear, 4)
+
+    c.g_b = false; check(c.g_b, false)
+    c.g_i8 = -108; check(c.g_i8, -108)
+    c.g_i16 = -1016; check(c.g_i16, -1016)
+    c.g_i32 = -1032; check(c.g_i32, -1032)
+    c.g_i64 = -1064; check(c.g_i64, i64(-1064))
+    c.g_u8 = 208; check(c.g_u8, 208)
+    c.g_u16 = 2016; check(c.g_u16, 2016)
+    c.g_u32 = 2032; check(c.g_u32, 2032)
+    c.g_u64 = 2064; check(c.g_u64, u64(2064))
+    c.g_f = 13; check(c.g_f, 13)
+    c.g_d = 15; check(c.g_d, 15)
+    if c.have_complex() then
+        c.g_dc = 17+18*i; check(c.g_dc, 17+18*i)
+        c.g_fc = 16+19*i; check(c.g_fc, 16+19*i)
+    end
+    c.g_sp = 'foo'; check(c.g_sp, 'foo')
+    c.g_e8 = c.BAR8; check(c.g_e8, c.BAR8)
+    c.g_e16 = c.BAR16; check(c.g_e16, c.BAR16)
+    c.g_e32 = c.BAR32; check(c.g_e32, c.BAR32)
+    c.g_date.nWeekDay = 3; check(c.g_date.nWeekDay, 3)
+
+    local align_attr = c.is_msvc and [[
+        struct align_attr_ALIGN_SUFFIX {
+            char pad;
+            __declspec(align(ALIGN)) TYPE v;
+        };
+
+        int print_align_attr_ALIGN_SUFFIX(char* buf, struct align_attr_ALIGN_SUFFIX* p);
+        ]] or [[
+        struct align_attr_ALIGN_SUFFIX {
+            char pad;
+            TYPE v __attribute__(aligned(ALIGN));
+        };
+
+        int print_align_attr_ALIGN_SUFFIX(char* buf, struct align_attr_ALIGN_SUFFIX* p);
+        ]]
+
+    for suffix, type in pairs(types) do
+        local test = test_values[type]
+        --print('checkbuf', suffix, type, buf, test)
+        checkbuf(type, c['print_' .. suffix](buf, test), suffix)
+
+        if first then
+            ffi.cdef(align:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', 0))
+        end
+
+        local v = ffi.new('struct align_0_' .. suffix, {0, test})
+        checkalign(type, v, c['print_align_0_' .. suffix](buf, v))
+
+        for _,align in ipairs{1,2,4,8,16} do
+            if align > c.max_alignment() then
+                break
+            end
+
+            if first then
+                ffi.cdef(palign:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', align))
+                ffi.cdef(align_attr:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', align))
+            end
+
+            local v = ffi.new('struct align_' .. align .. '_' .. suffix, {0, test})
+            checkalign(type, v, c['print_align_' .. align .. '_' .. suffix](buf, v))
+
+            -- MSVC doesn't support aligned attributes on enums
+            if not type:match('^enum e[0-9]*$') or not c.is_msvc then
+                local v2 = ffi.new('struct align_attr_' .. align .. '_' .. suffix, {0, test})
+                checkalign(type, v2, c['print_align_attr_' .. align .. '_' .. suffix](buf, v2))
+            end
+        end
+
+        if not c.is_msvc then
+            if first then
+                local h = [[
+                struct align_attr_def_SUFFIX {
+                    char pad;
+                    TYPE v __attribute__(aligned);
+                };
+                int print_align_attr_def_SUFFIX(char* buf, struct align_attr_def_SUFFIX* p);
+                ]]
+                ffi.cdef(h:gsub('SUFFIX', suffix):gsub('TYPE', type))
+            end
+
+            local v = ffi.new('struct align_attr_def_' .. suffix, {0, test})
+            -- print(type)
+            -- print("Align " .. c['print_align_attr_def_' .. suffix](buf, v))
+            -- print(ffi.string(buf))
+            -- checkalign(type, v, c['print_align_attr_def_' .. suffix](buf, v))
+        end
+    end
+
+    local psz = ffi.new('size_t[1]')
+    local palign = ffi.new('size_t[1]')
+    local function check_align(type, test, ret)
+        --print('check_align', type, test, ret, ffi.string(buf), psz[0], palign[0])
+        check(tonumber(palign[0]), ffi.alignof(type))
+        check(tonumber(psz[0]), ffi.sizeof(type))
+        check(ret, #test)
+        check(test, ffi.string(buf))
+    end
+
+    for _, tnum in ipairs{8, 16, 32, 64} do
+        if first then
+            ffi.cdef(bitfields:gsub('TNUM',tnum))
+        end
+
+        check_align('struct bc'..tnum, '1 2', c['print_bc'..tnum](psz, palign, buf, {1,2}))
+        check_align('struct blz'..tnum, '1 2', c['print_blz'..tnum](psz, palign, buf, {1,2}))
+
+        for _, znum in ipairs{8, 16, 32, 64} do
+            for _, bnum in ipairs{7, 15, 31, 63} do
+                if bnum > znum then
+                    break
+                end
+                if first then
+                    ffi.cdef(bitzero:gsub('TNUM',tnum):gsub('ZNUM',znum):gsub('BNUM', bnum))
+                end
+                check_align('struct bz_'..tnum..'_'..znum..'_'..bnum, '1 2 3', c['print_bz_'..tnum..'_'..znum..'_'..bnum](psz, palign, buf, {1,2,3}))
+            end
+        end
+
+        for _, bnum in ipairs{7, 15, 31, 63} do
+            if bnum > tnum then
+                break
+            end
+            if first then
+                ffi.cdef(bitalign:gsub('TNUM',tnum):gsub('BNUM',bnum))
+            end
+            check_align('struct ba_'..tnum..'_'..bnum, '1 2', c['print_ba_'..tnum..'_'..bnum](psz, palign, buf, {1,2}))
+        end
+    end
+
+    check_align('struct Date', '1 2 3 4', c.print_date(psz, palign, buf, {1,2,3,4}))
+    check_align('struct Date2', '1 2 3 4', c.print_date2(psz, palign, buf, {1,2,3,4}))
+    check_align('struct sysv1', '1 2 3', c.print_sysv1(psz, palign, buf, {1,2,3}))
+    check_align('struct sysv2', '1 2 3 4 5 6', c.print_sysv2(psz, palign, buf, {1,2,3,4,5,6}))
+    check_align('struct sysv3', '1 2', c.print_sysv3(psz, palign, buf, {1,2}))
+    check_align('union sysv4', '1', c.print_sysv4(psz, palign, buf, {1}))
+    check_align('struct sysv5', '1 2 3', c.print_sysv5(psz, palign, buf, {1,2,3}))
+    check_align('struct sysv6', '1 2 3', c.print_sysv6(psz, palign, buf, {1,2,3}))
+    check_align('struct sysv7', '1 2 3 4 5', c.print_sysv7(psz, palign, buf, {1,2,3,4,5}))
+
+    local cbs = [[
+    typedef const char* (*__cdecl sfunc)(const char*);
+    int call_i(int (*__cdecl func)(int), int arg);
+    float call_f(float (*__cdecl func)(float), float arg);
+    double call_d(double (*__cdecl func)(double), double arg);
+    const char* call_s(sfunc func, const char* arg);
+    _Bool call_b(_Bool (*__cdecl func)(_Bool), _Bool arg);
+    double complex call_dc(double complex (*__cdecl func)(double complex), double complex arg);
+    float complex call_fc(float complex (*__cdecl func)(float complex), float complex arg);
+    enum e8 call_e8(enum e8 (*__cdecl func)(enum e8), enum e8 arg);
+    enum e16 call_e16(enum e16 (*__cdecl func)(enum e16), enum e16 arg);
+    enum e32 call_e32(enum e32 (*__cdecl func)(enum e32), enum e32 arg);
+    ]]
+
+    ffi.cdef(cbs:gsub('__cdecl', convention))
+
+    local u3 = ffi.new('uint64_t', 3)
+    check(c.call_i(function(a) return 2*a end, 3), 6)
+    assert(math.abs(c.call_d(function(a) return 2*a end, 3.2) - 6.4) < 0.0000000001)
+    assert(math.abs(c.call_f(function(a) return 2*a end, 3.2) - 6.4) < 0.000001)
+    check(ffi.string(c.call_s(function(s) return s + u3 end, 'foobar')), 'bar')
+    check(c.call_b(function(v) return not v end, true), false)
+    check(c.call_e8(function(v) return v + 1 end, c.FOO8), c.BAR8)
+    check(c.call_e16(function(v) return v + 1 end, c.FOO16), c.BAR16)
+    check(c.call_e32(function(v) return v + 1 end, c.FOO32), c.BAR32)
+
+    if c.have_complex() then
+        check(c.call_dc(function(v) return v + 2+3*i end, 4+6*i), 6+9*i)
+        check(c.call_fc(function(v) return v + 1+2*i end, 7+4*i), 8+6*i)
+    end
+
+    local u2 = ffi.new('uint64_t', 2)
+    local cb = ffi.new('sfunc', function(s) return s + u3 end)
+    check(ffi.string(cb('foobar')), 'bar')
+    check(ffi.string(c.call_s(cb, 'foobar')), 'bar')
+    cb:set(function(s) return s + u2 end)
+    check(ffi.string(c.call_s(cb, 'foobar')), 'obar')
+
+    local fp = ffi.new('struct fptr')
+    assert(fp.p == ffi.C.NULL)
+    fp.p = function(a) return 2*a end
+    assert(fp.p ~= ffi.C.NULL)
+    check(c.call_fptr(fp, 4), 8)
+    local suc, err = pcall(function() fp.p:set(function() end) end)
+    assert(not suc)
+    check(err:gsub('^.*: ',''), "can't set the function for a non-lua callback")
+
+    check(c.call_fptr({function(a) return 3*a end}, 5), 15)
+
+    local suc, err = pcall(c.call_s, function(s) error(ffi.string(s), 0) end, 'my error')
+    check(suc, false)
+    check(err, 'my error')
+
+    check(ffi.errno(), c.get_errno())
+    c.set_errno(3)
+    check(ffi.errno(), 3)
+    check(c.get_errno(), 3)
+    check(ffi.errno(4), 3)
+    check(ffi.errno(), 4)
+    check(c.get_errno(), 4)
+
+    local gccattr = {
+        __cdecl = 'int test_pow(int v) __attribute__((cdecl));',
+        __stdcall = 'int test_pow(int v) __attribute__(stdcall);',
+        __fastcall = '__attribute__(fastcall) int test_pow(int v);',
+    }
+
+    ffi.cdef(gccattr[convention])
+    check(c.test_pow(5), 25)
+
+    ffi.cdef [[
+        int va_list_size, va_list_align;
+        int vsnprintf(char* buf, size_t sz, const char* fmt, va_list ap);
+    ]]
+    ffi.new('va_list')
+    assert(ffi.debug().functions.vsnprintf ~= nil)
+    assert(ffi.istype('va_list', ffi.new('__builtin_va_list')))
+    assert(ffi.istype('va_list', ffi.new('__gnuc_va_list')))
+    check(ffi.sizeof('va_list'), c.va_list_size)
+    check(ffi.alignof('va_list'), c.va_list_align)
+
+    first = false
+end
+
+local c = ffi.C
+
+assert(c.sprintf(buf, "%g", 5.3) == 3 and ffi.string(buf) == '5.3')
+assert(c.sprintf(buf, "%d", false) == 1 and ffi.string(buf) == '0')
+assert(c.sprintf(buf, "%d%g", false, 6.7) == 4 and ffi.string(buf) == '06.7')
+
+assert(ffi.sizeof('uint32_t[?]', 32) == 32 * 4)
+assert(ffi.sizeof(ffi.new('uint32_t[?]', 32)) == 32 * 4)
+
+ffi.cdef [[
+struct vls {
+    struct {
+        char a;
+        struct {
+            char b;
+            char v[?];
+        } c;
+    } d;
+};
+struct vls2 {
+    char pad;
+    union {
+        uint8_t a;
+        uint16_t b;
+    };
+};
+]]
+
+assert(ffi.sizeof('struct vls', 3) == 5)
+assert(ffi.sizeof(ffi.new('struct vls', 4).d.c) == 5)
+assert(ffi.offsetof('struct vls2', 'a') == 2)
+assert(ffi.sizeof('struct vls2') == 4)
+
+ffi.cdef [[ static const int DUMMY = 8 << 2; ]]
+assert(ffi.C.DUMMY == 32)
+
+ffi.new('struct {const char* foo;}', {'foo'})
+
+assert(not pcall(function()
+    ffi.new('struct {char* foo;}', {'ff'})
+end))
+
+local mt = {}
+local vls = ffi.new(ffi.metatype('struct vls', mt), 1)
+
+assert(not pcall(function() return vls.key end))
+
+mt.__index = function(vls, key)
+    return function(vls, a, b)
+        return 'in index ' .. key .. ' ' .. vls.d.a .. ' ' .. a .. ' ' .. b
+    end
+end
+
+vls.d.a = 3
+check(vls:key('a', 'b'), 'in index key 3 a b')
+
+assert(not pcall(function() vls.k = 3 end))
+
+mt.__newindex = function(vls, key, val)
+    error('in newindex ' .. key .. ' ' .. vls.d.a .. ' ' .. val, 0)
+end
+
+vls.d.a = 4
+local suc, err = pcall(function() vls.key = 'val' end)
+assert(not suc)
+check(err, 'in newindex key 4 val')
+
+mt.__add = function(vls, a) return vls.d.a + a end
+mt.__sub = function(vls, a) return vls.d.a - a end
+mt.__mul = function(vls, a) return vls.d.a * a end
+mt.__div = function(vls, a) return vls.d.a / a end
+mt.__mod = function(vls, a) return vls.d.a % a end
+mt.__pow = function(vls, a) return vls.d.a ^ a end
+mt.__eq = function(vls, a) return u64(vls.d.a) == a end
+mt.__lt = function(vls, a) return u64(vls.d.a) < a end
+mt.__le = function(vls, a) return u64(vls.d.a) <= a end
+mt.__call = function(vls, a, b) return '__call', vls.d.a .. a .. (b or 'nil')  end
+mt.__unm = function(vls) return -vls.d.a end
+mt.__concat = function(vls, a) return vls.d.a .. a end
+mt.__len = function(vls) return vls.d.a end
+mt.__tostring = function(vls) return 'string ' .. vls.d.a end
+
+vls.d.a = 5
+check(vls + 5, 10)
+check(vls - 5, 0)
+check(vls * 5, 25)
+check(vls / 5, 1)
+check(vls % 3, 2)
+check(vls ^ 3, 125)
+check(vls == u64(4), false)
+check(vls == u64(5), true)
+check(vls == u64(6), false)
+check(vls < u64(4), false)
+check(vls < u64(5), false)
+check(vls < u64(6), true)
+check(vls <= u64(4), false)
+check(vls <= u64(5), true)
+check(vls <= u64(6), true)
+check(-vls, -5)
+local a,b = vls('6')
+check(a, '__call')
+check(b, '56nil')
+check(tostring(vls), 'string 5')
+
+if _VERSION ~= 'Lua 5.1' then
+    check(vls .. 'str', '5str')
+    check(#vls, 5)
+end
+
+check(tostring(1.1+3.2*i), '1.1+3.2i')
+check((1+3*i)*(2+4*i), -10+10*i)
+check((3+2*i)*(3-2*i), 13+0*i)
+
+-- Should ignore unknown attributes
+ffi.cdef [[
+typedef int ALenum;
+__attribute__((dllimport)) void __attribute__((__cdecl__)) alEnable( ALenum capability );
+]]
+
+check(ffi.sizeof('struct {char foo[alignof(uint64_t)];}'), ffi.alignof('uint64_t'))
+
+-- Check native number type for int64_t/uint64_t function args/returns in Lua 5.3
+if _VERSION == "Lua 5.3" then
+    local native_7F = 0x7FFFFFFFFFFFFFFF
+    local cdata_long_7F =  ffi.new("int64_t",  0x7FFFFFFFFFFFFFFF)
+    local cdata_ulong_7F = ffi.new("uint64_t", 0x7FFFFFFFFFFFFFFF)
+
+    local native_80 = 0x8000000000000000
+
+    for _, func in ipairs{ffi.C.add_i64, ffi.C.add_u64} do
+        -- 0x7FFFFFFFFFFFFFFF (native)         + 1 == 0x8000000000000000 (native)
+        local res = func(native_7F, 1)
+        assert(type(res) == "number", "native_7F: returned value not a number")
+        assert(res == native_80, "native_7F: math error")
+
+        -- 0x7FFFFFFFFFFFFFFF (cdata int64_t)  + 1 == 0x8000000000000000 (native)
+        local res = func(cdata_long_7F, 1)
+        assert(type(res) == "number", "cdata_long_7F: returned value not a number")
+        assert(res == native_80, "cdata_long_7F: math error")
+
+        -- 0x7FFFFFFFFFFFFFFF (cdata uint64_t) + 1 == 0x8000000000000000 (native)
+        local res = func(cdata_ulong_7F, 1)
+        assert(type(res) == "number", "cdata_ulong_7F: returned value not a number")
+        assert(res == native_80, "cdata_ulong_7F: math error")
+    end
+end
+
+-- Long double is not supported yet but it should be parsed
+ffi.cdef('long double foo(long double val);')
+check(tostring(ffi.debug().functions.foo):match('ctype(%b<>)'), '<long double (*)(long double)>')
+
+ffi.cdef [[
+typedef int byte1 __attribute__(mode(QI));
+typedef int byte2 __attribute__(mode(HI));
+typedef int byte4 __attribute__(mode(SI));
+typedef int byte8 __attribute__(mode(DI));
+typedef unsigned ubyte8 __attribute__(mode(DI));
+typedef int word __attribute__(mode(word));
+typedef int pointer __attribute__(mode(pointer));
+typedef int byte __attribute__(mode(byte));
+typedef float float4 __attribute__(mode(SF));
+typedef float float8 __attribute__(mode(DF));
+]]
+assert(ffi.istype('int8_t', ffi.new('byte1')))
+assert(ffi.istype('int16_t', ffi.new('byte2')))
+assert(ffi.istype('int32_t', ffi.new('byte4')))
+assert(ffi.istype('int64_t', ffi.new('byte8')))
+assert(ffi.istype('uint64_t', ffi.new('ubyte8')))
+check(ffi.sizeof('void*'), ffi.sizeof('pointer'))
+check(ffi.alignof('void*'), ffi.alignof('pointer'))
+check(ffi.sizeof('void*'), ffi.sizeof('word'))
+check(ffi.alignof('void*'), ffi.alignof('word'))
+assert(ffi.istype('int8_t', ffi.new('byte')))
+assert(ffi.istype('float', ffi.new('float4')))
+assert(ffi.istype('double', ffi.new('float8')))
+
+ffi.cdef('void register_foo(register int val);')
+check(tostring(ffi.debug().functions.register_foo):match('%b<>'), '<void (*)(int)>')
+
+ffi.cdef [[
+    typedef struct __sFILE FILE;
+]]
+
+assert(not ffi.istype('int', ffi.new('int*')))
+assert(not ffi.istype('int[]', ffi.new('int*')))
+assert(not ffi.istype('int[3]', ffi.new('int*')))
+assert(not ffi.istype('int[3]', ffi.new('int[2]')))
+assert(ffi.istype('const int[3]', ffi.new('const int[3]')))
+assert(ffi.istype('int[3]', ffi.new('const int[3]')))
+
+-- Crazy function pointer that takes an int and a function pointer and returns
+-- a function pointer. Type of &signal.
+check(tostring(ffi.typeof('void (*foo(int, void(*)(int)))(int)')):match('%b<>'), '<void (*(*)(int, void (*)(int)))(int)>')
+
+-- Make sure we pass all arguments to tonumber
+check(tonumber('FE', 16), 0xFE)
+
+-- Allow casts from pointer to numeric types
+ffi.cast('long', ffi.C.NULL)
+ffi.cast('int8_t', ffi.C.NULL)
+assert(not pcall(function() ffi.new('long', ffi.C.NULL) end))
+
+-- ffi.new and ffi.cast allow unpacked struct/arrays
+assert(ffi.new('int[3]', 1)[0] == 1)
+assert(ffi.new('int[3]', {1})[0] == 1)
+assert(ffi.new('int[3]', 1, 2)[1] == 2)
+assert(ffi.new('int[3]', {1, 2})[1] == 2)
+
+ffi.cdef[[
+struct var {
+    char ch[?];
+};
+]]
+local d = ffi.new('char[4]')
+local v = ffi.cast('struct var*', d)
+v.ch = {1,2,3,4}
+assert(v.ch[3] == 4)
+v.ch = "bar"
+assert(v.ch[3] == 0)
+assert(v.ch[2] == string.byte('r'))
+assert(d[1] == string.byte('a'))
+
+ffi.cast('char*', 1)
+
+-- 2 arg form of ffi.copy
+ffi.copy(d, 'bar')
+
+-- unsigned should be ignored for pointer rules
+ffi.cdef[[
+int strncmp(const signed char *s1, const unsigned char *s2, size_t n);
+]]
+assert(ffi.C.strncmp("two", "three", 3) ~= 0)
+
+ffi.fill(d, 3, 1)
+assert(d[2] == 1)
+ffi.fill(d, 3)
+assert(d[2] == 0)
+
+-- tests for __new
+ffi.cdef[[
+struct newtest {
+    int a;
+    int b;
+    int c;
+};
+]]
+
+local tp = ffi.metatype("struct newtest", {__new =
+  function(tp, x, y, z)
+    tp = ffi.new(tp)
+    tp.a, tp.b, tp.c = x, y, z
+    return tp
+  end})
+local v = tp(1, 2, 3)
+assert(v.a == 1 and v.b == 2 and v.c == 3)
+
+local tp = ffi.metatype("struct newtest", {__new =
+  function(tp, x, y, z)
+    tp = ffi.new(tp, {a = x, b = y, c = z})
+    return tp
+  end})
+local v = tp(1, 2, 3)
+assert(v.a == 1 and v.b == 2 and v.c == 3)
+
+-- tests for __pairs and __ipairs; not iterating just testing what is returned
+local tp = ffi.metatype("struct newtest",
+  {__pairs = function(tp) return tp.a, tp.b end, __ipairs = function(tp) return tp.b, tp.c end}
+)
+if _VERSION ~= 'Lua 5.1' then
+    local v = tp(1, 2, 3)
+    x, y = pairs(v)
+    assert(x == 1 and y == 2)
+    x, y = ipairs(v)
+    assert(x == 2 and y == 3)
+end
+
+-- test for pointer to struct having same metamethods
+local st = ffi.cdef "struct ptest {int a, b;};"
+local tp = ffi.metatype("struct ptest", {__index = function(s, k) return k end, __len = function(s) return 3 end})
+
+local a = tp(1, 2)
+assert(a.banana == "banana")
+assert(#a == 3)
+local b = ffi.new("int[2]")
+local c = ffi.cast("struct ptest *", b)
+assert(c.banana == "banana") -- should have same methods
+assert(#c == 3)
+
+
+ffi.cdef [[
+char buf[512];
+void test_call_echo(const char* c);
+void test_call_pppppii(void* a, void* b, void* c, void* d, void* e, int f, int g);
+void test_call_pppppiiiiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, int i4, int i5, int i6);
+void test_call_pppppffffff(void* p1, void* p2, void* p3, void* p4, void* p5, float f1, float f2, float f3, float f4, float f5, float f6);
+void test_call_pppppiifiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, float f3, int i4, int i5, int i6);
+void test_call_pppppiiifii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, float i4, int i5, int i6);
+]]
+
+ffi.C.test_call_echo("input")
+assert(ffi.C.buf == "input")
+
+local function ptr(x) return ffi.new('void*', x) end
+
+ffi.C.test_call_pppppii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7)
+assert(ffi.C.buf == "0x1 0x2 0x3 0x4 0x5 6 7")
+
+ffi.C.test_call_pppppiiiiii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8, 9, 10, 11)
+assert(ffi.C.buf == "0x1 0x2 0x3 0x4 0x5 6 7 8 9 10 11")
+
+ffi.C.test_call_pppppffffff(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6.5, 7.5, 8.5, 9.5, 10.5, 11.5)
+assert(ffi.C.buf == "0x1 0x2 0x3 0x4 0x5 6.5 7.5 8.5 9.5 10.5 11.5")
+
+ffi.C.test_call_pppppiifiii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8.5, 9, 10, 11)
+assert(ffi.C.buf == "0x1 0x2 0x3 0x4 0x5 6 7 8.5 9 10 11")
+
+ffi.C.test_call_pppppiiifii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8, 9.5, 10, 11)
+assert(ffi.C.buf == "0x1 0x2 0x3 0x4 0x5 6 7 8 9.5 10 11")
+
+local sum = ffi.C.add_dc(ffi.new('complex', 1, 2), ffi.new('complex', 3, 5))
+assert(ffi.istype('complex', sum))
+
+sum = ffi.C.add_fc(ffi.new('complex float', 1, 2), ffi.new('complex float', 3, 5))
+assert(ffi.istype('complex float', sum))
+
+ffi.cdef [[
+struct Arrays {
+    int ints[3];
+    unsigned int uints[3];
+};
+struct ArrayOfArrays {
+    struct Arrays arrays[3];
+};
+]]
+
+local struct = ffi.new('struct Arrays')
+local structOfStructs = ffi.new('struct ArrayOfArrays')
+for i=0,2 do
+    struct.ints[i] = i
+    struct.uints[i] = i
+    structOfStructs.arrays[0].ints[i] = i
+end
+for i=0,2 do
+    assert(struct.ints[i] == i)
+    assert(struct.uints[i] == i)
+    assert(structOfStructs.arrays[0].ints[i] == i)
+end
+
+-- Test ffi.string
+local buf = ffi.new('char[5]')
+ffi.fill(buf, 4, 97)
+buf[4] = 0
+
+assert(ffi.string(buf) == 'aaaa')
+assert(ffi.string(buf, 4) == 'aaaa')
+assert(ffi.string(buf, 2) == 'aa')
+assert(ffi.string(buf, 0) == '')
+assert(ffi.string(buf, ffi.new('long long', 2)) == 'aa')
+assert(ffi.string(buf, ffi.new('int', 2)) == 'aa')
+
+-- Test io.tmpfile()
+ffi.cdef [[
+    int fprintf ( FILE * stream, const char * format, ... );
+]]
+local f = io.tmpfile()
+ffi.C.fprintf(f, "test: %s\n", "foo")
+
+f:seek("set", 0)
+local str = f:read('*l')
+assert(str == 'test: foo', str)
+f:close()
+
+print('Test PASSED')

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/commands.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/commands.w	2017-02-09 19:02:30 UTC (rev 43176)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/commands.w	2017-02-09 22:44:03 UTC (rev 43177)
@@ -1,878 +1,879 @@
-% commands.w
-%
-% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-\def\eTeX{e-\TeX}
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ The symbolic names for glue parameters are put into \TeX's hash table
-by using the routine called |primitive|, defined below. Let us enter them
-now, so that we don't have to list all those parameter names anywhere else.
-
- at c
-void initialize_commands(void)
-{
-
-    primitive_tex("lineskip", assign_glue_cmd, glue_base + line_skip_code, glue_base);
-    primitive_tex("baselineskip", assign_glue_cmd, glue_base + baseline_skip_code, glue_base);
-    primitive_tex("parskip", assign_glue_cmd, glue_base + par_skip_code, glue_base);
-    primitive_tex("abovedisplayskip", assign_glue_cmd, glue_base + above_display_skip_code, glue_base);
-    primitive_tex("belowdisplayskip", assign_glue_cmd, glue_base + below_display_skip_code, glue_base);
-    primitive_tex("abovedisplayshortskip", assign_glue_cmd, glue_base + above_display_short_skip_code, glue_base);
-    primitive_tex("belowdisplayshortskip", assign_glue_cmd, glue_base + below_display_short_skip_code, glue_base);
-    primitive_tex("leftskip", assign_glue_cmd, glue_base + left_skip_code, glue_base);
-    primitive_tex("rightskip", assign_glue_cmd, glue_base + right_skip_code, glue_base);
-    primitive_tex("topskip", assign_glue_cmd, glue_base + top_skip_code, glue_base);
-    primitive_tex("splittopskip", assign_glue_cmd, glue_base + split_top_skip_code, glue_base);
-    primitive_tex("tabskip", assign_glue_cmd, glue_base + tab_skip_code, glue_base);
-    primitive_tex("spaceskip", assign_glue_cmd, glue_base + space_skip_code, glue_base);
-    primitive_tex("xspaceskip", assign_glue_cmd, glue_base + xspace_skip_code, glue_base);
-    primitive_tex("parfillskip", assign_glue_cmd, glue_base + par_fill_skip_code, glue_base);
-    primitive_tex("thinmuskip", assign_mu_glue_cmd, glue_base + thin_mu_skip_code, glue_base + thin_mu_skip_code);
-    primitive_tex("medmuskip", assign_mu_glue_cmd, glue_base + med_mu_skip_code, glue_base + thin_mu_skip_code);
-    primitive_tex("thickmuskip", assign_mu_glue_cmd, glue_base + thick_mu_skip_code, glue_base + thin_mu_skip_code);
-    primitive_luatex("mathsurroundskip", assign_glue_cmd, glue_base + math_skip_code, glue_base);
-    primitive_luatex("mathsurroundmode", assign_int_cmd, int_base + math_skip_mode_code, int_base);
-    primitive_tex("output", assign_toks_cmd, output_routine_loc, local_base);
-    primitive_tex("everypar", assign_toks_cmd, every_par_loc, local_base);
-    primitive_tex("everymath", assign_toks_cmd, every_math_loc, local_base);
-    primitive_tex("everydisplay", assign_toks_cmd, every_display_loc, local_base);
-    primitive_tex("everyhbox", assign_toks_cmd, every_hbox_loc, local_base);
-    primitive_tex("everyvbox", assign_toks_cmd, every_vbox_loc, local_base);
-    primitive_tex("everyjob", assign_toks_cmd, every_job_loc, local_base);
-    primitive_tex("everycr", assign_toks_cmd, every_cr_loc, local_base);
-    primitive_tex("errhelp", assign_toks_cmd, err_help_loc, local_base);
-
-    /* The integer parameter names must be entered into the hash table */
-
-    primitive_tex("pretolerance", assign_int_cmd, int_base + pretolerance_code, int_base);
-    primitive_tex("tolerance", assign_int_cmd, int_base + tolerance_code, int_base);
-    primitive_tex("linepenalty", assign_int_cmd, int_base + line_penalty_code, int_base);
-    primitive_tex("hyphenpenalty", assign_int_cmd, int_base + hyphen_penalty_code, int_base);
-    primitive_tex("exhyphenpenalty", assign_int_cmd, int_base + ex_hyphen_penalty_code, int_base);
-    primitive_tex("clubpenalty", assign_int_cmd, int_base + club_penalty_code, int_base);
-    primitive_tex("widowpenalty", assign_int_cmd, int_base + widow_penalty_code, int_base);
-    primitive_tex("displaywidowpenalty", assign_int_cmd, int_base + display_widow_penalty_code, int_base);
-    primitive_tex("brokenpenalty", assign_int_cmd, int_base + broken_penalty_code, int_base);
-    primitive_tex("binoppenalty", assign_int_cmd, int_base + bin_op_penalty_code, int_base);
-    primitive_tex("relpenalty", assign_int_cmd, int_base + rel_penalty_code, int_base);
-    primitive_tex("predisplaypenalty", assign_int_cmd, int_base + pre_display_penalty_code, int_base);
-    primitive_tex("postdisplaypenalty", assign_int_cmd, int_base + post_display_penalty_code, int_base);
-    primitive_tex("interlinepenalty", assign_int_cmd, int_base + inter_line_penalty_code, int_base);
-    primitive_tex("doublehyphendemerits", assign_int_cmd, int_base + double_hyphen_demerits_code, int_base);
-    primitive_tex("finalhyphendemerits", assign_int_cmd, int_base + final_hyphen_demerits_code, int_base);
-    primitive_tex("adjdemerits", assign_int_cmd, int_base + adj_demerits_code, int_base);
-    primitive_tex("mag", assign_int_cmd, int_base + mag_code, int_base);
-    primitive_tex("delimiterfactor", assign_int_cmd, int_base + delimiter_factor_code, int_base);
-    primitive_tex("looseness", assign_int_cmd, int_base + looseness_code, int_base);
-    primitive_tex("time", assign_int_cmd, int_base + time_code, int_base);
-    primitive_tex("day", assign_int_cmd, int_base + day_code, int_base);
-    primitive_tex("month", assign_int_cmd, int_base + month_code, int_base);
-    primitive_tex("year", assign_int_cmd, int_base + year_code, int_base);
-    primitive_tex("showboxbreadth", assign_int_cmd, int_base + show_box_breadth_code, int_base);
-    primitive_tex("showboxdepth", assign_int_cmd, int_base + show_box_depth_code, int_base);
-    primitive_tex("hbadness", assign_int_cmd, int_base + hbadness_code, int_base);
-    primitive_tex("vbadness", assign_int_cmd, int_base + vbadness_code, int_base);
-    primitive_tex("pausing", assign_int_cmd, int_base + pausing_code, int_base);
-    primitive_tex("tracingonline", assign_int_cmd, int_base + tracing_online_code, int_base);
-    primitive_tex("tracingmacros", assign_int_cmd, int_base + tracing_macros_code, int_base);
-    primitive_tex("tracingstats", assign_int_cmd, int_base + tracing_stats_code, int_base);
-    primitive_tex("tracingparagraphs", assign_int_cmd, int_base + tracing_paragraphs_code, int_base);
-    primitive_tex("tracingpages", assign_int_cmd, int_base + tracing_pages_code, int_base);
-    primitive_tex("tracingoutput", assign_int_cmd, int_base + tracing_output_code, int_base);
-    primitive_tex("tracinglostchars", assign_int_cmd, int_base + tracing_lost_chars_code, int_base);
-    primitive_tex("tracingcommands", assign_int_cmd, int_base + tracing_commands_code, int_base);
-    primitive_tex("tracingrestores", assign_int_cmd, int_base + tracing_restores_code, int_base);
-    primitive_tex("uchyph", assign_int_cmd, int_base + uc_hyph_code, int_base);
-    primitive_tex("outputpenalty", assign_int_cmd, int_base + output_penalty_code, int_base);
-    primitive_tex("maxdeadcycles", assign_int_cmd, int_base + max_dead_cycles_code, int_base);
-    primitive_tex("hangafter", assign_int_cmd, int_base + hang_after_code, int_base);
-    primitive_tex("floatingpenalty", assign_int_cmd, int_base + floating_penalty_code, int_base);
-    primitive_tex("globaldefs", assign_int_cmd, int_base + global_defs_code, int_base);
-    primitive_tex("fam", assign_int_cmd, int_base + cur_fam_code, int_base);
-    primitive_tex("escapechar", assign_int_cmd, int_base + escape_char_code, int_base);
-    primitive_tex("defaulthyphenchar", assign_int_cmd, int_base + default_hyphen_char_code, int_base);
-    primitive_tex("defaultskewchar", assign_int_cmd, int_base + default_skew_char_code, int_base);
-    primitive_tex("endlinechar", assign_int_cmd, int_base + end_line_char_code, int_base);
-    primitive_tex("newlinechar", assign_int_cmd, int_base + new_line_char_code, int_base);
-    primitive_tex("language", assign_int_cmd, int_base + language_code, int_base);
-    primitive_tex("setlanguage", assign_int_cmd, int_base + cur_lang_code, int_base);
-    primitive_tex("firstvalidlanguage", assign_int_cmd, int_base + first_valid_language_code, int_base);
-    primitive_tex("exhyphenchar", assign_int_cmd, int_base + ex_hyphen_char_code, int_base);
-    primitive_tex("lefthyphenmin", assign_int_cmd, int_base + left_hyphen_min_code, int_base);
-    primitive_tex("righthyphenmin", assign_int_cmd, int_base + right_hyphen_min_code, int_base);
-    primitive_tex("holdinginserts", assign_int_cmd, int_base + holding_inserts_code, int_base);
-    primitive_tex("errorcontextlines", assign_int_cmd, int_base + error_context_lines_code, int_base);
-    primitive_luatex("nokerns", assign_int_cmd, int_base + disable_kern_code, int_base);
-    primitive_luatex("noligs", assign_int_cmd, int_base + disable_lig_code, int_base);
-    primitive_luatex("nospaces", assign_int_cmd, int_base + disable_space_code, int_base);
-    primitive_luatex("catcodetable", assign_int_cmd, int_base + cat_code_table_code, int_base);
-    primitive_luatex("outputbox", assign_int_cmd, int_base + output_box_code, int_base);
-    primitive_luatex("outputmode", assign_int_cmd, int_base + output_mode_code, int_base);
-    primitive_luatex("adjustspacing", assign_int_cmd, int_base + adjust_spacing_code, int_base);
-    primitive_luatex("protrudechars", assign_int_cmd, int_base + protrude_chars_code, int_base);
-    primitive_luatex("tracingfonts", assign_int_cmd, int_base + tracing_fonts_code, int_base);
-    primitive_luatex("draftmode", assign_int_cmd, int_base + draft_mode_code, int_base);
-    primitive_tex("parindent", assign_dimen_cmd, dimen_base + par_indent_code, dimen_base);
-    primitive_tex("mathsurround", assign_dimen_cmd, dimen_base + math_surround_code, dimen_base);
-    primitive_tex("lineskiplimit", assign_dimen_cmd, dimen_base + line_skip_limit_code, dimen_base);
-    primitive_tex("hsize", assign_dimen_cmd, dimen_base + hsize_code, dimen_base);
-    primitive_tex("vsize", assign_dimen_cmd, dimen_base + vsize_code, dimen_base);
-    primitive_tex("maxdepth", assign_dimen_cmd, dimen_base + max_depth_code, dimen_base);
-    primitive_tex("splitmaxdepth", assign_dimen_cmd, dimen_base + split_max_depth_code, dimen_base);
-    primitive_tex("boxmaxdepth", assign_dimen_cmd, dimen_base + box_max_depth_code, dimen_base);
-    primitive_tex("hfuzz", assign_dimen_cmd, dimen_base + hfuzz_code, dimen_base);
-    primitive_tex("vfuzz", assign_dimen_cmd, dimen_base + vfuzz_code, dimen_base);
-    primitive_tex("delimitershortfall", assign_dimen_cmd, dimen_base + delimiter_shortfall_code, dimen_base);
-    primitive_tex("nulldelimiterspace", assign_dimen_cmd, dimen_base + null_delimiter_space_code, dimen_base);
-    primitive_tex("scriptspace", assign_dimen_cmd, dimen_base + script_space_code, dimen_base);
-    primitive_tex("predisplaysize", assign_dimen_cmd, dimen_base + pre_display_size_code, dimen_base);
-    primitive_tex("displaywidth", assign_dimen_cmd, dimen_base + display_width_code, dimen_base);
-    primitive_tex("displayindent", assign_dimen_cmd, dimen_base + display_indent_code, dimen_base);
-    primitive_tex("overfullrule", assign_dimen_cmd, dimen_base + overfull_rule_code, dimen_base);
-    primitive_tex("hangindent", assign_dimen_cmd, dimen_base + hang_indent_code, dimen_base);
-    primitive_tex("hoffset", assign_dimen_cmd, dimen_base + h_offset_code, dimen_base);
-    primitive_tex("voffset", assign_dimen_cmd, dimen_base + v_offset_code, dimen_base);
-    primitive_tex("emergencystretch", assign_dimen_cmd, dimen_base + emergency_stretch_code, dimen_base);
-    primitive_luatex("pagewidth", assign_dimen_cmd, dimen_base + page_width_code, dimen_base);
-    primitive_luatex("pageheight", assign_dimen_cmd, dimen_base + page_height_code, dimen_base);
-    primitive_luatex("pxdimen", assign_dimen_cmd, dimen_base + px_dimen_code, dimen_base);
-
-    /* Many of \TeX's primitives need no |equiv|, since they are identifiable
-       by their |eq_type| alone. These primitives are loaded into the hash table
-       as follows: */
-
-    primitive_tex(" ", ex_space_cmd, 0, 0);
-    primitive_tex("/", ital_corr_cmd, 0, 0);
-    primitive_tex("accent", accent_cmd, 0, 0);
-    primitive_tex("advance", advance_cmd, 0, 0);
-    primitive_tex("afterassignment", after_assignment_cmd, 0, 0);
-    primitive_tex("aftergroup", after_group_cmd, 0, 0);
-    primitive_tex("begingroup", begin_group_cmd, 0, 0);
-    primitive_tex("char", char_num_cmd, 0, 0);
-    primitive_tex("csname", cs_name_cmd, 0, 0);
-    primitive_luatex("lastnamedcs", cs_name_cmd, 1, 0);
-    primitive_luatex("begincsname", cs_name_cmd, 2, 0);
-    primitive_tex("delimiter", delim_num_cmd, 0, 0);
-    primitive_luatex("Udelimiter", delim_num_cmd, 1, 0);
-    primitive_tex("divide", divide_cmd, 0, 0);
-    primitive_tex("endcsname", end_cs_name_cmd, 0, 0);
-    primitive_tex("endgroup", end_group_cmd, 0, 0);
-    cs_text(frozen_end_group) = maketexstring("endgroup");
-    eqtb[frozen_end_group] = eqtb[cur_val];
-    primitive_tex("expandafter", expand_after_cmd, 0, 0);
-    primitive_tex("font", def_font_cmd, 0, 0);
-    primitive_luatex("letterspacefont", letterspace_font_cmd, 0, 0);
-    primitive_luatex("expandglyphsinfont", normal_cmd, expand_font_code, 0);
-    primitive_luatex("copyfont", copy_font_cmd, 0, 0);
-    primitive_luatex("setfontid", set_font_id_cmd, 0, 0);
-    primitive_tex("fontdimen", assign_font_dimen_cmd, 0, 0);
-    primitive_tex("halign", halign_cmd, 0, 0);
-    primitive_tex("hrule", hrule_cmd, 0, 0);
-    primitive_luatex("nohrule", no_hrule_cmd, 0, 0);
-    primitive_tex("ignorespaces", ignore_spaces_cmd, 0, 0);
-    primitive_tex("insert", insert_cmd, 0, 0);
-    primitive_luatex("leftghost", char_ghost_cmd, 0, 0);
-    primitive_tex("mark", mark_cmd, 0, 0);
-    primitive_tex("mathaccent", math_accent_cmd, 0, 0);
-    primitive_luatex("Umathaccent", math_accent_cmd, 1, 0);
-    primitive_tex("mathchar", math_char_num_cmd, 0, 0);
-    primitive_luatex("Umathchar", math_char_num_cmd, 1, 0);
-    primitive_luatex("Umathcharnum", math_char_num_cmd, 2, 0);
-    primitive_tex("mathchoice", math_choice_cmd, 0, 0);
-    primitive_luatex("Ustack", math_choice_cmd, 1, 0);
-    primitive_tex("multiply", multiply_cmd, 0, 0);
-    primitive_tex("noalign", no_align_cmd, 0, 0);
-    primitive_tex("noboundary", boundary_cmd, 0, 0);
-    primitive_tex("boundary", boundary_cmd, 1, 0);
-    primitive_tex("protrusionboundary", boundary_cmd, 2, 0);
-    primitive_tex("wordboundary", boundary_cmd, 3, 0);
-    primitive_tex("noexpand", no_expand_cmd, 0, 0);
-    primitive_luatex("primitive", no_expand_cmd, 1, 0);
-    primitive_tex("nonscript", non_script_cmd, 0, 0);
-    primitive_tex("omit", omit_cmd, 0, 0);
-    primitive_tex("parshape", set_tex_shape_cmd, par_shape_loc, par_shape_loc);
-    primitive_tex("penalty", break_penalty_cmd, 0, 0);
-    primitive_tex("prevgraf", set_prev_graf_cmd, 0, 0);
-    primitive_tex("radical", radical_cmd, 0, 0);
-    primitive_luatex("Uradical", radical_cmd, 1, 0);
-    primitive_luatex("Uroot", radical_cmd, 2, 0);
-    primitive_luatex("Uunderdelimiter", radical_cmd, 3, 0);
-    primitive_luatex("Uoverdelimiter", radical_cmd, 4, 0);
-    primitive_luatex("Udelimiterunder", radical_cmd, 5, 0);
-    primitive_luatex("Udelimiterover", radical_cmd, 6, 0);
-    primitive_luatex("Uhextensible", radical_cmd, 7, 0);
-    primitive_tex("read", read_to_cs_cmd, 0, 0);
-    primitive_tex("relax", relax_cmd, too_big_char, too_big_char);
-    cs_text(frozen_relax) = maketexstring("relax");
-    eqtb[frozen_relax] = eqtb[cur_val];
-    primitive_luatex("rightghost", char_ghost_cmd, 1, 0);
-    primitive_tex("setbox", set_box_cmd, 0, 0);
-    primitive_tex("the", the_cmd, 0, 0);
-    primitive_luatex("toksapp", combine_toks_cmd, 0, 0);
-    primitive_luatex("tokspre", combine_toks_cmd, 1, 0);
-    primitive_luatex("etoksapp", combine_toks_cmd, 2, 0);
-    primitive_luatex("etokspre", combine_toks_cmd, 3, 0);
-    primitive_tex("toks", toks_register_cmd, 0, 0);
-    primitive_tex("vadjust", vadjust_cmd, 0, 0);
-    primitive_tex("valign", valign_cmd, 0, 0);
-    primitive_tex("vcenter", vcenter_cmd, 0, 0);
-    primitive_tex("vrule", vrule_cmd, 0, 0);
-    primitive_luatex("novrule", no_vrule_cmd, 0, 0);
-    primitive_tex("par", par_end_cmd, too_big_char, too_big_char);      /* cf.\ |scan_file_name| */
-    par_loc = cur_val;
-    par_token = cs_token_flag + par_loc;
-    @<Create a bunch of primitives@>;
-    @<Create the math param primitives@>;
-    @<Create another bunch of primitives@>;
-}
-
-
-@ These are in a separate module due to a CWEAVE limitation.
-
-@<Create a bunch of primitives@>=
-
-    /*
-        The processing of \.{\\input} involves the |start_input| subroutine,
-        which will be declared later; the processing of \.{\\endinput} is trivial.
-    */
-
-    primitive_tex("input", input_cmd, 0, 0);
-    primitive_tex("endinput", input_cmd, 1, 0);
-    primitive_tex("topmark", top_bot_mark_cmd, top_mark_code, 0);
-    primitive_tex("firstmark", top_bot_mark_cmd, first_mark_code, 0);
-    primitive_tex("botmark", top_bot_mark_cmd, bot_mark_code, 0);
-    primitive_tex("splitfirstmark", top_bot_mark_cmd, split_first_mark_code, 0);
-    primitive_tex("splitbotmark", top_bot_mark_cmd, split_bot_mark_code, 0);
-    primitive_luatex("clearmarks", mark_cmd, clear_marks_code, 0);
-    primitive_etex("marks", mark_cmd, marks_code, 0);
-    primitive_etex("topmarks", top_bot_mark_cmd, top_mark_code + marks_code, 0);
-    primitive_etex("firstmarks", top_bot_mark_cmd, first_mark_code + marks_code, 0);
-    primitive_etex("botmarks", top_bot_mark_cmd, bot_mark_code + marks_code, 0);
-    primitive_etex("splitfirstmarks", top_bot_mark_cmd, split_first_mark_code + marks_code, 0);
-    primitive_etex("splitbotmarks", top_bot_mark_cmd, split_bot_mark_code + marks_code, 0);
-
-    /*
-        The hash table is initialized with `\.{\\count}', `\.{\\attribute}',
-        `\.{\\dimen}', `\.{\\skip}', and `\.{\\muskip}' all having |register|
-        as their command code; they are distinguished by the |chr_code|, which
-        is either |int_val|, |attr_val|, |dimen_val|, |glue_val|, or |mu_val|.
-    */
-
-    primitive_tex("count", register_cmd, int_val_level, 0);
-    primitive_luatex("attribute", register_cmd, attr_val_level, 0);
-    primitive_tex("dimen", register_cmd, dimen_val_level, 0);
-    primitive_tex("skip", register_cmd, glue_val_level, 0);
-    primitive_tex("muskip", register_cmd, mu_val_level, 0);
-
-    primitive_tex("spacefactor", set_aux_cmd, hmode, 0);
-    primitive_tex("prevdepth", set_aux_cmd, vmode, 0);
-    primitive_tex("deadcycles", set_page_int_cmd, 0, 0);
-    primitive_tex("insertpenalties", set_page_int_cmd, 1, 0);
-    primitive_tex("wd", set_box_dimen_cmd, width_offset, 0);
-    primitive_tex("ht", set_box_dimen_cmd, height_offset, 0);
-    primitive_tex("dp", set_box_dimen_cmd, depth_offset, 0);
-    primitive_tex("lastpenalty", last_item_cmd, lastpenalty_code, 0);
-    primitive_tex("lastkern", last_item_cmd, lastkern_code, 0);
-    primitive_tex("lastskip", last_item_cmd, lastskip_code, 0);
-    primitive_tex("inputlineno", last_item_cmd, input_line_no_code, 0);
-    primitive_tex("badness", last_item_cmd, badness_code, 0);
-    primitive_luatex("luatexversion", last_item_cmd, luatex_version_code, 0);
-    primitive_luatex("lastsavedboxresourceindex", last_item_cmd, last_saved_box_resource_index_code, 0);
-    primitive_luatex("lastsavedimageresourceindex", last_item_cmd, last_saved_image_resource_index_code, 0);
-    primitive_luatex("lastsavedimageresourcepages", last_item_cmd, last_saved_image_resource_pages_code, 0);
-    primitive_luatex("lastxpos", last_item_cmd, last_x_pos_code, 0);
-    primitive_luatex("lastypos", last_item_cmd, last_y_pos_code, 0);
-    primitive_luatex("randomseed", last_item_cmd, random_seed_code, 0);
-
-    primitive_tex("number", convert_cmd, number_code, 0);
-    primitive_tex("romannumeral", convert_cmd, roman_numeral_code, 0);
-    primitive_tex("string", convert_cmd, string_code, 0);
-    primitive_tex("csstring", convert_cmd, cs_string_code, 0);
-    primitive_tex("meaning", convert_cmd, meaning_code, 0);
-    primitive_etex("eTeXVersion", convert_cmd, etex_code, 0);
-    primitive_tex("fontname", convert_cmd, font_name_code, 0);
-    primitive_luatex("fontid", convert_cmd, font_id_code, 0);
-    primitive_luatex("luatexrevision", convert_cmd, luatex_revision_code, 0);
-    primitive_luatex("luatexdatestamp", convert_cmd, luatex_date_code, 0);
-    primitive_luatex("luatexbanner", convert_cmd, luatex_banner_code, 0);
-    primitive_luatex("leftmarginkern", convert_cmd, left_margin_kern_code, 0);
-    primitive_luatex("rightmarginkern", convert_cmd, right_margin_kern_code, 0);
-    primitive_luatex("uniformdeviate", convert_cmd, uniform_deviate_code, 0);
-    primitive_luatex("normaldeviate", convert_cmd, normal_deviate_code, 0);
-    primitive_core("directlua", convert_cmd, lua_code, 0);
-    primitive_luatex("luafunction", convert_cmd, lua_function_code, 0);
-    primitive_luatex("luaescapestring", convert_cmd, lua_escape_string_code, 0);
-    primitive_luatex("mathstyle", convert_cmd, math_style_code, 0);
-    primitive_luatex("expanded", convert_cmd, expanded_code, 0);
-    primitive_tex("jobname", convert_cmd, job_name_code, 0);
-    primitive_luatex("formatname", convert_cmd, format_name_code, 0);
-    primitive_luatex("Uchar", convert_cmd, uchar_code, 0);
-
-    primitive_luatex("Umathcharclass", convert_cmd, math_char_class_code, 0);
-    primitive_luatex("Umathcharfam", convert_cmd, math_char_fam_code, 0);
-    primitive_luatex("Umathcharslot", convert_cmd, math_char_slot_code, 0);
-
-    primitive_tex("if", if_test_cmd, if_char_code, 0);
-    primitive_tex("ifcat", if_test_cmd, if_cat_code, 0);
-    primitive_tex("ifnum", if_test_cmd, if_int_code, 0);
-    primitive_tex("ifdim", if_test_cmd, if_dim_code, 0);
-    primitive_tex("ifodd", if_test_cmd, if_odd_code, 0);
-    primitive_tex("ifvmode", if_test_cmd, if_vmode_code, 0);
-    primitive_tex("ifhmode", if_test_cmd, if_hmode_code, 0);
-    primitive_tex("ifmmode", if_test_cmd, if_mmode_code, 0);
-    primitive_tex("ifinner", if_test_cmd, if_inner_code, 0);
-    primitive_tex("ifvoid", if_test_cmd, if_void_code, 0);
-
-    primitive_tex("ifhbox", if_test_cmd, if_hbox_code, 0);
-    primitive_tex("ifvbox", if_test_cmd, if_vbox_code, 0);
-    primitive_tex("ifx", if_test_cmd, ifx_code, 0);
-    primitive_tex("ifeof", if_test_cmd, if_eof_code, 0);
-    primitive_tex("iftrue", if_test_cmd, if_true_code, 0);
-    primitive_tex("iffalse", if_test_cmd, if_false_code, 0);
-    primitive_tex("ifcase", if_test_cmd, if_case_code, 0);
-    primitive_luatex("ifprimitive", if_test_cmd, if_primitive_code, 0);
-    primitive_tex("fi", fi_or_else_cmd, fi_code, 0);
-    cs_text(frozen_fi) = maketexstring("fi");
-    eqtb[frozen_fi] = eqtb[cur_val];
-    primitive_tex("or", fi_or_else_cmd, or_code, 0);
-    primitive_tex("else", fi_or_else_cmd, else_code, 0);
-
-    /*
-        \TeX\ always knows at least one font, namely the null font. It has no
-        characters, and its seven parameters are all equal to zero.
-    */
-
-    primitive_tex("nullfont", set_font_cmd, null_font, 0);
-    cs_text(frozen_null_font) = maketexstring("nullfont");
-    eqtb[frozen_null_font] = eqtb[cur_val];
-
-    primitive_tex("span", tab_mark_cmd, span_code, tab_mark_cmd_code);
-    primitive_luatex("aligntab", tab_mark_cmd, tab_mark_cmd_code, tab_mark_cmd_code);
-    primitive_luatex("alignmark", mac_param_cmd, tab_mark_cmd_code, tab_mark_cmd_code);
-    primitive_tex("cr", car_ret_cmd, cr_code, cr_code);
-    cs_text(frozen_cr) = maketexstring("cr");
-    eqtb[frozen_cr] = eqtb[cur_val];
-    primitive_tex("crcr", car_ret_cmd, cr_cr_code, cr_code);
-    cs_text(frozen_end_template) = maketexstring("endtemplate");
-    cs_text(frozen_endv) = maketexstring("endtemplate");
-    set_eq_type(frozen_endv, endv_cmd);
-    set_equiv(frozen_endv, null_list);
-    set_eq_level(frozen_endv, level_one);
-    eqtb[frozen_end_template] = eqtb[frozen_endv];
-    set_eq_type(frozen_end_template, end_template_cmd);
-
-    primitive_tex("pagegoal", set_page_dimen_cmd, 0, 0);
-    primitive_tex("pagetotal", set_page_dimen_cmd, 1, 0);
-    primitive_tex("pagestretch", set_page_dimen_cmd, 2, 0);
-    primitive_tex("pagefilstretch", set_page_dimen_cmd, 3, 0);
-    primitive_tex("pagefillstretch", set_page_dimen_cmd, 4, 0);
-    primitive_tex("pagefilllstretch", set_page_dimen_cmd, 5, 0);
-    primitive_tex("pageshrink", set_page_dimen_cmd, 6, 0);
-    primitive_tex("pagedepth", set_page_dimen_cmd, 7, 0);
-
-    /*
-        Either \.{\\dump} or \.{\\end} will cause |main_control| to enter the
-        endgame, since both of them have `|stop|' as their command code.
-    */
-
-    primitive_tex("end", stop_cmd, 0, 0);
-    primitive_tex("dump", stop_cmd, 1, 0);
-
-    primitive_tex("hskip", hskip_cmd, skip_code, 0);
-    primitive_tex("hfil", hskip_cmd, fil_code, 0);
-    primitive_tex("hfill", hskip_cmd, fill_code, 0);
-    primitive_tex("hss", hskip_cmd, ss_code, 0);
-    primitive_tex("hfilneg", hskip_cmd, fil_neg_code, 0);
-    primitive_tex("vskip", vskip_cmd, skip_code, 0);
-    primitive_tex("vfil", vskip_cmd, fil_code, 0);
-    primitive_tex("vfill", vskip_cmd, fill_code, 0);
-    primitive_tex("vss", vskip_cmd, ss_code, 0);
-    primitive_tex("vfilneg", vskip_cmd, fil_neg_code, 0);
-    primitive_tex("mskip", mskip_cmd, mskip_code, 0);
-    primitive_tex("kern", kern_cmd, explicit_kern, 0);
-    primitive_tex("mkern", mkern_cmd, mu_glue, 0);
-    primitive_tex("moveleft", hmove_cmd, 1, 0);
-    primitive_tex("moveright", hmove_cmd, 0, 0);
-    primitive_tex("raise", vmove_cmd, 1, 0);
-    primitive_tex("lower", vmove_cmd, 0, 0);
-    primitive_tex("box", make_box_cmd, box_code, 0);
-    primitive_tex("copy", make_box_cmd, copy_code, 0);
-    primitive_tex("lastbox", make_box_cmd, last_box_code, 0);
-    primitive_tex("vsplit", make_box_cmd, vsplit_code, 0);
-    primitive_tex("tpack", make_box_cmd, tpack_code, 0);
-    primitive_tex("vpack", make_box_cmd, vpack_code, 0);
-    primitive_tex("hpack", make_box_cmd, hpack_code, 0);
-    primitive_tex("vtop", make_box_cmd, vtop_code, 0);
-    primitive_tex("vbox", make_box_cmd, vtop_code + vmode, 0);
-    primitive_tex("hbox", make_box_cmd, vtop_code + hmode, 0);
-    primitive_tex("shipout", leader_ship_cmd, a_leaders - 1, 0);        /* |ship_out_flag=leader_flag-1| */
-    primitive_tex("leaders", leader_ship_cmd, a_leaders, 0);
-    primitive_tex("cleaders", leader_ship_cmd, c_leaders, 0);
-    primitive_tex("xleaders", leader_ship_cmd, x_leaders, 0);
-    primitive_luatex("gleaders", leader_ship_cmd, g_leaders, 0);
-    primitive_luatex("boxdir", assign_box_dir_cmd, 0, 0);
-    primitive_tex("indent", start_par_cmd, 1, 0);
-    primitive_tex("noindent", start_par_cmd, 0, 0);
-    primitive_luatex("quitvmode", start_par_cmd, 2, 0);
-    primitive_tex("unpenalty", remove_item_cmd, penalty_node, 0);
-    primitive_tex("unkern", remove_item_cmd, kern_node, 0);
-    primitive_tex("unskip", remove_item_cmd, glue_node, 0);
-    primitive_tex("unhbox", un_hbox_cmd, box_code, 0);
-    primitive_tex("unhcopy", un_hbox_cmd, copy_code, 0);
-    primitive_tex("unvbox", un_vbox_cmd, box_code, 0);
-    primitive_tex("unvcopy", un_vbox_cmd, copy_code, 0);
-    primitive_tex("-", discretionary_cmd, explicit_disc, 0);
-    primitive_tex("discretionary", discretionary_cmd, discretionary_disc, 0);
-    primitive_luatex("localleftbox", assign_local_box_cmd, 0, 0);
-    primitive_luatex("localrightbox", assign_local_box_cmd, 1, 0);
-
-    primitive_luatex("Ustartmath", math_shift_cs_cmd, text_style, 0);
-    primitive_luatex("Ustopmath", math_shift_cs_cmd, cramped_text_style, 0);
-    primitive_luatex("Ustartdisplaymath", math_shift_cs_cmd, display_style, 0);
-    primitive_luatex("Ustopdisplaymath", math_shift_cs_cmd, cramped_display_style, 0);
-    primitive_tex("eqno", eq_no_cmd, 0, 0);
-    primitive_tex("leqno", eq_no_cmd, 1, 0);
-    primitive_tex("mathord", math_comp_cmd, ord_noad_type, 0);
-    primitive_tex("mathop", math_comp_cmd, op_noad_type_normal, 0);
-    primitive_tex("mathbin", math_comp_cmd, bin_noad_type, 0);
-    primitive_tex("mathrel", math_comp_cmd, rel_noad_type, 0);
-    primitive_tex("mathopen", math_comp_cmd, open_noad_type, 0);
-    primitive_tex("mathclose", math_comp_cmd, close_noad_type, 0);
-    primitive_tex("mathpunct", math_comp_cmd, punct_noad_type, 0);
-    primitive_tex("mathinner", math_comp_cmd, inner_noad_type, 0);
-    primitive_tex("underline", math_comp_cmd, under_noad_type, 0);
-    primitive_tex("overline", math_comp_cmd, over_noad_type, 0);
-    primitive_tex("displaylimits", limit_switch_cmd, op_noad_type_normal, 0);
-    primitive_tex("limits", limit_switch_cmd, op_noad_type_limits, 0);
-    primitive_tex("nolimits", limit_switch_cmd, op_noad_type_no_limits, 0);
-    primitive_tex("displaystyle", math_style_cmd, display_style, 0);
-    primitive_tex("textstyle", math_style_cmd, text_style, 0);
-    primitive_tex("scriptstyle", math_style_cmd, script_style, 0);
-    primitive_tex("scriptscriptstyle", math_style_cmd, script_script_style, 0);
-    primitive_luatex("crampeddisplaystyle", math_style_cmd, cramped_display_style, 0);
-    primitive_luatex("crampedtextstyle", math_style_cmd, cramped_text_style, 0);
-    primitive_luatex("crampedscriptstyle", math_style_cmd, cramped_script_style, 0);
-    primitive_luatex("crampedscriptscriptstyle", math_style_cmd, cramped_script_script_style, 0);
-    primitive_luatex("Usuperscript", super_sub_script_cmd, sup_mark_cmd, sup_mark_cmd);
-    primitive_luatex("Usubscript", super_sub_script_cmd, sub_mark_cmd, sup_mark_cmd);
-    primitive_tex("above", above_cmd, above_code, 0);
-    primitive_tex("over", above_cmd, over_code, 0);
-    primitive_tex("atop", above_cmd, atop_code, 0);
-    primitive_luatex("Uskewed", above_cmd, skewed_code, 0);
-    primitive_tex("abovewithdelims", above_cmd, delimited_code + above_code, 0);
-    primitive_tex("overwithdelims", above_cmd, delimited_code + over_code, 0);
-    primitive_tex("atopwithdelims", above_cmd, delimited_code + atop_code, 0);
-    primitive_luatex("Uskewedwithdelims", above_cmd, delimited_code + skewed_code, 0);
-    primitive_tex("left", left_right_cmd, left_noad_side, 0);
-    primitive_tex("right", left_right_cmd, right_noad_side, 0);
-    primitive_tex("middle", left_right_cmd, middle_noad_side, 0);
-    primitive_tex("Uleft", left_right_cmd, 10+left_noad_side, 0);
-    primitive_tex("Uright", left_right_cmd, 10+right_noad_side, 0);
-    primitive_tex("Umiddle", left_right_cmd, 10+middle_noad_side, 0);
-    primitive_luatex("Uvextensible", left_right_cmd, 10+no_noad_side, 0);
-    cs_text(frozen_right) = maketexstring("right");
-    eqtb[frozen_right] = eqtb[cur_val];
-
-    primitive_tex("long", prefix_cmd, 1, 0);
-    primitive_tex("outer", prefix_cmd, 2, 0);
-    primitive_tex("global", prefix_cmd, 4, 0);
-    primitive_tex("def", def_cmd, 0, 0);
-    primitive_tex("gdef", def_cmd, 1, 0);
-    primitive_tex("edef", def_cmd, 2, 0);
-    primitive_tex("xdef", def_cmd, 3, 0);
-    primitive_tex("let", let_cmd, normal, 0);
-    primitive_tex("futurelet", let_cmd, normal + 1, 0);
-    primitive_luatex("letcharcode", let_cmd, normal + 2, 0);
-    primitive_tex("chardef", shorthand_def_cmd, char_def_code, 0);
-    primitive_tex("mathchardef", shorthand_def_cmd, math_char_def_code, 0);
-    primitive_luatex("Umathchardef", shorthand_def_cmd, xmath_char_def_code, 0);
-    primitive_luatex("Umathcharnumdef", shorthand_def_cmd, umath_char_def_code, 0);
-    primitive_tex("countdef", shorthand_def_cmd, count_def_code, 0);
-    primitive_luatex("attributedef", shorthand_def_cmd, attribute_def_code, 0);
-    primitive_tex("dimendef", shorthand_def_cmd, dimen_def_code, 0);
-    primitive_tex("skipdef", shorthand_def_cmd, skip_def_code, 0);
-    primitive_tex("muskipdef", shorthand_def_cmd, mu_skip_def_code, 0);
-    primitive_tex("toksdef", shorthand_def_cmd, toks_def_code, 0);
-    primitive_tex("catcode", def_char_code_cmd, cat_code_base, cat_code_base);
-    primitive_tex("mathcode", def_char_code_cmd, math_code_base, cat_code_base);
-    primitive_tex("lccode", def_char_code_cmd, lc_code_base, cat_code_base);
-    primitive_tex("uccode", def_char_code_cmd, uc_code_base, cat_code_base);
-    primitive_tex("sfcode", def_char_code_cmd, sf_code_base, cat_code_base);
-    primitive_tex("delcode", def_del_code_cmd, del_code_base, del_code_base);
-    primitive_tex("textfont", def_family_cmd, text_size, 0);
-    primitive_tex("scriptfont", def_family_cmd, script_size, 0);
-    primitive_tex("scriptscriptfont", def_family_cmd, script_script_size, 0);
-    primitive_luatex("Umathquad", set_math_param_cmd, math_param_quad, 0);
-    primitive_luatex("Umathaxis", set_math_param_cmd, math_param_axis, 0);
-
-@ These are in a separate module due to a CWEAVE limitation.
-
-@<Create the math param primitives@>=
-    primitive_luatex("Umathoperatorsize", set_math_param_cmd, math_param_operator_size, 0);
-    primitive_luatex("Umathoverbarkern", set_math_param_cmd, math_param_overbar_kern, 0);
-    primitive_luatex("Umathoverbarrule", set_math_param_cmd, math_param_overbar_rule, 0);
-    primitive_luatex("Umathoverbarvgap", set_math_param_cmd, math_param_overbar_vgap, 0);
-    primitive_luatex("Umathunderbarkern", set_math_param_cmd, math_param_underbar_kern, 0);
-    primitive_luatex("Umathunderbarrule", set_math_param_cmd, math_param_underbar_rule, 0);
-    primitive_luatex("Umathunderbarvgap", set_math_param_cmd, math_param_underbar_vgap, 0);
-    primitive_luatex("Umathradicalkern", set_math_param_cmd, math_param_radical_kern, 0);
-    primitive_luatex("Umathradicalrule", set_math_param_cmd, math_param_radical_rule, 0);
-    primitive_luatex("Umathradicalvgap", set_math_param_cmd, math_param_radical_vgap, 0);
-    primitive_luatex("Umathradicaldegreebefore", set_math_param_cmd, math_param_radical_degree_before, 0);
-    primitive_luatex("Umathradicaldegreeafter", set_math_param_cmd, math_param_radical_degree_after, 0);
-    primitive_luatex("Umathradicaldegreeraise", set_math_param_cmd, math_param_radical_degree_raise, 0);
-    primitive_luatex("Umathstackvgap", set_math_param_cmd, math_param_stack_vgap, 0);
-    primitive_luatex("Umathstacknumup", set_math_param_cmd, math_param_stack_num_up, 0);
-    primitive_luatex("Umathstackdenomdown", set_math_param_cmd, math_param_stack_denom_down, 0);
-    primitive_luatex("Umathfractionrule", set_math_param_cmd, math_param_fraction_rule, 0);
-    primitive_luatex("Umathfractionnumvgap", set_math_param_cmd, math_param_fraction_num_vgap, 0);
-    primitive_luatex("Umathfractionnumup", set_math_param_cmd, math_param_fraction_num_up, 0);
-    primitive_luatex("Umathfractiondenomvgap", set_math_param_cmd, math_param_fraction_denom_vgap, 0);
-    primitive_luatex("Umathfractiondenomdown", set_math_param_cmd, math_param_fraction_denom_down, 0);
-    primitive_luatex("Umathfractiondelsize", set_math_param_cmd, math_param_fraction_del_size, 0);
-    primitive_luatex("Umathskewedfractionvgap", set_math_param_cmd, math_param_skewed_fraction_vgap, 0);
-    primitive_luatex("Umathskewedfractionhgap", set_math_param_cmd, math_param_skewed_fraction_hgap, 0);
-    primitive_luatex("Umathlimitabovevgap", set_math_param_cmd, math_param_limit_above_vgap, 0);
-    primitive_luatex("Umathlimitabovebgap", set_math_param_cmd, math_param_limit_above_bgap, 0);
-    primitive_luatex("Umathlimitabovekern", set_math_param_cmd, math_param_limit_above_kern, 0);
-    primitive_luatex("Umathlimitbelowvgap", set_math_param_cmd, math_param_limit_below_vgap, 0);
-    primitive_luatex("Umathlimitbelowbgap", set_math_param_cmd, math_param_limit_below_bgap, 0);
-    primitive_luatex("Umathlimitbelowkern", set_math_param_cmd, math_param_limit_below_kern, 0);
-    primitive_luatex("Umathnolimitsubfactor", set_math_param_cmd, math_param_nolimit_sub_factor, 0); /* bonus */
-    primitive_luatex("Umathnolimitsupfactor", set_math_param_cmd, math_param_nolimit_sup_factor, 0); /* bonus */
-    primitive_luatex("Umathunderdelimitervgap", set_math_param_cmd, math_param_under_delimiter_vgap, 0);
-    primitive_luatex("Umathunderdelimiterbgap", set_math_param_cmd, math_param_under_delimiter_bgap, 0);
-    primitive_luatex("Umathoverdelimitervgap", set_math_param_cmd, math_param_over_delimiter_vgap, 0);
-    primitive_luatex("Umathoverdelimiterbgap", set_math_param_cmd, math_param_over_delimiter_bgap, 0);
-    primitive_luatex("Umathsubshiftdrop", set_math_param_cmd, math_param_sub_shift_drop, 0);
-    primitive_luatex("Umathsupshiftdrop", set_math_param_cmd, math_param_sup_shift_drop, 0);
-    primitive_luatex("Umathsubshiftdown", set_math_param_cmd, math_param_sub_shift_down, 0);
-    primitive_luatex("Umathsubsupshiftdown", set_math_param_cmd, math_param_sub_sup_shift_down, 0);
-    primitive_luatex("Umathsubtopmax", set_math_param_cmd, math_param_sub_top_max, 0);
-    primitive_luatex("Umathsupshiftup", set_math_param_cmd, math_param_sup_shift_up, 0);
-    primitive_luatex("Umathsupbottommin", set_math_param_cmd, math_param_sup_bottom_min, 0);
-    primitive_luatex("Umathsupsubbottommax", set_math_param_cmd, math_param_sup_sub_bottom_max, 0);
-    primitive_luatex("Umathsubsupvgap", set_math_param_cmd, math_param_subsup_vgap, 0);
-    primitive_luatex("Umathspaceafterscript", set_math_param_cmd, math_param_space_after_script, 0);
-    primitive_luatex("Umathconnectoroverlapmin", set_math_param_cmd, math_param_connector_overlap_min, 0);
-    primitive_luatex("Umathordordspacing", set_math_param_cmd, math_param_ord_ord_spacing, 0);
-    primitive_luatex("Umathordopspacing", set_math_param_cmd, math_param_ord_op_spacing, 0);
-    primitive_luatex("Umathordbinspacing", set_math_param_cmd, math_param_ord_bin_spacing, 0);
-    primitive_luatex("Umathordrelspacing", set_math_param_cmd, math_param_ord_rel_spacing, 0);
-    primitive_luatex("Umathordopenspacing", set_math_param_cmd, math_param_ord_open_spacing, 0);
-    primitive_luatex("Umathordclosespacing", set_math_param_cmd, math_param_ord_close_spacing, 0);
-    primitive_luatex("Umathordpunctspacing", set_math_param_cmd, math_param_ord_punct_spacing, 0);
-    primitive_luatex("Umathordinnerspacing", set_math_param_cmd, math_param_ord_inner_spacing, 0);
-    primitive_luatex("Umathopordspacing", set_math_param_cmd, math_param_op_ord_spacing, 0);
-    primitive_luatex("Umathopopspacing", set_math_param_cmd, math_param_op_op_spacing, 0);
-    primitive_luatex("Umathopbinspacing", set_math_param_cmd, math_param_op_bin_spacing, 0);
-    primitive_luatex("Umathoprelspacing", set_math_param_cmd, math_param_op_rel_spacing, 0);
-    primitive_luatex("Umathopopenspacing", set_math_param_cmd, math_param_op_open_spacing, 0);
-    primitive_luatex("Umathopclosespacing", set_math_param_cmd, math_param_op_close_spacing, 0);
-    primitive_luatex("Umathoppunctspacing", set_math_param_cmd, math_param_op_punct_spacing, 0);
-    primitive_luatex("Umathopinnerspacing", set_math_param_cmd, math_param_op_inner_spacing, 0);
-    primitive_luatex("Umathbinordspacing", set_math_param_cmd, math_param_bin_ord_spacing, 0);
-    primitive_luatex("Umathbinopspacing", set_math_param_cmd, math_param_bin_op_spacing, 0);
-    primitive_luatex("Umathbinbinspacing", set_math_param_cmd, math_param_bin_bin_spacing, 0);
-    primitive_luatex("Umathbinrelspacing", set_math_param_cmd, math_param_bin_rel_spacing, 0);
-    primitive_luatex("Umathbinopenspacing", set_math_param_cmd, math_param_bin_open_spacing, 0);
-    primitive_luatex("Umathbinclosespacing", set_math_param_cmd, math_param_bin_close_spacing, 0);
-    primitive_luatex("Umathbinpunctspacing", set_math_param_cmd, math_param_bin_punct_spacing, 0);
-    primitive_luatex("Umathbininnerspacing", set_math_param_cmd, math_param_bin_inner_spacing, 0);
-    primitive_luatex("Umathrelordspacing", set_math_param_cmd, math_param_rel_ord_spacing, 0);
-    primitive_luatex("Umathrelopspacing", set_math_param_cmd, math_param_rel_op_spacing, 0);
-    primitive_luatex("Umathrelbinspacing", set_math_param_cmd, math_param_rel_bin_spacing, 0);
-    primitive_luatex("Umathrelrelspacing", set_math_param_cmd, math_param_rel_rel_spacing, 0);
-    primitive_luatex("Umathrelopenspacing", set_math_param_cmd, math_param_rel_open_spacing, 0);
-    primitive_luatex("Umathrelclosespacing", set_math_param_cmd, math_param_rel_close_spacing, 0);
-    primitive_luatex("Umathrelpunctspacing", set_math_param_cmd, math_param_rel_punct_spacing, 0);
-    primitive_luatex("Umathrelinnerspacing", set_math_param_cmd, math_param_rel_inner_spacing, 0);
-    primitive_luatex("Umathopenordspacing", set_math_param_cmd, math_param_open_ord_spacing, 0);
-    primitive_luatex("Umathopenopspacing", set_math_param_cmd, math_param_open_op_spacing, 0);
-    primitive_luatex("Umathopenbinspacing", set_math_param_cmd, math_param_open_bin_spacing, 0);
-    primitive_luatex("Umathopenrelspacing", set_math_param_cmd, math_param_open_rel_spacing, 0);
-    primitive_luatex("Umathopenopenspacing", set_math_param_cmd, math_param_open_open_spacing, 0);
-    primitive_luatex("Umathopenclosespacing", set_math_param_cmd, math_param_open_close_spacing, 0);
-    primitive_luatex("Umathopenpunctspacing", set_math_param_cmd, math_param_open_punct_spacing, 0);
-    primitive_luatex("Umathopeninnerspacing", set_math_param_cmd, math_param_open_inner_spacing, 0);
-    primitive_luatex("Umathcloseordspacing", set_math_param_cmd, math_param_close_ord_spacing, 0);
-    primitive_luatex("Umathcloseopspacing", set_math_param_cmd, math_param_close_op_spacing, 0);
-    primitive_luatex("Umathclosebinspacing", set_math_param_cmd, math_param_close_bin_spacing, 0);
-    primitive_luatex("Umathcloserelspacing", set_math_param_cmd, math_param_close_rel_spacing, 0);
-    primitive_luatex("Umathcloseopenspacing", set_math_param_cmd, math_param_close_open_spacing, 0);
-    primitive_luatex("Umathcloseclosespacing", set_math_param_cmd, math_param_close_close_spacing, 0);
-    primitive_luatex("Umathclosepunctspacing", set_math_param_cmd, math_param_close_punct_spacing, 0);
-    primitive_luatex("Umathcloseinnerspacing", set_math_param_cmd, math_param_close_inner_spacing, 0);
-    primitive_luatex("Umathpunctordspacing", set_math_param_cmd, math_param_punct_ord_spacing, 0);
-    primitive_luatex("Umathpunctopspacing", set_math_param_cmd, math_param_punct_op_spacing, 0);
-    primitive_luatex("Umathpunctbinspacing", set_math_param_cmd, math_param_punct_bin_spacing, 0);
-    primitive_luatex("Umathpunctrelspacing", set_math_param_cmd, math_param_punct_rel_spacing, 0);
-    primitive_luatex("Umathpunctopenspacing", set_math_param_cmd, math_param_punct_open_spacing, 0);
-    primitive_luatex("Umathpunctclosespacing", set_math_param_cmd, math_param_punct_close_spacing, 0);
-    primitive_luatex("Umathpunctpunctspacing", set_math_param_cmd, math_param_punct_punct_spacing, 0);
-    primitive_luatex("Umathpunctinnerspacing", set_math_param_cmd, math_param_punct_inner_spacing, 0);
-    primitive_luatex("Umathinnerordspacing", set_math_param_cmd, math_param_inner_ord_spacing, 0);
-    primitive_luatex("Umathinneropspacing", set_math_param_cmd, math_param_inner_op_spacing, 0);
-    primitive_luatex("Umathinnerbinspacing", set_math_param_cmd, math_param_inner_bin_spacing, 0);
-    primitive_luatex("Umathinnerrelspacing", set_math_param_cmd, math_param_inner_rel_spacing, 0);
-    primitive_luatex("Umathinneropenspacing", set_math_param_cmd, math_param_inner_open_spacing, 0);
-    primitive_luatex("Umathinnerclosespacing", set_math_param_cmd, math_param_inner_close_spacing, 0);
-    primitive_luatex("Umathinnerpunctspacing", set_math_param_cmd, math_param_inner_punct_spacing, 0);
-    primitive_luatex("Umathinnerinnerspacing", set_math_param_cmd, math_param_inner_inner_spacing, 0);
-
-@ These are in a separate module due to a CWEAVE limitation.
-
-@<Create another bunch of primitives@>=
-    primitive_luatex("Umathcode", extdef_math_code_cmd, math_code_base, math_code_base);
-    primitive_luatex("Udelcode", extdef_del_code_cmd, del_code_base, del_code_base);
-    primitive_luatex("Umathcodenum", extdef_math_code_cmd, math_code_base + 1, math_code_base);
-    primitive_luatex("Udelcodenum", extdef_del_code_cmd, del_code_base + 1, del_code_base);
-    primitive_tex("hyphenation", hyph_data_cmd, 0, 0);
-    primitive_tex("patterns", hyph_data_cmd, 1, 0);
-    primitive_luatex("prehyphenchar", hyph_data_cmd, 2, 0);
-    primitive_luatex("posthyphenchar", hyph_data_cmd, 3, 0);
-    primitive_luatex("preexhyphenchar", hyph_data_cmd, 4, 0);
-    primitive_luatex("postexhyphenchar", hyph_data_cmd, 5, 0);
-    primitive_luatex("hyphenationmin", hyph_data_cmd, 6, 0);
-    primitive_luatex("hjcode", hyph_data_cmd, 7, 0);
-    primitive_tex("hyphenchar", assign_font_int_cmd, 0, 0);
-    primitive_tex("skewchar", assign_font_int_cmd, 1, 0);
-    primitive_luatex("lpcode", assign_font_int_cmd, lp_code_base, 0);
-    primitive_luatex("rpcode", assign_font_int_cmd, rp_code_base, 0);
-    primitive_luatex("efcode", assign_font_int_cmd, ef_code_base, 0);
-    primitive_luatex("tagcode", assign_font_int_cmd, tag_code, 0);
-    primitive_luatex("ignoreligaturesinfont", assign_font_int_cmd, no_lig_code, 0);
-    primitive_tex("batchmode", set_interaction_cmd, batch_mode, 0);
-    primitive_tex("nonstopmode", set_interaction_cmd, nonstop_mode, 0);
-    primitive_tex("scrollmode", set_interaction_cmd, scroll_mode, 0);
-    primitive_tex("errorstopmode", set_interaction_cmd, error_stop_mode, 0);
-    primitive_tex("openin", in_stream_cmd, 1, 0);
-    primitive_tex("closein", in_stream_cmd, 0, 0);
-    primitive_tex("message", message_cmd, 0, 0);
-    primitive_tex("errmessage", message_cmd, 1, 0);
-    primitive_tex("lowercase", case_shift_cmd, lc_code_base, lc_code_base);
-    primitive_tex("uppercase", case_shift_cmd, uc_code_base, lc_code_base);
-    primitive_tex("show", xray_cmd, show_code, 0);
-    primitive_tex("showbox", xray_cmd, show_box_code, 0);
-    primitive_tex("showthe", xray_cmd, show_the_code, 0);
-    primitive_tex("showlists", xray_cmd, show_lists, 0);
-
-    primitive_tex("openout", extension_cmd, open_code, 0);
-    primitive_tex("write", extension_cmd, write_code, 0);
-    write_loc = cur_val;
-    primitive_tex("closeout", extension_cmd, close_code, 0);
-    primitive_tex("special", extension_cmd, special_code, 0);
-    cs_text(frozen_special) = maketexstring("special");
-    eqtb[frozen_special] = eqtb[cur_val];
-    primitive_tex("immediate", extension_cmd, immediate_code, 0);
-    primitive_luatex("localinterlinepenalty", assign_int_cmd, int_base + local_inter_line_penalty_code, int_base);
-    primitive_luatex("localbrokenpenalty", assign_int_cmd, int_base + local_broken_penalty_code, int_base);
-    primitive_luatex("pagedir", assign_dir_cmd, int_base + page_direction_code, dir_base);
-    primitive_luatex("bodydir", assign_dir_cmd, int_base + body_direction_code, dir_base);
-    primitive_luatex("pardir", assign_dir_cmd, int_base + par_direction_code, dir_base);
-    primitive_luatex("textdir", assign_dir_cmd, int_base + text_direction_code, dir_base);
-    primitive_luatex("mathdir", assign_dir_cmd, int_base + math_direction_code, dir_base);
-    primitive_luatex("linedir", assign_dir_cmd, int_base + line_direction_code, dir_base);
-    primitive_luatex("pageleftoffset", assign_dimen_cmd, dimen_base + page_left_offset_code, dimen_base);
-    primitive_luatex("pagetopoffset", assign_dimen_cmd, dimen_base + page_top_offset_code, dimen_base);
-    primitive_luatex("pagerightoffset", assign_dimen_cmd, dimen_base + page_right_offset_code, dimen_base);
-    primitive_luatex("pagebottomoffset", assign_dimen_cmd, dimen_base + page_bottom_offset_code, dimen_base);
-    primitive_luatex("saveboxresource", extension_cmd, save_box_resource_code, 0);
-    primitive_luatex("useboxresource", extension_cmd, use_box_resource_code, 0);
-    primitive_luatex("saveimageresource", extension_cmd, save_image_resource_code, 0);
-    primitive_luatex("useimageresource", extension_cmd, use_image_resource_code, 0);
-    primitive_luatex("savepos", normal_cmd, save_pos_code, 0);
-    primitive_luatex("savecatcodetable", normal_cmd, save_cat_code_table_code, 0);
-    primitive_luatex("initcatcodetable", normal_cmd, init_cat_code_table_code, 0);
-    primitive_luatex("setrandomseed", normal_cmd, set_random_seed_code, 0);
-    primitive_luatex("latelua", normal_cmd, late_lua_code, 0);
-    primitive_luatex("insertht", convert_cmd, insert_ht_code, 0);
-    primitive_luatex("dviextension", extension_cmd, dvi_extension_code, 0);
-    primitive_luatex("dvifeedback", feedback_cmd, dvi_feedback_code, 0);
-    primitive_luatex("dvivariable", variable_cmd, dvi_variable_code, 0);
-    primitive_luatex("pdfextension", extension_cmd, pdf_extension_code, 0);
-    primitive_luatex("pdffeedback", feedback_cmd, pdf_feedback_code, 0);
-    primitive_luatex("pdfvariable", variable_cmd, pdf_variable_code, 0);
-    primitive_luatex("mathoption", option_cmd, math_option_code, 0);
-
-    /*
-        some of the internal integer parameters are not associated with actual
-        primitives at all.
-    */
-
-    primitive_no("nolocalwhatsits", assign_int_cmd, int_base + no_local_whatsits_code, int_base);
-    primitive_no("nolocaldirs", assign_int_cmd, int_base + no_local_dirs_code, int_base);
-
-
-@ @c
-void initialize_etex_commands(void)
-{
-    primitive_etex("lastnodetype", last_item_cmd, last_node_type_code, 0);
-    primitive_etex("eTeXversion", last_item_cmd, eTeX_version_code, 0);
-    primitive_etex("eTeXminorversion", last_item_cmd, eTeX_minor_version_code, 0);
-    primitive_etex("eTeXrevision", convert_cmd, eTeX_revision_code, 0);
-
-    /*
-        First we implement the additional \eTeX\ parameters in the table of equivalents.
-    */
-
-    primitive_etex("everyeof", assign_toks_cmd, every_eof_loc, local_base);
-    primitive_etex("tracingassigns", assign_int_cmd, int_base + tracing_assigns_code, int_base);
-    primitive_etex("tracinggroups", assign_int_cmd, int_base + tracing_groups_code, int_base);
-    primitive_etex("tracingifs", assign_int_cmd, int_base + tracing_ifs_code, int_base);
-    primitive_etex("tracingscantokens", assign_int_cmd, int_base + tracing_scan_tokens_code, int_base);
-    primitive_etex("tracingnesting", assign_int_cmd, int_base + tracing_nesting_code, int_base);
-    primitive_etex("predisplaydirection", assign_int_cmd, int_base + pre_display_direction_code, int_base);
-    primitive_etex("lastlinefit", assign_int_cmd, int_base + last_line_fit_code, int_base);
-    primitive_etex("savingvdiscards", assign_int_cmd, int_base + saving_vdiscards_code, int_base);
-    primitive_etex("savinghyphcodes", assign_int_cmd, int_base + saving_hyph_codes_code, int_base);
-    primitive_luatex("suppressfontnotfounderror", assign_int_cmd, int_base + suppress_fontnotfound_error_code, int_base);
-    primitive_luatex("suppresslongerror", assign_int_cmd, int_base + suppress_long_error_code, int_base);
-    primitive_luatex("suppressmathparerror", assign_int_cmd, int_base + suppress_mathpar_error_code, int_base);
-    primitive_luatex("suppressifcsnameerror", assign_int_cmd, int_base + suppress_ifcsname_error_code, int_base);
-    primitive_luatex("suppressoutererror", assign_int_cmd, int_base + suppress_outer_error_code, int_base);
-    primitive_luatex("matheqnogapstep", assign_int_cmd, int_base + math_eqno_gap_step_code, int_base);
-    primitive_luatex("mathdisplayskipmode", assign_int_cmd, int_base + math_display_skip_mode_code, int_base);
-    primitive_luatex("mathscriptsmode", assign_int_cmd, int_base + math_scripts_mode_code, int_base);
-    primitive_luatex("mathnolimitsmode", assign_int_cmd, int_base + math_nolimits_mode_code, int_base);
-    primitive_luatex("mathrulesmode", assign_int_cmd, int_base + math_rules_mode_code, int_base);
-    primitive_luatex("mathrulesfam", assign_int_cmd, int_base + math_rules_fam_code, int_base);
-    primitive_luatex("synctex", assign_int_cmd, int_base + synctex_code, int_base);
-
-    primitive_etex("currentgrouplevel", last_item_cmd, current_group_level_code, 0);
-    primitive_etex("currentgrouptype", last_item_cmd, current_group_type_code, 0);
-
-    primitive_etex("currentiflevel", last_item_cmd, current_if_level_code, 0);
-    primitive_etex("currentiftype", last_item_cmd, current_if_type_code, 0);
-    primitive_etex("currentifbranch", last_item_cmd, current_if_branch_code, 0);
-    primitive_etex("fontcharwd", last_item_cmd, font_char_wd_code, 0);
-    primitive_etex("fontcharht", last_item_cmd, font_char_ht_code, 0);
-    primitive_etex("fontchardp", last_item_cmd, font_char_dp_code, 0);
-    primitive_etex("fontcharic", last_item_cmd, font_char_ic_code, 0);
-
-    primitive_etex("parshapelength", last_item_cmd, par_shape_length_code, 0);
-    primitive_etex("parshapeindent", last_item_cmd, par_shape_indent_code, 0);
-    primitive_etex("parshapedimen", last_item_cmd, par_shape_dimen_code, 0);
-
-    primitive_luatex("shapemode", assign_int_cmd, int_base + shape_mode_code, int_base);
-    primitive_luatex("hyphenationbounds", assign_int_cmd, int_base + hyphenation_bounds_code, int_base);
-
-    primitive_etex("showgroups", xray_cmd, show_groups, 0);
-
-    /*
-        The \.{\\showtokens} command displays a token list.
-    */
-
-    primitive_etex("showtokens", xray_cmd, show_tokens, 0);
-
-    /*
-        The \.{\\unexpanded} primitive prevents expansion of tokens much as
-        the result from \.{\\the} applied to a token variable.  The
-        \.{\\detokenize} primitive converts a token list into a list of
-        character tokens much as if the token list were written to a file.  We
-        use the fact that the command modifiers for \.{\\unexpanded} and
-        \.{\\detokenize} are odd whereas those for \.{\\the} and \.{\\showthe}
-        are even.
-    */
-
-    primitive_etex("unexpanded", the_cmd, 1, 0);
-    primitive_etex("detokenize", the_cmd, show_tokens, 0);
-
-    /*
-        The \.{\\showifs} command displays all currently active conditionals.
-    */
-
-    primitive_etex("showifs", xray_cmd, show_ifs, 0);
-
-    /*
-        The \.{\\interactionmode} primitive allows to query and set the interaction mode.
-    */
-
-    primitive_etex("interactionmode", set_page_int_cmd, 2, 0);
-
-    /*
-        The |scan_tokens| feature of \eTeX\ defines the \.{\\scantokens} primitive.
-    */
-
-    primitive_etex("scantokens", input_cmd, 2, 0);
-    primitive_luatex("scantextokens", input_cmd, 3, 0);
-
-    primitive_etex("readline", read_to_cs_cmd, 1, 0);
-
-    primitive_etex("unless", expand_after_cmd, 1, 0);
-    primitive_etex("ifdefined", if_test_cmd, if_def_code, 0);
-    primitive_etex("ifcsname", if_test_cmd, if_cs_code, 0);
-    primitive_etex("iffontchar", if_test_cmd, if_font_char_code, 0);
-    primitive_luatex("ifincsname", if_test_cmd, if_in_csname_code, 0);
-    primitive_luatex("ifabsnum", if_test_cmd, if_abs_num_code, 0);
-    primitive_luatex("ifabsdim", if_test_cmd, if_abs_dim_code, 0);
-
-    /*
-        The |protected| feature of \eTeX\ defines the \.{\\protected} prefix
-        command for macro definitions.  Such macros are protected against
-        expansions when lists of expanded tokens are built, e.g., for \.{\\edef}
-        or during \.{\\write}.
-    */
-
-    primitive_etex("protected", prefix_cmd, 8, 0);
-
-    /*
-        Here are the additional \eTeX\ primitives for expressions.
-    */
-
-    primitive_etex("numexpr", last_item_cmd, eTeX_expr - int_val_level + int_val_level, 0);
-    primitive_etex("dimexpr", last_item_cmd, eTeX_expr - int_val_level + dimen_val_level, 0);
-    primitive_etex("glueexpr", last_item_cmd, eTeX_expr - int_val_level + glue_val_level, 0);
-    primitive_etex("muexpr", last_item_cmd, eTeX_expr - int_val_level + mu_val_level, 0);
-
-    primitive_etex("gluestretchorder", last_item_cmd, glue_stretch_order_code, 0);
-    primitive_etex("glueshrinkorder", last_item_cmd, glue_shrink_order_code, 0);
-    primitive_etex("gluestretch", last_item_cmd, glue_stretch_code, 0);
-    primitive_etex("glueshrink", last_item_cmd, glue_shrink_code, 0);
-
-    primitive_etex("mutoglue", last_item_cmd, mu_to_glue_code, 0);
-    primitive_etex("gluetomu", last_item_cmd, glue_to_mu_code, 0);
-
-    /*
-        The \.{\\pagediscards} and \.{\\splitdiscards} commands share the
-        command code |un_vbox| with \.{\\unvbox} and \.{\\unvcopy}, they are
-        distinguished by their |chr_code| values |last_box_code| and
-        |vsplit_code|.  These |chr_code| values are larger than |box_code| and
-        |copy_code|.
-    */
-
-    primitive_etex("pagediscards", un_vbox_cmd, last_box_code, 0);
-    primitive_etex("splitdiscards", un_vbox_cmd, vsplit_code, 0);
-
-    /*
-        The \.{\\interlinepenalties}, \.{\\clubpenalties}, \.{\\widowpenalties},
-        and \.{\\displaywidowpenalties} commands allow to define arrays of
-        penalty values to be used instead of the corresponding single values.
-    */
-
-    primitive_etex("interlinepenalties", set_etex_shape_cmd, inter_line_penalties_loc, etex_pen_base);
-    primitive_etex("clubpenalties", set_etex_shape_cmd, club_penalties_loc, etex_pen_base);
-    primitive_etex("widowpenalties", set_etex_shape_cmd, widow_penalties_loc, etex_pen_base);
-    primitive_etex("displaywidowpenalties", set_etex_shape_cmd, display_widow_penalties_loc, etex_pen_base);
-
-}
+% commands.w
+%
+% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org>
+%
+% This file is part of LuaTeX.
+%
+% LuaTeX is free software; you can redistribute it and/or modify it under
+% the terms of the GNU General Public License as published by the Free
+% Software Foundation; either version 2 of the License, or (at your
+% option) any later version.
+%
+% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+% License for more details.
+%
+% You should have received a copy of the GNU General Public License along
+% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+\def\eTeX{e-\TeX}
+
+@ @c
+
+
+#include "ptexlib.h"
+
+@ The symbolic names for glue parameters are put into \TeX's hash table
+by using the routine called |primitive|, defined below. Let us enter them
+now, so that we don't have to list all those parameter names anywhere else.
+
+ at c
+void initialize_commands(void)
+{
+
+    primitive_tex("lineskip", assign_glue_cmd, glue_base + line_skip_code, glue_base);
+    primitive_tex("baselineskip", assign_glue_cmd, glue_base + baseline_skip_code, glue_base);
+    primitive_tex("parskip", assign_glue_cmd, glue_base + par_skip_code, glue_base);
+    primitive_tex("abovedisplayskip", assign_glue_cmd, glue_base + above_display_skip_code, glue_base);
+    primitive_tex("belowdisplayskip", assign_glue_cmd, glue_base + below_display_skip_code, glue_base);
+    primitive_tex("abovedisplayshortskip", assign_glue_cmd, glue_base + above_display_short_skip_code, glue_base);
+    primitive_tex("belowdisplayshortskip", assign_glue_cmd, glue_base + below_display_short_skip_code, glue_base);
+    primitive_tex("leftskip", assign_glue_cmd, glue_base + left_skip_code, glue_base);
+    primitive_tex("rightskip", assign_glue_cmd, glue_base + right_skip_code, glue_base);
+    primitive_tex("topskip", assign_glue_cmd, glue_base + top_skip_code, glue_base);
+    primitive_tex("splittopskip", assign_glue_cmd, glue_base + split_top_skip_code, glue_base);
+    primitive_tex("tabskip", assign_glue_cmd, glue_base + tab_skip_code, glue_base);
+    primitive_tex("spaceskip", assign_glue_cmd, glue_base + space_skip_code, glue_base);
+    primitive_tex("xspaceskip", assign_glue_cmd, glue_base + xspace_skip_code, glue_base);
+    primitive_tex("parfillskip", assign_glue_cmd, glue_base + par_fill_skip_code, glue_base);
+    primitive_tex("thinmuskip", assign_mu_glue_cmd, glue_base + thin_mu_skip_code, glue_base + thin_mu_skip_code);
+    primitive_tex("medmuskip", assign_mu_glue_cmd, glue_base + med_mu_skip_code, glue_base + thin_mu_skip_code);
+    primitive_tex("thickmuskip", assign_mu_glue_cmd, glue_base + thick_mu_skip_code, glue_base + thin_mu_skip_code);
+    primitive_luatex("mathsurroundskip", assign_glue_cmd, glue_base + math_skip_code, glue_base);
+    primitive_luatex("mathsurroundmode", assign_int_cmd, int_base + math_skip_mode_code, int_base);
+    primitive_tex("output", assign_toks_cmd, output_routine_loc, local_base);
+    primitive_tex("everypar", assign_toks_cmd, every_par_loc, local_base);
+    primitive_tex("everymath", assign_toks_cmd, every_math_loc, local_base);
+    primitive_tex("everydisplay", assign_toks_cmd, every_display_loc, local_base);
+    primitive_tex("everyhbox", assign_toks_cmd, every_hbox_loc, local_base);
+    primitive_tex("everyvbox", assign_toks_cmd, every_vbox_loc, local_base);
+    primitive_tex("everyjob", assign_toks_cmd, every_job_loc, local_base);
+    primitive_tex("everycr", assign_toks_cmd, every_cr_loc, local_base);
+    primitive_tex("errhelp", assign_toks_cmd, err_help_loc, local_base);
+
+    /* The integer parameter names must be entered into the hash table */
+
+    primitive_tex("pretolerance", assign_int_cmd, int_base + pretolerance_code, int_base);
+    primitive_tex("tolerance", assign_int_cmd, int_base + tolerance_code, int_base);
+    primitive_tex("linepenalty", assign_int_cmd, int_base + line_penalty_code, int_base);
+    primitive_tex("hyphenpenalty", assign_int_cmd, int_base + hyphen_penalty_code, int_base);
+    primitive_tex("exhyphenpenalty", assign_int_cmd, int_base + ex_hyphen_penalty_code, int_base);
+    primitive_tex("clubpenalty", assign_int_cmd, int_base + club_penalty_code, int_base);
+    primitive_tex("widowpenalty", assign_int_cmd, int_base + widow_penalty_code, int_base);
+    primitive_tex("displaywidowpenalty", assign_int_cmd, int_base + display_widow_penalty_code, int_base);
+    primitive_tex("brokenpenalty", assign_int_cmd, int_base + broken_penalty_code, int_base);
+    primitive_tex("binoppenalty", assign_int_cmd, int_base + bin_op_penalty_code, int_base);
+    primitive_tex("relpenalty", assign_int_cmd, int_base + rel_penalty_code, int_base);
+    primitive_tex("predisplaypenalty", assign_int_cmd, int_base + pre_display_penalty_code, int_base);
+    primitive_tex("postdisplaypenalty", assign_int_cmd, int_base + post_display_penalty_code, int_base);
+    primitive_tex("interlinepenalty", assign_int_cmd, int_base + inter_line_penalty_code, int_base);
+    primitive_tex("doublehyphendemerits", assign_int_cmd, int_base + double_hyphen_demerits_code, int_base);
+    primitive_tex("finalhyphendemerits", assign_int_cmd, int_base + final_hyphen_demerits_code, int_base);
+    primitive_tex("adjdemerits", assign_int_cmd, int_base + adj_demerits_code, int_base);
+    primitive_tex("mag", assign_int_cmd, int_base + mag_code, int_base);
+    primitive_tex("delimiterfactor", assign_int_cmd, int_base + delimiter_factor_code, int_base);
+    primitive_tex("looseness", assign_int_cmd, int_base + looseness_code, int_base);
+    primitive_tex("time", assign_int_cmd, int_base + time_code, int_base);
+    primitive_tex("day", assign_int_cmd, int_base + day_code, int_base);
+    primitive_tex("month", assign_int_cmd, int_base + month_code, int_base);
+    primitive_tex("year", assign_int_cmd, int_base + year_code, int_base);
+    primitive_tex("showboxbreadth", assign_int_cmd, int_base + show_box_breadth_code, int_base);
+    primitive_tex("showboxdepth", assign_int_cmd, int_base + show_box_depth_code, int_base);
+    primitive_tex("hbadness", assign_int_cmd, int_base + hbadness_code, int_base);
+    primitive_tex("vbadness", assign_int_cmd, int_base + vbadness_code, int_base);
+    primitive_tex("pausing", assign_int_cmd, int_base + pausing_code, int_base);
+    primitive_tex("tracingonline", assign_int_cmd, int_base + tracing_online_code, int_base);
+    primitive_tex("tracingmacros", assign_int_cmd, int_base + tracing_macros_code, int_base);
+    primitive_tex("tracingstats", assign_int_cmd, int_base + tracing_stats_code, int_base);
+    primitive_tex("tracingparagraphs", assign_int_cmd, int_base + tracing_paragraphs_code, int_base);
+    primitive_tex("tracingpages", assign_int_cmd, int_base + tracing_pages_code, int_base);
+    primitive_tex("tracingoutput", assign_int_cmd, int_base + tracing_output_code, int_base);
+    primitive_tex("tracinglostchars", assign_int_cmd, int_base + tracing_lost_chars_code, int_base);
+    primitive_tex("tracingcommands", assign_int_cmd, int_base + tracing_commands_code, int_base);
+    primitive_tex("tracingrestores", assign_int_cmd, int_base + tracing_restores_code, int_base);
+    primitive_tex("uchyph", assign_int_cmd, int_base + uc_hyph_code, int_base);
+    primitive_tex("outputpenalty", assign_int_cmd, int_base + output_penalty_code, int_base);
+    primitive_tex("maxdeadcycles", assign_int_cmd, int_base + max_dead_cycles_code, int_base);
+    primitive_tex("hangafter", assign_int_cmd, int_base + hang_after_code, int_base);
+    primitive_tex("floatingpenalty", assign_int_cmd, int_base + floating_penalty_code, int_base);
+    primitive_tex("globaldefs", assign_int_cmd, int_base + global_defs_code, int_base);
+    primitive_tex("fam", assign_int_cmd, int_base + cur_fam_code, int_base);
+    primitive_tex("escapechar", assign_int_cmd, int_base + escape_char_code, int_base);
+    primitive_tex("defaulthyphenchar", assign_int_cmd, int_base + default_hyphen_char_code, int_base);
+    primitive_tex("defaultskewchar", assign_int_cmd, int_base + default_skew_char_code, int_base);
+    primitive_tex("endlinechar", assign_int_cmd, int_base + end_line_char_code, int_base);
+    primitive_tex("newlinechar", assign_int_cmd, int_base + new_line_char_code, int_base);
+    primitive_tex("language", assign_int_cmd, int_base + language_code, int_base);
+    primitive_tex("setlanguage", assign_int_cmd, int_base + cur_lang_code, int_base);
+    primitive_tex("firstvalidlanguage", assign_int_cmd, int_base + first_valid_language_code, int_base);
+    primitive_tex("exhyphenchar", assign_int_cmd, int_base + ex_hyphen_char_code, int_base);
+    primitive_tex("lefthyphenmin", assign_int_cmd, int_base + left_hyphen_min_code, int_base);
+    primitive_tex("righthyphenmin", assign_int_cmd, int_base + right_hyphen_min_code, int_base);
+    primitive_tex("holdinginserts", assign_int_cmd, int_base + holding_inserts_code, int_base);
+    primitive_tex("errorcontextlines", assign_int_cmd, int_base + error_context_lines_code, int_base);
+    primitive_luatex("nokerns", assign_int_cmd, int_base + disable_kern_code, int_base);
+    primitive_luatex("noligs", assign_int_cmd, int_base + disable_lig_code, int_base);
+    primitive_luatex("nospaces", assign_int_cmd, int_base + disable_space_code, int_base);
+    primitive_luatex("catcodetable", assign_int_cmd, int_base + cat_code_table_code, int_base);
+    primitive_luatex("outputbox", assign_int_cmd, int_base + output_box_code, int_base);
+    primitive_luatex("outputmode", assign_int_cmd, int_base + output_mode_code, int_base);
+    primitive_luatex("adjustspacing", assign_int_cmd, int_base + adjust_spacing_code, int_base);
+    primitive_luatex("protrudechars", assign_int_cmd, int_base + protrude_chars_code, int_base);
+    primitive_luatex("tracingfonts", assign_int_cmd, int_base + tracing_fonts_code, int_base);
+    primitive_luatex("draftmode", assign_int_cmd, int_base + draft_mode_code, int_base);
+    primitive_tex("parindent", assign_dimen_cmd, dimen_base + par_indent_code, dimen_base);
+    primitive_tex("mathsurround", assign_dimen_cmd, dimen_base + math_surround_code, dimen_base);
+    primitive_tex("lineskiplimit", assign_dimen_cmd, dimen_base + line_skip_limit_code, dimen_base);
+    primitive_tex("hsize", assign_dimen_cmd, dimen_base + hsize_code, dimen_base);
+    primitive_tex("vsize", assign_dimen_cmd, dimen_base + vsize_code, dimen_base);
+    primitive_tex("maxdepth", assign_dimen_cmd, dimen_base + max_depth_code, dimen_base);
+    primitive_tex("splitmaxdepth", assign_dimen_cmd, dimen_base + split_max_depth_code, dimen_base);
+    primitive_tex("boxmaxdepth", assign_dimen_cmd, dimen_base + box_max_depth_code, dimen_base);
+    primitive_tex("hfuzz", assign_dimen_cmd, dimen_base + hfuzz_code, dimen_base);
+    primitive_tex("vfuzz", assign_dimen_cmd, dimen_base + vfuzz_code, dimen_base);
+    primitive_tex("delimitershortfall", assign_dimen_cmd, dimen_base + delimiter_shortfall_code, dimen_base);
+    primitive_tex("nulldelimiterspace", assign_dimen_cmd, dimen_base + null_delimiter_space_code, dimen_base);
+    primitive_tex("scriptspace", assign_dimen_cmd, dimen_base + script_space_code, dimen_base);
+    primitive_tex("predisplaysize", assign_dimen_cmd, dimen_base + pre_display_size_code, dimen_base);
+    primitive_tex("displaywidth", assign_dimen_cmd, dimen_base + display_width_code, dimen_base);
+    primitive_tex("displayindent", assign_dimen_cmd, dimen_base + display_indent_code, dimen_base);
+    primitive_tex("overfullrule", assign_dimen_cmd, dimen_base + overfull_rule_code, dimen_base);
+    primitive_tex("hangindent", assign_dimen_cmd, dimen_base + hang_indent_code, dimen_base);
+    primitive_tex("hoffset", assign_dimen_cmd, dimen_base + h_offset_code, dimen_base);
+    primitive_tex("voffset", assign_dimen_cmd, dimen_base + v_offset_code, dimen_base);
+    primitive_tex("emergencystretch", assign_dimen_cmd, dimen_base + emergency_stretch_code, dimen_base);
+    primitive_luatex("pagewidth", assign_dimen_cmd, dimen_base + page_width_code, dimen_base);
+    primitive_luatex("pageheight", assign_dimen_cmd, dimen_base + page_height_code, dimen_base);
+    primitive_luatex("pxdimen", assign_dimen_cmd, dimen_base + px_dimen_code, dimen_base);
+    primitive_luatex("predisplaygapfactor", assign_int_cmd, int_base + math_pre_display_gap_factor_code, int_base);
+
+    /* Many of \TeX's primitives need no |equiv|, since they are identifiable
+       by their |eq_type| alone. These primitives are loaded into the hash table
+       as follows: */
+
+    primitive_tex(" ", ex_space_cmd, 0, 0);
+    primitive_tex("/", ital_corr_cmd, 0, 0);
+    primitive_tex("accent", accent_cmd, 0, 0);
+    primitive_tex("advance", advance_cmd, 0, 0);
+    primitive_tex("afterassignment", after_assignment_cmd, 0, 0);
+    primitive_tex("aftergroup", after_group_cmd, 0, 0);
+    primitive_tex("begingroup", begin_group_cmd, 0, 0);
+    primitive_tex("char", char_num_cmd, 0, 0);
+    primitive_tex("csname", cs_name_cmd, 0, 0);
+    primitive_luatex("lastnamedcs", cs_name_cmd, 1, 0);
+    primitive_luatex("begincsname", cs_name_cmd, 2, 0);
+    primitive_tex("delimiter", delim_num_cmd, 0, 0);
+    primitive_luatex("Udelimiter", delim_num_cmd, 1, 0);
+    primitive_tex("divide", divide_cmd, 0, 0);
+    primitive_tex("endcsname", end_cs_name_cmd, 0, 0);
+    primitive_tex("endgroup", end_group_cmd, 0, 0);
+    cs_text(frozen_end_group) = maketexstring("endgroup");
+    eqtb[frozen_end_group] = eqtb[cur_val];
+    primitive_tex("expandafter", expand_after_cmd, 0, 0);
+    primitive_tex("font", def_font_cmd, 0, 0);
+    primitive_luatex("letterspacefont", letterspace_font_cmd, 0, 0);
+    primitive_luatex("expandglyphsinfont", normal_cmd, expand_font_code, 0);
+    primitive_luatex("copyfont", copy_font_cmd, 0, 0);
+    primitive_luatex("setfontid", set_font_id_cmd, 0, 0);
+    primitive_tex("fontdimen", assign_font_dimen_cmd, 0, 0);
+    primitive_tex("halign", halign_cmd, 0, 0);
+    primitive_tex("hrule", hrule_cmd, 0, 0);
+    primitive_luatex("nohrule", no_hrule_cmd, 0, 0);
+    primitive_tex("ignorespaces", ignore_spaces_cmd, 0, 0);
+    primitive_tex("insert", insert_cmd, 0, 0);
+    primitive_luatex("leftghost", char_ghost_cmd, 0, 0);
+    primitive_tex("mark", mark_cmd, 0, 0);
+    primitive_tex("mathaccent", math_accent_cmd, 0, 0);
+    primitive_luatex("Umathaccent", math_accent_cmd, 1, 0);
+    primitive_tex("mathchar", math_char_num_cmd, 0, 0);
+    primitive_luatex("Umathchar", math_char_num_cmd, 1, 0);
+    primitive_luatex("Umathcharnum", math_char_num_cmd, 2, 0);
+    primitive_tex("mathchoice", math_choice_cmd, 0, 0);
+    primitive_luatex("Ustack", math_choice_cmd, 1, 0);
+    primitive_tex("multiply", multiply_cmd, 0, 0);
+    primitive_tex("noalign", no_align_cmd, 0, 0);
+    primitive_tex("noboundary", boundary_cmd, 0, 0);
+    primitive_tex("boundary", boundary_cmd, 1, 0);
+    primitive_tex("protrusionboundary", boundary_cmd, 2, 0);
+    primitive_tex("wordboundary", boundary_cmd, 3, 0);
+    primitive_tex("noexpand", no_expand_cmd, 0, 0);
+    primitive_luatex("primitive", no_expand_cmd, 1, 0);
+    primitive_tex("nonscript", non_script_cmd, 0, 0);
+    primitive_tex("omit", omit_cmd, 0, 0);
+    primitive_tex("parshape", set_tex_shape_cmd, par_shape_loc, par_shape_loc);
+    primitive_tex("penalty", break_penalty_cmd, 0, 0);
+    primitive_tex("prevgraf", set_prev_graf_cmd, 0, 0);
+    primitive_tex("radical", radical_cmd, 0, 0);
+    primitive_luatex("Uradical", radical_cmd, 1, 0);
+    primitive_luatex("Uroot", radical_cmd, 2, 0);
+    primitive_luatex("Uunderdelimiter", radical_cmd, 3, 0);
+    primitive_luatex("Uoverdelimiter", radical_cmd, 4, 0);
+    primitive_luatex("Udelimiterunder", radical_cmd, 5, 0);
+    primitive_luatex("Udelimiterover", radical_cmd, 6, 0);
+    primitive_luatex("Uhextensible", radical_cmd, 7, 0);
+    primitive_tex("read", read_to_cs_cmd, 0, 0);
+    primitive_tex("relax", relax_cmd, too_big_char, too_big_char);
+    cs_text(frozen_relax) = maketexstring("relax");
+    eqtb[frozen_relax] = eqtb[cur_val];
+    primitive_luatex("rightghost", char_ghost_cmd, 1, 0);
+    primitive_tex("setbox", set_box_cmd, 0, 0);
+    primitive_tex("the", the_cmd, 0, 0);

@@ Diff output truncated at 1234567 characters. @@


More information about the tex-live-commits mailing list