Browse Source

RELEASE LuaJIT-2.0.0-beta2

Mike Pall 15 years ago
parent
commit
3e30b4475e
46 changed files with 1238 additions and 390 deletions
  1. 56 0
      COPYRIGHT
  2. 76 20
      Makefile
  3. 2 2
      README
  4. 141 6
      doc/api.html
  5. 31 1
      doc/changes.html
  6. 23 0
      doc/faq.html
  7. 33 26
      doc/install.html
  8. 3 3
      doc/running.html
  9. 18 3
      doc/status.html
  10. 82 0
      etc/luajit.1
  11. 24 0
      etc/luajit.pc
  12. 216 106
      src/Makefile
  13. 2 2
      src/Makefile.dep
  14. 2 5
      src/buildvm_asm.c
  15. 6 1
      src/buildvm_fold.c
  16. 2 1
      src/buildvm_peobj.c
  17. 110 1
      src/buildvm_x86.dasc
  18. 5 91
      src/lib_aux.c
  19. 6 3
      src/lib_io.c
  20. 3 2
      src/lib_jit.c
  21. 4 15
      src/lib_math.c
  22. 1 0
      src/lib_package.c
  23. 5 2
      src/lib_string.c
  24. 12 12
      src/lib_table.c
  25. 134 2
      src/lj_api.c
  26. 7 4
      src/lj_asm.c
  27. 15 2
      src/lj_dispatch.c
  28. 46 0
      src/lj_err.c
  29. 4 0
      src/lj_errmsg.h
  30. 1 1
      src/lj_func.c
  31. 1 2
      src/lj_gc.c
  32. 1 0
      src/lj_ir.c
  33. 9 0
      src/lj_lib.h
  34. 2 1
      src/lj_obj.h
  35. 4 4
      src/lj_opt_fold.c
  36. 1 1
      src/lj_opt_loop.c
  37. 2 2
      src/lj_opt_mem.c
  38. 62 8
      src/lj_record.c
  39. 2 2
      src/lj_tab.c
  40. 48 34
      src/lj_trace.c
  41. 1 1
      src/lj_trace.h
  42. 3 3
      src/lj_vm.h
  43. 4 4
      src/lua.hpp
  44. 12 3
      src/luaconf.h
  45. 10 10
      src/luajit.c
  46. 6 4
      src/luajit.h

+ 56 - 0
COPYRIGHT

@@ -0,0 +1,56 @@
+===============================================================================
+LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/
+
+Copyright (C) 2005-2009 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 ]
+
+===============================================================================
+[ LuaJIT includes code from Lua 5.1, which has this license statement: ]
+
+Copyright (C) 1994-2008 Lua.org, PUC-Rio.
+
+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.
+
+===============================================================================
+[ LuaJIT includes code from dlmalloc, which has this license statement: ]
+
+This is a version (aka dlmalloc) of malloc/free/realloc written by
+Doug Lea and released to the public domain, as explained at
+http://creativecommons.org/licenses/publicdomain
+
+===============================================================================

+ 76 - 20
Makefile

@@ -12,46 +12,104 @@
 # Copyright (C) 2005-2009 Mike Pall. See Copyright Notice in luajit.h
 ##############################################################################
 
-BASEVER= 2.0.0
-VERSION= 2.0.0-beta1
+MAJVER=  2
+MINVER=  0
+RELVER=  0
+PREREL=  -beta2
+VERSION= $(MAJVER).$(MINVER).$(RELVER)$(PREREL)
+ABIVER=  5.1
+NODOTABIVER=  51
 
 ##############################################################################
 #
 # Change the installation path as needed and modify src/luaconf.h accordingly.
 # Note: PREFIX must be an absolute path!
 #
-PREFIX= /usr/local
+export PREFIX= /usr/local
 ##############################################################################
 
-INSTALL_BIN= $(PREFIX)/bin
-INSTALL_NAME= luajit-$(VERSION)
-INSTALL_T= $(INSTALL_BIN)/$(INSTALL_NAME)
-INSTALL_TSYM= $(INSTALL_BIN)/luajit
-INSTALL_INC= $(PREFIX)/include/luajit-$(BASEVER)
-INSTALL_JITLIB= $(PREFIX)/share/luajit-$(VERSION)/jit
-
+DPREFIX= $(DESTDIR)$(PREFIX)
+INSTALL_BIN=   $(DPREFIX)/bin
+INSTALL_LIB=   $(DPREFIX)/lib
+INSTALL_SHARE= $(DPREFIX)/share
+INSTALL_INC=   $(DPREFIX)/include/luajit-$(MAJVER).$(MINVER)
+
+INSTALL_JITLIB= $(INSTALL_SHARE)/luajit-$(VERSION)/jit
+INSTALL_LMOD= $(INSTALL_SHARE)/lua/$(ABIVER)
+INSTALL_CMOD= $(INSTALL_LIB)/lua/$(ABIVER)
+INSTALL_MAN= $(INSTALL_SHARE)/man/man1
+INSTALL_PKGCONFIG= $(INSTALL_LIB)/pkgconfig
+
+INSTALL_TNAME= luajit-$(VERSION)
+INSTALL_TSYMNAME= luajit
+INSTALL_ANAME= libluajit-$(ABIVER).a
+INSTALL_SONAME= libluajit-$(ABIVER).so.$(MAJVER).$(MINVER).$(RELVER)
+INSTALL_SOSHORT= libluajit-$(ABIVER).so
+INSTALL_DYLIBNAME= libluajit-$(NODOTABIVER).$(MAJVER).$(MINVER).$(RELVER).dylib
+INSTALL_DYLIBSHORT1= libluajit-$(NODOTABIVER).dylib
+INSTALL_DYLIBSHORT2= libluajit-$(NODOTABIVER).$(MAJVER).dylib
+INSTALL_PCNAME= luajit.pc
+
+INSTALL_STATIC= $(INSTALL_LIB)/$(INSTALL_ANAME)
+INSTALL_DYN= $(INSTALL_LIB)/$(INSTALL_SONAME)
+INSTALL_SHORT1= $(INSTALL_LIB)/$(INSTALL_SOSHORT)
+INSTALL_SHORT2= $(INSTALL_LIB)/$(INSTALL_SOSHORT)
+INSTALL_T= $(INSTALL_BIN)/$(INSTALL_TNAME)
+INSTALL_TSYM= $(INSTALL_BIN)/$(INSTALL_TSYMNAME)
+INSTALL_PC= $(INSTALL_PKGCONFIG)/$(INSTALL_PCNAME)
+
+INSTALL_DIRS= $(INSTALL_BIN) $(INSTALL_LIB) $(INSTALL_INC) $(INSTALL_MAN) \
+  $(INSTALL_PKGCONFIG) $(INSTALL_JITLIB) $(INSTALL_LMOD) $(INSTALL_CMOD)
+
+RM= rm -f
 MKDIR= mkdir -p
-SYMLINK= ln -f -s
+SYMLINK= ln -sf
 INSTALL_X= install -m 0755
 INSTALL_F= install -m 0644
-
-FILES_T= luajit
+LDCONFIG= ldconfig -n
+SED_PC= sed -e "s|^prefix=.*|prefix=$(PREFIX)|"
+
+FILE_T= luajit
+FILE_A= libluajit.a
+FILE_SO= libluajit.so
+FILE_MAN= luajit.1
+FILE_PC= luajit.pc
 FILES_INC= lua.h lualib.h lauxlib.h luaconf.h lua.hpp luajit.h
 FILES_JITLIB= bc.lua v.lua dump.lua dis_x86.lua dis_x64.lua vmdef.lua
 
+ifeq (,$(findstring Windows,$(OS)))
+  ifeq (Darwin,$(shell uname -s))
+    INSTALL_SONAME= $(INSTALL_DYLIBNAME)
+    INSTALL_SHORT1= $(INSTALL_LIB)/$(INSTALL_DYLIBSHORT1)
+    INSTALL_SHORT2= $(INSTALL_LIB)/$(INSTALL_DYLIBSHORT2)
+    LDCONFIG= :
+  endif
+endif
+
 ##############################################################################
 
 INSTALL_DEP= src/luajit
 
-all $(INSTALL_DEP):
+default all $(INSTALL_DEP):
 	@echo "==== Building LuaJIT $(VERSION) ===="
 	$(MAKE) -C src
 	@echo "==== Successfully built LuaJIT $(VERSION) ===="
 
 install: $(INSTALL_DEP)
 	@echo "==== Installing LuaJIT $(VERSION) to $(PREFIX) ===="
-	$(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_JITLIB)
-	cd src && $(INSTALL_X) $(FILES_T) $(INSTALL_T)
+	$(MKDIR) $(INSTALL_DIRS)
+	cd src && $(INSTALL_X) $(FILE_T) $(INSTALL_T)
+	cd src && test -f $(FILE_A) && $(INSTALL_F) $(FILE_A) $(INSTALL_STATIC) || :
+	$(RM) $(INSTALL_DYN) $(INSTALL_SHORT1) $(INSTALL_SHORT2)
+	cd src && test -f $(FILE_SO) && \
+	  $(INSTALL_F) $(FILE_SO) $(INSTALL_DYN) && \
+	  $(LDCONFIG) $(INSTALL_LIB) && \
+	  $(SYMLINK) $(INSTALL_SONAME) $(INSTALL_SHORT1) && \
+	  $(SYMLINK) $(INSTALL_SONAME) $(INSTALL_SHORT2) || :
+	cd etc && $(INSTALL_F) $(FILE_MAN) $(INSTALL_MAN)
+	cd etc && $(SED_PC) $(FILE_PC) > $(FILE_PC).tmp && \
+	  $(INSTALL_F) $(FILE_PC).tmp $(INSTALL_PC) && \
+	  $(RM) $(FILE_PC).tmp
 	cd src && $(INSTALL_F) $(FILES_INC) $(INSTALL_INC)
 	cd lib && $(INSTALL_F) $(FILES_JITLIB) $(INSTALL_JITLIB)
 	@echo "==== Successfully installed LuaJIT $(VERSION) to $(PREFIX) ===="
@@ -59,7 +117,7 @@ install: $(INSTALL_DEP)
 	@echo "Note: the beta releases deliberately do NOT install a symlink for luajit"
 	@echo "You can do this now by running this command (with sudo):"
 	@echo ""
-	@echo "  $(SYMLINK) $(INSTALL_NAME) $(INSTALL_TSYM)"
+	@echo "  $(SYMLINK) $(INSTALL_TNAME) $(INSTALL_TSYM)"
 	@echo ""
 
 ##############################################################################
@@ -77,8 +135,6 @@ cleaner:
 distclean:
 	$(MAKE) -C src distclean
 
-SUB_TARGETS= amalg clean cleaner distclean
-
-.PHONY: all install $(SUB_TARGETS)
+.PHONY: all install amalg clean cleaner distclean
 
 ##############################################################################

+ 2 - 2
README

@@ -1,4 +1,4 @@
-README for LuaJIT 2.0.0-beta1
+README for LuaJIT 2.0.0-beta2
 -----------------------------
 
 LuaJIT is a Just-In-Time (JIT) compiler for the Lua programming language.
@@ -7,7 +7,7 @@ Project Homepage: http://luajit.org/
 
 LuaJIT is Copyright (C) 2005-2009 Mike Pall.
 LuaJIT is free software, released under the MIT/X license.
-See full Copyright Notice in src/luajit.h
+See full Copyright Notice in the COPYRIGHT file or in luajit.h.
 
 Documentation for LuaJIT is available in HTML format.
 Please point your favorite browser to:

+ 141 - 6
doc/api.html

@@ -100,12 +100,6 @@ These functions are typically used with the command line options
 Flushes the whole cache of compiled code.
 </p>
 
-<h3 id="jit_flush_tr"><tt>jit.flush(tr)</tt></h3>
-<p>
-Flushes the code for the specified root trace and all of its
-side traces from the cache.
-</p>
-
 <h3 id="jit_onoff_func"><tt>jit.on(func|true [,true|false])<br>
 jit.off(func|true [,true|false])<br>
 jit.flush(func|true [,true|false])</tt></h3>
@@ -142,6 +136,13 @@ of a module to turn off JIT compilation for the whole module for
 debugging purposes.
 </p>
 
+<h3 id="jit_flush_tr"><tt>status = jit.flush(tr)</tt></h3>
+<p>
+Tries to flush the code for the specified trace and all of its
+side traces from the cache. Returns <tt>true</tt> on success.
+Returns <tt>false</tt> if there are still links to this trace.
+</p>
+
 <h3 id="jit_version"><tt>jit.version</tt></h3>
 <p>
 Contains the LuaJIT version string.
@@ -189,6 +190,140 @@ The debug modules <tt>-jbc</tt>, <tt>-jv</tt> and <tt>-jdump</tt> make
 extensive use of these functions. Please check out their source code,
 if you want to know more.
 </p>
+
+<h2 id="c_api">C API extensions</h2>
+<p>
+LuaJIT adds some extensions to the Lua/C API. The LuaJIT include
+directory must be in the compiler search path (<tt>-I<i>path</i></tt>)
+to be able to include the required header for C code:
+</p>
+<pre class="code">
+#include "luajit.h"
+</pre>
+<p>
+Or for C++ code:
+</p>
+<pre class="code">
+#include "lua.hpp"
+</pre>
+
+<h2 id="luaJIT_setmode"><tt>luaJIT_setmode(L, idx, mode)</tt>
+&mdash; Control VM</h2>
+<p>
+This is a C API extension to allow control of the VM from C code. The
+full prototype of <tt>LuaJIT_setmode</tt> is:
+</p>
+<pre class="code">
+LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode);
+</pre>
+<p>
+The returned status is either success (<tt>1</tt>) or failure (<tt>0</tt>).
+The second argument is either <tt>0</tt> or a stack index (similar to the
+other Lua/C API functions).
+</p>
+<p>
+The third argument specifies the mode, which is 'or'ed with a flag.
+The flag can be <tt>LUAJIT_MODE_OFF</tt> to turn a feature on,
+<tt>LUAJIT_MODE_ON</tt> to turn a feature off, or
+<tt>LUAJIT_MODE_FLUSH</tt> to flush cached code.
+</p>
+<p>
+The following modes are defined:
+</p>
+
+<h3 id="mode_engine"><tt>luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|flag)</tt></h3>
+<p>
+Turn the whole JIT compiler on or off or flush the whole cache of compiled code.
+</p>
+
+<h3 id="mode_func"><tt>luaJIT_setmode(L, idx, LUAJIT_MODE_FUNC|flag)</tt><br>
+<tt>luaJIT_setmode(L, idx, LUAJIT_MODE_ALLFUNC|flag)</tt><br>
+<tt>luaJIT_setmode(L, idx, LUAJIT_MODE_ALLSUBFUNC|flag)</tt></h3>
+<p>
+This sets the mode for the function at the stack index <tt>idx</tt> or
+the parent of the calling function (<tt>idx = 0</tt>). It either
+enables JIT compilation for a function, disables it and flushes any
+already compiled code or only flushes already compiled code. This
+applies recursively to all subfunctions of the function with
+<tt>LUAJIT_MODE_ALLFUNC</tt> or only to the subfunctions with
+<tt>LUAJIT_MODE_ALLSUBFUNC</tt>.
+</p>
+
+<h3 id="mode_engine"><tt>luaJIT_setmode(L, trace,<br>
+&nbsp;&nbsp;LUAJIT_MODE_TRACE|LUAJIT_MODE_FLUSH)</tt></h3>
+<p>
+Tries to flush the code for the specified trace and all of its
+side traces from the cache.
+</p>
+
+<h3 id="mode_engine"><tt>luaJIT_setmode(L, idx, LUAJIT_MODE_WRAPCFUNC|flag)</tt></h3>
+<p>
+This mode defines a wrapper function for calls to C functions. The
+first time this is called with <tt>LUAJIT_MODE_ON</tt>, the stack
+index at <tt>idx</tt> must be a <tt>lightuserdata</tt> object holding
+a pointer to the wrapper function. All <b>subsequently created C
+functions</b> are called through the wrapper functions. After the initial
+definition <tt>idx</tt> can be left at <tt>0</tt> when turning the mode
+on or off.
+</p>
+<p>
+The wrapper function can be used for debugging purposes or to catch
+and convert foreign exceptions. Recommended usage can be seen in this
+C++ code excerpt:
+</p>
+<pre class="code">
+#include &lt;exception&gt;
+#include "lua.hpp"
+
+// Catch C++ exceptions and convert them to Lua error messages.
+// Customize as needed for your own exception classes.
+static int wrap_exceptions(lua_State *L, lua_CFunction f)
+{
+  try {
+    return f(L);  // Call wrapped function and return result.
+  } catch (const char *s) {  // Catch and convert exceptions.
+    lua_pushstring(L, s);
+  } catch (std::exception& e) {
+    lua_pushstring(L, e.what());
+  } catch (...) {
+    lua_pushliteral(L, "caught (...)");
+  }
+  return lua_error(L);  // Rethrow as a Lua error.
+}
+
+static int myregister(lua_State *L)
+{
+  ...
+  // Define wrapper function and enable it.
+  lua_pushlightuserdata(L, (void *)wrap_exceptions);
+  luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_ON);
+  lua_pop(L, 1);
+  luaL_register(L, "mymodule", myfuncs);  // Pass luaL_Reg list.
+  luaJIT_setmode(L, 0, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_OFF);
+  ...
+  // Wrap some more C++ functions which might throw an exception.
+  luaJIT_setmode(L, 0, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_ON);
+  lua_pushcfunction(L, mythrowingfunc1);
+  lua_pushcclosure(L, mythrowingfunc2, 1);
+  luaJIT_setmode(L, 0, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_OFF);
+  ...
+}
+</pre>
+<p>
+Note that you can only define <b>a single global wrapper function</b>,
+so be careful when using this mechanism from multiple C++ modules.
+Also note that this mechanism is not without overhead. It should only
+be enabled for definitions of C++ functions that can actually throw
+exceptions. If you're embedding LuaJIT into an application, only
+enable it <b>after</b> running <tt>luaL_openlibs</tt>.
+</p>
+<p>
+LuaJIT already intercepts exception handling for systems using
+ELF/DWARF2 stack unwinding (e.g. Linux). This is a zero-cost mechanism
+and always enabled. You don't need to use any wrapper functions,
+except when you want to get a more specific error message than
+<tt>"C++&nbsp;exception"</tt>.
+</p>
 <br class="flush">
 </div>
 <div id="foot">

+ 31 - 1
doc/changes.html

@@ -43,7 +43,7 @@ div.major { max-width: 600px; padding: 1em; margin: 1em 0 1em 0; }
 <div id="main">
 <p>
 This is a list of changes between the released versions of LuaJIT.<br>
-The current <span style="color: #c00000;">development version</span> is <strong>LuaJIT&nbsp;2.0.0-beta1</strong>.<br>
+The current <span style="color: #c00000;">development version</span> is <strong>LuaJIT&nbsp;2.0.0-beta2</strong>.<br>
 The current <span style="color: #0000c0;">stable version</span> is <strong>LuaJIT&nbsp;1.1.5</strong>.
 </p>
 <p>
@@ -53,6 +53,36 @@ to see whether newer versions are available.
 </p>
 
 <div class="major" style="background: #ffd0d0;">
+<h2 id="LuaJIT-2.0.0-beta2">LuaJIT 2.0.0-beta2 &mdash; 2009-11-09</h2>
+<ul>
+<li>Reorganize build system. Build static+shared library on POSIX.</li>
+<li>Allow C++ exception conversion on all platforms
+using a wrapper function.</li>
+<li>Automatically catch C++ exceptions and rethrow Lua error
+(ELF/DWARF2 only).</li>
+<li>Check for the correct x87 FPU precision at strategic points.</li>
+<li>Always use wrappers for libm functions.</li>
+<li>Resurrect metamethod name strings before copying them.</li>
+<li>Mark current trace, even if compiler is idle.</li>
+<li>Ensure FILE metatable is created only once.</li>
+<li>Fix type comparisons when different integer types are involved.</li>
+<li>Fix getmetatable() recording.</li>
+<li>Fix TDUP with dead keys in template table.</li>
+<li><tt>jit.flush(tr)</tt> returns status.
+Prevent manual flush of a trace that's still linked.</li>
+<li>Improve register allocation heuristics for invariant references.</li>
+<li>Compile the push/pop variants of <tt>table.insert()</tt> and
+<tt>table.remove()</tt>.</li>
+<li>Compatibility with MSVC <tt>link&nbsp/debug</tt>.</li>
+<li>Fix <tt>lua_iscfunction()</tt>.</li>
+<li>Fix <tt>math.random()</tt> when compiled with <tt>-fpic</tt> (OSX).</li>
+<li>Fix <tt>table.maxn()</tt>.</li>
+<li>Bump <tt>MACOSX_DEPLOYMENT_TARGET</tt> to <tt>10.4</tt></li>
+<li><tt>luaL_check*()</tt> and <tt>luaL_opt*()</tt> now support
+negative arguments, too.<br>
+This matches the behavior of Lua 5.1, but not the specification.</li>
+</ul>
+
 <h2 id="LuaJIT-2.0.0-beta1">LuaJIT 2.0.0-beta1 &mdash; 2009-10-31</h2>
 <ul>
 <li>This is the first public release of LuaJIT 2.0.</li>

+ 23 - 0
doc/faq.html

@@ -72,6 +72,7 @@ Search for: <a href="http://scholar.google.com/scholar?q=JIT+Compiler"><span cla
 Search for: <a href="http://scholar.google.com/scholar?q=Dynamic+Language+Optimizations"><span class="ext">&raquo;</span>&nbsp;Dynamic Language Optimizations</a><br>
 Search for: <a href="http://scholar.google.com/scholar?q=SSA+Form"><span class="ext">&raquo;</span>&nbsp;SSA Form</a><br>
 Search for: <a href="http://scholar.google.com/scholar?q=Linear+Scan+Register+Allocation"><span class="ext">&raquo;</span>&nbsp;Linear Scan Register Allocation</a><br>
+Here is a list of the <a href="http://article.gmane.org/gmane.comp.lang.lua.general/58908"><span class="ext">&raquo;</span>&nbsp;innovative features in LuaJIT</a>.<br>
 And, you know, reading the source is of course the only way to enlightenment. :-)
 </dd>
 </dl>
@@ -86,6 +87,28 @@ functions from Lua 5.0.<br>Please convert your code to the
 vararg syntax</a>.</dd>
 </dl>
 
+<dl>
+<dt>Q: Why do I get this error: "bad FPU precision"?<br>
+<dt>Q: I get weird behavior after initializing Direct3D.<br>
+<dt>Q: Some FPU operations crash after I load a Delphi DLL.<br>
+</dt>
+<dd>
+
+DirectX/Direct3D (up to version 9) sets the x87 FPU to single-precision
+mode by default. This violates the Windows ABI and interferes with the
+operation of many programs &mdash; LuaJIT is affected, too. Please make
+sure you always use the <tt>D3DCREATE_FPU_PRESERVE</tt> flag when
+initializing Direct3D.<br>
+
+Direct3D version 10 or higher do not show this behavior anymore.
+Consider testing your application with older versions, too.<br>
+
+Similarly, the Borland/Delphi runtime modifies the FPU control word and
+enables FP exceptions. Of course this violates the Windows ABI, too.
+Please check the Delphi docs for the Set8087CW method.
+
+</dl>
+
 <dl>
 <dt>Q: Sometimes Ctrl-C fails to stop my Lua program. Why?</dt>
 <dd>The interrupt signal handler sets a Lua debug hook. But this is

+ 33 - 26
doc/install.html

@@ -58,17 +58,15 @@ application under x64-based systems, too.
 <h2>Configuring LuaJIT</h2>
 <p>
 The standard configuration should work fine for most installations.
-Usually there is no need to tweak the settings, except when you want to
-install to a non-standard path. The following three files hold all
-user-configurable settings:
+Usually there is no need to tweak the settings. The following files
+hold all user-configurable settings:
 </p>
 <ul>
-<li><tt>src/luaconf.h</tt> sets some configuration variables, in
-particular the default paths for loading modules.</li>
-<li><tt>Makefile</tt> has settings for installing LuaJIT (POSIX
+<li><tt>src/luaconf.h</tt> sets some configuration variables.</li>
+<li><tt>Makefile</tt> has settings for <b>installing</b> LuaJIT (POSIX
 only).</li>
-<li><tt>src/Makefile</tt> has settings for compiling LuaJIT under POSIX,
-MinGW and Cygwin.</li>
+<li><tt>src/Makefile</tt> has settings for <b>compiling</b> LuaJIT
+under POSIX, MinGW and Cygwin.</li>
 <li><tt>src/msvcbuild.bat</tt> has settings for compiling LuaJIT with
 MSVC.</li>
 </ul>
@@ -97,9 +95,8 @@ terminal window and change to this directory. Now unpack the archive
 and change to the newly created directory:
 </p>
 <pre class="code">
-tar zxf LuaJIT-2.0.0-beta1.tar.gz
-cd LuaJIT-2.0.0-beta1
-</pre>
+tar zxf LuaJIT-2.0.0-beta2.tar.gz
+cd LuaJIT-2.0.0-beta2</pre>
 <h3>Building LuaJIT</h3>
 <p>
 The supplied Makefiles try to auto-detect the settings needed for your
@@ -109,6 +106,18 @@ which is probably the default on your system, anyway. Simply run:
 <pre class="code">
 make
 </pre>
+<p>
+By default modules are only searched under the prefix <tt>/usr/local</tt>.
+You can add an extra prefix to the search paths by appending the
+<tt>PREFIX</tt> option, e.g.:
+</p>
+<pre class="code">
+make PREFIX=/home/myself/lj2
+</pre>
+<p>
+Note for OSX: <tt>MACOSX_DEPLOYMENT_TARGET</tt> is set to <tt>10.4</tt>
+in <tt>src/Makefile</tt>. Change it, if you want to build on an older version.
+</p>
 <h3>Installing LuaJIT</h3>
 <p>
 The top-level Makefile installs LuaJIT by default under
@@ -124,20 +133,19 @@ sudo make install
 Otherwise specify the directory prefix as an absolute path, e.g.:
 </p>
 <pre class="code">
-sudo make install PREFIX=/opt/lj2
+make install PREFIX=/home/myself/lj2
 </pre>
 <p>
-But note that the installation prefix and the prefix for the module paths
-(configured in <tt>src/luaconf.h</tt>) must match.
+Obviously the prefixes given during build and installation need to be the same.
 </p>
 <p style="color: #c00000;">
 Note: to avoid overwriting a previous version, the beta test releases
 only install the LuaJIT executable under the versioned name (i.e.
-<tt>luajit-2.0.0-beta1</tt>). You probably want to create a symlink
+<tt>luajit-2.0.0-beta2</tt>). You probably want to create a symlink
 for convenience, with a command like this:
 </p>
 <pre class="code" style="color: #c00000;">
-sudo ln -sf luajit-2.0.0-beta1 /usr/local/bin/luajit
+sudo ln -sf luajit-2.0.0-beta2&nbsp;/usr/local/bin/luajit
 </pre>
 
 <h2 id="windows">Windows Systems</h2>
@@ -145,8 +153,8 @@ sudo ln -sf luajit-2.0.0-beta1 /usr/local/bin/luajit
 <p>
 Either install one of the open source SDKs
 (<a href="http://mingw.org/"><span class="ext">&raquo;</span>&nbsp;MinGW</a> or
-<a href="http://www.cygwin.com/"><span class="ext">&raquo;</span>&nbsp;Cygwin</a>) which come with modified
-versions of GCC plus the required development headers.
+<a href="http://www.cygwin.com/"><span class="ext">&raquo;</span>&nbsp;Cygwin</a>), which come with a modified
+GCC plus the required development headers.
 </p>
 <p>
 Or install Microsoft's Visual C++ (MSVC) &mdash; the freely downloadable
@@ -159,8 +167,8 @@ Next, download the source package and unpack it using an archive manager
 </p>
 <h3>Building with MSVC</h3>
 <p>
-Open a "Visual Studio .NET Command Prompt" and <tt>cd</tt> to the
-directory where you've unpacked the sources. Then run this command:
+Open a "Visual Studio .NET Command Prompt", <tt>cd</tt> to the
+directory where you've unpacked the sources and run these commands:
 </p>
 <pre class="code">
 cd src
@@ -176,14 +184,12 @@ are in your path. Then <tt>cd</tt> to the directory where
 you've unpacked the sources and run this command for MinGW:
 </p>
 <pre class="code">
-cd src
 mingw32-make
 </pre>
 <p>
 Or this command for Cygwin:
 </p>
 <pre class="code">
-cd src
 make
 </pre>
 <p>
@@ -191,10 +197,11 @@ Then follow the installation instructions below.
 </p>
 <h3>Installing LuaJIT</h3>
 <p>
-Copy <tt>luajit.exe</tt> and <tt>lua51.dll</tt>
-to a newly created directory (any location is ok). Add <tt>lua</tt>
-and <tt>lua\jit</tt> directories below it and copy all Lua files
-from the <tt>lib</tt> directory of the distribution to the latter directory.
+Copy <tt>luajit.exe</tt> and <tt>lua51.dll</tt> (built in the <tt>src</tt>
+directory) to a newly created directory (any location is ok).
+Add <tt>lua</tt> and <tt>lua\jit</tt> directories below it and copy
+all Lua files from the <tt>lib</tt> directory of the distribution
+to the latter directory.
 </p>
 <p>
 There are no hardcoded

+ 3 - 3
doc/running.html

@@ -69,11 +69,11 @@ interactive mode, too.
 <p class="indent" style="color: #c00000;">
 Note: the beta test releases only install under the versioned name on
 POSIX systems (to avoid overwriting a previous version). You either need
-to type <tt>luajit-2.0.0-beta1</tt> to start it or create a symlink
+to type <tt>luajit-2.0.0-beta2</tt> to start it or create a symlink
 with a command like this:
 </p>
 <pre class="code" style="color: #c00000;">
-sudo ln -sf luajit-2.0.0-beta1 /usr/local/bin/luajit
+sudo ln -sf luajit-2.0.0-beta2&nbsp;/usr/local/bin/luajit
 </pre>
 <p>
 Unlike previous versions <b>optimization is turned on by default</b> in
@@ -119,7 +119,7 @@ itself. For a description of their options and output format, please
 read the comment block at the start of their source.
 They can be found in the <tt>lib</tt> directory of the source
 distribution or installed under the <tt>jit</tt> directory. By default
-this is <tt>/usr/local/share/luajit-2.0.0-beta1/jit</tt> on POSIX
+this is <tt>/usr/local/share/luajit-2.0.0-beta2/jit</tt> on POSIX
 systems.
 </p>
 

+ 18 - 3
doc/status.html

@@ -90,7 +90,22 @@ known incompatibilities with standard Lua:
 <ul>
 <li>
 The Lua <b>debug API</b> is missing a couple of features (call/return
-hooks) and shows slightly different behavior (no per-coroutine hooks).
+hooks) and shows slightly different behavior (no per-coroutine hooks,
+no tail call counting).
+</li>
+<li>
+<b>Bytecode</b> currently cannot be loaded or dumped. Note that
+the bytecode format differs from Lua&nbsp;5.1 &mdash; loading foreign
+bytecode is not supported at all.
+</li>
+<li>
+Some of the <b>configuration options</b> of Lua&nbsp;5.1 are not supported:
+<ul>
+<li>The <b>number type</b> cannot be changed (it's always a <tt>double</tt>).</li>
+<li>The stand-alone executable cannot be linked with <b>readline</b>
+to enable line editing. It's planned to add support for loading it
+on-demand.</li>
+</ul>
 </li>
 <li>
 Most other issues you're likely to find (e.g. with the existing test
@@ -105,7 +120,7 @@ demonstrable need is shown.
 <li>
 The <b>JIT compiler</b> is not complete (yet) and falls back to the
 interpreter in some cases. All of this works transparently, so unless
-you use -jv, you'll probably never notice (the interpreter is quite
+you use <tt>-jv</tt>, you'll probably never notice (the interpreter is quite
 fast, too). Here are the known issues:
 <ul>
 <li>
@@ -119,7 +134,7 @@ effort.
 </li>
 <li>
 <b>Recursion</b> is not traced yet. Often no trace will be generated at
-all or some unroll limit will catch it and aborts the trace.
+all or some unroll limit will catch it and abort the trace.
 </li>
 <li>
 The trace compiler currently does not back off specialization for

+ 82 - 0
etc/luajit.1

@@ -0,0 +1,82 @@
+.TH luajit 1 "" "" "LuaJIT documentation"
+.SH NAME
+luajit \- Just-In-Time Compiler for the Lua Language
+\fB
+.SH SYNOPSIS
+.B luajit
+[\fIoptions\fR]... [\fIscript\fR [\fIargs\fR]...]
+.SH "WEB SITE"
+.IR http://luajit.org
+.SH DESCRIPTION
+.PP
+This is the command-line program to run Lua programs with \fBLuaJIT\fR.
+.PP
+\fBLuaJIT\fR is a just-in-time (JIT) compiler for the Lua language.
+The virtual machine (VM) is based on a fast interpreter combined with
+a trace compiler. It can significantly improve the performance of Lua programs.
+.PP
+\fBLuaJIT\fR is API\- and ABI-compatible with the VM of the standard
+Lua\ 5.1 interpreter. When embedding the VM into an application,
+the built library can be used as a drop-in replacement.
+.SH OPTIONS
+.TP
+.BI "\-e " chunk
+Run the given chunk of Lua code.
+.TP
+.BI "\-l " library
+Load the named library, just like \fBrequire("\fR\fIlibrary\fR\fB")\fR.
+.TP
+.BI "\-j " command
+Perform LuaJIT control command (optional space after \fB\-j\fR).
+.TP
+.BI "\-O" [opt]
+Control LuaJIT optimizations.
+.TP
+.B "\-i"
+Run in interactive mode.
+.TP
+.B "\-v"
+Show \fBLuaJIT\fR version.
+.TP
+.B "\-\-"
+Stop processing options.
+.TP
+.B "\-"
+Read script from stdin instead.
+.PP
+After all options are processed, the given \fIscript\fR is run.
+The arguments are passed in the global \fIarg\fR table.
+.PP
+Interactive mode is only entered, if no \fIscript\fR and no \fB\-e\fR
+option is given. Interactive mode can be left with EOF (\fICtrl\-Z\fB).
+.SH EXAMPLES
+.TP
+luajit hello.lua world
+
+Prints "Hello world", assuming \fIhello.lua\fR contains:
+.br
+  print("Hello", arg[1])
+.TP
+luajit \-e "local x=0; for i=1,1e9 do x=x+i end; print(x)"
+
+Calculates the sum of the numbers from 1 to 1000000000.
+.br
+And finishes in a reasonable amount of time, too.
+.TP
+luajit \-jv \-e "for i=1,10 do for j=1,10 do for k=1,100 do end end end"
+
+Runs some nested loops and shows the resulting traces.
+.SH COPYRIGHT
+.PP
+\fBLuaJIT\fR is Copyright \(co 2005-2009 Mike Pall.
+.br
+\fBLuaJIT\fR is open source software, released under the MIT/X license.
+.SH SEE ALSO
+.PP
+More details in the provided HTML docs or at:
+.IR http://luajit.org
+.br
+More about the Lua language can be found at:
+.IR http://lua.org/docs.html
+.PP
+lua(1)

+ 24 - 0
etc/luajit.pc

@@ -0,0 +1,24 @@
+# Package information for LuaJIT to be used by pkg-config.
+majver=2
+minver=0
+relver=0
+version=${majver}.${minver}.${relver}-beta2
+abiver=5.1
+
+prefix=/usr/local
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+libname=luajit-${abiver}
+includedir=${prefix}/include/luajit-${majver}.${minver}
+
+INSTALL_LMOD=${prefix}/share/lua/${abiver}
+INSTALL_CMOD=${prefix}/lib/lua/${abiver}
+
+Name: LuaJIT
+Description: Just-in-time compiler for Lua
+URL: http://luajit.org
+Version: ${version}
+Requires:
+Libs: -L${libdir} -l${libname}
+Libs.private: -Wl,-E -lm -ldl
+Cflags: -I${includedir}

+ 216 - 106
src/Makefile

@@ -8,10 +8,17 @@
 # Copyright (C) 2005-2009 Mike Pall. See Copyright Notice in luajit.h
 ##############################################################################
 
+MAJVER=  2
+MINVER=  0
+RELVER=  0
+ABIVER=  5.1
+NODOTABIVER= 51
+
 ##############################################################################
 # Compiler options: change them as needed. This mainly affects the speed of
 # the JIT compiler itself, not the speed of the JIT compiled code.
 # Turn any of the optional settings on by removing the '#' in front of them.
+# You need to 'make clean' and 'make' again, if you change any options.
 #
 # Note: LuaJIT can only be compiled for x86, and not for x64 (yet)!
 #       In the meantime, the x86 binary runs fine under a x64 OS.
@@ -81,89 +88,142 @@ XCFLAGS=
 #XCFLAGS+= -DLUA_USE_ASSERT
 #
 ##############################################################################
+
+##############################################################################
+# Build mode: override the mode as needed. Default is mixed mode on POSIX.
+# On Windows this is the same as dynamic mode.
+#
+# Mixed mode creates a static + dynamic library and a statically linked luajit.
+BUILDMODE= mixed
+#
+# Static mode creates a static library and a statically linked luajit.
+#BUILDMODE= static
+#
+# Dynamic mode creates a dynamic library and a dynamically linked luajit.
+# Note: this executable will only run when the library is installed!
+#BUILDMODE= dynamic
+##############################################################################
 # You probably don't need to change anything below this line.
 ##############################################################################
 
+##############################################################################
+# Flags and options for host and target.
+##############################################################################
+
 CCOPTIONS= $(CCDEBUG) $(CCOPT) $(CCWARN) $(CFLAGS) $(XCFLAGS)
 LDOPTIONS= $(CCDEBUG) $(LDFLAGS)
 
 HOST_CC= $(CC)
 HOST_RM= rm -f
+# NOTE: The LuaJIT distribution comes with a pre-generated buildvm_*.h.
+# You DO NOT NEED an installed copy of (plain) Lua 5.1 to run DynASM unless
+# you want to MODIFY the corresponding *.dasc file. You can also use LuaJIT
+# itself (bootstrapped from the pre-generated file) to run DynASM of course.
+HOST_LUA= lua
+
 HOST_XCFLAGS=
 HOST_XLDFLAGS=
 HOST_XLIBS=
+HOST_CFLAGS= $(CCOPTIONS) $(HOST_XCFLAGS) $(TARGET_ARCH)
+HOST_LDFLAGS= $(LDOPTIONS) $(HOST_XLDFLAGS)
+HOST_LIBS= $(HOST_XLIBS)
+
+# Cross-compilation example: make CROSS=i586-mingw32msvc- TARGET_SYS=Windows
+CROSS=
+STATIC_CC = $(CROSS)$(CC)
+DYNAMIC_CC = $(CROSS)$(CC) -fPIC
+TARGET_CC= $(STATIC_CC)
+TARGET_STCC= $(STATIC_CC)
+TARGET_DYNCC= $(DYNAMIC_CC)
+TARGET_LD= $(CROSS)$(CC)
+TARGET_AR= $(CROSS)ar rcus
+TARGET_STRIP= $(CROSS)strip
+
+TARGET_SONAME= libluajit-$(ABIVER).so.$(MAJVER)
+TARGET_DYLIBNAME= libluajit-$(NODOTABIVER).$(MAJVER).$(MINVER).$(RELVER).dylib
+TARGET_DLLNAME= lua$(NODOTABIVER).dll
+TARGET_XSHLDFLAGS= -shared -fPIC -Wl,-soname,$(TARGET_SONAME)
+TARGET_DYNXLDOPTS=
 
-TARGET_CC= $(CC)
-TARGET_STRIP= strip
-TARGET_XCFLAGS= -D_FILE_OFFSET_BITS=64
-TARGET_XLDFLAGS=
-TARGET_XSHLDFLAGS= -shared
-TARGET_XLIBS=
 TARGET_ARCH= $(patsubst %,-DLUAJIT_TARGET=LUAJIT_ARCH_%,$(TARGET))
 TARGET_DISABLE= -U_FORTIFY_SOURCE
-ifneq (,$(findstring stack-protector,$(shell $(CC) -dumpspecs)))
+ifneq (,$(findstring stack-protector,$(shell $(TARGET_CC) -dumpspecs)))
   TARGET_DISABLE+= -fno-stack-protector
 endif
 
+TARGET_XCFLAGS= -D_FILE_OFFSET_BITS=64
+TARGET_XLDFLAGS=
+TARGET_XLDOPTS=
+TARGET_XLIBS=
+TARGET_CFLAGS= $(CCOPTIONS) $(TARGET_DISABLE) $(TARGET_XCFLAGS)
+TARGET_LDFLAGS= $(LDOPTIONS) $(TARGET_XLDFLAGS) $(TARGET_XLDOPTS)
+TARGET_SHLDFLAGS= $(LDOPTIONS) $(TARGET_XSHLDFLAGS)
+TARGET_LIBS= -lm $(TARGET_XLIBS)
+
+ifneq (,$(PREFIX))
+ifneq (/usr/local,$(PREFIX))
+  TARGET_XCFLAGS+= -DLUA_XROOT=\"$(PREFIX)/\"
+  ifneq (/usr,$(PREFIX))
+    TARGET_DYNXLDOPTS= -Wl,-rpath,$(PREFIX)/lib
+  endif
+endif
+endif
+
+##############################################################################
+# System detection.
+##############################################################################
+
 ifneq (,$(findstring Windows,$(OS)))
-  TARGET_SYS= Windows
+  HOST_SYS= Windows
 else
-  TARGET_SYS:= $(shell uname -s)
+  HOST_SYS:= $(shell uname -s)
   ifneq (,$(findstring CYGWIN,$(TARGET_SYS)))
-    TARGET_SYS= Windows
+    HOST_SYS= Windows
   endif
 endif
+ifeq (Windows,$(HOST_SYS))
+  HOST_RM= del
+endif
 
-ifeq (Linux,$(TARGET_SYS))
-  TARGET_XLIBS= -ldl
-  TARGET_XLDFLAGS= -Wl,-E
-else
+TARGET_SYS= $(HOST_SYS)
 ifeq (Windows,$(TARGET_SYS))
-  HOST_RM= del
-  TARGET_STRIP= strip --strip-unneeded
+  TARGET_STRIP+= --strip-unneeded
+  TARGET_XSHLDFLAGS= -shared
+  TARGET_DYNXLDOPTS=
 else
 ifeq (Darwin,$(TARGET_SYS))
-  TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup
-  TARGET_STRIP= strip -x
-  export MACOSX_DEPLOYMENT_TARGET=10.3
+  export MACOSX_DEPLOYMENT_TARGET=10.4
+  TARGET_STRIP+= -x
+  TARGET_AR+= 2>/dev/null
+  TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC
+  ifneq (,$(TARGET_DYNXLDOPTS))
+    TARGET_DYNXLDOPTS=
+    TARGET_XSHLDFLAGS+= -install_name $(PREFIX)/lib/$(TARGET_DYLIBNAME)
+  endif
 else
   TARGET_XLDFLAGS= -Wl,-E
+  ifeq (Linux,$(TARGET_SYS))
+    TARGET_XLIBS= -ldl
+  endif
 endif
 endif
-endif
-
-# NOTE: The LuaJIT distribution comes with a pre-generated buildvm_*.h.
-# You DO NOT NEED an installed copy of (plain) Lua 5.1 to run DynASM unless
-# you want to MODIFY the corresponding *.dasc file. You can also use LuaJIT
-# itself (bootstrapped from the pre-generated file) to run DynASM of course.
-DASM_LUA= lua
-
-Q= @
-E= @echo
-#Q=
-#E= @:
-
-##############################################################################
 
-TARGET_CFLAGS= $(CCOPTIONS) $(TARGET_DISABLE) $(TARGET_XCFLAGS)
-TARGET_LDFLAGS= $(LDOPTIONS) $(TARGET_XLDFLAGS)
-TARGET_SHLDFLAGS= $(LDOPTIONS) $(TARGET_XSHLDFLAGS)
-TARGET_LIBS= -lm $(TARGET_XLIBS)
 ifneq (,$(CCDEBUG))
   TARGET_STRIP= @:
 endif
 
-HOST_CFLAGS= $(CCOPTIONS) $(HOST_XCFLAGS) $(TARGET_ARCH)
-HOST_LDFLAGS= $(LDOPTIONS) $(HOST_XLDFLAGS)
-HOST_LIBS= $(HOST_XLIBS)
+##############################################################################
+# Files and pathnames.
+##############################################################################
 
 DASM_DIR= ../dynasm
-DASM= $(DASM_LUA) $(DASM_DIR)/dynasm.lua
+DASM= $(HOST_LUA) $(DASM_DIR)/dynasm.lua
 DASM_FLAGS=
 DASM_DISTFLAGS= -LN
 
 BUILDVM_O= buildvm.o buildvm_asm.o buildvm_peobj.o buildvm_lib.o buildvm_fold.o
 BUILDVM_T= buildvm
+BUILDVM_X= ./$(BUILDVM_T)
 
 HOST_O= $(BUILDVM_O)
 HOST_T= $(BUILDVM_T)
@@ -188,53 +248,113 @@ LJCORE_O= lj_gc.o lj_err.o lj_ctype.o lj_bc.o lj_obj.o \
 	  $(LJLIB_O) lib_init.o
 
 LJVMCORE_O= $(LJVM_O) $(LJCORE_O)
+LJVMCORE_DYNO= $(LJVMCORE_O:.o=_dyn.o)
+
+LIB_VMDEF= ../lib/vmdef.lua
+LIB_VMDEFP= $(LIB_VMDEF)
 
-# NYI: Need complete support for building as a shared library on POSIX.
-#      This is currently *only* suitable for MinGW and Cygwin, see below.
 LUAJIT_O= luajit.o
-LUAJIT_SO= luajit.so
+LUAJIT_A= libluajit.a
+LUAJIT_SO= libluajit.so
 LUAJIT_T= luajit
 
-LIB_VMDEF= ../lib/vmdef.lua
+ALL_T= $(LUAJIT_T) $(LUAJIT_A) $(LUAJIT_SO) $(BUILDVM_T)
+ALL_GEN= $(LJVM_S) lj_ffdef.h lj_libdef.h lj_recdef.h $(LIB_VMDEFP) lj_folddef.h
+ALL_DYNGEN= buildvm_x86.h
+WIN_RM= *.obj *.lib *.exp *.dll *.exe *.manifest *.pdb *.ilk
+ALL_RM= $(ALL_T) $(ALL_GEN) *.o $(WIN_RM)
 
-TARGET_DEP= $(LIB_VMDEF)
-TARGET_O= $(LJVMCORE_O) $(LUAJIT_O)
-TARGET_T= $(LUAJIT_T)
+##############################################################################
+# Build mode handling.
+##############################################################################
 
-ALL_GEN= $(LJVM_S) lj_ffdef.h lj_libdef.h lj_recdef.h $(LIB_VMDEF) lj_folddef.h
-ALL_DYNGEN= buildvm_x86.h
-WIN_RM= *.obj *.lib *.exp *.dll *.exe *.manifest
-ALL_RM= $(LUAJIT_T) $(LUAJIT_SO) $(HOST_T) $(ALL_GEN) *.o $(WIN_RM)
+# Mixed mode defaults.
+TARGET_O= $(LUAJIT_A)
+TARGET_T= $(LUAJIT_T) $(LUAJIT_SO)
+TARGET_DEP= $(LIB_VMDEF) $(LUAJIT_SO)
 
+ifeq (Windows,$(HOST_SYS))
+  BUILDVM_T= buildvm.exe
+  LIB_VMDEFP= $(subst /,\\,$(LIB_VMDEF))
+endif
 ifeq (Windows,$(TARGET_SYS))
+  DYNAMIC_CC= $(STATIC_CC)
   LJVM_BOUT= $(LJVM_O)
   LJVM_MODE= peobj
-  LIB_VMDEF= ..\lib\vmdef.lua
-  # Imported symbols are bound to a specific DLL name under Windows.
-  LUAJIT_SO= lua51.dll
+  LUAJIT_SO= $(TARGET_DLLNAME)
   LUAJIT_T= luajit.exe
-  BUILDVM_T= buildvm.exe
-  #
-  # You can comment out the following two lines to build a static executable.
-  # But then you won't be able to dynamically load any C modules, because
-  # they bind to lua51.dll.
-  #
-  TARGET_XCFLAGS+= -DLUA_BUILD_AS_DLL
-  TARGET_O= $(LUAJIT_SO) $(LUAJIT_O)
+  ifneq ($(HOST_SYS),$(TARGET_SYS))
+    HOST_XCFLAGS+= -malign-double
+  endif
+  # Mixed mode is not supported on Windows. And static mode doesn't work well.
+  # C modules cannot be loaded, because they bind to lua51.dll.
+  ifneq (static,$(BUILDMODE))
+    BUILDMODE= dynamic
+    TARGET_XCFLAGS+= -DLUA_BUILD_AS_DLL
+  endif
 endif
 
-##############################################################################
+ifeq (static,$(BUILDMODE))
+  TARGET_DYNCC= @:
+  TARGET_T= $(LUAJIT_T)
+  TARGET_DEP= $(LIB_VMDEF)
+else
+ifeq (dynamic,$(BUILDMODE))
+  TARGET_CC= $(DYNAMIC_CC)
+  TARGET_DYNCC= @:
+  LJVMCORE_DYNO= $(LJVMCORE_O)
+  TARGET_O= $(LUAJIT_SO)
+  TARGET_XLDOPTS= $(TARGET_DYNXLDOPTS)
+else
+ifeq (Darwin,$(TARGET_SYS))
+  TARGET_DYNCC= @:
+  LJVMCORE_DYNO= $(LJVMCORE_O)
+endif
+endif
+endif
 
-default: $(TARGET_T)
+Q= @
+E= @echo
+#Q=
+#E= @:
 
-all:	$(TARGET_T)
+##############################################################################
+# Make targets.
+##############################################################################
+
+default all:	$(TARGET_T)
 
 amalg:
 	@grep "^[+|]" ljamalg.c
 	$(MAKE) all "LJCORE_O=ljamalg.o"
 
-MAKE_TARGETS= amalg
+clean:
+	$(HOST_RM) $(ALL_RM)
+
+cleaner:
+	$(HOST_RM) $(ALL_RM) $(ALL_DYNGEN)
+
+distclean:	clean
+	$(E) "DYNASM    $@"
+	$(Q)$(DASM) $(DASM_DISTFLAGS) -o buildvm_x86.h buildvm_x86.dasc
+
+depend:
+	@test -f lj_ffdef.h || touch lj_ffdef.h
+	@test -f lj_libdef.h || touch lj_libdef.h
+	@test -f lj_recdef.h || touch lj_recdef.h
+	@test -f lj_folddef.h || touch lj_folddef.h
+	@test -f buildvm_x86.h || touch buildvm_x86.h
+	@$(HOST_CC) $(HOST_CFLAGS) -MM *.c | sed "s|$(DASM_DIR)|\$$(DASM_DIR)|g" >Makefile.dep
+	@test -s lj_ffdef.h || $(HOST_RM) lj_ffdef.h
+	@test -s lj_libdef.h || $(HOST_RM) lj_libdef.h
+	@test -s lj_recdef.h || $(HOST_RM) lj_recdef.h
+	@test -s lj_folddef.h || $(HOST_RM) lj_folddef.h
+	@test -s buildvm_x86.h || $(HOST_RM) buildvm_x86.h
+
+.PHONY: default all amalg clean cleaner distclean depend
 
+##############################################################################
+# Rules for generated files.
 ##############################################################################
 
 buildvm_x86.h: buildvm_x86.dasc
@@ -247,80 +367,70 @@ $(BUILDVM_T): $(BUILDVM_O)
 
 $(LJVM_BOUT): $(BUILDVM_T)
 	$(E) "BUILDVM   $@"
-	$(Q)./$(BUILDVM_T) -m $(LJVM_MODE) -o $@
+	$(Q)$(BUILDVM_X) -m $(LJVM_MODE) -o $@
 
 lj_ffdef.h: $(BUILDVM_T) $(LJLIB_C)
 	$(E) "BUILDVM   $@"
-	$(Q)./$(BUILDVM_T) -m ffdef -o $@ $(LJLIB_C)
+	$(Q)$(BUILDVM_X) -m ffdef -o $@ $(LJLIB_C)
 
 lj_libdef.h: $(BUILDVM_T) $(LJLIB_C)
 	$(E) "BUILDVM   $@"
-	$(Q)./$(BUILDVM_T) -m libdef -o $@ $(LJLIB_C)
+	$(Q)$(BUILDVM_X) -m libdef -o $@ $(LJLIB_C)
 
 lj_recdef.h: $(BUILDVM_T) $(LJLIB_C)
 	$(E) "BUILDVM   $@"
-	$(Q)./$(BUILDVM_T) -m recdef -o $@ $(LJLIB_C)
+	$(Q)$(BUILDVM_X) -m recdef -o $@ $(LJLIB_C)
 
 $(LIB_VMDEF): $(BUILDVM_T) $(LJLIB_C)
 	$(E) "BUILDVM   $@"
-	$(Q)./$(BUILDVM_T) -m vmdef -o $@ $(LJLIB_C)
+	$(Q)$(BUILDVM_X) -m vmdef -o $(LIB_VMDEFP) $(LJLIB_C)
 
 lj_folddef.h: $(BUILDVM_T) lj_opt_fold.c
 	$(E) "BUILDVM   $@"
-	$(Q)./$(BUILDVM_T) -m folddef -o $@ lj_opt_fold.c
-
-$(LUAJIT_SO): $(LJVMCORE_O)
-	$(E) "LINK      $@"
-	$(Q)$(TARGET_CC) $(TARGET_SHLDFLAGS) -o $@ $(LJVMCORE_O) $(TARGET_LIBS)
-	$(Q)$(TARGET_STRIP) $@
-
-$(LUAJIT_T): $(TARGET_O) $(TARGET_DEP)
-	$(E) "LINK      $@"
-	$(Q)$(TARGET_CC) $(TARGET_LDFLAGS) -o $@ $(TARGET_O) $(TARGET_LIBS)
-	$(Q)$(TARGET_STRIP) $@
-	$(E) "OK        Successfully built LuaJIT"
+	$(Q)$(BUILDVM_X) -m folddef -o $@ lj_opt_fold.c
 
 ##############################################################################
+# Object file rules.
+##############################################################################
 
 %.o: %.c
 	$(E) "CC        $@"
+	$(Q)$(TARGET_DYNCC) $(TARGET_CFLAGS) -c -o $(@:.o=_dyn.o) $<
 	$(Q)$(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ $<
 
 %.o: %.s
 	$(E) "ASM       $@"
+	$(Q)$(TARGET_DYNCC) $(TARGET_CFLAGS) -c -o $(@:.o=_dyn.o) $<
 	$(Q)$(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ $<
 
+$(LUAJIT_O):
+	$(E) "CC        $@"
+	$(Q)$(TARGET_STCC) $(TARGET_CFLAGS) -c -o $@ $<
+
 $(HOST_O): %.o: %.c
 	$(E) "HOSTCC    $@"
 	$(Q)$(HOST_CC) $(HOST_CFLAGS) -c -o $@ $<
 
 include Makefile.dep
 
+##############################################################################
+# Target file rules.
 ##############################################################################
 
-clean:
-	$(HOST_RM) $(ALL_RM)
-
-cleaner:	clean
-	$(HOST_RM) $(ALL_DYNGEN)
+$(LUAJIT_A): $(LJVMCORE_O)
+	$(E) "AR        $@"
+	$(Q)$(TARGET_AR) $@ $(LJVMCORE_O)
 
-distclean:	clean
-	$(E) "DYNASM    $@"
-	$(Q)$(DASM) $(DASM_DISTFLAGS) -o buildvm_x86.h buildvm_x86.dasc
-
-depend:
-	@test -f lj_ffdef.h || touch lj_ffdef.h
-	@test -f lj_libdef.h || touch lj_libdef.h
-	@test -f lj_recdef.h || touch lj_recdef.h
-	@test -f lj_folddef.h || touch lj_folddef.h
-	@test -f buildvm_x86.h || touch buildvm_x86.h
-	@$(HOST_CC) $(HOST_CFLAGS) -MM *.c | sed "s|$(DASM_DIR)|\$$(DASM_DIR)|g" >Makefile.dep
-	@test -s lj_ffdef.h || $(HOST_RM) lj_ffdef.h
-	@test -s lj_libdef.h || $(HOST_RM) lj_libdef.h
-	@test -s lj_recdef.h || $(HOST_RM) lj_recdef.h
-	@test -s lj_folddef.h || $(HOST_RM) lj_folddef.h
-	@test -s buildvm_x86.h || $(HOST_RM) buildvm_x86.h
+# The dependency on _O, but linking with _DYNO is intentional.
+$(LUAJIT_SO): $(LJVMCORE_O)
+	$(E) "DYNLINK   $@"
+	$(Q)$(TARGET_LD) $(TARGET_SHLDFLAGS) -o $@ $(LJVMCORE_DYNO) $(TARGET_LIBS)
+	$(Q)$(TARGET_STRIP) $@
 
-.PHONY: default all $(MAKE_TARGETS) clean cleaner distclean depend
+$(LUAJIT_T): $(TARGET_O) $(LUAJIT_O) $(TARGET_DEP)
+	$(E) "LINK      $@"
+	$(Q)$(TARGET_LD) $(TARGET_LDFLAGS) -o $@ $(LUAJIT_O) $(TARGET_O) $(TARGET_LIBS)
+	$(Q)$(TARGET_STRIP) $@
+	$(E) "OK        Successfully built LuaJIT"
 
 ##############################################################################

+ 2 - 2
src/Makefile.dep

@@ -34,8 +34,8 @@ lib_os.o: lib_os.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
 lib_package.o: lib_package.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
   lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h
 lib_string.o: lib_string.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
-  lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_state.h \
-  lj_ff.h lj_ffdef.h lj_ctype.h lj_lib.h lj_libdef.h
+  lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h \
+  lj_state.h lj_ff.h lj_ffdef.h lj_ctype.h lj_lib.h lj_libdef.h
 lib_table.o: lib_table.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
   lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_lib.h \
   lj_libdef.h

+ 2 - 5
src/buildvm_asm.c

@@ -71,10 +71,7 @@ err:
     exit(1);
   }
   emit_asm_bytes(ctx, cp, n);
-  if (!strncmp(sym, LABEL_PREFIX, sizeof(LABEL_PREFIX)-1))
-    fprintf(ctx->fp, "\t%s _%s\n", opname, sym);
-  else
-    fprintf(ctx->fp, "\t%s _" LABEL_PREFIX "wrapper_%s\n", opname, sym);
+  fprintf(ctx->fp, "\t%s _%s\n", opname, sym);
 }
 
 /* Emit an assembler label. */
@@ -135,7 +132,7 @@ void emit_asm(BuildCtx *ctx)
   fprintf(ctx->fp, "\t.text\n");
   emit_asm_align(ctx, 4);
 
-  emit_asm_label(ctx, LABEL_ASM_BEGIN, 0, 1);
+  emit_asm_label(ctx, LABEL_ASM_BEGIN, 0, 0);
   if (ctx->mode == BUILD_elfasm)
     fprintf(ctx->fp, ".Lbegin:\n");
 

+ 6 - 1
src/buildvm_fold.c

@@ -188,7 +188,12 @@ void emit_fold(BuildCtx *ctx)
       } else if ((p[0] == 'F' || p[0] == 'X') && p[1] == '(' && q) {
 	p += 2;
 	*q = '\0';
-	fprintf(ctx->fp, funcidx ? ",\n  %s" : "  %s", p);
+	if (funcidx)
+	  fprintf(ctx->fp, ",\n");
+	if (p[-2] == 'X')
+	  fprintf(ctx->fp, "  %s", p);
+	else
+	  fprintf(ctx->fp, "  fold_%s", p);
 	funcidx++;
       } else {
 	buf[strlen(buf)-1] = '\0';

+ 2 - 1
src/buildvm_peobj.c

@@ -264,7 +264,8 @@ void emit_peobj(BuildCtx *ctx)
       emit_peobj_sym(ctx, name, 0,
 		     PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
     }
-    emit_peobj_sym_func(ctx, PEOBJ_SYM_PREFIX LABEL_ASM_BEGIN, 0);
+    emit_peobj_sym(ctx, PEOBJ_SYM_PREFIX LABEL_ASM_BEGIN, 0,
+		   PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN);
     for (i = nzsym; i < ctx->nsym; i++) {
       int pi = ctx->perm[i];
       if (pi >= ctx->npc) {

+ 110 - 1
src/buildvm_x86.dasc

@@ -287,6 +287,35 @@ static void build_subroutines(BuildCtx *ctx, int cmov)
   |  lea RA, [BASE+RA*8]
   |  jmp <9
   |
+  |->gate_cwrap:			// Call gate for wrapped C functions.
+  |  // RA = new base, RB = CFUNC, RC = nargs+1, (BASE = old base), PC = return
+  |  mov [RA-4], PC
+  |  mov KBASE, CFUNC:RB->f
+  |  mov L:RB, SAVE_L
+  |  lea RC, [RA+NARGS:RC*8-8]
+  |  mov L:RB->base, RA
+  |  lea RA, [RC+8*LUA_MINSTACK]
+  |  mov ARG2, KBASE
+  |  mov ARG1, L:RB
+  |  mov L:RB->top, RC
+  |  cmp RA, L:RB->maxstack
+  |  ja ->gate_c_growstack		// Need to grow stack.
+  |  set_vmstate C
+  |  // (lua_State *L, lua_CFunction f)
+  |  call aword [DISPATCH+DISPATCH_GL(wrapf)]
+  |  set_vmstate INTERP
+  |  // nresults returned in eax (RD).
+  |  mov BASE, L:RB->base
+  |  lea RA, [BASE+RD*8]
+  |  neg RA
+  |  add RA, L:RB->top			// RA = (L->top-(L->base+nresults))*8
+  |->vm_returnc:
+  |  add RD, 1				// RD = nresults+1
+  |  mov NRESULTS, RD
+  |  test PC, FRAME_TYPE
+  |  jz ->BC_RET_Z			// Handle regular return to Lua.
+  |  jmp ->vm_return
+  |
   |->gate_c:				// Call gate for C functions.
   |  // RA = new base, RB = CFUNC, RC = nargs+1, (BASE = old base), PC = return
   |  mov [RA-4], PC
@@ -312,6 +341,7 @@ static void build_subroutines(BuildCtx *ctx, int cmov)
   |  mov NRESULTS, RD
   |  test PC, FRAME_TYPE
   |  jz ->BC_RET_Z			// Handle regular return to Lua.
+  |  // Fallthrough.
   |
   |//-- Return handling (non-inline) ---------------------------------------
   |
@@ -1455,7 +1485,7 @@ static void build_subroutines(BuildCtx *ctx, int cmov)
   |  mov ARG5, RA
   |  fstp FPARG1
   |  mov RB, BASE
-  |  call extern func
+  |  call extern lj_wrapper_ .. func
   |  mov RA, ARG5
   |  mov BASE, RB
   |  jmp ->fff_resn
@@ -3584,6 +3614,85 @@ static void emit_asm_debug(BuildCtx *ctx)
 	"\t.byte 0x83\n\t.uleb128 0x5\n"	/* offset ebx */
 	"\t.align 4\n"
 	".LEFDE0:\n\n", (int)ctx->codesz);
+    fprintf(ctx->fp, "\t.section .eh_frame,\"a\",@progbits\n");
+    fprintf(ctx->fp,
+	".Lframe1:\n"
+	"\t.long .LECIE1-.LSCIE1\n"
+	".LSCIE1:\n"
+	"\t.long 0\n"
+	"\t.byte 0x1\n"
+	"\t.string \"zPR\"\n"
+	"\t.uleb128 0x1\n"
+	"\t.sleb128 -4\n"
+	"\t.byte 0x8\n"
+	"\t.uleb128 6\n"			/* augmentation length */
+	"\t.byte 0x1b\n"			/* pcrel|sdata4 */
+	"\t.long lj_err_unwind_dwarf-.\n"
+	"\t.byte 0x1b\n"			/* pcrel|sdata4 */
+	"\t.byte 0xc\n\t.uleb128 0x4\n\t.uleb128 0x4\n"
+	"\t.byte 0x88\n\t.uleb128 0x1\n"
+	"\t.align 4\n"
+	".LECIE1:\n\n");
+    fprintf(ctx->fp,
+	".LSFDE1:\n"
+	"\t.long .LEFDE1-.LASFDE1\n"
+	".LASFDE1:\n"
+	"\t.long .LASFDE1-.Lframe1\n"
+	"\t.long .Lbegin-.\n"
+	"\t.long %d\n"
+	"\t.uleb128 0\n"			/* augmentation length */
+	"\t.byte 0xe\n\t.uleb128 0x30\n"	/* def_cfa_offset */
+	"\t.byte 0x85\n\t.uleb128 0x2\n"	/* offset ebp */
+	"\t.byte 0x87\n\t.uleb128 0x3\n"	/* offset edi */
+	"\t.byte 0x86\n\t.uleb128 0x4\n"	/* offset esi */
+	"\t.byte 0x83\n\t.uleb128 0x5\n"	/* offset ebx */
+	"\t.align 4\n"
+	".LEFDE1:\n\n", (int)ctx->codesz);
+    break;
+  case BUILD_machasm:
+    /* NYI: OSX ignores it. Something must be missing. */
+    fprintf(ctx->fp, "\t.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support\n");
+    fprintf(ctx->fp,
+	"EH_frame1:\n"
+	"\t.set L$set$0,LECIE1-LSCIE1\n"
+	"\t.long L$set$0\n"
+	"LSCIE1:\n"
+	"\t.long 0\n"
+	"\t.byte 0x1\n"
+	"\t.ascii \"zPR\"\n"
+	"\t.byte 0x1\n"
+	"\t.byte 128-4\n"
+	"\t.byte 0x8\n"
+	"\t.byte 6\n"				/* augmentation length */
+	"\t.byte 0x9b\n"			/* indirect|pcrel|sdata4 */
+	"\t.long L_lj_err_unwind_dwarf$non_lazy_ptr-.\n"
+	"\t.byte 0x1b\n"			/* pcrel|sdata4 */
+	"\t.byte 0xc\n\t.byte 0x5\n\t.byte 0x4\n"  /* esp=5 on 32 bit MACH-O. */
+	"\t.byte 0x88\n\t.byte 0x1\n"
+	"\t.align 2\n"
+	"LECIE1:\n\n");
+    fprintf(ctx->fp,
+	"_lj_vm_asm_begin.eh:\n"
+	"LSFDE1:\n"
+	"\t.set L$set$1,LEFDE1-LASFDE1\n"
+	"\t.long L$set$1\n"
+	"LASFDE1:\n"
+	"\t.long LASFDE1-EH_frame1\n"
+	"\t.long _lj_vm_asm_begin-.\n"
+	"\t.long %d\n"
+	"\t.byte 0\n"				/* augmentation length */
+	"\t.byte 0xe\n\t.byte 0x30\n"		/* def_cfa_offset */
+	"\t.byte 0x84\n\t.byte 0x2\n"		/* offset ebp (4 for MACH-O)*/
+	"\t.byte 0x87\n\t.byte 0x3\n"		/* offset edi */
+	"\t.byte 0x86\n\t.byte 0x4\n"		/* offset esi */
+	"\t.byte 0x83\n\t.byte 0x5\n"		/* offset ebx */
+	"\t.align 2\n"
+	"LEFDE1:\n\n", (int)ctx->codesz);
+      fprintf(ctx->fp,
+	"\t.non_lazy_symbol_pointer\n"
+	"L_lj_err_unwind_dwarf$non_lazy_ptr:\n"
+	".indirect_symbol _lj_err_unwind_dwarf\n"
+	".long 0\n");
     break;
   default:  /* Difficult for other modes. */
     break;

+ 5 - 91
src/lib_aux.c

@@ -20,97 +20,6 @@
 #include "lj_err.h"
 #include "lj_lib.h"
 
-/* convert a stack index to positive */
-#define abs_index(L, i) \
-  ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
-
-/* -- Type checks --------------------------------------------------------- */
-
-LUALIB_API void luaL_checkstack(lua_State *L, int size, const char *msg)
-{
-  if (!lua_checkstack(L, size))
-    lj_err_callerv(L, LJ_ERR_STKOVM, msg);
-}
-
-LUALIB_API void luaL_checktype(lua_State *L, int narg, int tt)
-{
-  if (lua_type(L, narg) != tt)
-    lj_err_argt(L, narg, tt);
-}
-
-LUALIB_API void luaL_checkany(lua_State *L, int narg)
-{
-  lj_lib_checkany(L, narg);
-}
-
-LUALIB_API const char *luaL_checklstring(lua_State *L, int narg, size_t *len)
-{
-  GCstr *s = lj_lib_checkstr(L, narg);
-  if (len != NULL) *len = s->len;
-  return strdata(s);
-}
-
-LUALIB_API const char *luaL_optlstring(lua_State *L, int narg,
-				       const char *def, size_t *len)
-{
-  GCstr *s = lj_lib_optstr(L, narg);
-  if (s) {
-    if (len != NULL) *len = s->len;
-    return strdata(s);
-  }
-  if (len != NULL) *len = def ? strlen(def) : 0;
-  return def;
-}
-
-LUALIB_API lua_Number luaL_checknumber(lua_State *L, int narg)
-{
-  return lj_lib_checknum(L, narg);
-}
-
-LUALIB_API lua_Number luaL_optnumber(lua_State *L, int narg, lua_Number def)
-{
-  lj_lib_opt(L, narg,
-    return lj_lib_checknum(L, narg);
-  ,
-    return def;
-  )
-}
-
-LUALIB_API lua_Integer luaL_checkinteger(lua_State *L, int narg)
-{
-#if LJ_64
-  return (lua_Integer)lj_lib_checknum(L, narg);
-#else
-  return lj_lib_checkint(L, narg);
-#endif
-}
-
-LUALIB_API lua_Integer luaL_optinteger(lua_State *L, int narg, lua_Integer def)
-{
-#if LJ_64
-  lj_lib_opt(L, narg,
-    return (lua_Integer)lj_lib_checknum(L, narg);
-  ,
-    return def;
-  )
-#else
-  return lj_lib_optint(L, narg, def);
-#endif
-}
-
-LUALIB_API int luaL_checkoption(lua_State *L, int narg, const char *def,
-				const char *const lst[])
-{
-  GCstr *s = lj_lib_optstr(L, narg);
-  const char *opt = s ? strdata(s) : def;
-  uint32_t i;
-  if (!opt) lj_err_argt(L, narg, LUA_TSTRING);
-  for (i = 0; lst[i]; i++)
-    if (strcmp(lst[i], opt) == 0)
-      return (int)i;
-  lj_err_argv(L, narg, LJ_ERR_INVOPTM, opt);
-}
-
 /* -- Module registration ------------------------------------------------- */
 
 LUALIB_API const char *luaL_findtable(lua_State *L, int idx,
@@ -149,6 +58,7 @@ static int libsize(const luaL_Reg *l)
 LUALIB_API void luaL_openlib(lua_State *L, const char *libname,
 			     const luaL_Reg *l, int nup)
 {
+  lj_lib_checkfpu(L);
   if (libname) {
     int size = libsize(l);
     /* check whether lib already exists */
@@ -285,6 +195,10 @@ LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
 
 #define FREELIST_REF	0
 
+/* Convert a stack index to an absolute index. */
+#define abs_index(L, i) \
+  ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
+
 LUALIB_API int luaL_ref(lua_State *L, int t)
 {
   int ref;

+ 6 - 3
src/lib_io.c

@@ -523,8 +523,11 @@ static void io_fenv_new(lua_State *L, int narr, lua_CFunction cls)
 
 LUALIB_API int luaopen_io(lua_State *L)
 {
-  LJ_LIB_REG_(L, NULL, io_method);
-  lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
+  lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
+  if (tvisnil(L->top-1)) {
+    LJ_LIB_REG_(L, NULL, io_method);
+    lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
+  }
   io_fenv_new(L, 0, lj_cf_io_pipe_close);  /* top-3 */
   io_fenv_new(L, 2, lj_cf_io_file_close);  /* top-2 */
   LJ_LIB_REG(L, io);
@@ -532,7 +535,7 @@ LUALIB_API int luaopen_io(lua_State *L)
   io_std_new(L, stdin, IO_INPUT, "stdin");
   io_std_new(L, stdout, IO_OUTPUT, "stdout");
   io_std_new(L, stderr, 0, "stderr");
-  lua_pop(L, 1);
+  L->top--;
   return 1;
 }
 

+ 3 - 2
src/lib_jit.c

@@ -73,8 +73,9 @@ LJLIB_CF(jit_flush)
 #if LJ_HASJIT
   if (L->base < L->top && (tvisnum(L->base) || tvisstr(L->base))) {
     int traceno = lj_lib_checkint(L, 1);
-    luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE);
-    return 0;
+    setboolV(L->top-1,
+	     luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE));
+    return 1;
   }
 #endif
   return setjitmode(L, LUAJIT_MODE_FLUSH);

+ 4 - 15
src/lib_math.c

@@ -69,11 +69,9 @@ LJLIB_ASM_(math_max)		LJLIB_REC(math_minmax IR_MAX)
 LJLIB_PUSH(3.14159265358979323846) LJLIB_SET(pi)
 LJLIB_PUSH(1e310) LJLIB_SET(huge)
 
-#ifdef __MACH__
 LJ_FUNCA double lj_wrapper_sinh(double x) { return sinh(x); }
 LJ_FUNCA double lj_wrapper_cosh(double x) { return cosh(x); }
 LJ_FUNCA double lj_wrapper_tanh(double x) { return tanh(x); }
-#endif
 
 /* ------------------------------------------------------------------------ */
 
@@ -98,8 +96,8 @@ typedef union { uint64_t u64; double d; } U64double;
   z = (((z<<q)^z) >> (k-s)) ^ ((z&((uint64_t)(int64_t)-1 << (64-k)))<<s); \
   r ^= z; tw->gen[i] = z;
 
-/* PRNG step function. Returns a double in the range 0.0 <= d < 1.0. */
-static double tw223_step(TW223State *tw)
+/* PRNG step function. Returns a double in the range 1.0 <= d < 2.0. */
+static LJ_NOINLINE double tw223_step(TW223State *tw)
 {
   uint64_t z, r = 0;
   U64double u;
@@ -108,16 +106,7 @@ static double tw223_step(TW223State *tw)
   TW223_GEN(2, 55, 24,  7)
   TW223_GEN(3, 47, 21,  8)
   u.u64 = (r & (((uint64_t)1 << 52)-1)) | ((uint64_t)0x3ff << 52);
-#if defined(__GNUC__) && LJ_TARGET_X86 && __pic__
-  /* Compensate for unbelievable GCC pessimization. */
-  {
-    volatile U64double u1;
-    u1.u64 = (uint64_t)0x3f8 << 52;
-    return u.d - u1.d;
-  }
-#else
-  return u.d - 1.0;
-#endif
+  return u.d;
 }
 
 /* PRNG initialization function. */
@@ -146,7 +135,7 @@ LJLIB_CF(math_random)
   TW223State *tw = (TW223State *)(uddata(udataV(lj_lib_upvalue(L, 1))));
   double d;
   if (LJ_UNLIKELY(!tw->valid)) tw223_init(tw, 0.0);
-  d = tw223_step(tw);
+  d = tw223_step(tw) - 1.0;
   if (n > 0) {
     double r1 = lj_lib_checknum(L, 1);
     if (n == 1) {

+ 1 - 0
src/lib_package.c

@@ -354,6 +354,7 @@ static int lj_cf_package_require(lua_State *L)
     lua_pushvalue(L, -1);  /* extra copy to be returned */
     lua_setfield(L, 2, name);  /* _LOADED[name] = true */
   }
+  lj_lib_checkfpu(L);
   return 1;
 }
 

+ 5 - 2
src/lib_string.c

@@ -16,6 +16,7 @@
 #include "lualib.h"
 
 #include "lj_obj.h"
+#include "lj_gc.h"
 #include "lj_err.h"
 #include "lj_str.h"
 #include "lj_tab.h"
@@ -774,6 +775,7 @@ LJLIB_CF(string_format)
 LUALIB_API int luaopen_string(lua_State *L)
 {
   GCtab *mt;
+  GCstr *mmstr;
   LJ_LIB_REG(L, string);
 #if defined(LUA_COMPAT_GFIND)
   lua_getfield(L, -1, "gmatch");
@@ -782,8 +784,9 @@ LUALIB_API int luaopen_string(lua_State *L)
   mt = lj_tab_new(L, 0, 1);
   /* NOBARRIER: G(L)->mmname[] is a GC root. */
   setgcref(G(L)->basemt[~LJ_TSTR], obj2gco(mt));
-  settabV(L, lj_tab_setstr(L, mt, strref(G(L)->mmname[MM_index])),
-	      tabV(L->top-1));
+  mmstr = strref(G(L)->mmname[MM_index]);
+  if (isdead(G(L), obj2gco(mmstr))) flipwhite(obj2gco(mmstr));
+  settabV(L, lj_tab_setstr(L, mt, mmstr), tabV(L->top-1));
   mt->nomm = cast_byte(~(1u<<MM_index));
   return 1;
 }

+ 12 - 12
src/lib_table.c

@@ -74,21 +74,21 @@ LJLIB_CF(table_maxn)
   TValue *array = tvref(t->array);
   Node *node;
   lua_Number m = 0;
-  uint32_t i;
-  for (i = 0; i < t->asize; i++)
+  ptrdiff_t i;
+  for (i = (ptrdiff_t)t->asize - 1; i >= 0; i--)
     if (!tvisnil(&array[i])) {
-      m = (lua_Number)i;
+      m = (lua_Number)(int32_t)i;
       break;
     }
   node = noderef(t->node);
-  for (i = 0; i <= t->hmask; i++)
+  for (i = (ptrdiff_t)t->hmask; i >= 0; i--)
     if (tvisnum(&node[i].key) && numV(&node[i].key) > m)
       m = numV(&node[i].key);
   setnumV(L->top-1, m);
   return 1;
 }
 
-LJLIB_CF(table_insert)
+LJLIB_CF(table_insert)		LJLIB_REC(.)
 {
   GCtab *t = lj_lib_checktab(L, 1);
   int32_t n, i = (int32_t)lj_tab_len(t) + 1;
@@ -111,20 +111,20 @@ LJLIB_CF(table_insert)
   }
   {
     TValue *dst = lj_tab_setint(L, t, i);
-    copyTV(L, dst, L->top-1);
+    copyTV(L, dst, L->top-1);  /* Set new value. */
     lj_gc_barriert(L, t, dst);
   }
   return 0;
 }
 
-LJLIB_CF(table_remove)
+LJLIB_CF(table_remove)		LJLIB_REC(.)
 {
   GCtab *t = lj_lib_checktab(L, 1);
   int32_t e = (int32_t)lj_tab_len(t);
   int32_t pos = lj_lib_optint(L, 2, e);
-  if (!(1 <= pos && pos <= e))  /* position is outside bounds? */
-    return 0;  /* nothing to remove */
-  lua_rawgeti(L, 1, pos);
+  if (!(1 <= pos && pos <= e))  /* Nothing to remove? */
+    return 0;
+  lua_rawgeti(L, 1, pos);  /* Get previous value. */
   /* NOBARRIER: This just moves existing elements around. */
   for (; pos < e; pos++) {
     cTValue *src = lj_tab_getint(t, pos+1);
@@ -135,8 +135,8 @@ LJLIB_CF(table_remove)
       setnilV(dst);
     }
   }
-  setnilV(lj_tab_setint(L, t, e));
-  return 1;
+  setnilV(lj_tab_setint(L, t, e));  /* Remove (last) value. */
+  return 1;  /* Return previous value. */
 }
 
 LJLIB_CF(table_concat)

+ 134 - 2
src/lj_api.c

@@ -91,6 +91,12 @@ LUA_API int lua_checkstack(lua_State *L, int size)
   return 1;
 }
 
+LUALIB_API void luaL_checkstack(lua_State *L, int size, const char *msg)
+{
+  if (!lua_checkstack(L, size))
+    lj_err_callerv(L, LJ_ERR_STKOVM, msg);
+}
+
 LUA_API void lua_xmove(lua_State *from, lua_State *to, int n)
 {
   TValue *f, *t;
@@ -193,6 +199,18 @@ LUA_API int lua_type(lua_State *L, int idx)
   }
 }
 
+LUALIB_API void luaL_checktype(lua_State *L, int idx, int tt)
+{
+  if (lua_type(L, idx) != tt)
+    lj_err_argt(L, idx, tt);
+}
+
+LUALIB_API void luaL_checkany(lua_State *L, int idx)
+{
+  if (index2adr(L, idx) == niltv(L))
+    lj_err_arg(L, idx, LJ_ERR_NOVAL);
+}
+
 LUA_API const char *lua_typename(lua_State *L, int t)
 {
   UNUSED(L);
@@ -202,7 +220,7 @@ LUA_API const char *lua_typename(lua_State *L, int t)
 LUA_API int lua_iscfunction(lua_State *L, int idx)
 {
   cTValue *o = index2adr(L, idx);
-  return !isluafunc(funcV(o));
+  return tvisfunc(o) && !isluafunc(funcV(o));
 }
 
 LUA_API int lua_isnumber(lua_State *L, int idx)
@@ -295,6 +313,30 @@ LUA_API lua_Number lua_tonumber(lua_State *L, int idx)
     return 0;
 }
 
+LUALIB_API lua_Number luaL_checknumber(lua_State *L, int idx)
+{
+  cTValue *o = index2adr(L, idx);
+  TValue tmp;
+  if (tvisnum(o))
+    return numV(o);
+  else if (!(tvisstr(o) && lj_str_numconv(strVdata(o), &tmp)))
+    lj_err_argt(L, idx, LUA_TNUMBER);
+  return numV(&tmp);
+}
+
+LUALIB_API lua_Number luaL_optnumber(lua_State *L, int idx, lua_Number def)
+{
+  cTValue *o = index2adr(L, idx);
+  TValue tmp;
+  if (tvisnum(o))
+    return numV(o);
+  else if (tvisnil(o))
+    return def;
+  else if (!(tvisstr(o) && lj_str_numconv(strVdata(o), &tmp)))
+    lj_err_argt(L, idx, LUA_TNUMBER);
+  return numV(&tmp);
+}
+
 LUA_API lua_Integer lua_tointeger(lua_State *L, int idx)
 {
   cTValue *o = index2adr(L, idx);
@@ -313,6 +355,44 @@ LUA_API lua_Integer lua_tointeger(lua_State *L, int idx)
 #endif
 }
 
+LUALIB_API lua_Integer luaL_checkinteger(lua_State *L, int idx)
+{
+  cTValue *o = index2adr(L, idx);
+  TValue tmp;
+  lua_Number n;
+  if (LJ_LIKELY(tvisnum(o)))
+    n = numV(o);
+  else if (tvisstr(o) && lj_str_numconv(strVdata(o), &tmp))
+    n = numV(&tmp);
+  else
+    lj_err_argt(L, idx, LUA_TNUMBER);
+#if LJ_64
+  return (lua_Integer)n;
+#else
+  return lj_num2int(n);
+#endif
+}
+
+LUALIB_API lua_Integer luaL_optinteger(lua_State *L, int idx, lua_Integer def)
+{
+  cTValue *o = index2adr(L, idx);
+  TValue tmp;
+  lua_Number n;
+  if (LJ_LIKELY(tvisnum(o)))
+    n = numV(o);
+  else if (tvisnil(o))
+    return def;
+  else if (tvisstr(o) && lj_str_numconv(strVdata(o), &tmp))
+    n = numV(&tmp);
+  else
+    lj_err_argt(L, idx, LUA_TNUMBER);
+#if LJ_64
+  return (lua_Integer)n;
+#else
+  return lj_num2int(n);
+#endif
+}
+
 LUA_API int lua_toboolean(lua_State *L, int idx)
 {
   cTValue *o = index2adr(L, idx);
@@ -337,6 +417,57 @@ LUA_API const char *lua_tolstring(lua_State *L, int idx, size_t *len)
   return strdata(s);
 }
 
+LUALIB_API const char *luaL_checklstring(lua_State *L, int idx, size_t *len)
+{
+  TValue *o = index2adr(L, idx);
+  GCstr *s;
+  if (LJ_LIKELY(tvisstr(o))) {
+    s = strV(o);
+  } else if (tvisnum(o)) {
+    lj_gc_check(L);
+    o = index2adr(L, idx);  /* GC may move the stack. */
+    s = lj_str_fromnum(L, &o->n);
+  } else {
+    lj_err_argt(L, idx, LUA_TSTRING);
+  }
+  if (len != NULL) *len = s->len;
+  return strdata(s);
+}
+
+LUALIB_API const char *luaL_optlstring(lua_State *L, int idx,
+				       const char *def, size_t *len)
+{
+  TValue *o = index2adr(L, idx);
+  GCstr *s;
+  if (LJ_LIKELY(tvisstr(o))) {
+    s = strV(o);
+  } else if (tvisnil(o)) {
+    if (len != NULL) *len = def ? strlen(def) : 0;
+    return def;
+  } else if (tvisnum(o)) {
+    lj_gc_check(L);
+    o = index2adr(L, idx);  /* GC may move the stack. */
+    s = lj_str_fromnum(L, &o->n);
+  } else {
+    lj_err_argt(L, idx, LUA_TSTRING);
+  }
+  if (len != NULL) *len = s->len;
+  return strdata(s);
+}
+
+LUALIB_API int luaL_checkoption(lua_State *L, int idx, const char *def,
+				const char *const lst[])
+{
+  ptrdiff_t i;
+  const char *s = lua_tolstring(L, idx, NULL);
+  if (s == NULL && (s = def) == NULL)
+    lj_err_argt(L, idx, LUA_TSTRING);
+  for (i = 0; lst[i]; i++)
+    if (strcmp(lst[i], s) == 0)
+      return (int)i;
+  lj_err_argv(L, idx, LJ_ERR_INVOPTM, s);
+}
+
 LUA_API size_t lua_objlen(lua_State *L, int idx)
 {
   TValue *o = index2adr(L, idx);
@@ -355,7 +486,8 @@ LUA_API size_t lua_objlen(lua_State *L, int idx)
 LUA_API lua_CFunction lua_tocfunction(lua_State *L, int idx)
 {
   cTValue *o = index2adr(L, idx);
-  return funcV(o)->c.gate == lj_gate_c ? funcV(o)->c.f : NULL;
+  ASMFunction gate = funcV(o)->c.gate;
+  return (gate == lj_gate_c || gate == lj_gate_cwrap) ? funcV(o)->c.f : NULL;
 }
 
 LUA_API void *lua_touserdata(lua_State *L, int idx)

+ 7 - 4
src/lj_asm.c

@@ -738,11 +738,14 @@ static Reg ra_allocref(ASMState *as, IRRef ref, RegSet allow)
       }
       RA_DBGX((as, "hintmiss  $f $r", ref, r));
     }
-    /* Invariants should preferably get unused registers. */
-    if (ref < as->loopref && !irt_isphi(ir->t))
-      r = rset_pickbot(pick);
-    else
+    /* Invariants should preferably get unmodified registers. */
+    if (ref < as->loopref && !irt_isphi(ir->t)) {
+      if ((pick & ~as->modset))
+	pick &= ~as->modset;
+      r = rset_pickbot(pick);  /* Reduce conflicts with inverse allocation. */
+    } else {
       r = rset_picktop(pick);
+    }
   } else {
     r = ra_evict(as, allow);
   }

+ 15 - 2
src/lj_dispatch.c

@@ -153,8 +153,7 @@ int luaJIT_setmode(lua_State *L, int idx, int mode)
   case LUAJIT_MODE_TRACE:
     if (!(mode & LUAJIT_MODE_FLUSH))
       return 0;  /* Failed. */
-    lj_trace_flush(G2J(g), idx);
-    break;
+    return lj_trace_flush(G2J(g), idx);
 #else
   case LUAJIT_MODE_ENGINE:
   case LUAJIT_MODE_FUNC:
@@ -165,6 +164,20 @@ int luaJIT_setmode(lua_State *L, int idx, int mode)
       return 0;  /* Failed. */
     break;
 #endif
+  case LUAJIT_MODE_WRAPCFUNC:
+    if ((mode & LUAJIT_MODE_ON)) {
+      if (idx != 0) {
+	cTValue *tv = idx > 0 ? L->base + (idx-1) : L->top + idx;
+	if (tvislightud(tv) && lightudV(tv) != NULL)
+	  g->wrapf = (lua_CFunction)lightudV(tv);
+	else
+	  return 0;  /* Failed. */
+      }
+      g->wrapmode = 1;
+    } else {
+      g->wrapmode = 0;
+    }
+    break;
   default:
     return 0;  /* Failed. */
   }

+ 46 - 0
src/lj_err.c

@@ -676,6 +676,8 @@ LJ_NORET LJ_NOINLINE static void err_argmsg(lua_State *L, int narg,
 {
   const char *fname = "?";
   const char *ftype = getfuncname(L, L->base - 1, &fname);
+  if (narg < 0 && narg > LUA_REGISTRYINDEX)
+    narg = (L->top - L->base) + narg + 1;
   if (ftype && ftype[3] == 'h' && --narg == 0)  /* Check for "method". */
     msg = lj_str_pushf(L, err2msg(LJ_ERR_BADSELF), fname, msg);
   else
@@ -761,3 +763,47 @@ LUALIB_API int luaL_error(lua_State *L, const char *fmt, ...)
   return 0;  /* unreachable */
 }
 
+/* -- C++ exception support ----------------------------------------------- */
+
+#if defined(__ELF__) || defined(__MACH__)
+typedef enum
+{
+  _URC_NO_REASON,
+  _URC_FOREIGN_EXCEPTION_CAUGHT,
+  _URC_FATAL_PHASE2_ERROR,
+  _URC_FATAL_PHASE1_ERROR,
+  _URC_NORMAL_STOP,
+  _URC_END_OF_STACK,
+  _URC_HANDLER_FOUND,
+  _URC_INSTALL_CONTEXT,
+  _URC_CONTINUE_UNWIND
+} _Unwind_Reason_Code;
+
+#define _UA_SEARCH_PHASE	1
+#define _UA_CLEANUP_PHASE	2
+#define _UA_HANDLER_FRAME	4
+#define _UA_FORCE_UNWIND	8
+#define _UA_END_OF_STACK	16
+
+extern void *_Unwind_GetCFA(void *ctx);
+extern void _Unwind_DeleteException(void *uex);
+
+/* DWARF2 personality handler referenced from .eh_frame. */
+LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, uint64_t uexclass,
+				 void *uex, void *ctx)
+{
+  if (version != 1)
+    return _URC_FATAL_PHASE1_ERROR;
+  UNUSED(uexclass);
+  if ((actions & _UA_SEARCH_PHASE))
+    return _URC_HANDLER_FOUND;
+  if ((actions & _UA_HANDLER_FRAME)) {
+    void *cf = _Unwind_GetCFA(ctx);
+    lua_State *L = cframe_L(cf);
+    _Unwind_DeleteException(uex);
+    lj_err_msg(L, LJ_ERR_ERRCPP);
+  }
+  return _URC_CONTINUE_UNWIND;
+}
+#endif
+

+ 4 - 0
src/lj_errmsg.h

@@ -8,6 +8,7 @@
 /* Basic error handling. */
 ERRDEF(ERRMEM,	"not enough memory")
 ERRDEF(ERRERR,	"error in error handling")
+ERRDEF(ERRCPP,	"C++ exception")
 
 /* Allocations. */
 ERRDEF(STROV,	"string length overflow")
@@ -56,6 +57,9 @@ ERRDEF(NOENV,	"no calling environment")
 ERRDEF(CYIELD,	"attempt to yield across C-call boundary")
 ERRDEF(BADLU,	"bad light userdata pointer")
 ERRDEF(NOGCMM,	"bad action while in __gc metamethod")
+#ifdef LUA_USE_WIN
+ERRDEF(BADFPU,	"bad FPU precision (use D3DCREATE_FPU_PRESERVE with DirectX)")
+#endif
 
 /* Standard library function errors. */
 ERRDEF(ASSERT,	"assertion failed!")

+ 1 - 1
src/lj_func.c

@@ -138,7 +138,7 @@ GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env)
   fn->c.nupvalues = cast_byte(nelems);
   /* NOBARRIER: The GCfunc is new (marked white). */
   setgcref(fn->c.env, obj2gco(env));
-  fn->c.gate = lj_gate_c;
+  fn->c.gate = G(L)->wrapmode ? lj_gate_cwrap : lj_gate_c;
   return fn;
 }
 

+ 1 - 2
src/lj_gc.c

@@ -230,8 +230,7 @@ static void gc_traverse_trace(global_State *g, Trace *T)
 
 /* The current trace is a GC root while not anchored in the prototype (yet). */
 #define gc_mark_curtrace(g) \
-  { if (G2J(g)->state != LJ_TRACE_IDLE && G2J(g)->curtrace != 0) \
-    gc_traverse_trace(g, &G2J(g)->cur); }
+  { if (G2J(g)->curtrace != 0) gc_traverse_trace(g, &G2J(g)->cur); }
 #else
 #define gc_mark_curtrace(g)	UNUSED(g)
 #endif

+ 1 - 0
src/lj_ir.c

@@ -252,6 +252,7 @@ TRef lj_ir_kgc(jit_State *J, GCobj *o, IRType t)
 {
   IRIns *ir, *cir = J->cur.ir;
   IRRef ref;
+  lua_assert(!isdead(J2G(J), o));
   for (ref = J->chain[IR_KGC]; ref; ref = cir[ref].prev)
     if (ir_kgc(&cir[ref]) == o)
       goto found;

+ 9 - 0
src/lj_lib.h

@@ -48,6 +48,15 @@ LJ_FUNC int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst);
 #define lj_lib_upvalue(L, n) \
   (&gcref((L->base-1)->fr.func)->fn.c.upvalue[(n)-1])
 
+#ifdef LUA_USE_WIN
+#define lj_lib_checkfpu(L) \
+  do { setnumV(L->top++, (lua_Number)1437217655); \
+    if (lua_tointeger(L, -1) != 1437217655) lj_err_caller(L, LJ_ERR_BADFPU); \
+    L->top--; } while (0)
+#else
+#define lj_lib_checkfpu(L)	UNUSED(L)
+#endif
+
 /* Library function declarations. Scanned by buildvm. */
 #define LJLIB_CF(name)		static int lj_cf_##name(lua_State *L)
 #define LJLIB_ASM(name)		static int lj_ffh_##name(lua_State *L)

+ 2 - 1
src/lj_obj.h

@@ -531,7 +531,7 @@ typedef struct global_State {
   uint8_t hookmask;	/* Hook mask. */
   uint8_t dispatchmode;	/* Dispatch mode. */
   uint8_t vmevmask;	/* VM event mask. */
-  uint8_t unused1;
+  uint8_t wrapmode;	/* Wrap mode. */
   GCRef mainthref;	/* Link to main thread. */
   TValue registrytv;	/* Anchor for registry. */
   TValue tmptv;		/* Temporary TValue. */
@@ -539,6 +539,7 @@ typedef struct global_State {
   int32_t hookcount;	/* Instruction hook countdown. */
   int32_t hookcstart;	/* Start count for instruction hook counter. */
   lua_Hook hookf;	/* Hook function. */
+  lua_CFunction wrapf;	/* Wrapper for C function calls. */
   lua_CFunction panic;	/* Called as a last resort for errors. */
   volatile int32_t vmstate;  /* VM state or current JIT code trace number. */
   GCRef jit_L;		/* Current JIT code lua_State or NULL. */

+ 4 - 4
src/lj_opt_fold.c

@@ -138,7 +138,7 @@ typedef IRRef (LJ_FASTCALL *FoldFunc)(jit_State *J);
 /* Macros for the fold specs, so buildvm can recognize them. */
 #define LJFOLD(x)
 #define LJFOLDX(x)
-#define LJFOLDF(name)	static TRef LJ_FASTCALL name(jit_State *J)
+#define LJFOLDF(name)	static TRef LJ_FASTCALL fold_##name(jit_State *J)
 /* Note: They must be at the start of a line or buildvm ignores them! */
 
 /* Barrier to prevent using operands across PHIs. */
@@ -979,7 +979,7 @@ LJFOLDF(comm_equal)
   /* For non-numbers only: x == x ==> drop; x ~= x ==> fail */
   if (fins->op1 == fins->op2 && !irt_isnum(fins->t))
     return CONDFOLD(fins->o == IR_EQ);
-  return comm_swap(J);
+  return fold_comm_swap(J);
 }
 
 LJFOLD(LT any any)
@@ -1013,7 +1013,7 @@ LJFOLDF(comm_dup)
 {
   if (fins->op1 == fins->op2)  /* x o x ==> x */
     return LEFTFOLD;
-  return comm_swap(J);
+  return fold_comm_swap(J);
 }
 
 LJFOLD(BXOR any any)
@@ -1021,7 +1021,7 @@ LJFOLDF(comm_bxor)
 {
   if (fins->op1 == fins->op2)  /* i xor i ==> 0 */
     return INTFOLD(0);
-  return comm_swap(J);
+  return fold_comm_swap(J);
 }
 
 /* -- Simplification of compound expressions ------------------------------ */

+ 1 - 1
src/lj_opt_loop.c

@@ -286,7 +286,7 @@ static void loop_unroll(jit_State *J)
 	if (!irt_sametype(t, irr->t)) {
 	  if (irt_isnum(t) && irt_isinteger(irr->t))  /* Fix int->num case. */
 	    subst[ins] = tref_ref(emitir(IRTN(IR_TONUM), ref, 0));
-	  else
+	  else if (!(irt_isinteger(t) && irt_isinteger(irr->t)))
 	    lj_trace_err(J, LJ_TRERR_TYPEINS);
 	}
       }

+ 2 - 2
src/lj_opt_mem.c

@@ -519,8 +519,8 @@ int lj_opt_fwd_wasnonnil(jit_State *J, IROpT loadop, IRRef xref)
     } else if (irt_isnil(store->t)) {  /* Must check any nil store. */
       IRRef skref = IR(store->op1)->op2;
       IRRef xkref = IR(xref)->op2;
-      /* Same key type MAY alias. */
-      if (irt_sametype(IR(skref)->t, IR(xkref)->t)) {
+      /* Same key type MAY alias. Need ALOAD check due to multiple int types. */
+      if (loadop == IR_ALOAD || irt_sametype(IR(skref)->t, IR(xkref)->t)) {
 	if (skref == xkref || !irref_isk(skref) || !irref_isk(xkref))
 	  return 0;  /* A nil store with same const key or var key MAY alias. */
 	/* Different const keys CANNOT alias. */

+ 62 - 8
src/lj_record.c

@@ -168,8 +168,8 @@ static int rec_objcmp(jit_State *J, TRef a, TRef b, cTValue *av, cTValue *bv)
 {
   int diff = !lj_obj_equal(av, bv);
   if (!tref_isk2(a, b)) {  /* Shortcut, also handles primitives. */
-    IRType ta = tref_type(a);
-    IRType tb = tref_type(b);
+    IRType ta = tref_isinteger(a) ? IRT_INT : tref_type(a);
+    IRType tb = tref_isinteger(b) ? IRT_INT : tref_type(b);
     if (ta != tb) {
       /* Widen mixed number/int comparisons to number/number comparison. */
       if (ta == IRT_INT && tb == IRT_NUM) {
@@ -447,7 +447,7 @@ static int rec_mm_lookup(jit_State *J, RecordIndex *ix, MMS mm)
     mix.tab = lj_ir_ktab(J, mt);
     goto nocheck;
   }
-  ix->mt = mix.tab;
+  ix->mt = mt ? mix.tab : TREF_NIL;
   emitir(IRTG(mt ? IR_NE : IR_EQ, IRT_TAB), mix.tab, lj_ir_knull(J, IRT_TAB));
 nocheck:
   if (mt) {
@@ -457,6 +457,8 @@ nocheck:
       copyTV(J->L, &ix->mobjv, mo);
     ix->mtv = mt;
     settabV(J->L, &mix.tabv, mt);
+    if (isdead(J2G(J), obj2gco(mmstr)))
+      flipwhite(obj2gco(mmstr));  /* Need same logic as lj_str_new(). */
     setstrV(J->L, &mix.keyv, mmstr);
     mix.key = lj_ir_kstr(J, mmstr);
     mix.val = 0;
@@ -880,7 +882,7 @@ static void recff_nyi(jit_State *J, TRef *res, RecordFFData *rd)
   lj_trace_err_info(J, LJ_TRERR_NYIFF);
 }
 
-LJ_NORET static void recff_err_ffu(jit_State *J, RecordFFData *rd)
+LJ_NORET static void recff_err_nyi(jit_State *J, RecordFFData *rd)
 {
   setfuncV(J->L, &J->errinfo, rd->fn);
   lj_trace_err_info(J, LJ_TRERR_NYIFFU);
@@ -986,7 +988,7 @@ static void recff_tonumber(jit_State *J, TRef *res, RecordFFData *rd)
     if (arg[1]) {
       TRef base = lj_ir_toint(J, arg[1]);
       if (!tref_isk(base) || IR(tref_ref(base))->i != 10)
-	recff_err_ffu(J, rd);
+	recff_err_nyi(J, rd);
     }
     if (tref_isstr(tr))
       tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0);
@@ -1016,7 +1018,7 @@ static void recff_tostring(jit_State *J, TRef *res, RecordFFData *rd)
     } else if (tref_isnumber(tr)) {
       res[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0);
     } else {
-      recff_err_ffu(J, rd);
+      recff_err_nyi(J, rd);
     }
   }
 }
@@ -1338,6 +1340,58 @@ static void recff_table_getn(jit_State *J, TRef *res, RecordFFData *rd)
   UNUSED(rd);
 }
 
+static void recff_table_remove(jit_State *J, TRef *res, RecordFFData *rd)
+{
+  if (tref_istab(arg[0])) {
+    if (!arg[1] || tref_isnil(arg[1])) {  /* Simple pop: t[#t] = nil */
+      TRef trlen = emitir(IRTI(IR_TLEN), arg[0], 0);
+      GCtab *t = tabV(&rd->argv[0]);
+      MSize len = lj_tab_len(t);
+      emitir(IRTGI(len ? IR_NE : IR_EQ), trlen, lj_ir_kint(J, 0));
+      if (len) {
+	RecordIndex ix;
+	ix.tab = arg[0];
+	ix.key = trlen;
+	settabV(J->L, &ix.tabv, t);
+	setintV(&ix.keyv, len);
+	ix.idxchain = 0;
+	if (rd->cres != 0) {  /* Specialize load only if result needed. */
+	  ix.val = 0;
+	  res[0] = rec_idx(J, &ix);  /* Load previous value. */
+	  /* Assumes ix.key/ix.tab is not modified for raw rec_idx(). */
+	}
+	ix.val = TREF_NIL;
+	rec_idx(J, &ix);  /* Remove value. */
+      } else {
+	rd->nres = 0;
+      }
+    } else {  /* Complex case: remove in the middle. */
+      recff_err_nyi(J, rd);
+    }
+  }  /* else: Interpreter will throw. */
+}
+
+static void recff_table_insert(jit_State *J, TRef *res, RecordFFData *rd)
+{
+  rd->nres = 0;
+  if (tref_istab(arg[0]) && arg[1]) {
+    if (!arg[2]) {  /* Simple push: t[#t+1] = v */
+      TRef trlen = emitir(IRTI(IR_TLEN), arg[0], 0);
+      GCtab *t = tabV(&rd->argv[0]);
+      RecordIndex ix;
+      ix.tab = arg[0];
+      ix.val = arg[1];
+      ix.key = emitir(IRTI(IR_ADD), trlen, lj_ir_kint(J, 1));
+      settabV(J->L, &ix.tabv, t);
+      setintV(&ix.keyv, lj_tab_len(t) + 1);
+      ix.idxchain = 0;
+      rec_idx(J, &ix);  /* Set new value. */
+    } else {  /* Complex case: insert in the middle. */
+      recff_err_nyi(J, rd);
+    }
+  }  /* else: Interpreter will throw. */
+}
+
 /* -- Record calls and returns -------------------------------------------- */
 
 #undef arg
@@ -1618,8 +1672,8 @@ void lj_record_ins(jit_State *J)
   case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT:
     /* Emit nothing for two numeric or string consts. */
     if (!(tref_isk2(ra,rc) && tref_isnumber_str(ra) && tref_isnumber_str(rc))) {
-      IRType ta = tref_type(ra);
-      IRType tc = tref_type(rc);
+      IRType ta = tref_isinteger(ra) ? IRT_INT : tref_type(ra);
+      IRType tc = tref_isinteger(rc) ? IRT_INT : tref_type(rc);
       int irop;
       if (ta != tc) {
 	/* Widen mixed number/int comparisons to number/number comparison. */

+ 2 - 2
src/lj_tab.c

@@ -191,8 +191,8 @@ GCtab *lj_tab_dup(lua_State *L, const GCtab *kt)
       Node *kn = &knode[i];
       Node *n = &node[i];
       Node *next = nextnode(kn);
-      copyTV(L, &n->val, &kn->val);
-      copyTV(L, &n->key, &kn->key);
+      /* Don't use copyTV here, since it asserts on a copy of a DEADKEY. */
+      n->val = kn->val; n->key = kn->key;
       setmref(n->next, next == NULL? next : (Node *)((char *)next + d));
     }
   }

+ 48 - 34
src/lj_trace.c

@@ -191,47 +191,58 @@ static void trace_unpatch(jit_State *J, Trace *T)
   }
 }
 
-/* Flush a root trace and any attached side traces. */
-void lj_trace_flush(jit_State *J, TraceNo traceno)
+/* Free a root trace and any attached side traces. */
+static void trace_freeroot(jit_State *J, Trace *T, TraceNo traceno)
 {
-  Trace *T = NULL;
-  GCproto *pt;
-  if (traceno > 0 && traceno <= J->sizetrace)
-    T = J->trace[traceno];
-  if (T == NULL)
-    return;
-  pt = &gcref(T->startpt)->pt;
-  if (T->root == 0 && pt != NULL) {
-    TraceNo side;
-    /* First unpatch any modified bytecode. */
-    trace_unpatch(J, T);
-    /* Unlink root trace from chain anchored in prototype. */
-    if (pt->trace == traceno) {  /* Trace is first in chain. Easy. */
-      pt->trace = T->nextroot;
-    } else {  /* Otherwise search in chain of root traces. */
-      Trace *T2 = J->trace[pt->trace];
-      while (T2->nextroot != traceno) {
-	lua_assert(T2->nextroot != 0);
-	T2 = J->trace[T2->nextroot];
-      }
-      T2->nextroot = T->nextroot;  /* Unlink from chain. */
+  GCproto *pt = &gcref(T->startpt)->pt;
+  TraceNo side;
+  lua_assert(T->root == 0 && pt != NULL);
+  /* First unpatch any modified bytecode. */
+  trace_unpatch(J, T);
+  /* Unlink root trace from chain anchored in prototype. */
+  if (pt->trace == traceno) {  /* Trace is first in chain. Easy. */
+    pt->trace = T->nextroot;
+  } else {  /* Otherwise search in chain of root traces. */
+    Trace *T2 = J->trace[pt->trace];
+    while (T2->nextroot != traceno) {
+      lua_assert(T2->nextroot != 0);
+      T2 = J->trace[T2->nextroot];
     }
-    /* Free all side traces. */
-    for (side = T->nextside; side != 0; ) {
-      TraceNo next = J->trace[side]->nextside;
-      trace_free(J, side);
-      side = next;
+    T2->nextroot = T->nextroot;  /* Unlink from chain. */
+  }
+  /* Free all side traces. */
+  for (side = T->nextside; side != 0; ) {
+    TraceNo next = J->trace[side]->nextside;
+    trace_free(J, side);
+    side = next;
+  }
+  /* Now free the trace itself. */
+  trace_free(J, traceno);
+}
+
+/* Flush a root trace + side traces, if there are no links to it. */
+int lj_trace_flush(jit_State *J, TraceNo traceno)
+{
+  if (traceno > 0 && traceno < J->sizetrace) {
+    Trace *T = J->trace[traceno];
+    if (T && T->root == 0) {
+      ptrdiff_t i;
+      for (i = (ptrdiff_t)J->sizetrace-1; i > 0; i--)
+	if (i != (ptrdiff_t)traceno && J->trace[i] &&
+	    J->trace[i]->root != traceno && J->trace[i]->link == traceno)
+	  return 0;  /* Failed: existing link to trace. */
+      trace_freeroot(J, T, traceno);
+      return 1;  /* Ok. */
     }
-    /* Now free the trace itself. */
-    trace_free(J, traceno);
-  }  /* Flush for non-root traces is currently ignored. */
+  }
+  return 0;  /* Failed. */
 }
 
 /* Flush all traces associated with a prototype. */
 void lj_trace_flushproto(global_State *g, GCproto *pt)
 {
   while (pt->trace != 0)
-    lj_trace_flush(G2J(g), pt->trace);
+    trace_freeroot(G2J(g), G2J(g)->trace[pt->trace], pt->trace);
 }
 
 /* Flush all traces. */
@@ -241,8 +252,11 @@ int lj_trace_flushall(lua_State *L)
   ptrdiff_t i;
   if ((J2G(J)->hookmask & HOOK_GC))
     return 1;
-  for (i = (ptrdiff_t)J->sizetrace-1; i > 0; i--)
-    lj_trace_flush(J, (TraceNo)i);
+  for (i = (ptrdiff_t)J->sizetrace-1; i > 0; i--) {
+    Trace *T = J->trace[i];
+    if (T && T->root == 0)
+      trace_freeroot(J, T, (TraceNo)i);
+  }
 #ifdef LUA_USE_ASSERT
   for (i = 0; i < (ptrdiff_t)J->sizetrace; i++)
     lua_assert(J->trace[i] == NULL);

+ 1 - 1
src/lj_trace.h

@@ -26,7 +26,7 @@ LJ_FUNC_NORET void lj_trace_err_info(jit_State *J, TraceError e);
 LJ_FUNC void lj_trace_freeproto(global_State *g, GCproto *pt);
 LJ_FUNC void lj_trace_reenableproto(GCproto *pt);
 LJ_FUNC void lj_trace_flushproto(global_State *g, GCproto *pt);
-LJ_FUNC void lj_trace_flush(jit_State *J, TraceNo traceno);
+LJ_FUNC int lj_trace_flush(jit_State *J, TraceNo traceno);
 LJ_FUNC int lj_trace_flushall(lua_State *L);
 LJ_FUNC void lj_trace_freestate(global_State *g);
 

+ 3 - 3
src/lj_vm.h

@@ -46,6 +46,7 @@ LJ_ASMF void lj_vm_powi(void);
 LJ_ASMF void lj_gate_lf(void);
 LJ_ASMF void lj_gate_lv(void);
 LJ_ASMF void lj_gate_c(void);
+LJ_ASMF void lj_gate_cwrap(void);
 
 /* Continuations for metamethods. */
 LJ_ASMF void lj_cont_cat(void);  /* Continue with concatenation. */
@@ -55,12 +56,11 @@ LJ_ASMF void lj_cont_condt(void);  /* Branch if result is true. */
 LJ_ASMF void lj_cont_condf(void);  /* Branch if result is false. */
 
 /* Start of the ASM code. */
-LJ_ASMF void lj_vm_asm_begin(void);
+LJ_ASMF char lj_vm_asm_begin[];
 
 /* Opcode handler offsets, relative to lj_vm_asm_begin. */
 LJ_ASMF const uint16_t lj_vm_op_ofs[];
 
-#define makeasmfunc(ofs) \
-  ((ASMFunction)((char *)lj_vm_asm_begin + (ofs)))
+#define makeasmfunc(ofs)	((ASMFunction)(lj_vm_asm_begin + (ofs)))
 
 #endif

+ 4 - 4
src/lua.hpp

@@ -1,9 +1,9 @@
-// lua.hpp
-// Lua header files for C++
-// <<extern "C">> not supplied automatically because Lua also compiles as C++
+// C++ wrapper for LuaJIT header files.
 
 extern "C" {
 #include "lua.h"
-#include "lualib.h"
 #include "lauxlib.h"
+#include "lualib.h"
+#include "luajit.h"
 }
+

+ 12 - 3
src/luaconf.h

@@ -34,13 +34,22 @@
   ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
 #else
 #define LUA_ROOT	"/usr/local/"
-#define LUA_JDIR	LUA_ROOT "share/luajit-2.0.0-beta1/"
 #define LUA_LDIR	LUA_ROOT "share/lua/5.1/"
 #define LUA_CDIR	LUA_ROOT "lib/lua/5.1/"
+#ifdef LUA_XROOT
+#define LUA_JDIR	LUA_XROOT "share/luajit-2.0.0-beta2/"
+#define LUA_XPATH \
+  ";" LUA_XROOT "share/lua/5.1/?.lua;" LUA_XROOT "share/lua/5.1/?/init.lua"
+#define LUA_XCPATH	LUA_XROOT "lib/lua/5.1/?.lua;"
+#else
+#define LUA_JDIR	LUA_ROOT "share/luajit-2.0.0-beta2/"
+#define LUA_XPATH
+#define LUA_XCPATH
+#endif
 #define LUA_PATH_DEFAULT \
-  "./?.lua;" LUA_JDIR"?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;"
+  "./?.lua;" LUA_JDIR"?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua" LUA_XPATH
 #define LUA_CPATH_DEFAULT \
-  "./?.so;" LUA_CDIR"?.so;" LUA_CDIR"loadall.so"
+  "./?.so;" LUA_CDIR"?.so;" LUA_XCPATH LUA_CDIR"loadall.so"
 #endif
 
 /* Environment variable names for path overrides and initialization code. */

+ 10 - 10
src/luajit.c

@@ -55,16 +55,16 @@ static void laction(int i)
 static void print_usage(void)
 {
   fprintf(stderr,
-  "usage: %s [options] [script [args]].\n"
+  "usage: %s [options]... [script [args]...].\n"
   "Available options are:\n"
-  "  -e stat  execute string " LUA_QL("stat") "\n"
-  "  -l name  require library " LUA_QL("name") "\n"
-  "  -j cmd   perform LuaJIT control command\n"
-  "  -O[lvl]  set LuaJIT optimization level\n"
-  "  -i       enter interactive mode after executing " LUA_QL("script") "\n"
-  "  -v       show version information\n"
-  "  --       stop handling options\n"
-  "  -        execute stdin and stop handling options\n"
+  "  -e chunk  Execute string " LUA_QL("chunk") ".\n"
+  "  -l name   Require library " LUA_QL("name") ".\n"
+  "  -j cmd    Perform LuaJIT control command.\n"
+  "  -O[opt]   Control LuaJIT optimizations.\n"
+  "  -i        Enter interactive mode after executing " LUA_QL("script") ".\n"
+  "  -v        Show version information.\n"
+  "  --        Stop handling options.\n"
+  "  -         Execute stdin and stop handling options.\n"
   ,
   progname);
   fflush(stderr);
@@ -143,7 +143,7 @@ static void print_jit_status(lua_State *L)
   fputs(lua_toboolean(L, n) ? "JIT: ON" : "JIT: OFF", stderr);
   for (n++; (s = lua_tostring(L, n)); n++)
     fprintf(stderr, " %s", s);
-  fputs("\n", stdout);
+  fputs("\n", stderr);
 }
 
 static int getargs(lua_State *L, char **argv, int n)

+ 6 - 4
src/luajit.h

@@ -30,9 +30,9 @@
 
 #include "lua.h"
 
-#define LUAJIT_VERSION		"LuaJIT 2.0.0-beta1"
+#define LUAJIT_VERSION		"LuaJIT 2.0.0-beta2"
 #define LUAJIT_VERSION_NUM	20000  /* Version 2.0.0 = 02.00.00. */
-#define LUAJIT_VERSION_SYM	luaJIT_version_2_0_0_beta1
+#define LUAJIT_VERSION_SYM	luaJIT_version_2_0_0_beta2
 #define LUAJIT_COPYRIGHT	"Copyright (C) 2005-2009 Mike Pall"
 #define LUAJIT_URL		"http://luajit.org/"
 
@@ -49,12 +49,14 @@ enum {
 
   LUAJIT_MODE_TRACE,		/* Flush a compiled trace. */
 
+  LUAJIT_MODE_WRAPCFUNC = 0x10,	/* Set wrapper mode for C function calls. */
+
   LUAJIT_MODE_MAX
 };
 
 /* Flags or'ed in to the mode. */
-#define LUAJIT_MODE_OFF		0x0000	/* Disable JIT compilation. */
-#define LUAJIT_MODE_ON		0x0100	/* (Re-)enable JIT compilation. */
+#define LUAJIT_MODE_OFF		0x0000	/* Turn feature off. */
+#define LUAJIT_MODE_ON		0x0100	/* Turn feature on. */
 #define LUAJIT_MODE_FLUSH	0x0200	/* Flush JIT-compiled code. */
 
 /* LuaJIT public C API. */