【新增】添加原版luajit版本v2.1代码
This commit is contained in:
56
thirdPart/luajit/COPYRIGHT
Normal file
56
thirdPart/luajit/COPYRIGHT
Normal file
@@ -0,0 +1,56 @@
|
||||
===============================================================================
|
||||
LuaJIT -- a Just-In-Time Compiler for Lua. https://luajit.org/
|
||||
|
||||
Copyright (C) 2005-2023 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: https://www.opensource.org/licenses/mit-license.php ]
|
||||
|
||||
===============================================================================
|
||||
[ LuaJIT includes code from Lua 5.1/5.2, which has this license statement: ]
|
||||
|
||||
Copyright (C) 1994-2012 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
|
||||
https://creativecommons.org/licenses/publicdomain
|
||||
|
||||
===============================================================================
|
||||
173
thirdPart/luajit/Makefile
Normal file
173
thirdPart/luajit/Makefile
Normal file
@@ -0,0 +1,173 @@
|
||||
##############################################################################
|
||||
# LuaJIT top level Makefile for installation. Requires GNU Make.
|
||||
#
|
||||
# Please read doc/install.html before changing any variables!
|
||||
#
|
||||
# Suitable for POSIX platforms (Linux, *BSD, OSX etc.).
|
||||
# Note: src/Makefile has many more configurable options.
|
||||
#
|
||||
# ##### This Makefile is NOT useful for Windows! #####
|
||||
# For MSVC, please follow the instructions given in src/msvcbuild.bat.
|
||||
# For MinGW and Cygwin, cd to src and run make with the Makefile there.
|
||||
#
|
||||
# Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
##############################################################################
|
||||
|
||||
MAJVER= 2
|
||||
MINVER= 1
|
||||
ABIVER= 5.1
|
||||
|
||||
# LuaJIT uses rolling releases. The release version is based on the time of
|
||||
# the latest git commit. The 'git' command must be available during the build.
|
||||
RELVER= $(shell cat src/luajit_relver.txt 2>/dev/null || : )
|
||||
# Note: setting it with := doesn't work, since it will change during the build.
|
||||
|
||||
MMVERSION= $(MAJVER).$(MINVER)
|
||||
VERSION= $(MMVERSION).$(RELVER)
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Change the installation path as needed. This automatically adjusts
|
||||
# the paths in src/luaconf.h, too. Note: PREFIX must be an absolute path!
|
||||
#
|
||||
export PREFIX= /usr/local
|
||||
export MULTILIB= lib
|
||||
##############################################################################
|
||||
|
||||
DPREFIX= $(DESTDIR)$(PREFIX)
|
||||
INSTALL_BIN= $(DPREFIX)/bin
|
||||
INSTALL_LIB= $(DPREFIX)/$(MULTILIB)
|
||||
INSTALL_SHARE= $(DPREFIX)/share
|
||||
INSTALL_DEFINC= $(DPREFIX)/include/luajit-$(MMVERSION)
|
||||
INSTALL_INC= $(INSTALL_DEFINC)
|
||||
|
||||
INSTALL_LJLIBD= $(INSTALL_SHARE)/luajit-$(MMVERSION)
|
||||
INSTALL_JITLIB= $(INSTALL_LJLIBD)/jit
|
||||
INSTALL_LMODD= $(INSTALL_SHARE)/lua
|
||||
INSTALL_LMOD= $(INSTALL_LMODD)/$(ABIVER)
|
||||
INSTALL_CMODD= $(INSTALL_LIB)/lua
|
||||
INSTALL_CMOD= $(INSTALL_CMODD)/$(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_SOSHORT1= libluajit-$(ABIVER).so
|
||||
INSTALL_SOSHORT2= libluajit-$(ABIVER).so.$(MAJVER)
|
||||
INSTALL_SONAME= libluajit-$(ABIVER).so.$(VERSION)
|
||||
INSTALL_DYLIBSHORT1= libluajit-$(ABIVER).dylib
|
||||
INSTALL_DYLIBSHORT2= libluajit-$(ABIVER).$(MAJVER).dylib
|
||||
INSTALL_DYLIBNAME= libluajit-$(ABIVER).$(VERSION).dylib
|
||||
INSTALL_PCNAME= luajit.pc
|
||||
|
||||
INSTALL_STATIC= $(INSTALL_LIB)/$(INSTALL_ANAME)
|
||||
INSTALL_DYN= $(INSTALL_LIB)/$(INSTALL_SONAME)
|
||||
INSTALL_SHORT1= $(INSTALL_LIB)/$(INSTALL_SOSHORT1)
|
||||
INSTALL_SHORT2= $(INSTALL_LIB)/$(INSTALL_SOSHORT2)
|
||||
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)
|
||||
UNINSTALL_DIRS= $(INSTALL_JITLIB) $(INSTALL_LJLIBD) $(INSTALL_INC) \
|
||||
$(INSTALL_LMOD) $(INSTALL_LMODD) $(INSTALL_CMOD) $(INSTALL_CMODD)
|
||||
|
||||
RM= rm -f
|
||||
MKDIR= mkdir -p
|
||||
RMDIR= rmdir 2>/dev/null
|
||||
SYMLINK= ln -sf
|
||||
INSTALL_X= install -m 0755
|
||||
INSTALL_F= install -m 0644
|
||||
UNINSTALL= $(RM)
|
||||
LDCONFIG= ldconfig -n 2>/dev/null
|
||||
SED_PC= sed -e "s|^prefix=.*|prefix=$(PREFIX)|" \
|
||||
-e "s|^multilib=.*|multilib=$(MULTILIB)|" \
|
||||
-e "s|^relver=.*|relver=$(RELVER)|"
|
||||
ifneq ($(INSTALL_DEFINC),$(INSTALL_INC))
|
||||
SED_PC+= -e "s|^includedir=.*|includedir=$(INSTALL_INC)|"
|
||||
endif
|
||||
|
||||
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 bcsave.lua dump.lua p.lua v.lua zone.lua \
|
||||
dis_x86.lua dis_x64.lua dis_arm.lua dis_arm64.lua \
|
||||
dis_arm64be.lua dis_ppc.lua dis_mips.lua dis_mipsel.lua \
|
||||
dis_mips64.lua dis_mips64el.lua \
|
||||
dis_mips64r6.lua dis_mips64r6el.lua \
|
||||
vmdef.lua
|
||||
|
||||
ifeq (,$(findstring Windows,$(OS)))
|
||||
HOST_SYS:= $(shell uname -s)
|
||||
else
|
||||
HOST_SYS= Windows
|
||||
endif
|
||||
TARGET_SYS?= $(HOST_SYS)
|
||||
|
||||
ifeq (Darwin,$(TARGET_SYS))
|
||||
INSTALL_SONAME= $(INSTALL_DYLIBNAME)
|
||||
INSTALL_SOSHORT1= $(INSTALL_DYLIBSHORT1)
|
||||
INSTALL_SOSHORT2= $(INSTALL_DYLIBSHORT2)
|
||||
LDCONFIG= :
|
||||
endif
|
||||
|
||||
##############################################################################
|
||||
|
||||
INSTALL_DEP= src/luajit
|
||||
|
||||
default all $(INSTALL_DEP):
|
||||
@echo "==== Building LuaJIT $(MMVERSION) ===="
|
||||
$(MAKE) -C src
|
||||
@echo "==== Successfully built LuaJIT $(MMVERSION) ===="
|
||||
|
||||
install: $(INSTALL_DEP)
|
||||
@echo "==== Installing LuaJIT $(VERSION) to $(PREFIX) ===="
|
||||
$(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_X) $(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 src/jit && $(INSTALL_F) $(FILES_JITLIB) $(INSTALL_JITLIB)
|
||||
$(SYMLINK) $(INSTALL_TNAME) $(INSTALL_TSYM)
|
||||
@echo "==== Successfully installed LuaJIT $(VERSION) to $(PREFIX) ===="
|
||||
|
||||
uninstall:
|
||||
@echo "==== Uninstalling LuaJIT $(VERSION) from $(PREFIX) ===="
|
||||
$(UNINSTALL) $(INSTALL_TSYM) $(INSTALL_T) $(INSTALL_STATIC) $(INSTALL_DYN) $(INSTALL_SHORT1) $(INSTALL_SHORT2) $(INSTALL_MAN)/$(FILE_MAN) $(INSTALL_PC)
|
||||
for file in $(FILES_JITLIB); do \
|
||||
$(UNINSTALL) $(INSTALL_JITLIB)/$$file; \
|
||||
done
|
||||
for file in $(FILES_INC); do \
|
||||
$(UNINSTALL) $(INSTALL_INC)/$$file; \
|
||||
done
|
||||
$(LDCONFIG) $(INSTALL_LIB)
|
||||
$(RMDIR) $(UNINSTALL_DIRS) || :
|
||||
@echo "==== Successfully uninstalled LuaJIT $(VERSION) from $(PREFIX) ===="
|
||||
|
||||
##############################################################################
|
||||
|
||||
amalg:
|
||||
@echo "==== Building LuaJIT $(MMVERSION) (amalgamation) ===="
|
||||
$(MAKE) -C src amalg
|
||||
@echo "==== Successfully built LuaJIT $(MMVERSION) (amalgamation) ===="
|
||||
|
||||
clean:
|
||||
$(MAKE) -C src clean
|
||||
|
||||
.PHONY: all install amalg clean
|
||||
|
||||
##############################################################################
|
||||
16
thirdPart/luajit/README
Normal file
16
thirdPart/luajit/README
Normal file
@@ -0,0 +1,16 @@
|
||||
README for LuaJIT 2.1
|
||||
---------------------
|
||||
|
||||
LuaJIT is a Just-In-Time (JIT) compiler for the Lua programming language.
|
||||
|
||||
Project Homepage: https://luajit.org/
|
||||
|
||||
LuaJIT is Copyright (C) 2005-2023 Mike Pall.
|
||||
LuaJIT is free software, released under the MIT license.
|
||||
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:
|
||||
|
||||
doc/luajit.html
|
||||
|
||||
166
thirdPart/luajit/doc/bluequad-print.css
Normal file
166
thirdPart/luajit/doc/bluequad-print.css
Normal file
@@ -0,0 +1,166 @@
|
||||
/* Copyright (C) 2004-2023 Mike Pall.
|
||||
*
|
||||
* You are welcome to use the general ideas of this design for your own sites.
|
||||
* But please do not steal the stylesheet, the layout or the color scheme.
|
||||
*/
|
||||
body {
|
||||
font-family: serif;
|
||||
font-size: 11pt;
|
||||
margin: 0 3em;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
a:link, a:visited, a:hover, a:active {
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
color: #0000ff;
|
||||
}
|
||||
h1, h2, h3 {
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
margin: 0.5em 0;
|
||||
padding: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 200%;
|
||||
}
|
||||
h2 {
|
||||
font-size: 150%;
|
||||
}
|
||||
h3 {
|
||||
font-size: 125%;
|
||||
}
|
||||
p {
|
||||
margin: 0 0 0.5em 0;
|
||||
padding: 0;
|
||||
}
|
||||
ul, ol {
|
||||
margin: 0.5em 0;
|
||||
padding: 0 0 0 2em;
|
||||
}
|
||||
ul {
|
||||
list-style: outside square;
|
||||
}
|
||||
ol {
|
||||
list-style: outside decimal;
|
||||
}
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
dl {
|
||||
margin: 1em 0;
|
||||
padding: 1em;
|
||||
border: 1px solid black;
|
||||
}
|
||||
dt {
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
dt sup {
|
||||
float: right;
|
||||
margin-left: 1em;
|
||||
}
|
||||
dd {
|
||||
margin: 0.5em 0 0 2em;
|
||||
padding: 0;
|
||||
}
|
||||
table {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
border: 1px solid black;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
tr {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
td {
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 0.2em 0.5em;
|
||||
border-top: 1px solid black;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
tr.separate td {
|
||||
border-top: double;
|
||||
}
|
||||
tt, pre, code, kbd, samp {
|
||||
font-family: monospace;
|
||||
font-size: 75%;
|
||||
}
|
||||
kbd {
|
||||
font-weight: bolder;
|
||||
}
|
||||
blockquote, pre {
|
||||
margin: 1em 2em;
|
||||
padding: 0;
|
||||
}
|
||||
img {
|
||||
border: none;
|
||||
vertical-align: baseline;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
img.left {
|
||||
float: left;
|
||||
margin: 0.5em 1em 0.5em 0;
|
||||
}
|
||||
img.right {
|
||||
float: right;
|
||||
margin: 0.5em 0 0.5em 1em;
|
||||
}
|
||||
.flush {
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
.hide, .noprint, #nav {
|
||||
display: none !important;
|
||||
}
|
||||
.pagebreak {
|
||||
page-break-before: always;
|
||||
}
|
||||
#site {
|
||||
text-align: right;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
margin: 0 1em;
|
||||
border-bottom: 1pt solid black;
|
||||
}
|
||||
#site a {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
#site a:link, #site a:visited {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background: transparent;
|
||||
color: #ffffff;
|
||||
}
|
||||
#logo {
|
||||
color: #ff8000;
|
||||
}
|
||||
#head {
|
||||
clear: both;
|
||||
margin: 0 1em;
|
||||
}
|
||||
#main {
|
||||
line-height: 1.3;
|
||||
text-align: justify;
|
||||
margin: 1em;
|
||||
}
|
||||
#foot {
|
||||
clear: both;
|
||||
font-size: 80%;
|
||||
text-align: center;
|
||||
margin: 0 1.25em;
|
||||
padding: 0.5em 0 0 0;
|
||||
border-top: 1pt solid black;
|
||||
page-break-before: avoid;
|
||||
page-break-after: avoid;
|
||||
}
|
||||
323
thirdPart/luajit/doc/bluequad.css
Normal file
323
thirdPart/luajit/doc/bluequad.css
Normal file
@@ -0,0 +1,323 @@
|
||||
/* Copyright (C) 2004-2023 Mike Pall.
|
||||
*
|
||||
* You are welcome to use the general ideas of this design for your own sites.
|
||||
* But please do not steal the stylesheet, the layout or the color scheme.
|
||||
*/
|
||||
/* colorscheme:
|
||||
*
|
||||
* site | head #4162bf/white | #6078bf/#e6ecff
|
||||
* ------+------ ----------------+-------------------
|
||||
* nav | main #bfcfff | #e6ecff/black
|
||||
*
|
||||
* nav: hiback loback #c5d5ff #b9c9f9
|
||||
* hiborder loborder #e6ecff #97a7d7
|
||||
* link hover #2142bf #ff0000
|
||||
*
|
||||
* link: link visited hover #2142bf #8122bf #ff0000
|
||||
*
|
||||
* main: boxback boxborder #f0f4ff #bfcfff
|
||||
*/
|
||||
body {
|
||||
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||
font-size: 10pt;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: #e0e0e0;
|
||||
color: #000000;
|
||||
}
|
||||
a:link {
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
color: #2142bf;
|
||||
}
|
||||
a:visited {
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
color: #8122bf;
|
||||
}
|
||||
a:hover, a:active {
|
||||
text-decoration: underline;
|
||||
background: transparent;
|
||||
color: #ff0000;
|
||||
}
|
||||
h1, h2, h3 {
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
margin: 0.5em 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
h1 {
|
||||
font-size: 200%;
|
||||
line-height: 3em; /* really 6em relative to body, match #site span */
|
||||
margin: 0;
|
||||
}
|
||||
h2 {
|
||||
font-size: 150%;
|
||||
color: #606060;
|
||||
}
|
||||
h3 {
|
||||
font-size: 125%;
|
||||
color: #404040;
|
||||
}
|
||||
p {
|
||||
max-width: 600px;
|
||||
margin: 0 0 0.5em 0;
|
||||
padding: 0;
|
||||
}
|
||||
b {
|
||||
color: #404040;
|
||||
}
|
||||
ul, ol {
|
||||
max-width: 600px;
|
||||
margin: 0.5em 0;
|
||||
padding: 0 0 0 2em;
|
||||
}
|
||||
ul {
|
||||
list-style: outside square;
|
||||
}
|
||||
ol {
|
||||
list-style: outside decimal;
|
||||
}
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
dl {
|
||||
max-width: 600px;
|
||||
margin: 1em 0;
|
||||
padding: 1em;
|
||||
border: 1px solid #bfcfff;
|
||||
background: #f0f4ff;
|
||||
}
|
||||
dt {
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
dt sup {
|
||||
float: right;
|
||||
margin-left: 1em;
|
||||
color: #808080;
|
||||
}
|
||||
dt a:visited {
|
||||
text-decoration: none;
|
||||
color: #2142bf;
|
||||
}
|
||||
dt a:hover, dt a:active {
|
||||
text-decoration: none;
|
||||
color: #ff0000;
|
||||
}
|
||||
dd {
|
||||
margin: 0.5em 0 0 2em;
|
||||
padding: 0;
|
||||
}
|
||||
div.tablewrap { /* for IE *sigh* */
|
||||
max-width: 600px;
|
||||
}
|
||||
table {
|
||||
table-layout: fixed;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
border: 1px solid #bfcfff;
|
||||
}
|
||||
tr {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
tr.odd {
|
||||
background: #f0f4ff;
|
||||
}
|
||||
tr.separate td {
|
||||
border-top: 1px solid #bfcfff;
|
||||
}
|
||||
td {
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 0.2em 0.5em;
|
||||
border: none;
|
||||
}
|
||||
tt, code, kbd, samp {
|
||||
font-family: Courier New, Courier, monospace;
|
||||
line-height: 1.2;
|
||||
font-size: 110%;
|
||||
}
|
||||
kbd {
|
||||
font-weight: bolder;
|
||||
}
|
||||
blockquote, pre {
|
||||
max-width: 600px;
|
||||
margin: 1em 2em;
|
||||
padding: 0;
|
||||
}
|
||||
pre {
|
||||
line-height: 1.1;
|
||||
}
|
||||
pre.code {
|
||||
line-height: 1.4;
|
||||
margin: 0.5em 0 1em 0.5em;
|
||||
padding: 0.5em 1em;
|
||||
border: 1px solid #bfcfff;
|
||||
background: #f0f4ff;
|
||||
}
|
||||
pre.mark {
|
||||
padding-left: 2em;
|
||||
}
|
||||
span.codemark {
|
||||
position:absolute;
|
||||
left: 16em;
|
||||
color: #4040c0;
|
||||
}
|
||||
span.mark {
|
||||
color: #4040c0;
|
||||
font-family: Courier New, Courier, monospace;
|
||||
line-height: 1.1;
|
||||
}
|
||||
img {
|
||||
border: none;
|
||||
vertical-align: baseline;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
img.left {
|
||||
float: left;
|
||||
margin: 0.5em 1em 0.5em 0;
|
||||
}
|
||||
img.right {
|
||||
float: right;
|
||||
margin: 0.5em 0 0.5em 1em;
|
||||
}
|
||||
.indent {
|
||||
padding-left: 1em;
|
||||
}
|
||||
.flush {
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
.hide, .noscreen {
|
||||
display: none !important;
|
||||
}
|
||||
.ext {
|
||||
color: #ff8000;
|
||||
}
|
||||
.note {
|
||||
padding: 0.5em 1em;
|
||||
border-left: 3px solid #bfcfff;
|
||||
}
|
||||
#site {
|
||||
clear: both;
|
||||
float: left;
|
||||
width: 13em;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: #ffffff;
|
||||
}
|
||||
#site a {
|
||||
font-size: 200%;
|
||||
}
|
||||
#site a:link, #site a:visited {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background: transparent;
|
||||
color: #ffffff;
|
||||
}
|
||||
#site span {
|
||||
line-height: 3em; /* really 6em relative to body, match h1 */
|
||||
}
|
||||
#logo {
|
||||
color: #ffb380;
|
||||
}
|
||||
#head {
|
||||
margin: 0;
|
||||
padding: 0 0 0 2em;
|
||||
border-left: solid 13em #4162bf;
|
||||
border-right: solid 3em #6078bf;
|
||||
background: #6078bf;
|
||||
color: #e6ecff;
|
||||
}
|
||||
#nav {
|
||||
clear: both;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
text-align: left;
|
||||
line-height: 1.5;
|
||||
width: 13em;
|
||||
padding-top: 1em;
|
||||
background: transparent;
|
||||
}
|
||||
#nav ul {
|
||||
list-style: none outside;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#nav li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#nav a {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 2px 1em;
|
||||
border-top: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
background: transparent;
|
||||
color: #2142bf;
|
||||
}
|
||||
#nav a:hover, #nav a:active {
|
||||
text-decoration: none;
|
||||
border-top: 1px solid #97a7d7;
|
||||
border-bottom: 1px solid #e6ecff;
|
||||
background: #b9c9f9;
|
||||
color: #ff0000;
|
||||
}
|
||||
#nav a.current, #nav a.current:hover, #nav a.current:active {
|
||||
border-top: 1px solid #e6ecff;
|
||||
border-bottom: 1px solid #97a7d7;
|
||||
background: #c5d5ff;
|
||||
color: #2142bf;
|
||||
}
|
||||
#nav ul ul a {
|
||||
padding: 0 1em 0 1.7em;
|
||||
}
|
||||
#nav ul ul ul a {
|
||||
padding: 0 0.5em 0 2.4em;
|
||||
}
|
||||
#main {
|
||||
line-height: 1.5;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 1em 2em;
|
||||
border-left: solid 13em #bfcfff;
|
||||
border-right: solid 3em #e6ecff;
|
||||
background: #e6ecff;
|
||||
}
|
||||
#foot {
|
||||
clear: both;
|
||||
font-size: 80%;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
padding: 0.5em;
|
||||
background: #6078bf;
|
||||
color: #ffffff;
|
||||
}
|
||||
#foot a:link, #foot a:visited {
|
||||
text-decoration: underline;
|
||||
background: transparent;
|
||||
color: #ffffff;
|
||||
}
|
||||
#foot a:hover, #foot a:active {
|
||||
text-decoration: underline;
|
||||
background: transparent;
|
||||
color: #bfcfff;
|
||||
}
|
||||
112
thirdPart/luajit/doc/contact.html
Normal file
112
thirdPart/luajit/doc/contact.html
Normal file
@@ -0,0 +1,112 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Contact</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1>Contact</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
<p>
|
||||
If you want to report bugs, propose fixes or suggest enhancements,
|
||||
please use the
|
||||
<a href="https://github.com/LuaJIT/LuaJIT/issues"><span class="ext">»</span> GitHub issue tracker</a>.
|
||||
</p>
|
||||
<p>
|
||||
Please send general questions to the
|
||||
<a href="https://luajit.org/list.html"><span class="ext">»</span> LuaJIT mailing list</a>.
|
||||
</p>
|
||||
<p>
|
||||
You can also send any questions you have directly to me:
|
||||
</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
var xS="@-:\" .0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ<abc>defghijklmnopqrstuvwxyz";function xD(s)
|
||||
{var len=s.length;var r="";for(var i=0;i<len;i++)
|
||||
{var c=s.charAt(i);var n=xS.indexOf(c);if(n!=-1)c=xS.charAt(69-n);r+=c;}
|
||||
document.write("<"+"p>"+r+"<"+"/p>\n");}
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
xD("fyZKB8xv\"FJytmz8.KAB0u52D")
|
||||
//--></script>
|
||||
<noscript>
|
||||
<p><img src="img/contact.png" alt="Contact info in image" width="170" height="13">
|
||||
</p>
|
||||
</noscript>
|
||||
|
||||
<p><i>
|
||||
Note: I cannot reply to GMail, Google Workplace, Outlook or Office365
|
||||
mail addresses, since they prefer to mindlessly filter out mails sent
|
||||
from small domains using independent mail servers, such as mine. If you
|
||||
don't like that, please complain to Google or Microsoft, not me.
|
||||
</i></p>
|
||||
|
||||
<h2>Copyright</h2>
|
||||
<p>
|
||||
All documentation is
|
||||
Copyright © 2005-2023 Mike Pall.
|
||||
</p>
|
||||
|
||||
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
689
thirdPart/luajit/doc/ext_buffer.html
Normal file
689
thirdPart/luajit/doc/ext_buffer.html
Normal file
@@ -0,0 +1,689 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>String Buffer Library</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
<style type="text/css">
|
||||
.lib {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
padding: 0 5px;
|
||||
font-size: 60%;
|
||||
border-radius: 5px;
|
||||
background: #c5d5ff;
|
||||
color: #000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1>String Buffer Library</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a class="current" href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
<p>
|
||||
The string buffer library allows <b>high-performance manipulation of
|
||||
string-like data</b>.
|
||||
</p>
|
||||
<p>
|
||||
Unlike Lua strings, which are constants, string buffers are
|
||||
<b>mutable</b> sequences of 8-bit (binary-transparent) characters. Data
|
||||
can be stored, formatted and encoded into a string buffer and later
|
||||
converted, extracted or decoded.
|
||||
</p>
|
||||
<p>
|
||||
The convenient string buffer API simplifies common string manipulation
|
||||
tasks, that would otherwise require creating many intermediate strings.
|
||||
String buffers improve performance by eliminating redundant memory
|
||||
copies, object creation, string interning and garbage collection
|
||||
overhead. In conjunction with the FFI library, they allow zero-copy
|
||||
operations.
|
||||
</p>
|
||||
<p>
|
||||
The string buffer library also includes a high-performance
|
||||
<a href="#serialize">serializer</a> for Lua objects.
|
||||
</p>
|
||||
|
||||
<h2 id="use">Using the String Buffer Library</h2>
|
||||
<p>
|
||||
The string buffer library is built into LuaJIT by default, but it's not
|
||||
loaded by default. Add this to the start of every Lua file that needs
|
||||
one of its functions:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local buffer = require("string.buffer")
|
||||
</pre>
|
||||
<p>
|
||||
The convention for the syntax shown on this page is that <tt>buffer</tt>
|
||||
refers to the buffer library and <tt>buf</tt> refers to an individual
|
||||
buffer object.
|
||||
</p>
|
||||
<p>
|
||||
Please note the difference between a Lua function call, e.g.
|
||||
<tt>buffer.new()</tt> (with a dot) and a Lua method call, e.g.
|
||||
<tt>buf:reset()</tt> (with a colon).
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_object">Buffer Objects</h3>
|
||||
<p>
|
||||
A buffer object is a garbage-collected Lua object. After creation with
|
||||
<tt>buffer.new()</tt>, it can (and should) be reused for many operations.
|
||||
When the last reference to a buffer object is gone, it will eventually
|
||||
be freed by the garbage collector, along with the allocated buffer
|
||||
space.
|
||||
</p>
|
||||
<p>
|
||||
Buffers operate like a FIFO (first-in first-out) data structure. Data
|
||||
can be appended (written) to the end of the buffer and consumed (read)
|
||||
from the front of the buffer. These operations may be freely mixed.
|
||||
</p>
|
||||
<p>
|
||||
The buffer space that holds the characters is managed automatically
|
||||
— it grows as needed and already consumed space is recycled. Use
|
||||
<tt>buffer.new(size)</tt> and <tt>buf:free()</tt>, if you need more
|
||||
control.
|
||||
</p>
|
||||
<p>
|
||||
The maximum size of a single buffer is the same as the maximum size of a
|
||||
Lua string, which is slightly below two gigabytes. For huge data sizes,
|
||||
neither strings nor buffers are the right data structure — use the
|
||||
FFI library to directly map memory or files up to the virtual memory
|
||||
limit of your OS.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_overview">Buffer Method Overview</h3>
|
||||
<ul>
|
||||
<li>
|
||||
The <tt>buf:put*()</tt>-like methods append (write) characters to the
|
||||
end of the buffer.
|
||||
</li>
|
||||
<li>
|
||||
The <tt>buf:get*()</tt>-like methods consume (read) characters from the
|
||||
front of the buffer.
|
||||
</li>
|
||||
<li>
|
||||
Other methods, like <tt>buf:tostring()</tt> only read the buffer
|
||||
contents, but don't change the buffer.
|
||||
</li>
|
||||
<li>
|
||||
The <tt>buf:set()</tt> method allows zero-copy consumption of a string
|
||||
or an FFI cdata object as a buffer.
|
||||
</li>
|
||||
<li>
|
||||
The FFI-specific methods allow zero-copy read/write-style operations or
|
||||
modifying the buffer contents in-place. Please check the
|
||||
<a href="#ffi_caveats">FFI caveats</a> below, too.
|
||||
</li>
|
||||
<li>
|
||||
Methods that don't need to return anything specific, return the buffer
|
||||
object itself as a convenience. This allows method chaining, e.g.:
|
||||
<tt>buf:reset():encode(obj)</tt> or <tt>buf:skip(len):get()</tt>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="create">Buffer Creation and Management</h2>
|
||||
|
||||
<h3 id="buffer_new"><tt>local buf = buffer.new([size [,options]])<br>
|
||||
local buf = buffer.new([options])</tt></h3>
|
||||
<p>
|
||||
Creates a new buffer object.
|
||||
</p>
|
||||
<p>
|
||||
The optional <tt>size</tt> argument ensures a minimum initial buffer
|
||||
size. This is strictly an optimization when the required buffer size is
|
||||
known beforehand. The buffer space will grow as needed, in any case.
|
||||
</p>
|
||||
<p>
|
||||
The optional table <tt>options</tt> sets various
|
||||
<a href="#serialize_options">serialization options</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_reset"><tt>buf = buf:reset()</tt></h3>
|
||||
<p>
|
||||
Reset (empty) the buffer. The allocated buffer space is not freed and
|
||||
may be reused.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_free"><tt>buf = buf:free()</tt></h3>
|
||||
<p>
|
||||
The buffer space of the buffer object is freed. The object itself
|
||||
remains intact, empty and may be reused.
|
||||
</p>
|
||||
<p>
|
||||
Note: you normally don't need to use this method. The garbage collector
|
||||
automatically frees the buffer space, when the buffer object is
|
||||
collected. Use this method, if you need to free the associated memory
|
||||
immediately.
|
||||
</p>
|
||||
|
||||
<h2 id="write">Buffer Writers</h2>
|
||||
|
||||
<h3 id="buffer_put"><tt>buf = buf:put([str|num|obj] [,…])</tt></h3>
|
||||
<p>
|
||||
Appends a string <tt>str</tt>, a number <tt>num</tt> or any object
|
||||
<tt>obj</tt> with a <tt>__tostring</tt> metamethod to the buffer.
|
||||
Multiple arguments are appended in the given order.
|
||||
</p>
|
||||
<p>
|
||||
Appending a buffer to a buffer is possible and short-circuited
|
||||
internally. But it still involves a copy. Better combine the buffer
|
||||
writes to use a single buffer.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_putf"><tt>buf = buf:putf(format, …)</tt></h3>
|
||||
<p>
|
||||
Appends the formatted arguments to the buffer. The <tt>format</tt>
|
||||
string supports the same options as <tt>string.format()</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_putcdata"><tt>buf = buf:putcdata(cdata, len)</tt><span class="lib">FFI</span></h3>
|
||||
<p>
|
||||
Appends the given <tt>len</tt> number of bytes from the memory pointed
|
||||
to by the FFI <tt>cdata</tt> object to the buffer. The object needs to
|
||||
be convertible to a (constant) pointer.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_set"><tt>buf = buf:set(str)<br>
|
||||
buf = buf:set(cdata, len)</tt><span class="lib">FFI</span></h3>
|
||||
<p>
|
||||
This method allows zero-copy consumption of a string or an FFI cdata
|
||||
object as a buffer. It stores a reference to the passed string
|
||||
<tt>str</tt> or the FFI <tt>cdata</tt> object in the buffer. Any buffer
|
||||
space originally allocated is freed. This is <i>not</i> an append
|
||||
operation, unlike the <tt>buf:put*()</tt> methods.
|
||||
</p>
|
||||
<p>
|
||||
After calling this method, the buffer behaves as if
|
||||
<tt>buf:free():put(str)</tt> or <tt>buf:free():put(cdata, len)</tt>
|
||||
had been called. However, the data is only referenced and not copied, as
|
||||
long as the buffer is only consumed.
|
||||
</p>
|
||||
<p>
|
||||
In case the buffer is written to later on, the referenced data is copied
|
||||
and the object reference is removed (copy-on-write semantics).
|
||||
</p>
|
||||
<p>
|
||||
The stored reference is an anchor for the garbage collector and keeps the
|
||||
originally passed string or FFI cdata object alive.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_reserve"><tt>ptr, len = buf:reserve(size)</tt><span class="lib">FFI</span><br>
|
||||
<tt>buf = buf:commit(used)</tt><span class="lib">FFI</span></h3>
|
||||
<p>
|
||||
The <tt>reserve</tt> method reserves at least <tt>size</tt> bytes of
|
||||
write space in the buffer. It returns an <tt>uint8_t *</tt> FFI
|
||||
cdata pointer <tt>ptr</tt> that points to this space.
|
||||
</p>
|
||||
<p>
|
||||
The available length in bytes is returned in <tt>len</tt>. This is at
|
||||
least <tt>size</tt> bytes, but may be more to facilitate efficient
|
||||
buffer growth. You can either make use of the additional space or ignore
|
||||
<tt>len</tt> and only use <tt>size</tt> bytes.
|
||||
</p>
|
||||
<p>
|
||||
The <tt>commit</tt> method appends the <tt>used</tt> bytes of the
|
||||
previously returned write space to the buffer data.
|
||||
</p>
|
||||
<p>
|
||||
This pair of methods allows zero-copy use of C read-style APIs:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local MIN_SIZE = 65536
|
||||
repeat
|
||||
local ptr, len = buf:reserve(MIN_SIZE)
|
||||
local n = C.read(fd, ptr, len)
|
||||
if n == 0 then break end -- EOF.
|
||||
if n < 0 then error("read error") end
|
||||
buf:commit(n)
|
||||
until false
|
||||
</pre>
|
||||
<p>
|
||||
The reserved write space is <i>not</i> initialized. At least the
|
||||
<tt>used</tt> bytes <b>must</b> be written to before calling the
|
||||
<tt>commit</tt> method. There's no need to call the <tt>commit</tt>
|
||||
method, if nothing is added to the buffer (e.g. on error).
|
||||
</p>
|
||||
|
||||
<h2 id="read">Buffer Readers</h2>
|
||||
|
||||
<h3 id="buffer_length"><tt>len = #buf</tt></h3>
|
||||
<p>
|
||||
Returns the current length of the buffer data in bytes.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_concat"><tt>res = str|num|buf .. str|num|buf […]</tt></h3>
|
||||
<p>
|
||||
The Lua concatenation operator <tt>..</tt> also accepts buffers, just
|
||||
like strings or numbers. It always returns a string and not a buffer.
|
||||
</p>
|
||||
<p>
|
||||
Note that although this is supported for convenience, this thwarts one
|
||||
of the main reasons to use buffers, which is to avoid string
|
||||
allocations. Rewrite it with <tt>buf:put()</tt> and <tt>buf:get()</tt>.
|
||||
</p>
|
||||
<p>
|
||||
Mixing this with unrelated objects that have a <tt>__concat</tt>
|
||||
metamethod may not work, since these probably only expect strings.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_skip"><tt>buf = buf:skip(len)</tt></h3>
|
||||
<p>
|
||||
Skips (consumes) <tt>len</tt> bytes from the buffer up to the current
|
||||
length of the buffer data.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_get"><tt>str, … = buf:get([len|nil] [,…])</tt></h3>
|
||||
<p>
|
||||
Consumes the buffer data and returns one or more strings. If called
|
||||
without arguments, the whole buffer data is consumed. If called with a
|
||||
number, up to <tt>len</tt> bytes are consumed. A <tt>nil</tt> argument
|
||||
consumes the remaining buffer space (this only makes sense as the last
|
||||
argument). Multiple arguments consume the buffer data in the given
|
||||
order.
|
||||
</p>
|
||||
<p>
|
||||
Note: a zero length or no remaining buffer data returns an empty string
|
||||
and not <tt>nil</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_tostring"><tt>str = buf:tostring()<br>
|
||||
str = tostring(buf)</tt></h3>
|
||||
<p>
|
||||
Creates a string from the buffer data, but doesn't consume it. The
|
||||
buffer remains unchanged.
|
||||
</p>
|
||||
<p>
|
||||
Buffer objects also define a <tt>__tostring</tt> metamethod. This means
|
||||
buffers can be passed to the global <tt>tostring()</tt> function and
|
||||
many other functions that accept this in place of strings. The important
|
||||
internal uses in functions like <tt>io.write()</tt> are short-circuited
|
||||
to avoid the creation of an intermediate string object.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_ref"><tt>ptr, len = buf:ref()</tt><span class="lib">FFI</span></h3>
|
||||
<p>
|
||||
Returns an <tt>uint8_t *</tt> FFI cdata pointer <tt>ptr</tt> that
|
||||
points to the buffer data. The length of the buffer data in bytes is
|
||||
returned in <tt>len</tt>.
|
||||
</p>
|
||||
<p>
|
||||
The returned pointer can be directly passed to C functions that expect a
|
||||
buffer and a length. You can also do bytewise reads
|
||||
(<tt>local x = ptr[i]</tt>) or writes
|
||||
(<tt>ptr[i] = 0x40</tt>) of the buffer data.
|
||||
</p>
|
||||
<p>
|
||||
In conjunction with the <tt>skip</tt> method, this allows zero-copy use
|
||||
of C write-style APIs:
|
||||
</p>
|
||||
<pre class="code">
|
||||
repeat
|
||||
local ptr, len = buf:ref()
|
||||
if len == 0 then break end
|
||||
local n = C.write(fd, ptr, len)
|
||||
if n < 0 then error("write error") end
|
||||
buf:skip(n)
|
||||
until n >= len
|
||||
</pre>
|
||||
<p>
|
||||
Unlike Lua strings, buffer data is <i>not</i> implicitly
|
||||
zero-terminated. It's not safe to pass <tt>ptr</tt> to C functions that
|
||||
expect zero-terminated strings. If you're not using <tt>len</tt>, then
|
||||
you're doing something wrong.
|
||||
</p>
|
||||
|
||||
<h2 id="serialize">Serialization of Lua Objects</h2>
|
||||
<p>
|
||||
The following functions and methods allow <b>high-speed serialization</b>
|
||||
(encoding) of a Lua object into a string and decoding it back to a Lua
|
||||
object. This allows convenient storage and transport of <b>structured
|
||||
data</b>.
|
||||
</p>
|
||||
<p>
|
||||
The encoded data is in an <a href="#serialize_format">internal binary
|
||||
format</a>. The data can be stored in files, binary-transparent
|
||||
databases or transmitted to other LuaJIT instances across threads,
|
||||
processes or networks.
|
||||
</p>
|
||||
<p>
|
||||
Encoding speed can reach up to 1 Gigabyte/second on a modern desktop- or
|
||||
server-class system, even when serializing many small objects. Decoding
|
||||
speed is mostly constrained by object creation cost.
|
||||
</p>
|
||||
<p>
|
||||
The serializer handles most Lua types, common FFI number types and
|
||||
nested structures. Functions, thread objects, other FFI cdata and full
|
||||
userdata cannot be serialized (yet).
|
||||
</p>
|
||||
<p>
|
||||
The encoder serializes nested structures as trees. Multiple references
|
||||
to a single object will be stored separately and create distinct objects
|
||||
after decoding. Circular references cause an error.
|
||||
</p>
|
||||
|
||||
<h3 id="serialize_methods">Serialization Functions and Methods</h3>
|
||||
|
||||
<h3 id="buffer_encode"><tt>str = buffer.encode(obj)<br>
|
||||
buf = buf:encode(obj)</tt></h3>
|
||||
<p>
|
||||
Serializes (encodes) the Lua object <tt>obj</tt>. The stand-alone
|
||||
function returns a string <tt>str</tt>. The buffer method appends the
|
||||
encoding to the buffer.
|
||||
</p>
|
||||
<p>
|
||||
<tt>obj</tt> can be any of the supported Lua types — it doesn't
|
||||
need to be a Lua table.
|
||||
</p>
|
||||
<p>
|
||||
This function may throw an error when attempting to serialize
|
||||
unsupported object types, circular references or deeply nested tables.
|
||||
</p>
|
||||
|
||||
<h3 id="buffer_decode"><tt>obj = buffer.decode(str)<br>
|
||||
obj = buf:decode()</tt></h3>
|
||||
<p>
|
||||
The stand-alone function deserializes (decodes) the string
|
||||
<tt>str</tt>, the buffer method deserializes one object from the
|
||||
buffer. Both return a Lua object <tt>obj</tt>.
|
||||
</p>
|
||||
<p>
|
||||
The returned object may be any of the supported Lua types —
|
||||
even <tt>nil</tt>.
|
||||
</p>
|
||||
<p>
|
||||
This function may throw an error when fed with malformed or incomplete
|
||||
encoded data. The stand-alone function throws when there's left-over
|
||||
data after decoding a single top-level object. The buffer method leaves
|
||||
any left-over data in the buffer.
|
||||
</p>
|
||||
<p>
|
||||
Attempting to deserialize an FFI type will throw an error, if the FFI
|
||||
library is not built-in or has not been loaded, yet.
|
||||
</p>
|
||||
|
||||
<h3 id="serialize_options">Serialization Options</h3>
|
||||
<p>
|
||||
The <tt>options</tt> table passed to <tt>buffer.new()</tt> may contain
|
||||
the following members (all optional):
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<tt>dict</tt> is a Lua table holding a <b>dictionary of strings</b> that
|
||||
commonly occur as table keys of objects you are serializing. These keys
|
||||
are compactly encoded as indexes during serialization. A well-chosen
|
||||
dictionary saves space and improves serialization performance.
|
||||
</li>
|
||||
<li>
|
||||
<tt>metatable</tt> is a Lua table holding a <b>dictionary of metatables</b>
|
||||
for the table objects you are serializing.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
<tt>dict</tt> needs to be an array of strings and <tt>metatable</tt> needs
|
||||
to be an array of tables. Both starting at index 1 and without holes (no
|
||||
<tt>nil</tt> in between). The tables are anchored in the buffer object and
|
||||
internally modified into a two-way index (don't do this yourself, just pass
|
||||
a plain array). The tables must not be modified after they have been passed
|
||||
to <tt>buffer.new()</tt>.
|
||||
</p>
|
||||
<p>
|
||||
The <tt>dict</tt> and <tt>metatable</tt> tables used by the encoder and
|
||||
decoder must be the same. Put the most common entries at the front. Extend
|
||||
at the end to ensure backwards-compatibility — older encodings can
|
||||
then still be read. You may also set some indexes to <tt>false</tt> to
|
||||
explicitly drop backwards-compatibility. Old encodings that use these
|
||||
indexes will throw an error when decoded.
|
||||
</p>
|
||||
<p>
|
||||
Metatables that are not found in the <tt>metatable</tt> dictionary are
|
||||
ignored when encoding. Decoding returns a table with a <tt>nil</tt>
|
||||
metatable.
|
||||
</p>
|
||||
<p>
|
||||
Note: parsing and preparation of the options table is somewhat
|
||||
expensive. Create a buffer object only once and recycle it for multiple
|
||||
uses. Avoid mixing encoder and decoder buffers, since the
|
||||
<tt>buf:set()</tt> method frees the already allocated buffer space:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local options = {
|
||||
dict = { "commonly", "used", "string", "keys" },
|
||||
}
|
||||
local buf_enc = buffer.new(options)
|
||||
local buf_dec = buffer.new(options)
|
||||
|
||||
local function encode(obj)
|
||||
return buf_enc:reset():encode(obj):get()
|
||||
end
|
||||
|
||||
local function decode(str)
|
||||
return buf_dec:set(str):decode()
|
||||
end
|
||||
</pre>
|
||||
|
||||
<h3 id="serialize_stream">Streaming Serialization</h3>
|
||||
<p>
|
||||
In some contexts, it's desirable to do piecewise serialization of large
|
||||
datasets, also known as <i>streaming</i>.
|
||||
</p>
|
||||
<p>
|
||||
This serialization format can be safely concatenated and supports streaming.
|
||||
Multiple encodings can simply be appended to a buffer and later decoded
|
||||
individually:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local buf = buffer.new()
|
||||
buf:encode(obj1)
|
||||
buf:encode(obj2)
|
||||
local copy1 = buf:decode()
|
||||
local copy2 = buf:decode()
|
||||
</pre>
|
||||
<p>
|
||||
Here's how to iterate over a stream:
|
||||
</p>
|
||||
<pre class="code">
|
||||
while #buf ~= 0 do
|
||||
local obj = buf:decode()
|
||||
-- Do something with obj.
|
||||
end
|
||||
</pre>
|
||||
<p>
|
||||
Since the serialization format doesn't prepend a length to its encoding,
|
||||
network applications may need to transmit the length, too.
|
||||
</p>
|
||||
|
||||
<h3 id="serialize_format">Serialization Format Specification</h3>
|
||||
<p>
|
||||
This serialization format is designed for <b>internal use</b> by LuaJIT
|
||||
applications. Serialized data is upwards-compatible and portable across
|
||||
all supported LuaJIT platforms.
|
||||
</p>
|
||||
<p>
|
||||
It's an <b>8-bit binary format</b> and not human-readable. It uses e.g.
|
||||
embedded zeroes and stores embedded Lua string objects unmodified, which
|
||||
are 8-bit-clean, too. Encoded data can be safely concatenated for
|
||||
streaming and later decoded one top-level object at a time.
|
||||
</p>
|
||||
<p>
|
||||
The encoding is reasonably compact, but tuned for maximum performance,
|
||||
not for minimum space usage. It compresses well with any of the common
|
||||
byte-oriented data compression algorithms.
|
||||
</p>
|
||||
<p>
|
||||
Although documented here for reference, this format is explicitly
|
||||
<b>not</b> intended to be a 'public standard' for structured data
|
||||
interchange across computer languages (like JSON or MessagePack). Please
|
||||
do not use it as such.
|
||||
</p>
|
||||
<p>
|
||||
The specification is given below as a context-free grammar with a
|
||||
top-level <tt>object</tt> as the starting point. Alternatives are
|
||||
separated by the <tt>|</tt> symbol and <tt>*</tt> indicates repeats.
|
||||
Grouping is implicit or indicated by <tt>{…}</tt>. Terminals are
|
||||
either plain hex numbers, encoded as bytes, or have a <tt>.format</tt>
|
||||
suffix.
|
||||
</p>
|
||||
<pre>
|
||||
object → nil | false | true
|
||||
| null | lightud32 | lightud64
|
||||
| int | num | tab | tab_mt
|
||||
| int64 | uint64 | complex
|
||||
| string
|
||||
|
||||
nil → 0x00
|
||||
false → 0x01
|
||||
true → 0x02
|
||||
|
||||
null → 0x03 // NULL lightuserdata
|
||||
lightud32 → 0x04 data.I // 32 bit lightuserdata
|
||||
lightud64 → 0x05 data.L // 64 bit lightuserdata
|
||||
|
||||
int → 0x06 int.I // int32_t
|
||||
num → 0x07 double.L
|
||||
|
||||
tab → 0x08 // Empty table
|
||||
| 0x09 h.U h*{object object} // Key/value hash
|
||||
| 0x0a a.U a*object // 0-based array
|
||||
| 0x0b a.U h.U a*object h*{object object} // Mixed
|
||||
| 0x0c a.U (a-1)*object // 1-based array
|
||||
| 0x0d a.U h.U (a-1)*object h*{object object} // Mixed
|
||||
tab_mt → 0x0e (index-1).U tab // Metatable dict entry
|
||||
|
||||
int64 → 0x10 int.L // FFI int64_t
|
||||
uint64 → 0x11 uint.L // FFI uint64_t
|
||||
complex → 0x12 re.L im.L // FFI complex
|
||||
|
||||
string → (0x20+len).U len*char.B
|
||||
| 0x0f (index-1).U // String dict entry
|
||||
|
||||
.B = 8 bit
|
||||
.I = 32 bit little-endian
|
||||
.L = 64 bit little-endian
|
||||
.U = prefix-encoded 32 bit unsigned number n:
|
||||
0x00..0xdf → n.B
|
||||
0xe0..0x1fdf → (0xe0|(((n-0xe0)>>8)&0x1f)).B ((n-0xe0)&0xff).B
|
||||
0x1fe0.. → 0xff n.I
|
||||
</pre>
|
||||
|
||||
<h2 id="error">Error handling</h2>
|
||||
<p>
|
||||
Many of the buffer methods can throw an error. Out-of-memory or usage
|
||||
errors are best caught with an outer wrapper for larger parts of code.
|
||||
There's not much one can do after that, anyway.
|
||||
</p>
|
||||
<p>
|
||||
OTOH, you may want to catch some errors individually. Buffer methods need
|
||||
to receive the buffer object as the first argument. The Lua colon-syntax
|
||||
<tt>obj:method()</tt> does that implicitly. But to wrap a method with
|
||||
<tt>pcall()</tt>, the arguments need to be passed like this:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local ok, err = pcall(buf.encode, buf, obj)
|
||||
if not ok then
|
||||
-- Handle error in err.
|
||||
end
|
||||
</pre>
|
||||
|
||||
<h2 id="ffi_caveats">FFI caveats</h2>
|
||||
<p>
|
||||
The string buffer library has been designed to work well together with
|
||||
the FFI library. But due to the low-level nature of the FFI library,
|
||||
some care needs to be taken:
|
||||
</p>
|
||||
<p>
|
||||
First, please remember that FFI pointers are zero-indexed. The space
|
||||
returned by <tt>buf:reserve()</tt> and <tt>buf:ref()</tt> starts at the
|
||||
returned pointer and ends before <tt>len</tt> bytes after that.
|
||||
</p>
|
||||
<p>
|
||||
I.e. the first valid index is <tt>ptr[0]</tt> and the last valid index
|
||||
is <tt>ptr[len-1]</tt>. If the returned length is zero, there's no valid
|
||||
index at all. The returned pointer may even be <tt>NULL</tt>.
|
||||
</p>
|
||||
<p>
|
||||
The space pointed to by the returned pointer is only valid as long as
|
||||
the buffer is not modified in any way (neither append, nor consume, nor
|
||||
reset, etc.). The pointer is also not a GC anchor for the buffer object
|
||||
itself.
|
||||
</p>
|
||||
<p>
|
||||
Buffer data is only guaranteed to be byte-aligned. Casting the returned
|
||||
pointer to a data type with higher alignment may cause unaligned
|
||||
accesses. It depends on the CPU architecture whether this is allowed or
|
||||
not (it's always OK on x86/x64 and mostly OK on other modern
|
||||
architectures).
|
||||
</p>
|
||||
<p>
|
||||
FFI pointers or references do not count as GC anchors for an underlying
|
||||
object. E.g. an <tt>array</tt> allocated with <tt>ffi.new()</tt> is
|
||||
anchored by <tt>buf:set(array, len)</tt>, but not by
|
||||
<tt>buf:set(array+offset, len)</tt>. The addition of the offset
|
||||
creates a new pointer, even when the offset is zero. In this case, you
|
||||
need to make sure there's still a reference to the original array as
|
||||
long as its contents are in use by the buffer.
|
||||
</p>
|
||||
<p>
|
||||
Even though each LuaJIT VM instance is single-threaded (but you can
|
||||
create multiple VMs), FFI data structures can be accessed concurrently.
|
||||
Be careful when reading/writing FFI cdata from/to buffers to avoid
|
||||
concurrent accesses or modifications. In particular, the memory
|
||||
referenced by <tt>buf:set(cdata, len)</tt> must not be modified
|
||||
while buffer readers are working on it. Shared, but read-only memory
|
||||
mappings of files are OK, but only if the file does not change.
|
||||
</p>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
183
thirdPart/luajit/doc/ext_c_api.html
Normal file
183
thirdPart/luajit/doc/ext_c_api.html
Normal file
@@ -0,0 +1,183 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Lua/C API Extensions</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1>Lua/C API Extensions</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a class="current" href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
<p>
|
||||
LuaJIT adds some extensions to the standard 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>
|
||||
— 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 off,
|
||||
<tt>LUAJIT_MODE_ON</tt> to turn a feature on, 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 sub-functions of the function with
|
||||
<tt>LUAJIT_MODE_ALLFUNC</tt> or only to the sub-functions with
|
||||
<tt>LUAJIT_MODE_ALLSUBFUNC</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="mode_trace"><tt>luaJIT_setmode(L, trace,<br>
|
||||
LUAJIT_MODE_TRACE|LUAJIT_MODE_FLUSH)</tt></h3>
|
||||
<p>
|
||||
Flushes the specified root trace and all of its side traces from the cache.
|
||||
The code for the trace will be retained as long as there are any other
|
||||
traces which link to it.
|
||||
</p>
|
||||
|
||||
<h3 id="mode_wrapcfunc"><tt>luaJIT_setmode(L, idx, LUAJIT_MODE_WRAPCFUNC|flag)</tt></h3>
|
||||
<p>
|
||||
This mode defines a wrapper function for calls to C functions. If
|
||||
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. From now on, all C functions are called through the wrapper
|
||||
function. If called with <tt>LUAJIT_MODE_OFF</tt> this mode is turned
|
||||
off and all C functions are directly called.
|
||||
</p>
|
||||
<p>
|
||||
The wrapper function can be used for debugging purposes or to catch
|
||||
and convert foreign exceptions. But please read the section on
|
||||
<a href="extensions.html#exceptions">C++ exception interoperability</a>
|
||||
first. Recommended usage can be seen in this C++ code excerpt:
|
||||
</p>
|
||||
<pre class="code">
|
||||
#include <exception>
|
||||
#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 myinit(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);
|
||||
...
|
||||
}
|
||||
</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.
|
||||
</p>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
326
thirdPart/luajit/doc/ext_ffi.html
Normal file
326
thirdPart/luajit/doc/ext_ffi.html
Normal file
@@ -0,0 +1,326 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>FFI Library</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1>FFI Library</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a class="current" href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
<p>
|
||||
|
||||
The FFI library allows <b>calling external C functions</b> and
|
||||
<b>using C data structures</b> from pure Lua code.
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
The FFI library largely obviates the need to write tedious manual
|
||||
Lua/C bindings in C. No need to learn a separate binding language
|
||||
— <b>it parses plain C declarations!</b> These can be
|
||||
cut-n-pasted from C header files or reference manuals. It's up to
|
||||
the task of binding large libraries without the need for dealing with
|
||||
fragile binding generators.
|
||||
|
||||
</p>
|
||||
<p>
|
||||
The FFI library is tightly integrated into LuaJIT (it's not available
|
||||
as a separate module). The code generated by the JIT-compiler for
|
||||
accesses to C data structures from Lua code is on par with the
|
||||
code a C compiler would generate. Calls to C functions can
|
||||
be inlined in JIT-compiled code, unlike calls to functions bound via
|
||||
the classic Lua/C API.
|
||||
</p>
|
||||
<p>
|
||||
This page gives a short introduction to the usage of the FFI library.
|
||||
<em>Please use the FFI sub-topics in the navigation bar to learn more.</em>
|
||||
</p>
|
||||
|
||||
<h2 id="call">Motivating Example: Calling External C Functions</h2>
|
||||
<p>
|
||||
It's really easy to call an external C library function:
|
||||
</p>
|
||||
<pre class="code mark">
|
||||
<span class="codemark">①
|
||||
②
|
||||
|
||||
|
||||
③</span>local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
<span style="color:#00a000;">int printf(const char *fmt, ...);</span>
|
||||
]]
|
||||
ffi.C.printf("Hello %s!", "world")
|
||||
</pre>
|
||||
<p>
|
||||
So, let's pick that apart:
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">①</span> Load the FFI library.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">②</span> Add a C declaration
|
||||
for the function. The part inside the double-brackets (in green) is
|
||||
just standard C syntax.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">③</span> Call the named
|
||||
C function — Yes, it's that simple!
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
Actually, what goes on behind the scenes is far from simple: <span
|
||||
style="color:#4040c0;">③</span> makes use of the standard
|
||||
C library namespace <tt>ffi.C</tt>. Indexing this namespace with
|
||||
a symbol name (<tt>"printf"</tt>) automatically binds it to the
|
||||
standard C library. The result is a special kind of object which,
|
||||
when called, runs the <tt>printf</tt> function. The arguments passed
|
||||
to this function are automatically converted from Lua objects to the
|
||||
corresponding C types.
|
||||
</p>
|
||||
<p>
|
||||
Ok, so maybe the use of <tt>printf()</tt> wasn't such a spectacular
|
||||
example. You could have done that with <tt>io.write()</tt> and
|
||||
<tt>string.format()</tt>, too. But you get the idea ...
|
||||
</p>
|
||||
<p>
|
||||
So here's something to pop up a message box on Windows:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
<span style="color:#00a000;">int MessageBoxA(void *w, const char *txt, const char *cap, int type);</span>
|
||||
]]
|
||||
ffi.C.MessageBoxA(nil, "Hello world!", "Test", 0)
|
||||
</pre>
|
||||
<p>
|
||||
Bing! Again, that was far too easy, no?
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
Compare this with the effort required to bind that function using the
|
||||
classic Lua/C API: create an extra C file, add a C function
|
||||
that retrieves and checks the argument types passed from Lua and calls
|
||||
the actual C function, add a list of module functions and their
|
||||
names, add a <tt>luaopen_*</tt> function and register all module
|
||||
functions, compile and link it into a shared library (DLL), move it to
|
||||
the proper path, add Lua code that loads the module aaaand ... finally
|
||||
call the binding function. Phew!
|
||||
</p>
|
||||
|
||||
<h2 id="cdata">Motivating Example: Using C Data Structures</h2>
|
||||
<p>
|
||||
The FFI library allows you to create and access C data
|
||||
structures. Of course, the main use for this is for interfacing with
|
||||
C functions. But they can be used stand-alone, too.
|
||||
</p>
|
||||
<p>
|
||||
Lua is built upon high-level data types. They are flexible, extensible
|
||||
and dynamic. That's why we all love Lua so much. Alas, this can be
|
||||
inefficient for certain tasks, where you'd really want a low-level
|
||||
data type. E.g. a large array of a fixed structure needs to be
|
||||
implemented with a big table holding lots of tiny tables. This imposes
|
||||
both a substantial memory overhead as well as a performance overhead.
|
||||
</p>
|
||||
<p>
|
||||
Here's a sketch of a library that operates on color images, plus a
|
||||
simple benchmark. First, the plain Lua version:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local floor = math.floor
|
||||
|
||||
local function image_ramp_green(n)
|
||||
local img = {}
|
||||
local f = 255/(n-1)
|
||||
for i=1,n do
|
||||
img[i] = { red = 0, green = floor((i-1)*f), blue = 0, alpha = 255 }
|
||||
end
|
||||
return img
|
||||
end
|
||||
|
||||
local function image_to_gray(img, n)
|
||||
for i=1,n do
|
||||
local y = floor(0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue)
|
||||
img[i].red = y; img[i].green = y; img[i].blue = y
|
||||
end
|
||||
end
|
||||
|
||||
local N = 400*400
|
||||
local img = image_ramp_green(N)
|
||||
for i=1,1000 do
|
||||
image_to_gray(img, N)
|
||||
end
|
||||
</pre>
|
||||
<p>
|
||||
This creates a table with 160.000 pixels, each of which is a table
|
||||
holding four number values in the range of 0-255. First, an image with
|
||||
a green ramp is created (1D for simplicity), then the image is
|
||||
converted to grayscale 1000 times. Yes, that's silly, but I was in
|
||||
need of a simple example ...
|
||||
</p>
|
||||
<p>
|
||||
And here's the FFI version. The modified parts have been marked in
|
||||
bold:
|
||||
</p>
|
||||
<pre class="code mark">
|
||||
<span class="codemark">①
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
②
|
||||
|
||||
③
|
||||
④
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
③
|
||||
⑤</span><b>local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
</b><span style="color:#00a000;">typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel;</span><b>
|
||||
]]</b>
|
||||
|
||||
local function image_ramp_green(n)
|
||||
<b>local img = ffi.new("rgba_pixel[?]", n)</b>
|
||||
local f = 255/(n-1)
|
||||
for i=<b>0,n-1</b> do
|
||||
<b>img[i].green = i*f</b>
|
||||
<b>img[i].alpha = 255</b>
|
||||
end
|
||||
return img
|
||||
end
|
||||
|
||||
local function image_to_grey(img, n)
|
||||
for i=<b>0,n-1</b> do
|
||||
local y = <b>0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue</b>
|
||||
img[i].red = y; img[i].green = y; img[i].blue = y
|
||||
end
|
||||
end
|
||||
|
||||
local N = 400*400
|
||||
local img = image_ramp_green(N)
|
||||
for i=1,1000 do
|
||||
image_to_grey(img, N)
|
||||
end
|
||||
</pre>
|
||||
<p>
|
||||
Ok, so that wasn't too difficult:
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">①</span> First, load the FFI
|
||||
library and declare the low-level data type. Here we choose a
|
||||
<tt>struct</tt> which holds four byte fields, one for each component
|
||||
of a 4x8 bit RGBA pixel.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">②</span> Creating the data
|
||||
structure with <tt>ffi.new()</tt> is straightforward — the
|
||||
<tt>'?'</tt> is a placeholder for the number of elements of a
|
||||
variable-length array.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">③</span> C arrays are
|
||||
zero-based, so the indexes have to run from <tt>0</tt> to
|
||||
<tt>n-1</tt>. One might want to allocate one more element instead to
|
||||
simplify converting legacy code.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">④</span> Since <tt>ffi.new()</tt>
|
||||
zero-fills the array by default, we only need to set the green and the
|
||||
alpha fields.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">⑤</span> The calls to
|
||||
<tt>math.floor()</tt> can be omitted here, because floating-point
|
||||
numbers are already truncated towards zero when converting them to an
|
||||
integer. This happens implicitly when the number is stored in the
|
||||
fields of each pixel.
|
||||
</p>
|
||||
<p>
|
||||
Now let's have a look at the impact of the changes: first, memory
|
||||
consumption for the image is down from 22 Megabytes to
|
||||
640 Kilobytes (400*400*4 bytes). That's a factor of 35x less! So,
|
||||
yes, tables do have a noticeable overhead. BTW: The original program
|
||||
would consume 40 Megabytes in plain Lua (on x64).
|
||||
</p>
|
||||
<p>
|
||||
Next, performance: the pure Lua version runs in 9.57 seconds (52.9
|
||||
seconds with the Lua interpreter) and the FFI version runs in 0.48
|
||||
seconds on my machine (YMMV). That's a factor of 20x faster (110x
|
||||
faster than the Lua interpreter).
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
The avid reader may notice that converting the pure Lua version over
|
||||
to use array indexes for the colors (<tt>[1]</tt> instead of
|
||||
<tt>.red</tt>, <tt>[2]</tt> instead of <tt>.green</tt> etc.) ought to
|
||||
be more compact and faster. This is certainly true (by a factor of
|
||||
~1.7x). Switching to a struct-of-arrays would help, too.
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
However, the resulting code would be less idiomatic and rather
|
||||
error-prone. And it still doesn't get even close to the performance of
|
||||
the FFI version of the code. Also, high-level data structures cannot
|
||||
be easily passed to other C functions, especially I/O functions,
|
||||
without undue conversion penalties.
|
||||
</p>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
568
thirdPart/luajit/doc/ext_ffi_api.html
Normal file
568
thirdPart/luajit/doc/ext_ffi_api.html
Normal file
@@ -0,0 +1,568 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>ffi.* API Functions</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
<style type="text/css">
|
||||
table.abitable { width: 30em; line-height: 1.2; }
|
||||
tr.abihead td { font-weight: bold; }
|
||||
td.abiparam { font-weight: bold; width: 6em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1><tt>ffi.*</tt> API Functions</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a class="current" href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
<p>
|
||||
This page describes the API functions provided by the FFI library in
|
||||
detail. It's recommended to read through the
|
||||
<a href="ext_ffi.html">introduction</a> and the
|
||||
<a href="ext_ffi_tutorial.html">FFI tutorial</a> first.
|
||||
</p>
|
||||
|
||||
<h2 id="glossary">Glossary</h2>
|
||||
<ul>
|
||||
<li><b>cdecl</b> — An abstract C type declaration (a Lua
|
||||
string).</li>
|
||||
<li><b>ctype</b> — A C type object. This is a special kind of
|
||||
<b>cdata</b> returned by <tt>ffi.typeof()</tt>. It serves as a
|
||||
<b>cdata</b> <a href="#ffi_new">constructor</a> when called.</li>
|
||||
<li><b>cdata</b> — A C data object. It holds a value of the
|
||||
corresponding <b>ctype</b>.</li>
|
||||
<li><b>ct</b> — A C type specification which can be used for
|
||||
most of the API functions. Either a <b>cdecl</b>, a <b>ctype</b> or a
|
||||
<b>cdata</b> serving as a template type.</li>
|
||||
<li><b>cb</b> — A callback object. This is a C data object
|
||||
holding a special function pointer. Calling this function from
|
||||
C code runs an associated Lua function.</li>
|
||||
<li><b>VLA</b> — A variable-length array is declared with a
|
||||
<tt>?</tt> instead of the number of elements, e.g. <tt>"int[?]"</tt>.
|
||||
The number of elements (<tt>nelem</tt>) must be given when it's
|
||||
<a href="#ffi_new">created</a>.</li>
|
||||
<li><b>VLS</b> — A variable-length struct is a <tt>struct</tt> C
|
||||
type where the last element is a <b>VLA</b>. The same rules for
|
||||
declaration and creation apply.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="decl">Declaring and Accessing External Symbols</h2>
|
||||
<p>
|
||||
External symbols must be declared first and can then be accessed by
|
||||
indexing a <a href="ext_ffi_semantics.html#clib">C library
|
||||
namespace</a>, which automatically binds the symbol to a specific
|
||||
library.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_cdef"><tt>ffi.cdef(def)</tt></h3>
|
||||
<p>
|
||||
Adds multiple C declarations for types or external symbols (named
|
||||
variables or functions). <tt>def</tt> must be a Lua string. It's
|
||||
recommended to use the syntactic sugar for string arguments as
|
||||
follows:
|
||||
</p>
|
||||
<pre class="code">
|
||||
ffi.cdef[[
|
||||
<span style="color:#00a000;">typedef struct foo { int a, b; } foo_t; // Declare a struct and typedef.
|
||||
int dofoo(foo_t *f, int n); /* Declare an external C function. */</span>
|
||||
]]
|
||||
</pre>
|
||||
<p>
|
||||
The contents of the string (the part in green above) must be a
|
||||
sequence of
|
||||
<a href="ext_ffi_semantics.html#clang">C declarations</a>,
|
||||
separated by semicolons. The trailing semicolon for a single
|
||||
declaration may be omitted.
|
||||
</p>
|
||||
<p>
|
||||
Please note, that external symbols are only <em>declared</em>, but they
|
||||
are <em>not bound</em> to any specific address, yet. Binding is
|
||||
achieved with C library namespaces (see below).
|
||||
</p>
|
||||
<p style="color: #c00000;">
|
||||
C declarations are not passed through a C pre-processor,
|
||||
yet. No pre-processor tokens are allowed, except for
|
||||
<tt>#pragma pack</tt>. Replace <tt>#define</tt> in existing
|
||||
C header files with <tt>enum</tt>, <tt>static const</tt>
|
||||
or <tt>typedef</tt> and/or pass the files through an external
|
||||
C pre-processor (once). Be careful not to include unneeded or
|
||||
redundant declarations from unrelated header files.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_C"><tt>ffi.C</tt></h3>
|
||||
<p>
|
||||
This is the default C library namespace — note the
|
||||
uppercase <tt>'C'</tt>. It binds to the default set of symbols or
|
||||
libraries on the target system. These are more or less the same as a
|
||||
C compiler would offer by default, without specifying extra link
|
||||
libraries.
|
||||
</p>
|
||||
<p>
|
||||
On POSIX systems, this binds to symbols in the default or global
|
||||
namespace. This includes all exported symbols from the executable and
|
||||
any libraries loaded into the global namespace. This includes at least
|
||||
<tt>libc</tt>, <tt>libm</tt>, <tt>libdl</tt> (on Linux),
|
||||
<tt>libgcc</tt> (if compiled with GCC), as well as any exported
|
||||
symbols from the Lua/C API provided by LuaJIT itself.
|
||||
</p>
|
||||
<p>
|
||||
On Windows systems, this binds to symbols exported from the
|
||||
<tt>*.exe</tt>, the <tt>lua51.dll</tt> (i.e. the Lua/C API
|
||||
provided by LuaJIT itself), the C runtime library LuaJIT was linked
|
||||
with (<tt>msvcrt*.dll</tt>), <tt>kernel32.dll</tt>,
|
||||
<tt>user32.dll</tt> and <tt>gdi32.dll</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_load"><tt>clib = ffi.load(name [,global])</tt></h3>
|
||||
<p>
|
||||
This loads the dynamic library given by <tt>name</tt> and returns
|
||||
a new C library namespace which binds to its symbols. On POSIX
|
||||
systems, if <tt>global</tt> is <tt>true</tt>, the library symbols are
|
||||
loaded into the global namespace, too.
|
||||
</p>
|
||||
<p>
|
||||
If <tt>name</tt> is a path, the library is loaded from this path.
|
||||
Otherwise <tt>name</tt> is canonicalized in a system-dependent way and
|
||||
searched in the default search path for dynamic libraries:
|
||||
</p>
|
||||
<p>
|
||||
On POSIX systems, if the name contains no dot, the extension
|
||||
<tt>.so</tt> is appended. Also, the <tt>lib</tt> prefix is prepended
|
||||
if necessary. So <tt>ffi.load("z")</tt> looks for <tt>"libz.so"</tt>
|
||||
in the default shared library search path.
|
||||
</p>
|
||||
<p>
|
||||
On Windows systems, if the name contains no dot, the extension
|
||||
<tt>.dll</tt> is appended. So <tt>ffi.load("ws2_32")</tt> looks for
|
||||
<tt>"ws2_32.dll"</tt> in the default DLL search path.
|
||||
</p>
|
||||
|
||||
<h2 id="create">Creating cdata Objects</h2>
|
||||
<p>
|
||||
The following API functions create cdata objects (<tt>type()</tt>
|
||||
returns <tt>"cdata"</tt>). All created cdata objects are
|
||||
<a href="ext_ffi_semantics.html#gc">garbage collected</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_new"><tt>cdata = ffi.new(ct [,nelem] [,init...])<br>
|
||||
cdata = <em>ctype</em>([nelem,] [init...])</tt></h3>
|
||||
<p>
|
||||
Creates a cdata object for the given <tt>ct</tt>. VLA/VLS types
|
||||
require the <tt>nelem</tt> argument. The second syntax uses a ctype as
|
||||
a constructor and is otherwise fully equivalent.
|
||||
</p>
|
||||
<p>
|
||||
The cdata object is initialized according to the
|
||||
<a href="ext_ffi_semantics.html#init">rules for initializers</a>,
|
||||
using the optional <tt>init</tt> arguments. Excess initializers cause
|
||||
an error.
|
||||
</p>
|
||||
<p>
|
||||
Performance notice: if you want to create many objects of one kind,
|
||||
parse the cdecl only once and get its ctype with
|
||||
<tt>ffi.typeof()</tt>. Then use the ctype as a constructor repeatedly.
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
Please note, that an anonymous <tt>struct</tt> declaration implicitly
|
||||
creates a new and distinguished ctype every time you use it for
|
||||
<tt>ffi.new()</tt>. This is probably <b>not</b> what you want,
|
||||
especially if you create more than one cdata object. Different anonymous
|
||||
<tt>structs</tt> are not considered assignment-compatible by the
|
||||
C standard, even though they may have the same fields! Also, they
|
||||
are considered different types by the JIT-compiler, which may cause an
|
||||
excessive number of traces. It's strongly suggested to either declare
|
||||
a named <tt>struct</tt> or <tt>typedef</tt> with <tt>ffi.cdef()</tt>
|
||||
or to create a single ctype object for an anonymous <tt>struct</tt>
|
||||
with <tt>ffi.typeof()</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_typeof"><tt>ctype = ffi.typeof(ct)</tt></h3>
|
||||
<p>
|
||||
Creates a ctype object for the given <tt>ct</tt>.
|
||||
</p>
|
||||
<p>
|
||||
This function is especially useful to parse a cdecl only once and then
|
||||
use the resulting ctype object as a <a href="#ffi_new">constructor</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_cast"><tt>cdata = ffi.cast(ct, init)</tt></h3>
|
||||
<p>
|
||||
Creates a scalar cdata object for the given <tt>ct</tt>. The cdata
|
||||
object is initialized with <tt>init</tt> using the "cast" variant of
|
||||
the <a href="ext_ffi_semantics.html#convert">C type conversion
|
||||
rules</a>.
|
||||
</p>
|
||||
<p>
|
||||
This functions is mainly useful to override the pointer compatibility
|
||||
checks or to convert pointers to addresses or vice versa.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_metatype"><tt>ctype = ffi.metatype(ct, metatable)</tt></h3>
|
||||
<p>
|
||||
Creates a ctype object for the given <tt>ct</tt> and associates it with
|
||||
a metatable. Only <tt>struct</tt>/<tt>union</tt> types, complex numbers
|
||||
and vectors are allowed. Other types may be wrapped in a
|
||||
<tt>struct</tt>, if needed.
|
||||
</p>
|
||||
<p>
|
||||
The association with a metatable is permanent and cannot be changed
|
||||
afterwards. Neither the contents of the <tt>metatable</tt> nor the
|
||||
contents of an <tt>__index</tt> table (if any) may be modified
|
||||
afterwards. The associated metatable automatically applies to all uses
|
||||
of this type, no matter how the objects are created or where they
|
||||
originate from. Note that predefined operations on types have
|
||||
precedence (e.g. declared field names cannot be overridden).
|
||||
</p>
|
||||
<p>
|
||||
All standard Lua metamethods are implemented. These are called directly,
|
||||
without shortcuts, and on any mix of types. For binary operations, the
|
||||
left operand is checked first for a valid ctype metamethod. The
|
||||
<tt>__gc</tt> metamethod only applies to <tt>struct</tt>/<tt>union</tt>
|
||||
types and performs an implicit <a href="#ffi_gc"><tt>ffi.gc()</tt></a>
|
||||
call during creation of an instance.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_gc"><tt>cdata = ffi.gc(cdata, finalizer)</tt></h3>
|
||||
<p>
|
||||
Associates a finalizer with a pointer or aggregate cdata object. The
|
||||
cdata object is returned unchanged.
|
||||
</p>
|
||||
<p>
|
||||
This function allows safe integration of unmanaged resources into the
|
||||
automatic memory management of the LuaJIT garbage collector. Typical
|
||||
usage:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local p = ffi.gc(ffi.C.malloc(n), ffi.C.free)
|
||||
...
|
||||
p = nil -- Last reference to p is gone.
|
||||
-- GC will eventually run finalizer: ffi.C.free(p)
|
||||
</pre>
|
||||
<p>
|
||||
A cdata finalizer works like the <tt>__gc</tt> metamethod for userdata
|
||||
objects: when the last reference to a cdata object is gone, the
|
||||
associated finalizer is called with the cdata object as an argument. The
|
||||
finalizer can be a Lua function or a cdata function or cdata function
|
||||
pointer. An existing finalizer can be removed by setting a <tt>nil</tt>
|
||||
finalizer, e.g. right before explicitly deleting a resource:
|
||||
</p>
|
||||
<pre class="code">
|
||||
ffi.C.free(ffi.gc(p, nil)) -- Manually free the memory.
|
||||
</pre>
|
||||
|
||||
<h2 id="info">C Type Information</h2>
|
||||
<p>
|
||||
The following API functions return information about C types.
|
||||
They are most useful for inspecting cdata objects.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_sizeof"><tt>size = ffi.sizeof(ct [,nelem])</tt></h3>
|
||||
<p>
|
||||
Returns the size of <tt>ct</tt> in bytes. Returns <tt>nil</tt> if
|
||||
the size is not known (e.g. for <tt>"void"</tt> or function types).
|
||||
Requires <tt>nelem</tt> for VLA/VLS types, except for cdata objects.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_alignof"><tt>align = ffi.alignof(ct)</tt></h3>
|
||||
<p>
|
||||
Returns the minimum required alignment for <tt>ct</tt> in bytes.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_offsetof"><tt>ofs [,bpos,bsize] = ffi.offsetof(ct, field)</tt></h3>
|
||||
<p>
|
||||
Returns the offset (in bytes) of <tt>field</tt> relative to the start
|
||||
of <tt>ct</tt>, which must be a <tt>struct</tt>. Additionally returns
|
||||
the position and the field size (in bits) for bit fields.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_istype"><tt>status = ffi.istype(ct, obj)</tt></h3>
|
||||
<p>
|
||||
Returns <tt>true</tt> if <tt>obj</tt> has the C type given by
|
||||
<tt>ct</tt>. Returns <tt>false</tt> otherwise.
|
||||
</p>
|
||||
<p>
|
||||
C type qualifiers (<tt>const</tt> etc.) are ignored. Pointers are
|
||||
checked with the standard pointer compatibility rules, but without any
|
||||
special treatment for <tt>void *</tt>. If <tt>ct</tt> specifies a
|
||||
<tt>struct</tt>/<tt>union</tt>, then a pointer to this type is accepted,
|
||||
too. Otherwise the types must match exactly.
|
||||
</p>
|
||||
<p>
|
||||
Note: this function accepts all kinds of Lua objects for the
|
||||
<tt>obj</tt> argument, but always returns <tt>false</tt> for non-cdata
|
||||
objects.
|
||||
</p>
|
||||
|
||||
<h2 id="util">Utility Functions</h2>
|
||||
|
||||
<h3 id="ffi_errno"><tt>err = ffi.errno([newerr])</tt></h3>
|
||||
<p>
|
||||
Returns the error number set by the last C function call which
|
||||
indicated an error condition. If the optional <tt>newerr</tt> argument
|
||||
is present, the error number is set to the new value and the previous
|
||||
value is returned.
|
||||
</p>
|
||||
<p>
|
||||
This function offers a portable and OS-independent way to get and set the
|
||||
error number. Note that only <em>some</em> C functions set the error
|
||||
number. And it's only significant if the function actually indicated an
|
||||
error condition (e.g. with a return value of <tt>-1</tt> or
|
||||
<tt>NULL</tt>). Otherwise, it may or may not contain any previously set
|
||||
value.
|
||||
</p>
|
||||
<p>
|
||||
You're advised to call this function only when needed and as close as
|
||||
possible after the return of the related C function. The
|
||||
<tt>errno</tt> value is preserved across hooks, memory allocations,
|
||||
invocations of the JIT compiler and other internal VM activity. The same
|
||||
applies to the value returned by <tt>GetLastError()</tt> on Windows, but
|
||||
you need to declare and call it yourself.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_string"><tt>str = ffi.string(ptr [,len])</tt></h3>
|
||||
<p>
|
||||
Creates an interned Lua string from the data pointed to by
|
||||
<tt>ptr</tt>.
|
||||
</p>
|
||||
<p>
|
||||
If the optional argument <tt>len</tt> is missing, <tt>ptr</tt> is
|
||||
converted to a <tt>"char *"</tt> and the data is assumed to be
|
||||
zero-terminated. The length of the string is computed with
|
||||
<tt>strlen()</tt>.
|
||||
</p>
|
||||
<p>
|
||||
Otherwise <tt>ptr</tt> is converted to a <tt>"void *"</tt> and
|
||||
<tt>len</tt> gives the length of the data. The data may contain
|
||||
embedded zeros and need not be byte-oriented (though this may cause
|
||||
endianess issues).
|
||||
</p>
|
||||
<p>
|
||||
This function is mainly useful to convert (temporary)
|
||||
<tt>"const char *"</tt> pointers returned by
|
||||
C functions to Lua strings and store them or pass them to other
|
||||
functions expecting a Lua string. The Lua string is an (interned) copy
|
||||
of the data and bears no relation to the original data area anymore.
|
||||
Lua strings are 8 bit clean and may be used to hold arbitrary,
|
||||
non-character data.
|
||||
</p>
|
||||
<p>
|
||||
Performance notice: it's faster to pass the length of the string, if
|
||||
it's known. E.g. when the length is returned by a C call like
|
||||
<tt>sprintf()</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_copy"><tt>ffi.copy(dst, src, len)<br>
|
||||
ffi.copy(dst, str)</tt></h3>
|
||||
<p>
|
||||
Copies the data pointed to by <tt>src</tt> to <tt>dst</tt>.
|
||||
<tt>dst</tt> is converted to a <tt>"void *"</tt> and <tt>src</tt>
|
||||
is converted to a <tt>"const void *"</tt>.
|
||||
</p>
|
||||
<p>
|
||||
In the first syntax, <tt>len</tt> gives the number of bytes to copy.
|
||||
Caveat: if <tt>src</tt> is a Lua string, then <tt>len</tt> must not
|
||||
exceed <tt>#src+1</tt>.
|
||||
</p>
|
||||
<p>
|
||||
In the second syntax, the source of the copy must be a Lua string. All
|
||||
bytes of the string <em>plus a zero-terminator</em> are copied to
|
||||
<tt>dst</tt> (i.e. <tt>#src+1</tt> bytes).
|
||||
</p>
|
||||
<p>
|
||||
Performance notice: <tt>ffi.copy()</tt> may be used as a faster
|
||||
(inlinable) replacement for the C library functions
|
||||
<tt>memcpy()</tt>, <tt>strcpy()</tt> and <tt>strncpy()</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_fill"><tt>ffi.fill(dst, len [,c])</tt></h3>
|
||||
<p>
|
||||
Fills the data pointed to by <tt>dst</tt> with <tt>len</tt> constant
|
||||
bytes, given by <tt>c</tt>. If <tt>c</tt> is omitted, the data is
|
||||
zero-filled.
|
||||
</p>
|
||||
<p>
|
||||
Performance notice: <tt>ffi.fill()</tt> may be used as a faster
|
||||
(inlinable) replacement for the C library function
|
||||
<tt>memset(dst, c, len)</tt>. Please note the different
|
||||
order of arguments!
|
||||
</p>
|
||||
|
||||
<h2 id="target">Target-specific Information</h2>
|
||||
|
||||
<h3 id="ffi_abi"><tt>status = ffi.abi(param)</tt></h3>
|
||||
<p>
|
||||
Returns <tt>true</tt> if <tt>param</tt> (a Lua string) applies for the
|
||||
target ABI (Application Binary Interface). Returns <tt>false</tt>
|
||||
otherwise. The following parameters are currently defined:
|
||||
</p>
|
||||
<table class="abitable">
|
||||
<tr class="abihead">
|
||||
<td class="abiparam">Parameter</td>
|
||||
<td class="abidesc">Description</td>
|
||||
</tr>
|
||||
<tr class="odd separate">
|
||||
<td class="abiparam">32bit</td><td class="abidesc">32 bit architecture</td></tr>
|
||||
<tr class="even">
|
||||
<td class="abiparam">64bit</td><td class="abidesc">64 bit architecture</td></tr>
|
||||
<tr class="odd separate">
|
||||
<td class="abiparam">le</td><td class="abidesc">Little-endian architecture</td></tr>
|
||||
<tr class="even">
|
||||
<td class="abiparam">be</td><td class="abidesc">Big-endian architecture</td></tr>
|
||||
<tr class="odd separate">
|
||||
<td class="abiparam">fpu</td><td class="abidesc">Target has a hardware FPU</td></tr>
|
||||
<tr class="even">
|
||||
<td class="abiparam">softfp</td><td class="abidesc">softfp calling conventions</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="abiparam">hardfp</td><td class="abidesc">hardfp calling conventions</td></tr>
|
||||
<tr class="even separate">
|
||||
<td class="abiparam">eabi</td><td class="abidesc">EABI variant of the standard ABI</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="abiparam">win</td><td class="abidesc">Windows variant of the standard ABI</td></tr>
|
||||
<tr class="even">
|
||||
<td class="abiparam">pauth</td><td class="abidesc">Pointer authentication ABI</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="abiparam">uwp</td><td class="abidesc">Universal Windows Platform</td></tr>
|
||||
<tr class="even">
|
||||
<td class="abiparam">gc64</td><td class="abidesc">64 bit GC references</td></tr>
|
||||
</table>
|
||||
|
||||
<h3 id="ffi_os"><tt>ffi.os</tt></h3>
|
||||
<p>
|
||||
Contains the target OS name. Same contents as
|
||||
<a href="ext_jit.html#jit_os"><tt>jit.os</tt></a>.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi_arch"><tt>ffi.arch</tt></h3>
|
||||
<p>
|
||||
Contains the target architecture name. Same contents as
|
||||
<a href="ext_jit.html#jit_arch"><tt>jit.arch</tt></a>.
|
||||
</p>
|
||||
|
||||
<h2 id="callback">Methods for Callbacks</h2>
|
||||
<p>
|
||||
The C types for <a href="ext_ffi_semantics.html#callback">callbacks</a>
|
||||
have some extra methods:
|
||||
</p>
|
||||
|
||||
<h3 id="callback_free"><tt>cb:free()</tt></h3>
|
||||
<p>
|
||||
Free the resources associated with a callback. The associated Lua
|
||||
function is unanchored and may be garbage collected. The callback
|
||||
function pointer is no longer valid and must not be called again
|
||||
(it may be reused by a subsequently created callback).
|
||||
</p>
|
||||
|
||||
<h3 id="callback_set"><tt>cb:set(func)</tt></h3>
|
||||
<p>
|
||||
Associate a new Lua function with a callback. The C type of the
|
||||
callback and the callback function pointer are unchanged.
|
||||
</p>
|
||||
<p>
|
||||
This method is useful to dynamically switch the receiver of callbacks
|
||||
without creating a new callback each time and registering it again (e.g.
|
||||
with a GUI library).
|
||||
</p>
|
||||
|
||||
<h2 id="extended">Extended Standard Library Functions</h2>
|
||||
<p>
|
||||
The following standard library functions have been extended to work
|
||||
with cdata objects:
|
||||
</p>
|
||||
|
||||
<h3 id="tonumber"><tt>n = tonumber(cdata)</tt></h3>
|
||||
<p>
|
||||
Converts a number cdata object to a <tt>double</tt> and returns it as
|
||||
a Lua number. This is particularly useful for boxed 64 bit
|
||||
integer values. Caveat: this conversion may incur a precision loss.
|
||||
</p>
|
||||
|
||||
<h3 id="tostring"><tt>s = tostring(cdata)</tt></h3>
|
||||
<p>
|
||||
Returns a string representation of the value of 64 bit integers
|
||||
(<tt><b>"</b>nnn<b>LL"</b></tt> or <tt><b>"</b>nnn<b>ULL"</b></tt>) or
|
||||
complex numbers (<tt><b>"</b>re±im<b>i"</b></tt>). Otherwise
|
||||
returns a string representation of the C type of a ctype object
|
||||
(<tt><b>"ctype<</b>type<b>>"</b></tt>) or a cdata object
|
||||
(<tt><b>"cdata<</b>type<b>>: </b>address"</tt>), unless you
|
||||
override it with a <tt>__tostring</tt> metamethod (see
|
||||
<a href="#ffi_metatype"><tt>ffi.metatype()</tt></a>).
|
||||
</p>
|
||||
|
||||
<h3 id="pairs"><tt>iter, obj, start = pairs(cdata)<br>
|
||||
iter, obj, start = ipairs(cdata)<br></tt></h3>
|
||||
<p>
|
||||
Calls the <tt>__pairs</tt> or <tt>__ipairs</tt> metamethod of the
|
||||
corresponding ctype.
|
||||
</p>
|
||||
|
||||
<h2 id="literals">Extensions to the Lua Parser</h2>
|
||||
<p>
|
||||
The parser for Lua source code treats numeric literals with the
|
||||
suffixes <tt>LL</tt> or <tt>ULL</tt> as signed or unsigned 64 bit
|
||||
integers. Case doesn't matter, but uppercase is recommended for
|
||||
readability. It handles decimal (<tt>42LL</tt>), hexadecimal
|
||||
(<tt>0x2aLL</tt>) and binary (<tt>0b101010LL</tt>) literals.
|
||||
</p>
|
||||
<p>
|
||||
The imaginary part of complex numbers can be specified by suffixing
|
||||
number literals with <tt>i</tt> or <tt>I</tt>, e.g. <tt>12.5i</tt>.
|
||||
Caveat: you'll need to use <tt>1i</tt> to get an imaginary part with
|
||||
the value one, since <tt>i</tt> itself still refers to a variable
|
||||
named <tt>i</tt>.
|
||||
</p>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
1269
thirdPart/luajit/doc/ext_ffi_semantics.html
Normal file
1269
thirdPart/luajit/doc/ext_ffi_semantics.html
Normal file
File diff suppressed because it is too large
Load Diff
597
thirdPart/luajit/doc/ext_ffi_tutorial.html
Normal file
597
thirdPart/luajit/doc/ext_ffi_tutorial.html
Normal file
@@ -0,0 +1,597 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>FFI Tutorial</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
<style type="text/css">
|
||||
table.idiomtable { font-size: 90%; line-height: 1.2; }
|
||||
table.idiomtable tt { font-size: 100%; }
|
||||
table.idiomtable td { vertical-align: top; }
|
||||
tr.idiomhead td { font-weight: bold; }
|
||||
td.idiomlua b { font-weight: normal; color: #2142bf; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1>FFI Tutorial</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a class="current" href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
<p>
|
||||
This page is intended to give you an overview of the features of the FFI
|
||||
library by presenting a few use cases and guidelines.
|
||||
</p>
|
||||
<p>
|
||||
This page makes no attempt to explain all of the FFI library, though.
|
||||
You'll want to have a look at the <a href="ext_ffi_api.html">ffi.* API
|
||||
function reference</a> and the <a href="ext_ffi_semantics.html">FFI
|
||||
semantics</a> to learn more.
|
||||
</p>
|
||||
|
||||
<h2 id="load">Loading the FFI Library</h2>
|
||||
<p>
|
||||
The FFI library is built into LuaJIT by default, but it's not loaded
|
||||
and initialized by default. The suggested way to use the FFI library
|
||||
is to add the following to the start of every Lua file that needs one
|
||||
of its functions:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local ffi = require("ffi")
|
||||
</pre>
|
||||
<p>
|
||||
Please note, this doesn't define an <tt>ffi</tt> variable in the table
|
||||
of globals — you really need to use the local variable. The
|
||||
<tt>require</tt> function ensures the library is only loaded once.
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
Note: If you want to experiment with the FFI from the interactive prompt
|
||||
of the command line executable, omit the <tt>local</tt>, as it doesn't
|
||||
preserve local variables across lines.
|
||||
</p>
|
||||
|
||||
<h2 id="sleep">Accessing Standard System Functions</h2>
|
||||
<p>
|
||||
The following code explains how to access standard system functions.
|
||||
We slowly print two lines of dots by sleeping for 10 milliseconds
|
||||
after each dot:
|
||||
</p>
|
||||
<pre class="code mark">
|
||||
<span class="codemark">
|
||||
①
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
②
|
||||
③
|
||||
④
|
||||
|
||||
|
||||
|
||||
⑤
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
⑥</span>local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
<span style="color:#00a000;">void Sleep(int ms);
|
||||
int poll(struct pollfd *fds, unsigned long nfds, int timeout);</span>
|
||||
]]
|
||||
|
||||
local sleep
|
||||
if ffi.os == "Windows" then
|
||||
function sleep(s)
|
||||
ffi.C.Sleep(s*1000)
|
||||
end
|
||||
else
|
||||
function sleep(s)
|
||||
ffi.C.poll(nil, 0, s*1000)
|
||||
end
|
||||
end
|
||||
|
||||
for i=1,160 do
|
||||
io.write("."); io.flush()
|
||||
sleep(0.01)
|
||||
end
|
||||
io.write("\n")
|
||||
</pre>
|
||||
<p>
|
||||
Here's the step-by-step explanation:
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">①</span> This defines the
|
||||
C library functions we're going to use. The part inside the
|
||||
double-brackets (in green) is just standard C syntax. You can
|
||||
usually get this info from the C header files or the
|
||||
documentation provided by each C library or C compiler.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">②</span> The difficulty we're
|
||||
facing here, is that there are different standards to choose from.
|
||||
Windows has a simple <tt>Sleep()</tt> function. On other systems there
|
||||
are a variety of functions available to achieve sub-second sleeps, but
|
||||
with no clear consensus. Thankfully <tt>poll()</tt> can be used for
|
||||
this task, too, and it's present on most non-Windows systems. The
|
||||
check for <tt>ffi.os</tt> makes sure we use the Windows-specific
|
||||
function only on Windows systems.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">③</span> Here we're wrapping the
|
||||
call to the C function in a Lua function. This isn't strictly
|
||||
necessary, but it's helpful to deal with system-specific issues only
|
||||
in one part of the code. The way we're wrapping it ensures the check
|
||||
for the OS is only done during initialization and not for every call.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">④</span> A more subtle point is
|
||||
that we defined our <tt>sleep()</tt> function (for the sake of this
|
||||
example) as taking the number of seconds, but accepting fractional
|
||||
seconds. Multiplying this by 1000 gets us milliseconds, but that still
|
||||
leaves it a Lua number, which is a floating-point value. Alas, the
|
||||
<tt>Sleep()</tt> function only accepts an integer value. Luckily for
|
||||
us, the FFI library automatically performs the conversion when calling
|
||||
the function (truncating the FP value towards zero, like in C).
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
Some readers will notice that <tt>Sleep()</tt> is part of
|
||||
<tt>KERNEL32.DLL</tt> and is also a <tt>stdcall</tt> function. So how
|
||||
can this possibly work? The FFI library provides the <tt>ffi.C</tt>
|
||||
default C library namespace, which allows calling functions from
|
||||
the default set of libraries, like a C compiler would. Also, the
|
||||
FFI library automatically detects <tt>stdcall</tt> functions, so you
|
||||
don't need to declare them as such.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">⑤</span> The <tt>poll()</tt>
|
||||
function takes a couple more arguments we're not going to use. You can
|
||||
simply use <tt>nil</tt> to pass a <tt>NULL</tt> pointer and <tt>0</tt>
|
||||
for the <tt>nfds</tt> parameter. Please note, that the
|
||||
number <tt>0</tt> <em>does not convert to a pointer value</em>,
|
||||
unlike in C++. You really have to pass pointers to pointer arguments
|
||||
and numbers to number arguments.
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
The page on <a href="ext_ffi_semantics.html">FFI semantics</a> has all
|
||||
of the gory details about
|
||||
<a href="ext_ffi_semantics.html#convert">conversions between Lua
|
||||
objects and C types</a>. For the most part you don't have to deal
|
||||
with this, as it's performed automatically and it's carefully designed
|
||||
to bridge the semantic differences between Lua and C.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">⑥</span> Now that we have defined
|
||||
our own <tt>sleep()</tt> function, we can just call it from plain Lua
|
||||
code. That wasn't so bad, huh? Turning these boring animated dots into
|
||||
a fascinating best-selling game is left as an exercise for the reader.
|
||||
:-)
|
||||
</p>
|
||||
|
||||
<h2 id="zlib">Accessing the zlib Compression Library</h2>
|
||||
<p>
|
||||
The following code shows how to access the <a
|
||||
href="https://zlib.net/"><span class="ext">»</span> zlib</a> compression library from Lua code.
|
||||
We'll define two convenience wrapper functions that take a string and
|
||||
compress or uncompress it to another string:
|
||||
</p>
|
||||
<pre class="code mark">
|
||||
<span class="codemark">
|
||||
①
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
②
|
||||
|
||||
|
||||
③
|
||||
|
||||
④
|
||||
|
||||
|
||||
⑤
|
||||
|
||||
|
||||
⑥
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
⑦</span>local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
<span style="color:#00a000;">unsigned long compressBound(unsigned long sourceLen);
|
||||
int compress2(uint8_t *dest, unsigned long *destLen,
|
||||
const uint8_t *source, unsigned long sourceLen, int level);
|
||||
int uncompress(uint8_t *dest, unsigned long *destLen,
|
||||
const uint8_t *source, unsigned long sourceLen);</span>
|
||||
]]
|
||||
local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")
|
||||
|
||||
local function compress(txt)
|
||||
local n = zlib.compressBound(#txt)
|
||||
local buf = ffi.new("uint8_t[?]", n)
|
||||
local buflen = ffi.new("unsigned long[1]", n)
|
||||
local res = zlib.compress2(buf, buflen, txt, #txt, 9)
|
||||
assert(res == 0)
|
||||
return ffi.string(buf, buflen[0])
|
||||
end
|
||||
|
||||
local function uncompress(comp, n)
|
||||
local buf = ffi.new("uint8_t[?]", n)
|
||||
local buflen = ffi.new("unsigned long[1]", n)
|
||||
local res = zlib.uncompress(buf, buflen, comp, #comp)
|
||||
assert(res == 0)
|
||||
return ffi.string(buf, buflen[0])
|
||||
end
|
||||
|
||||
-- Simple test code.
|
||||
local txt = string.rep("abcd", 1000)
|
||||
print("Uncompressed size: ", #txt)
|
||||
local c = compress(txt)
|
||||
print("Compressed size: ", #c)
|
||||
local txt2 = uncompress(c, #txt)
|
||||
assert(txt2 == txt)
|
||||
</pre>
|
||||
<p>
|
||||
Here's the step-by-step explanation:
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">①</span> This defines some of the
|
||||
C functions provided by zlib. For the sake of this example, some
|
||||
type indirections have been reduced and it uses the predefined
|
||||
fixed-size integer types, while still adhering to the zlib API/ABI.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">②</span> This loads the zlib shared
|
||||
library. On POSIX systems, it's named <tt>libz.so</tt> and usually
|
||||
comes pre-installed. Since <tt>ffi.load()</tt> automatically adds any
|
||||
missing standard prefixes/suffixes, we can simply load the
|
||||
<tt>"z"</tt> library. On Windows it's named <tt>zlib1.dll</tt> and
|
||||
you'll have to download it first from the
|
||||
<a href="https://zlib.net/"><span class="ext">»</span> zlib site</a>. The check for
|
||||
<tt>ffi.os</tt> makes sure we pass the right name to
|
||||
<tt>ffi.load()</tt>.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">③</span> First, the maximum size of
|
||||
the compression buffer is obtained by calling the
|
||||
<tt>zlib.compressBound</tt> function with the length of the
|
||||
uncompressed string. The next line allocates a byte buffer of this
|
||||
size. The <tt>[?]</tt> in the type specification indicates a
|
||||
variable-length array (VLA). The actual number of elements of this
|
||||
array is given as the 2nd argument to <tt>ffi.new()</tt>.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">④</span> This may look strange at
|
||||
first, but have a look at the declaration of the <tt>compress2</tt>
|
||||
function from zlib: the destination length is defined as a pointer!
|
||||
This is because you pass in the maximum buffer size and get back the
|
||||
actual length that was used.
|
||||
</p>
|
||||
<p>
|
||||
In C you'd pass in the address of a local variable
|
||||
(<tt>&buflen</tt>). But since there's no address-of operator in
|
||||
Lua, we'll just pass in a one-element array. Conveniently, it can be
|
||||
initialized with the maximum buffer size in one step. Calling the
|
||||
actual <tt>zlib.compress2</tt> function is then straightforward.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">⑤</span> We want to return the
|
||||
compressed data as a Lua string, so we'll use <tt>ffi.string()</tt>.
|
||||
It needs a pointer to the start of the data and the actual length. The
|
||||
length has been returned in the <tt>buflen</tt> array, so we'll just
|
||||
get it from there.
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
Note that since the function returns now, the <tt>buf</tt> and
|
||||
<tt>buflen</tt> variables will eventually be garbage collected. This
|
||||
is fine, because <tt>ffi.string()</tt> has copied the contents to a
|
||||
newly created (interned) Lua string. If you plan to call this function
|
||||
lots of times, consider reusing the buffers and/or handing back the
|
||||
results in buffers instead of strings. This will reduce the overhead
|
||||
for garbage collection and string interning.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">⑥</span> The <tt>uncompress</tt>
|
||||
functions does the exact opposite of the <tt>compress</tt> function.
|
||||
The compressed data doesn't include the size of the original string,
|
||||
so this needs to be passed in. Otherwise, no surprises here.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">⑦</span> The code, that makes use
|
||||
of the functions we just defined, is just plain Lua code. It doesn't
|
||||
need to know anything about the LuaJIT FFI — the convenience
|
||||
wrapper functions completely hide it.
|
||||
</p>
|
||||
<p>
|
||||
One major advantage of the LuaJIT FFI is that you are now able to
|
||||
write those wrappers <em>in Lua</em>. And at a fraction of the time it
|
||||
would cost you to create an extra C module using the Lua/C API.
|
||||
Many of the simpler C functions can probably be used directly
|
||||
from your Lua code, without any wrappers.
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
Side note: the zlib API uses the <tt>long</tt> type for passing
|
||||
lengths and sizes around. But all those zlib functions actually only
|
||||
deal with 32 bit values. This is an unfortunate choice for a
|
||||
public API, but may be explained by zlib's history — we'll just
|
||||
have to deal with it.
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
First, you should know that a <tt>long</tt> is a 64 bit type e.g.
|
||||
on POSIX/x64 systems, but a 32 bit type on Windows/x64 and on
|
||||
32 bit systems. Thus a <tt>long</tt> result can be either a plain
|
||||
Lua number or a boxed 64 bit integer cdata object, depending on
|
||||
the target system.
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
Ok, so the <tt>ffi.*</tt> functions generally accept cdata objects
|
||||
wherever you'd want to use a number. That's why we get a away with
|
||||
passing <tt>n</tt> to <tt>ffi.string()</tt> above. But other Lua
|
||||
library functions or modules don't know how to deal with this. So for
|
||||
maximum portability, one needs to use <tt>tonumber()</tt> on returned
|
||||
<tt>long</tt> results before passing them on. Otherwise the
|
||||
application might work on some systems, but would fail in a POSIX/x64
|
||||
environment.
|
||||
</p>
|
||||
|
||||
<h2 id="metatype">Defining Metamethods for a C Type</h2>
|
||||
<p>
|
||||
The following code explains how to define metamethods for a C type.
|
||||
We define a simple point type and add some operations to it:
|
||||
</p>
|
||||
<pre class="code mark">
|
||||
<span class="codemark">
|
||||
①
|
||||
|
||||
|
||||
|
||||
②
|
||||
|
||||
③
|
||||
|
||||
④
|
||||
|
||||
|
||||
|
||||
⑤
|
||||
|
||||
⑥</span>local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
<span style="color:#00a000;">typedef struct { double x, y; } point_t;</span>
|
||||
]]
|
||||
|
||||
local point
|
||||
local mt = {
|
||||
__add = function(a, b) return point(a.x+b.x, a.y+b.y) end,
|
||||
__len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,
|
||||
__index = {
|
||||
area = function(a) return a.x*a.x + a.y*a.y end,
|
||||
},
|
||||
}
|
||||
point = ffi.metatype("point_t", mt)
|
||||
|
||||
local a = point(3, 4)
|
||||
print(a.x, a.y) --> 3 4
|
||||
print(#a) --> 5
|
||||
print(a:area()) --> 25
|
||||
local b = a + point(0.5, 8)
|
||||
print(#b) --> 12.5
|
||||
</pre>
|
||||
<p>
|
||||
Here's the step-by-step explanation:
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">①</span> This defines the C type for a
|
||||
two-dimensional point object.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">②</span> We have to declare the variable
|
||||
holding the point constructor first, because it's used inside of a
|
||||
metamethod.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">③</span> Let's define an <tt>__add</tt>
|
||||
metamethod which adds the coordinates of two points and creates a new
|
||||
point object. For simplicity, this function assumes that both arguments
|
||||
are points. But it could be any mix of objects, if at least one operand
|
||||
is of the required type (e.g. adding a point plus a number or vice
|
||||
versa). Our <tt>__len</tt> metamethod returns the distance of a point to
|
||||
the origin.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">④</span> If we run out of operators, we can
|
||||
define named methods, too. Here, the <tt>__index</tt> table defines an
|
||||
<tt>area</tt> function. For custom indexing needs, one might want to
|
||||
define <tt>__index</tt> and <tt>__newindex</tt> <em>functions</em> instead.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">⑤</span> This associates the metamethods with
|
||||
our C type. This only needs to be done once. For convenience, a
|
||||
constructor is returned by
|
||||
<a href="ext_ffi_api.html#ffi_metatype"><tt>ffi.metatype()</tt></a>.
|
||||
We're not required to use it, though. The original C type can still
|
||||
be used e.g. to create an array of points. The metamethods automatically
|
||||
apply to any and all uses of this type.
|
||||
</p>
|
||||
<p>
|
||||
Please note, that the association with a metatable is permanent and
|
||||
<b>the metatable must not be modified afterwards!</b> Ditto for the
|
||||
<tt>__index</tt> table.
|
||||
</p>
|
||||
<p>
|
||||
<span class="mark">⑥</span> Here are some simple usage examples
|
||||
for the point type and their expected results. The predefined
|
||||
operations (such as <tt>a.x</tt>) can be freely mixed with the newly
|
||||
defined metamethods. Note that <tt>area</tt> is a method and must be
|
||||
called with the Lua syntax for methods: <tt>a:area()</tt>, not
|
||||
<tt>a.area()</tt>.
|
||||
</p>
|
||||
<p>
|
||||
The C type metamethod mechanism is most useful when used in
|
||||
conjunction with C libraries that are written in an object-oriented
|
||||
style. Creators return a pointer to a new instance, and methods take an
|
||||
instance pointer as the first argument. Sometimes you can just point
|
||||
<tt>__index</tt> to the library namespace and <tt>__gc</tt> to the
|
||||
destructor and you're done. But often enough you'll want to add
|
||||
convenience wrappers, e.g. to return actual Lua strings or when
|
||||
returning multiple values.
|
||||
</p>
|
||||
<p>
|
||||
Some C libraries only declare instance pointers as an opaque
|
||||
<tt>void *</tt> type. In this case you can use a fake type for all
|
||||
declarations, e.g. a pointer to a named (incomplete) struct will do:
|
||||
<tt>typedef struct foo_type *foo_handle</tt>. The C side doesn't
|
||||
know what you declare with the LuaJIT FFI, but as long as the underlying
|
||||
types are compatible, everything still works.
|
||||
</p>
|
||||
|
||||
<h2 id="idioms">Translating C Idioms</h2>
|
||||
<p>
|
||||
Here's a list of common C idioms and their translation to the
|
||||
LuaJIT FFI:
|
||||
</p>
|
||||
<table class="idiomtable">
|
||||
<tr class="idiomhead">
|
||||
<td class="idiomdesc">Idiom</td>
|
||||
<td class="idiomc">C code</td>
|
||||
<td class="idiomlua">Lua code</td>
|
||||
</tr>
|
||||
<tr class="odd separate">
|
||||
<td class="idiomdesc">Pointer dereference<br><tt>int *p;</tt></td><td class="idiomc"><tt>x = *p;<br>*p = y;</tt></td><td class="idiomlua"><tt>x = <b>p[0]</b><br><b>p[0]</b> = y</tt></td></tr>
|
||||
<tr class="even">
|
||||
<td class="idiomdesc">Pointer indexing<br><tt>int i, *p;</tt></td><td class="idiomc"><tt>x = p[i];<br>p[i+1] = y;</tt></td><td class="idiomlua"><tt>x = p[i]<br>p[i+1] = y</tt></td></tr>
|
||||
<tr class="odd">
|
||||
<td class="idiomdesc">Array indexing<br><tt>int i, a[];</tt></td><td class="idiomc"><tt>x = a[i];<br>a[i+1] = y;</tt></td><td class="idiomlua"><tt>x = a[i]<br>a[i+1] = y</tt></td></tr>
|
||||
<tr class="even separate">
|
||||
<td class="idiomdesc"><tt>struct</tt>/<tt>union</tt> dereference<br><tt>struct foo s;</tt></td><td class="idiomc"><tt>x = s.field;<br>s.field = y;</tt></td><td class="idiomlua"><tt>x = s.field<br>s.field = y</tt></td></tr>
|
||||
<tr class="odd">
|
||||
<td class="idiomdesc"><tt>struct</tt>/<tt>union</tt> pointer deref.<br><tt>struct foo *sp;</tt></td><td class="idiomc"><tt>x = sp->field;<br>sp->field = y;</tt></td><td class="idiomlua"><tt>x = <b>s.field</b><br><b>s.field</b> = y</tt></td></tr>
|
||||
<tr class="even separate">
|
||||
<td class="idiomdesc">Pointer arithmetic<br><tt>int i, *p;</tt></td><td class="idiomc"><tt>x = p + i;<br>y = p - i;</tt></td><td class="idiomlua"><tt>x = p + i<br>y = p - i</tt></td></tr>
|
||||
<tr class="odd">
|
||||
<td class="idiomdesc">Pointer difference<br><tt>int *p1, *p2;</tt></td><td class="idiomc"><tt>x = p1 - p2;</tt></td><td class="idiomlua"><tt>x = p1 - p2</tt></td></tr>
|
||||
<tr class="even">
|
||||
<td class="idiomdesc">Array element pointer<br><tt>int i, a[];</tt></td><td class="idiomc"><tt>x = &a[i];</tt></td><td class="idiomlua"><tt>x = <b>a+i</b></tt></td></tr>
|
||||
<tr class="odd">
|
||||
<td class="idiomdesc">Cast pointer to address<br><tt>int *p;</tt></td><td class="idiomc"><tt>x = (intptr_t)p;</tt></td><td class="idiomlua"><tt>x = <b>tonumber(<br> ffi.cast("intptr_t",<br> p))</b></tt></td></tr>
|
||||
<tr class="even separate">
|
||||
<td class="idiomdesc">Functions with outargs<br><tt>void foo(int *inoutlen);</tt></td><td class="idiomc"><tt>int len = x;<br>foo(&len);<br>y = len;</tt></td><td class="idiomlua"><tt><b>local len =<br> ffi.new("int[1]", x)<br>foo(len)<br>y = len[0]</b></tt></td></tr>
|
||||
<tr class="odd">
|
||||
<td class="idiomdesc"><a href="ext_ffi_semantics.html#convert_vararg">Vararg conversions</a><br><tt>int printf(char *fmt, ...);</tt></td><td class="idiomc"><tt>printf("%g", 1.0);<br>printf("%d", 1);<br> </tt></td><td class="idiomlua"><tt>printf("%g", 1);<br>printf("%d",<br> <b>ffi.new("int", 1)</b>)</tt></td></tr>
|
||||
</table>
|
||||
|
||||
<h2 id="cache">To Cache or Not to Cache</h2>
|
||||
<p>
|
||||
It's a common Lua idiom to cache library functions in local variables
|
||||
or upvalues, e.g.:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local byte, char = string.byte, string.char
|
||||
local function foo(x)
|
||||
return char(byte(x)+1)
|
||||
end
|
||||
</pre>
|
||||
<p>
|
||||
This replaces several hash-table lookups with a (faster) direct use of
|
||||
a local or an upvalue. This is less important with LuaJIT, since the
|
||||
JIT compiler optimizes hash-table lookups a lot and is even able to
|
||||
hoist most of them out of the inner loops. It can't eliminate
|
||||
<em>all</em> of them, though, and it saves some typing for often-used
|
||||
functions. So there's still a place for this, even with LuaJIT.
|
||||
</p>
|
||||
<p>
|
||||
The situation is a bit different with C function calls via the
|
||||
FFI library. The JIT compiler has special logic to eliminate <em>all
|
||||
of the lookup overhead</em> for functions resolved from a
|
||||
<a href="ext_ffi_semantics.html#clib">C library namespace</a>!
|
||||
Thus it's not helpful and actually counter-productive to cache
|
||||
individual C functions like this:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local <b>funca</b>, <b>funcb</b> = ffi.C.funca, ffi.C.funcb -- <span style="color:#c00000;">Not helpful!</span>
|
||||
local function foo(x, n)
|
||||
for i=1,n do <b>funcb</b>(<b>funca</b>(x, i), 1) end
|
||||
end
|
||||
</pre>
|
||||
<p>
|
||||
This turns them into indirect calls and generates bigger and slower
|
||||
machine code. Instead, you'll want to cache the namespace itself and
|
||||
rely on the JIT compiler to eliminate the lookups:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local <b>C</b> = ffi.C -- <span style="color:#00a000;">Instead use this!</span>
|
||||
local function foo(x, n)
|
||||
for i=1,n do <b>C.funcb</b>(<b>C.funca</b>(x, i), 1) end
|
||||
end
|
||||
</pre>
|
||||
<p>
|
||||
This generates both shorter and faster code. So <b>don't cache
|
||||
C functions</b>, but <b>do</b> cache namespaces! Most often the
|
||||
namespace is already in a local variable at an outer scope, e.g. from
|
||||
<tt>local lib = ffi.load(...)</tt>. Note that copying
|
||||
it to a local variable in the function scope is unnecessary.
|
||||
</p>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
197
thirdPart/luajit/doc/ext_jit.html
Normal file
197
thirdPart/luajit/doc/ext_jit.html
Normal file
@@ -0,0 +1,197 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>jit.* Library</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1><tt>jit.*</tt> Library</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a class="current" href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
<p>
|
||||
The functions in this built-in module control the behavior of the JIT
|
||||
compiler engine. Note that JIT-compilation is fully automatic —
|
||||
you probably won't need to use any of the following functions unless
|
||||
you have special needs.
|
||||
</p>
|
||||
|
||||
<h3 id="jit_onoff"><tt>jit.on()<br>
|
||||
jit.off()</tt></h3>
|
||||
<p>
|
||||
Turns the whole JIT compiler on (default) or off.
|
||||
</p>
|
||||
<p>
|
||||
These functions are typically used with the command line options
|
||||
<tt>-j on</tt> or <tt>-j off</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="jit_flush"><tt>jit.flush()</tt></h3>
|
||||
<p>
|
||||
Flushes the whole cache of compiled code.
|
||||
</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>
|
||||
<p>
|
||||
<tt>jit.on</tt> enables JIT compilation for a Lua function (this is
|
||||
the default).
|
||||
</p>
|
||||
<p>
|
||||
<tt>jit.off</tt> disables JIT compilation for a Lua function and
|
||||
flushes any already compiled code from the code cache.
|
||||
</p>
|
||||
<p>
|
||||
<tt>jit.flush</tt> flushes the code, but doesn't affect the
|
||||
enable/disable status.
|
||||
</p>
|
||||
<p>
|
||||
The current function, i.e. the Lua function calling this library
|
||||
function, can also be specified by passing <tt>true</tt> as the first
|
||||
argument.
|
||||
</p>
|
||||
<p>
|
||||
If the second argument is <tt>true</tt>, JIT compilation is also
|
||||
enabled, disabled or flushed recursively for all sub-functions of a
|
||||
function. With <tt>false</tt> only the sub-functions are affected.
|
||||
</p>
|
||||
<p>
|
||||
The <tt>jit.on</tt> and <tt>jit.off</tt> functions only set a flag
|
||||
which is checked when the function is about to be compiled. They do
|
||||
not trigger immediate compilation.
|
||||
</p>
|
||||
<p>
|
||||
Typical usage is <tt>jit.off(true, true)</tt> in the main chunk
|
||||
of a module to turn off JIT compilation for the whole module for
|
||||
debugging purposes.
|
||||
</p>
|
||||
|
||||
<h3 id="jit_flush_tr"><tt>jit.flush(tr)</tt></h3>
|
||||
<p>
|
||||
Flushes the root trace, specified by its number, and all of its side
|
||||
traces from the cache. The code for the trace will be retained as long
|
||||
as there are any other traces which link to it.
|
||||
</p>
|
||||
|
||||
<h3 id="jit_status"><tt>status, ... = jit.status()</tt></h3>
|
||||
<p>
|
||||
Returns the current status of the JIT compiler. The first result is
|
||||
either <tt>true</tt> or <tt>false</tt> if the JIT compiler is turned
|
||||
on or off. The remaining results are strings for CPU-specific features
|
||||
and enabled optimizations.
|
||||
</p>
|
||||
|
||||
<h3 id="jit_version"><tt>jit.version</tt></h3>
|
||||
<p>
|
||||
Contains the LuaJIT version string.
|
||||
</p>
|
||||
|
||||
<h3 id="jit_version_num"><tt>jit.version_num</tt></h3>
|
||||
<p>
|
||||
Contains the version number of the LuaJIT core. Version xx.yy.zz
|
||||
is represented by the decimal number xxyyzz.<br>
|
||||
<b>DEPRECATED after the switch to
|
||||
<a href="https://luajit.org/status.html#release"><span class="ext">»</span> rolling releases</a>. zz is frozen at 99.</b>
|
||||
</p>
|
||||
|
||||
<h3 id="jit_os"><tt>jit.os</tt></h3>
|
||||
<p>
|
||||
Contains the target OS name:
|
||||
"Windows", "Linux", "OSX", "BSD", "POSIX" or "Other".
|
||||
</p>
|
||||
|
||||
<h3 id="jit_arch"><tt>jit.arch</tt></h3>
|
||||
<p>
|
||||
Contains the target architecture name:
|
||||
"x86", "x64", "arm", "arm64", "arm64be", "ppc", "mips", "mipsel", "mips64", "mips64el", "mips64r6", "mips64r6el".
|
||||
</p>
|
||||
|
||||
<h2 id="jit_opt"><tt>jit.opt.*</tt> — JIT compiler optimization control</h2>
|
||||
<p>
|
||||
This submodule provides the backend for the <tt>-O</tt> command line
|
||||
option.
|
||||
</p>
|
||||
<p>
|
||||
You can also use it programmatically, e.g.:
|
||||
</p>
|
||||
<pre class="code">
|
||||
jit.opt.start(2) -- same as -O2
|
||||
jit.opt.start("-dce")
|
||||
jit.opt.start("hotloop=10", "hotexit=2")
|
||||
</pre>
|
||||
<p>
|
||||
Unlike in LuaJIT 1.x, the module is built-in and
|
||||
<b>optimization is turned on by default!</b>
|
||||
It's no longer necessary to run <tt>require("jit.opt").start()</tt>,
|
||||
which was one of the ways to enable optimization.
|
||||
</p>
|
||||
|
||||
<h2 id="jit_util"><tt>jit.util.*</tt> — JIT compiler introspection</h2>
|
||||
<p>
|
||||
This submodule holds functions to introspect the bytecode, generated
|
||||
traces, the IR and the generated machine code. The functionality
|
||||
provided by this module is still in flux and therefore undocumented.
|
||||
</p>
|
||||
<p>
|
||||
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>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
359
thirdPart/luajit/doc/ext_profiler.html
Normal file
359
thirdPart/luajit/doc/ext_profiler.html
Normal file
@@ -0,0 +1,359 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Profiler</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1>Profiler</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a class="current" href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
<p>
|
||||
LuaJIT has an integrated statistical profiler with very low overhead. It
|
||||
allows sampling the currently executing stack and other parameters in
|
||||
regular intervals.
|
||||
</p>
|
||||
<p>
|
||||
The integrated profiler can be accessed from three levels:
|
||||
</p>
|
||||
<ul>
|
||||
<li>The <a href="#hl_profiler">bundled high-level profiler</a>, invoked by the
|
||||
<a href="#j_p"><tt>-jp</tt></a> command line option.</li>
|
||||
<li>A <a href="#ll_lua_api">low-level Lua API</a> to control the profiler.</li>
|
||||
<li>A <a href="#ll_c_api">low-level C API</a> to control the profiler.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="hl_profiler">High-Level Profiler</h2>
|
||||
<p>
|
||||
The bundled high-level profiler offers basic profiling functionality. It
|
||||
generates simple textual summaries or source code annotations. It can be
|
||||
accessed with the <a href="#j_p"><tt>-jp</tt></a> command line option
|
||||
or from Lua code by loading the underlying <tt>jit.p</tt> module.
|
||||
</p>
|
||||
<p>
|
||||
To cut to the chase — run this to get a CPU usage profile by
|
||||
function name:
|
||||
</p>
|
||||
<pre class="code">
|
||||
luajit -jp myapp.lua
|
||||
</pre>
|
||||
<p>
|
||||
It's <em>not</em> a stated goal of the bundled profiler to add every
|
||||
possible option or to cater for special profiling needs. The low-level
|
||||
profiler APIs are documented below. They may be used by third-party
|
||||
authors to implement advanced functionality, e.g. IDE integration or
|
||||
graphical profilers.
|
||||
</p>
|
||||
<p>
|
||||
Note: Sampling works for both interpreted and JIT-compiled code. The
|
||||
results for JIT-compiled code may sometimes be surprising. LuaJIT
|
||||
heavily optimizes and inlines Lua code — there's no simple
|
||||
one-to-one correspondence between source code lines and the sampled
|
||||
machine code.
|
||||
</p>
|
||||
|
||||
<h3 id="j_p"><tt>-jp=[options[,output]]</tt></h3>
|
||||
<p>
|
||||
The <tt>-jp</tt> command line option starts the high-level profiler.
|
||||
When the application run by the command line terminates, the profiler
|
||||
stops and writes the results to <tt>stdout</tt> or to the specified
|
||||
<tt>output</tt> file.
|
||||
</p>
|
||||
<p>
|
||||
The <tt>options</tt> argument specifies how the profiling is to be
|
||||
performed:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>f</tt> — Stack dump: function name, otherwise module:line.
|
||||
This is the default mode.</li>
|
||||
<li><tt>F</tt> — Stack dump: ditto, but dump module:name.</li>
|
||||
<li><tt>l</tt> — Stack dump: module:line.</li>
|
||||
<li><tt><number></tt> — stack dump depth (callee ←
|
||||
caller). Default: 1.</li>
|
||||
<li><tt>-<number></tt> — Inverse stack dump depth (caller
|
||||
→ callee).</li>
|
||||
<li><tt>s</tt> — Split stack dump after first stack level. Implies
|
||||
depth ≥ 2 or depth ≤ -2.</li>
|
||||
<li><tt>p</tt> — Show full path for module names.</li>
|
||||
<li><tt>v</tt> — Show VM states.</li>
|
||||
<li><tt>z</tt> — Show <a href="#jit_zone">zones</a>.</li>
|
||||
<li><tt>r</tt> — Show raw sample counts. Default: show percentages.</li>
|
||||
<li><tt>a</tt> — Annotate excerpts from source code files.</li>
|
||||
<li><tt>A</tt> — Annotate complete source code files.</li>
|
||||
<li><tt>G</tt> — Produce raw output suitable for graphical tools.</li>
|
||||
<li><tt>m<number></tt> — Minimum sample percentage to be shown.
|
||||
Default: 3%.</li>
|
||||
<li><tt>i<number></tt> — Sampling interval in milliseconds.
|
||||
Default: 10ms.<br>
|
||||
Note: The actual sampling precision is OS-dependent.</li>
|
||||
</ul>
|
||||
<p>
|
||||
The default output for <tt>-jp</tt> is a list of the most CPU consuming
|
||||
spots in the application. Increasing the stack dump depth with (say)
|
||||
<tt>-jp=2</tt> may help to point out the main callers or callees of
|
||||
hotspots. But sample aggregation is still flat per unique stack dump.
|
||||
</p>
|
||||
<p>
|
||||
To get a two-level view (split view) of callers/callees, use
|
||||
<tt>-jp=s</tt> or <tt>-jp=-s</tt>. The percentages shown for the second
|
||||
level are relative to the first level.
|
||||
</p>
|
||||
<p>
|
||||
To see how much time is spent in each line relative to a function, use
|
||||
<tt>-jp=fl</tt>.
|
||||
</p>
|
||||
<p>
|
||||
To see how much time is spent in different VM states or
|
||||
<a href="#jit_zone">zones</a>, use <tt>-jp=v</tt> or <tt>-jp=z</tt>.
|
||||
</p>
|
||||
<p>
|
||||
Combinations of <tt>v/z</tt> with <tt>f/F/l</tt> produce two-level
|
||||
views, e.g. <tt>-jp=vf</tt> or <tt>-jp=fv</tt>. This shows the time
|
||||
spent in a VM state or zone vs. hotspots. This can be used to answer
|
||||
questions like "Which time-consuming functions are only interpreted?" or
|
||||
"What's the garbage collector overhead for a specific function?".
|
||||
</p>
|
||||
<p>
|
||||
Multiple options can be combined — but not all combinations make
|
||||
sense, see above. E.g. <tt>-jp=3si4m1</tt> samples three stack levels
|
||||
deep in 4ms intervals and shows a split view of the CPU consuming
|
||||
functions and their callers with a 1% threshold.
|
||||
</p>
|
||||
<p>
|
||||
Source code annotations produced by <tt>-jp=a</tt> or <tt>-jp=A</tt> are
|
||||
always flat and at the line level. Obviously, the source code files need
|
||||
to be readable by the profiler script.
|
||||
</p>
|
||||
<p>
|
||||
The high-level profiler can also be started and stopped from Lua code with:
|
||||
</p>
|
||||
<pre class="code">
|
||||
require("jit.p").start(options, output)
|
||||
...
|
||||
require("jit.p").stop()
|
||||
</pre>
|
||||
|
||||
<h3 id="jit_zone"><tt>jit.zone</tt> — Zones</h3>
|
||||
<p>
|
||||
Zones can be used to provide information about different parts of an
|
||||
application to the high-level profiler. E.g. a game could make use of an
|
||||
<tt>"AI"</tt> zone, a <tt>"PHYS"</tt> zone, etc. Zones are hierarchical,
|
||||
organized as a stack.
|
||||
</p>
|
||||
<p>
|
||||
The <tt>jit.zone</tt> module needs to be loaded explicitly:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local zone = require("jit.zone")
|
||||
</pre>
|
||||
<ul>
|
||||
<li><tt>zone("name")</tt> pushes a named zone to the zone stack.</li>
|
||||
<li><tt>zone()</tt> pops the current zone from the zone stack and
|
||||
returns its name.</li>
|
||||
<li><tt>zone:get()</tt> returns the current zone name or <tt>nil</tt>.</li>
|
||||
<li><tt>zone:flush()</tt> flushes the zone stack.</li>
|
||||
</ul>
|
||||
<p>
|
||||
To show the time spent in each zone use <tt>-jp=z</tt>. To show the time
|
||||
spent relative to hotspots use e.g. <tt>-jp=zf</tt> or <tt>-jp=fz</tt>.
|
||||
</p>
|
||||
|
||||
<h2 id="ll_lua_api">Low-level Lua API</h2>
|
||||
<p>
|
||||
The <tt>jit.profile</tt> module gives access to the low-level API of the
|
||||
profiler from Lua code. This module needs to be loaded explicitly:
|
||||
<pre class="code">
|
||||
local profile = require("jit.profile")
|
||||
</pre>
|
||||
<p>
|
||||
This module can be used to implement your own higher-level profiler.
|
||||
A typical profiling run starts the profiler, captures stack dumps in
|
||||
the profiler callback, adds them to a hash table to aggregate the number
|
||||
of samples, stops the profiler and then analyzes all captured
|
||||
stack dumps. Other parameters can be sampled in the profiler callback,
|
||||
too. But it's important not to spend too much time in the callback,
|
||||
since this may skew the statistics.
|
||||
</p>
|
||||
|
||||
<h3 id="profile_start"><tt>profile.start(mode, cb)</tt>
|
||||
— Start profiler</h3>
|
||||
<p>
|
||||
This function starts the profiler. The <tt>mode</tt> argument is a
|
||||
string holding options:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>f</tt> — Profile with precision down to the function level.</li>
|
||||
<li><tt>l</tt> — Profile with precision down to the line level.</li>
|
||||
<li><tt>i<number></tt> — Sampling interval in milliseconds (default
|
||||
10ms).</br>
|
||||
Note: The actual sampling precision is OS-dependent.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
The <tt>cb</tt> argument is a callback function which is called with
|
||||
three arguments: <tt>(thread, samples, vmstate)</tt>. The callback is
|
||||
called on a separate coroutine, the <tt>thread</tt> argument is the
|
||||
state that holds the stack to sample for profiling. Note: do
|
||||
<em>not</em> modify the stack of that state or call functions on it.
|
||||
</p>
|
||||
<p>
|
||||
<tt>samples</tt> gives the number of accumulated samples since the last
|
||||
callback (usually 1).
|
||||
</p>
|
||||
<p>
|
||||
<tt>vmstate</tt> holds the VM state at the time the profiling timer
|
||||
triggered. This may or may not correspond to the state of the VM when
|
||||
the profiling callback is called. The state is either <tt>'N'</tt>
|
||||
native (compiled) code, <tt>'I'</tt> interpreted code, <tt>'C'</tt>
|
||||
C code, <tt>'G'</tt> the garbage collector, or <tt>'J'</tt> the JIT
|
||||
compiler.
|
||||
</p>
|
||||
|
||||
<h3 id="profile_stop"><tt>profile.stop()</tt>
|
||||
— Stop profiler</h3>
|
||||
<p>
|
||||
This function stops the profiler.
|
||||
</p>
|
||||
|
||||
<h3 id="profile_dump"><tt>dump = profile.dumpstack([thread,] fmt, depth)</tt>
|
||||
— Dump stack </h3>
|
||||
<p>
|
||||
This function allows taking stack dumps in an efficient manner. It
|
||||
returns a string with a stack dump for the <tt>thread</tt> (coroutine),
|
||||
formatted according to the <tt>fmt</tt> argument:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>p</tt> — Preserve the full path for module names. Otherwise,
|
||||
only the file name is used.</li>
|
||||
<li><tt>f</tt> — Dump the function name if it can be derived. Otherwise,
|
||||
use module:line.</li>
|
||||
<li><tt>F</tt> — Ditto, but dump module:name.</li>
|
||||
<li><tt>l</tt> — Dump module:line.</li>
|
||||
<li><tt>Z</tt> — Zap the following characters for the last dumped
|
||||
frame.</li>
|
||||
<li>All other characters are added verbatim to the output string.</li>
|
||||
</ul>
|
||||
<p>
|
||||
The <tt>depth</tt> argument gives the number of frames to dump, starting
|
||||
at the topmost frame of the thread. A negative number dumps the frames in
|
||||
inverse order.
|
||||
</p>
|
||||
<p>
|
||||
The first example prints a list of the current module names and line
|
||||
numbers of up to 10 frames in separate lines. The second example prints
|
||||
semicolon-separated function names for all frames (up to 100) in inverse
|
||||
order:
|
||||
</p>
|
||||
<pre class="code">
|
||||
print(profile.dumpstack(thread, "l\n", 10))
|
||||
print(profile.dumpstack(thread, "lZ;", -100))
|
||||
</pre>
|
||||
|
||||
<h2 id="ll_c_api">Low-level C API</h2>
|
||||
<p>
|
||||
The profiler can be controlled directly from C code, e.g. for
|
||||
use by IDEs. The declarations are in <tt>"luajit.h"</tt> (see
|
||||
<a href="ext_c_api.html">Lua/C API</a> extensions).
|
||||
</p>
|
||||
|
||||
<h3 id="luaJIT_profile_start"><tt>luaJIT_profile_start(L, mode, cb, data)</tt>
|
||||
— Start profiler</h3>
|
||||
<p>
|
||||
This function starts the profiler. <a href="#profile_start">See
|
||||
above</a> for a description of the <tt>mode</tt> argument.
|
||||
</p>
|
||||
<p>
|
||||
The <tt>cb</tt> argument is a callback function with the following
|
||||
declaration:
|
||||
</p>
|
||||
<pre class="code">
|
||||
typedef void (*luaJIT_profile_callback)(void *data, lua_State *L,
|
||||
int samples, int vmstate);
|
||||
</pre>
|
||||
<p>
|
||||
<tt>data</tt> is available for use by the callback. <tt>L</tt> is the
|
||||
state that holds the stack to sample for profiling. Note: do
|
||||
<em>not</em> modify this stack or call functions on this stack —
|
||||
use a separate coroutine for this purpose. <a href="#profile_start">See
|
||||
above</a> for a description of <tt>samples</tt> and <tt>vmstate</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="luaJIT_profile_stop"><tt>luaJIT_profile_stop(L)</tt>
|
||||
— Stop profiler</h3>
|
||||
<p>
|
||||
This function stops the profiler.
|
||||
</p>
|
||||
|
||||
<h3 id="luaJIT_profile_dumpstack"><tt>p = luaJIT_profile_dumpstack(L, fmt, depth, len)</tt>
|
||||
— Dump stack </h3>
|
||||
<p>
|
||||
This function allows taking stack dumps in an efficient manner.
|
||||
<a href="#profile_dump">See above</a> for a description of <tt>fmt</tt>
|
||||
and <tt>depth</tt>.
|
||||
</p>
|
||||
<p>
|
||||
This function returns a <tt>const char *</tt> pointing to a
|
||||
private string buffer of the profiler. The <tt>int *len</tt>
|
||||
argument returns the length of the output string. The buffer is
|
||||
overwritten on the next call and deallocated when the profiler stops.
|
||||
You either need to consume the content immediately or copy it for later
|
||||
use.
|
||||
</p>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
498
thirdPart/luajit/doc/extensions.html
Normal file
498
thirdPart/luajit/doc/extensions.html
Normal file
@@ -0,0 +1,498 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Extensions</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
<style type="text/css">
|
||||
table.exc {
|
||||
line-height: 1.2;
|
||||
}
|
||||
tr.exchead td {
|
||||
font-weight: bold;
|
||||
}
|
||||
td.excplatform {
|
||||
width: 48%;
|
||||
}
|
||||
td.exccompiler {
|
||||
width: 29%;
|
||||
}
|
||||
td.excinterop {
|
||||
width: 23%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1>Extensions</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a class="current" href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
|
||||
<p>
|
||||
LuaJIT is fully upwards-compatible with Lua 5.1. It supports all
|
||||
<a href="https://www.lua.org/manual/5.1/manual.html#5"><span class="ext">»</span> standard Lua
|
||||
library functions</a> and the full set of
|
||||
<a href="https://www.lua.org/manual/5.1/manual.html#3"><span class="ext">»</span> Lua/C API
|
||||
functions</a>.
|
||||
</p>
|
||||
<p>
|
||||
LuaJIT is also fully ABI-compatible to Lua 5.1 at the linker/dynamic
|
||||
loader level. This means you can compile a C module against the
|
||||
standard Lua headers and load the same shared library from either Lua
|
||||
or LuaJIT.
|
||||
</p>
|
||||
<p>
|
||||
LuaJIT extends the standard Lua VM with new functionality and adds
|
||||
several extension modules. Please note, this page is only about
|
||||
<em>functional</em> enhancements and not about performance enhancements,
|
||||
such as the optimized VM, the faster interpreter or the JIT compiler.
|
||||
</p>
|
||||
|
||||
<h2 id="modules">Extensions Modules</h2>
|
||||
<p>
|
||||
LuaJIT comes with several built-in extension modules:
|
||||
</p>
|
||||
|
||||
<h3 id="bit"><tt>bit.*</tt> — Bitwise operations</h3>
|
||||
<p>
|
||||
LuaJIT supports all bitwise operations as defined by
|
||||
<a href="https://bitop.luajit.org"><span class="ext">»</span> Lua BitOp</a>:
|
||||
</p>
|
||||
<pre class="code">
|
||||
bit.tobit bit.tohex bit.bnot bit.band bit.bor bit.bxor
|
||||
bit.lshift bit.rshift bit.arshift bit.rol bit.ror bit.bswap
|
||||
</pre>
|
||||
<p>
|
||||
This module is a LuaJIT built-in — you don't need to download or
|
||||
install Lua BitOp. The Lua BitOp site has full documentation for all
|
||||
<a href="https://bitop.luajit.org/api.html"><span class="ext">»</span> Lua BitOp API functions</a>.
|
||||
The FFI adds support for
|
||||
<a href="ext_ffi_semantics.html#cdata_arith">64 bit bitwise operations</a>,
|
||||
using the same API functions.
|
||||
</p>
|
||||
<p>
|
||||
Please make sure to <tt>require</tt> the module before using any of
|
||||
its functions:
|
||||
</p>
|
||||
<pre class="code">
|
||||
local bit = require("bit")
|
||||
</pre>
|
||||
<p>
|
||||
An already installed Lua BitOp module is ignored by LuaJIT.
|
||||
This way you can use bit operations from both Lua and LuaJIT on a
|
||||
shared installation.
|
||||
</p>
|
||||
|
||||
<h3 id="ffi"><tt>ffi.*</tt> — FFI library</h3>
|
||||
<p>
|
||||
The <a href="ext_ffi.html">FFI library</a> allows calling external
|
||||
C functions and the use of C data structures from pure Lua
|
||||
code.
|
||||
</p>
|
||||
|
||||
<h3 id="jit"><tt>jit.*</tt> — JIT compiler control</h3>
|
||||
<p>
|
||||
The functions in this module
|
||||
<a href="ext_jit.html">control the behavior of the JIT compiler engine</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="c_api">C API extensions</h3>
|
||||
<p>
|
||||
LuaJIT adds some
|
||||
<a href="ext_c_api.html">extra functions to the Lua/C API</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="profiler">Profiler</h3>
|
||||
<p>
|
||||
LuaJIT has an <a href="ext_profiler.html">integrated profiler</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="library">Enhanced Standard Library Functions</h2>
|
||||
|
||||
<h3 id="xpcall"><tt>xpcall(f, err [,args...])</tt> passes arguments</h3>
|
||||
<p>
|
||||
Unlike the standard implementation in Lua 5.1, <tt>xpcall()</tt>
|
||||
passes any arguments after the error function to the function
|
||||
which is called in a protected context.
|
||||
</p>
|
||||
|
||||
<h3 id="load"><tt>load*()</tt> handle UTF-8 source code</h3>
|
||||
<p>
|
||||
Non-ASCII characters are handled transparently by the Lua source code parser.
|
||||
This allows the use of UTF-8 characters in identifiers and strings.
|
||||
A UTF-8 BOM is skipped at the start of the source code.
|
||||
</p>
|
||||
|
||||
<h3 id="load_mode"><tt>load*()</tt> add a mode parameter</h3>
|
||||
<p>
|
||||
As an extension from Lua 5.2, the functions <tt>loadstring()</tt>,
|
||||
<tt>loadfile()</tt> and (new) <tt>load()</tt> add an optional
|
||||
<tt>mode</tt> parameter.
|
||||
</p>
|
||||
<p>
|
||||
The default mode string is <tt>"bt"</tt>, which allows loading of both
|
||||
source code and bytecode. Use <tt>"t"</tt> to allow only source code
|
||||
or <tt>"b"</tt> to allow only bytecode to be loaded.
|
||||
</p>
|
||||
<p>
|
||||
By default, the <tt>load*</tt> functions generate the native bytecode format.
|
||||
For cross-compilation purposes, add <tt>W</tt> to the mode string to
|
||||
force the 32 bit format and <tt>X</tt> to force the 64 bit format.
|
||||
Add both to force the opposite format. Note that non-native bytecode
|
||||
generated by <tt>load*</tt> cannot be run, but can still be passed
|
||||
to <tt>string.dump</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="tostring"><tt>tostring()</tt> etc. canonicalize NaN and ±Inf</h3>
|
||||
<p>
|
||||
All number-to-string conversions consistently convert non-finite numbers
|
||||
to the same strings on all platforms. NaN results in <tt>"nan"</tt>,
|
||||
positive infinity results in <tt>"inf"</tt> and negative infinity results
|
||||
in <tt>"-inf"</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="tonumber"><tt>tonumber()</tt> etc. use builtin string to number conversion</h3>
|
||||
<p>
|
||||
All string-to-number conversions consistently convert integer and
|
||||
floating-point inputs in decimal, hexadecimal and binary on all platforms.
|
||||
<tt>strtod()</tt> is <em>not</em> used anymore, which avoids numerous
|
||||
problems with poor C library implementations. The builtin conversion
|
||||
function provides full precision according to the IEEE-754 standard, it
|
||||
works independently of the current locale and it supports hex floating-point
|
||||
numbers (e.g. <tt>0x1.5p-3</tt>).
|
||||
</p>
|
||||
|
||||
<h3 id="string_dump"><tt>string.dump(f [,mode])</tt> generates portable bytecode</h3>
|
||||
<p>
|
||||
An extra argument has been added to <tt>string.dump()</tt>. If set to
|
||||
<tt>true</tt> or to a string which contains the character <tt>s</tt>,
|
||||
'stripped' bytecode without debug information is generated. This speeds
|
||||
up later bytecode loading and reduces memory usage. See also the
|
||||
<a href="running.html#opt_b"><tt>-b</tt> command line option</a>.
|
||||
</p>
|
||||
<p>
|
||||
The generated bytecode is portable and can be loaded on any architecture
|
||||
that LuaJIT supports. However, the bytecode compatibility versions must
|
||||
match. Bytecode only stays compatible within a major+minor version
|
||||
(x.y.aaa → x.y.bbb), except for development branches. Foreign bytecode
|
||||
(e.g. from Lua 5.1) is incompatible and cannot be loaded.
|
||||
</p>
|
||||
<p>
|
||||
Note: <tt>LJ_GC64</tt> mode requires a different frame layout, which implies
|
||||
a different, incompatible bytecode format between 32 bit and 64 bit ports.
|
||||
This may be rectified in the future. In the meantime, use the <tt>W</tt>
|
||||
and </tt>X</tt> <a href="#load_mode">modes of the <tt>load*</tt> functions</a>
|
||||
for cross-compilation purposes.
|
||||
</p>
|
||||
<p>
|
||||
Due to VM hardening, bytecode is not deterministic. Add <tt>d</tt> to the
|
||||
mode string to dump it in a deterministic manner: identical source code
|
||||
always gives a byte-for-byte identical bytecode dump. This feature is
|
||||
mainly useful for reproducible builds.
|
||||
</p>
|
||||
|
||||
<h3 id="table_new"><tt>table.new(narray, nhash)</tt> allocates a pre-sized table</h3>
|
||||
<p>
|
||||
An extra library function <tt>table.new()</tt> can be made available via
|
||||
<tt>require("table.new")</tt>. This creates a pre-sized table, just like
|
||||
the C API equivalent <tt>lua_createtable()</tt>. This is useful for big
|
||||
tables if the final table size is known and automatic table resizing is
|
||||
too expensive.
|
||||
</p>
|
||||
|
||||
<h3 id="table_clear"><tt>table.clear(tab)</tt> clears a table</h3>
|
||||
<p>
|
||||
An extra library function <tt>table.clear()</tt> can be made available
|
||||
via <tt>require("table.clear")</tt>. This clears all keys and values
|
||||
from a table, but preserves the allocated array/hash sizes. This is
|
||||
useful when a table, which is linked from multiple places, needs to be
|
||||
cleared and/or when recycling a table for use by the same context. This
|
||||
avoids managing backlinks, saves an allocation and the overhead of
|
||||
incremental array/hash part growth.
|
||||
</p>
|
||||
<p>
|
||||
Please note, this function is meant for very specific situations. In most
|
||||
cases it's better to replace the (usually single) link with a new table
|
||||
and let the GC do its work.
|
||||
</p>
|
||||
|
||||
<h3 id="math_random">Enhanced PRNG for <tt>math.random()</tt></h3>
|
||||
<p>
|
||||
LuaJIT uses a Tausworthe PRNG with period 2^223 to implement
|
||||
<tt>math.random()</tt> and <tt>math.randomseed()</tt>. The quality of
|
||||
the PRNG results is much superior compared to the standard Lua
|
||||
implementation, which uses the platform-specific ANSI rand().
|
||||
</p>
|
||||
<p>
|
||||
The PRNG generates the same sequences from the same seeds on all
|
||||
platforms and makes use of all bits in the seed argument.
|
||||
<tt>math.random()</tt> without arguments generates 52 pseudo-random bits
|
||||
for every call. The result is uniformly distributed between 0.0 and 1.0.
|
||||
It's correctly scaled up and rounded for <tt>math.random(n [,m])</tt> to
|
||||
preserve uniformity.
|
||||
</p>
|
||||
<p>
|
||||
Important: Neither this nor any other PRNG based on the simplistic
|
||||
<tt>math.random()</tt> API is suitable for cryptographic use.
|
||||
</p>
|
||||
|
||||
<h3 id="io"><tt>io.*</tt> functions handle 64 bit file offsets</h3>
|
||||
<p>
|
||||
The file I/O functions in the standard <tt>io.*</tt> library handle
|
||||
64 bit file offsets. In particular, this means it's possible
|
||||
to open files larger than 2 Gigabytes and to reposition or obtain
|
||||
the current file position for offsets beyond 2 GB
|
||||
(<tt>fp:seek()</tt> method).
|
||||
</p>
|
||||
|
||||
<h3 id="debug_meta"><tt>debug.*</tt> functions identify metamethods</h3>
|
||||
<p>
|
||||
<tt>debug.getinfo()</tt> and <tt>lua_getinfo()</tt> also return information
|
||||
about invoked metamethods. The <tt>namewhat</tt> field is set to
|
||||
<tt>"metamethod"</tt> and the <tt>name</tt> field has the name of
|
||||
the corresponding metamethod (e.g. <tt>"__index"</tt>).
|
||||
</p>
|
||||
|
||||
<h2 id="resumable">Fully Resumable VM</h2>
|
||||
<p>
|
||||
The LuaJIT VM is fully resumable. This means you can yield from a
|
||||
coroutine even across contexts, where this would not possible with
|
||||
the standard Lua 5.1 VM: e.g. you can yield across <tt>pcall()</tt>
|
||||
and <tt>xpcall()</tt>, across iterators and across metamethods.
|
||||
</p>
|
||||
|
||||
<h2 id="lua52">Extensions from Lua 5.2</h2>
|
||||
<p>
|
||||
LuaJIT supports some language and library extensions from Lua 5.2.
|
||||
Features that are unlikely to break existing code are unconditionally
|
||||
enabled:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>goto</tt> and <tt>::labels::</tt>.</li>
|
||||
<li>Hex escapes <tt>'\x3F'</tt> and <tt>'\z'</tt> escape in strings.</li>
|
||||
<li><tt>load(string|reader [, chunkname [,mode [,env]]])</tt>.</li>
|
||||
<li><tt>loadstring()</tt> is an alias for <tt>load()</tt>.</li>
|
||||
<li><tt>loadfile(filename [,mode [,env]])</tt>.</li>
|
||||
<li><tt>math.log(x [,base])</tt>.</li>
|
||||
<li><tt>string.rep(s, n [,sep])</tt>.</li>
|
||||
<li><tt>string.format()</tt>: <tt>%q</tt> reversible.
|
||||
<tt>%s</tt> checks <tt>__tostring</tt>.
|
||||
<tt>%a</tt> and <tt>"%A</tt> added.</li>
|
||||
<li>String matching pattern <tt>%g</tt> added.</li>
|
||||
<li><tt>io.read("*L")</tt>.</li>
|
||||
<li><tt>io.lines()</tt> and <tt>file:lines()</tt> process
|
||||
<tt>io.read()</tt> options.</li>
|
||||
<li><tt>os.exit(status|true|false [,close])</tt>.</li>
|
||||
<li><tt>package.searchpath(name, path [, sep [, rep]])</tt>.</li>
|
||||
<li><tt>package.loadlib(name, "*")</tt>.</li>
|
||||
<li><tt>debug.getinfo()</tt> returns <tt>nparams</tt> and <tt>isvararg</tt>
|
||||
for option <tt>"u"</tt>.</li>
|
||||
<li><tt>debug.getlocal()</tt> accepts function instead of level.</li>
|
||||
<li><tt>debug.getlocal()</tt> and <tt>debug.setlocal()</tt> accept negative
|
||||
indexes for varargs.</li>
|
||||
<li><tt>debug.getupvalue()</tt> and <tt>debug.setupvalue()</tt> handle
|
||||
C functions.</li>
|
||||
<li><tt>debug.upvalueid()</tt> and <tt>debug.upvaluejoin()</tt>.</li>
|
||||
<li>Lua/C API extensions:
|
||||
<tt>lua_version()</tt>
|
||||
<tt>lua_upvalueid()</tt>
|
||||
<tt>lua_upvaluejoin()</tt>
|
||||
<tt>lua_loadx()</tt>
|
||||
<tt>lua_copy()</tt>
|
||||
<tt>lua_tonumberx()</tt>
|
||||
<tt>lua_tointegerx()</tt>
|
||||
<tt>luaL_fileresult()</tt>
|
||||
<tt>luaL_execresult()</tt>
|
||||
<tt>luaL_loadfilex()</tt>
|
||||
<tt>luaL_loadbufferx()</tt>
|
||||
<tt>luaL_traceback()</tt>
|
||||
<tt>luaL_setfuncs()</tt>
|
||||
<tt>luaL_pushmodule()</tt>
|
||||
<tt>luaL_newlibtable()</tt>
|
||||
<tt>luaL_newlib()</tt>
|
||||
<tt>luaL_testudata()</tt>
|
||||
<tt>luaL_setmetatable()</tt>
|
||||
</li>
|
||||
<li>Command line option <tt>-E</tt>.</li>
|
||||
<li>Command line checks <tt>__tostring</tt> for errors.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Other features are only enabled, if LuaJIT is built with
|
||||
<tt>-DLUAJIT_ENABLE_LUA52COMPAT</tt>:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>goto</tt> is a keyword and not a valid variable name anymore.</li>
|
||||
<li><tt>break</tt> can be placed anywhere. Empty statements (<tt>;;</tt>)
|
||||
are allowed.</li>
|
||||
<li><tt>__lt</tt>, <tt>__le</tt> are invoked for mixed types.</li>
|
||||
<li><tt>__len</tt> for tables. <tt>rawlen()</tt> library function.</li>
|
||||
<li><tt>pairs()</tt> and <tt>ipairs()</tt> check for <tt>__pairs</tt> and
|
||||
<tt>__ipairs</tt>.</li>
|
||||
<li><tt>coroutine.running()</tt> returns two results.</li>
|
||||
<li><tt>table.pack()</tt> and <tt>table.unpack()</tt>
|
||||
(same as <tt>unpack()</tt>).</li>
|
||||
<li><tt>io.write()</tt> and <tt>file:write()</tt> return file handle
|
||||
instead of <tt>true</tt>.</li>
|
||||
<li><tt>os.execute()</tt> and <tt>pipe:close()</tt> return detailed
|
||||
exit status.</li>
|
||||
<li><tt>debug.setmetatable()</tt> returns object.</li>
|
||||
<li><tt>debug.getuservalue()</tt> and <tt>debug.setuservalue()</tt>.</li>
|
||||
<li>Remove <tt>math.mod()</tt>, <tt>string.gfind()</tt>.</li>
|
||||
<li><tt>package.searchers</tt>.</li>
|
||||
<li><tt>module()</tt> returns the module table.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Note: this provides only partial compatibility with Lua 5.2 at the
|
||||
language and Lua library level. LuaJIT is API+ABI-compatible with
|
||||
Lua 5.1, which prevents implementing features that would otherwise
|
||||
break the Lua/C API and ABI (e.g. <tt>_ENV</tt>).
|
||||
</p>
|
||||
|
||||
<h2 id="lua53">Extensions from Lua 5.3</h2>
|
||||
<p>
|
||||
LuaJIT supports some extensions from Lua 5.3:
|
||||
<ul>
|
||||
<li>Unicode escape <tt>'\u{XX...}'</tt> embeds the UTF-8 encoding in string literals.</li>
|
||||
<li>The argument table <tt>arg</tt> can be read (and modified) by <tt>LUA_INIT</tt> and <tt>-e</tt> chunks.</li>
|
||||
<li><tt>io.read()</tt> and <tt>file:read()</tt> accept formats with or without a leading <tt>*</tt>.</li>
|
||||
<li><tt>assert()</tt> accepts any type of error object.</li>
|
||||
<li><tt>table.move(a1, f, e, t [,a2])</tt>.</li>
|
||||
<li><tt>coroutine.isyieldable()</tt>.</li>
|
||||
<li>Lua/C API extensions:
|
||||
<tt>lua_isyieldable()</tt>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="exceptions">C++ Exception Interoperability</h2>
|
||||
<p>
|
||||
LuaJIT has built-in support for interoperating with C++ exceptions.
|
||||
The available range of features depends on the target platform and
|
||||
the toolchain used to compile LuaJIT:
|
||||
</p>
|
||||
<table class="exc">
|
||||
<tr class="exchead">
|
||||
<td class="excplatform">Platform</td>
|
||||
<td class="exccompiler">Compiler</td>
|
||||
<td class="excinterop">Interoperability</td>
|
||||
</tr>
|
||||
<tr class="odd separate">
|
||||
<td class="excplatform">External frame unwinding</td>
|
||||
<td class="exccompiler">GCC, Clang, MSVC</td>
|
||||
<td class="excinterop"><b style="color: #00a000;">Full</b></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td class="excplatform">Internal frame unwinding + DWARF2</td>
|
||||
<td class="exccompiler">GCC, Clang</td>
|
||||
<td class="excinterop"><b style="color: #c06000;">Limited</b></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td class="excplatform">Windows 64 bit</td>
|
||||
<td class="exccompiler">non-MSVC</td>
|
||||
<td class="excinterop"><b style="color: #c06000;">Limited</b></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td class="excplatform">Other platforms</td>
|
||||
<td class="exccompiler">Other compilers</td>
|
||||
<td class="excinterop"><b style="color: #a00000;">No</b></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
<b style="color: #00a000;">Full interoperability</b> means:
|
||||
</p>
|
||||
<ul>
|
||||
<li>C++ exceptions can be caught on the Lua side with <tt>pcall()</tt>,
|
||||
<tt>lua_pcall()</tt> etc.</li>
|
||||
<li>C++ exceptions will be converted to the generic Lua error
|
||||
<tt>"C++ exception"</tt>, unless you use the
|
||||
<a href="ext_c_api.html#mode_wrapcfunc">C call wrapper</a> feature.</li>
|
||||
<li>It's safe to throw C++ exceptions across non-protected Lua frames
|
||||
on the C stack. The contents of the C++ exception object
|
||||
pass through unmodified.</li>
|
||||
<li>Lua errors can be caught on the C++ side with <tt>catch(...)</tt>.
|
||||
The corresponding Lua error message can be retrieved from the Lua stack.</li>
|
||||
<li>Throwing Lua errors across C++ frames is safe. C++ destructors
|
||||
will be called.</li>
|
||||
</ul>
|
||||
<p>
|
||||
<b style="color: #c06000;">Limited interoperability</b> means:
|
||||
</p>
|
||||
<ul>
|
||||
<li>C++ exceptions can be caught on the Lua side with <tt>pcall()</tt>,
|
||||
<tt>lua_pcall()</tt> etc.</li>
|
||||
<li>C++ exceptions will be converted to the generic Lua error
|
||||
<tt>"C++ exception"</tt>, unless you use the
|
||||
<a href="ext_c_api.html#mode_wrapcfunc">C call wrapper</a> feature.</li>
|
||||
<li>C++ exceptions will be caught by non-protected Lua frames and
|
||||
are rethrown as a generic Lua error. The C++ exception object will
|
||||
be destroyed.</li>
|
||||
<li>Lua errors <b>cannot</b> be caught on the C++ side.</li>
|
||||
<li>Throwing Lua errors across C++ frames will <b>not</b> call
|
||||
C++ destructors.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<b style="color: #a00000;">No interoperability</b> means:
|
||||
</p>
|
||||
<ul>
|
||||
<li>It's <b>not</b> safe to throw C++ exceptions across Lua frames.</li>
|
||||
<li>C++ exceptions <b>cannot</b> be caught on the Lua side.</li>
|
||||
<li>Lua errors <b>cannot</b> be caught on the C++ side.</li>
|
||||
<li>Throwing Lua errors across C++ frames will <b>not</b> call
|
||||
C++ destructors.</li>
|
||||
</ul>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
thirdPart/luajit/doc/img/contact.png
Normal file
BIN
thirdPart/luajit/doc/img/contact.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
582
thirdPart/luajit/doc/install.html
Normal file
582
thirdPart/luajit/doc/install.html
Normal file
@@ -0,0 +1,582 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Installation</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
<style type="text/css">
|
||||
table.compat {
|
||||
line-height: 1.2;
|
||||
font-size: 80%;
|
||||
}
|
||||
table.compat td {
|
||||
border: 1px solid #bfcfff;
|
||||
height: 1.5em;
|
||||
}
|
||||
table.compat tr.compathead td {
|
||||
font-weight: bold;
|
||||
border-bottom: 2px solid #bfcfff;
|
||||
}
|
||||
td.compatname {
|
||||
width: 10%;
|
||||
}
|
||||
td.compatbits {
|
||||
width: 5%;
|
||||
}
|
||||
td.compatx {
|
||||
width: 21%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1>Installation</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a class="current" href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
<p>
|
||||
LuaJIT is only distributed as source code — get it from the
|
||||
<a href="https://luajit.org/download.html"><span class="ext">»</span> git repository</a>. This page explains how to build
|
||||
and install the LuaJIT binary and library for different operating systems.
|
||||
</p>
|
||||
<p>
|
||||
For the impatient (on POSIX systems):
|
||||
</p>
|
||||
<pre class="code">
|
||||
make && sudo make install
|
||||
</pre>
|
||||
|
||||
<h2 id="req">Requirements</h2>
|
||||
<p>
|
||||
LuaJIT currently builds out-of-the box on most systems. Please check the
|
||||
supported operating systems and CPU architectures on the
|
||||
<a href="https://luajit.org/status.html"><span class="ext">»</span> status page</a>.
|
||||
</p>
|
||||
<p>
|
||||
Building LuaJIT requires a recent toolchain based on GCC, Clang/LLVM or
|
||||
MSVC++.
|
||||
</p>
|
||||
<p>
|
||||
The Makefile-based build system requires GNU Make and supports
|
||||
cross-builds.
|
||||
</p>
|
||||
<p>
|
||||
Batch files are provided for MSVC++ builds and console cross-builds.
|
||||
</p>
|
||||
|
||||
<h2>Configuring LuaJIT</h2>
|
||||
<p>
|
||||
The standard configuration should work fine for most installations.
|
||||
Usually there is no need to tweak the settings. The following files
|
||||
hold all user-configurable settings:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>Makefile</tt> has settings for <b>installing</b> LuaJIT (POSIX
|
||||
only).</li>
|
||||
<li><tt>src/Makefile</tt> has settings for <b>compiling</b> LuaJIT
|
||||
under POSIX, MinGW or Cygwin.</li>
|
||||
<li><tt>src/msvcbuild.bat</tt> has settings for compiling LuaJIT with
|
||||
MSVC (Visual Studio).</li>
|
||||
</ul>
|
||||
<p>
|
||||
Please read the instructions given in these files, before changing
|
||||
any settings.
|
||||
</p>
|
||||
<p>
|
||||
All LuaJIT 64 bit ports use 64 bit GC objects by default (<tt>LJ_GC64</tt>).
|
||||
For x64, you can select the old 32-on-64 bit mode by adding
|
||||
<tt>XCFLAGS=-DLUAJIT_DISABLE_GC64</tt> to the make command.
|
||||
Please check the note about the
|
||||
<a href="extensions.html#string_dump">bytecode format</a> differences, too.
|
||||
</p>
|
||||
|
||||
<h2 id="posix">POSIX Systems (Linux, macOS, *BSD etc.)</h2>
|
||||
<h3>Prerequisites</h3>
|
||||
<p>
|
||||
Depending on your distribution, you may need to install a package for a
|
||||
compiler (GCC or Clang/LLVM), the development headers and/or a complete SDK.
|
||||
E.g. on a current Debian/Ubuntu, install <tt>build-essential</tt> with the
|
||||
package manager.
|
||||
</p>
|
||||
</pre>
|
||||
<h3>Building LuaJIT</h3>
|
||||
<p>
|
||||
The supplied Makefiles try to auto-detect the settings needed for your
|
||||
operating system and your compiler. They need to be run with GNU Make,
|
||||
which is probably the default on your system, anyway. Simply run:
|
||||
</p>
|
||||
<pre class="code">
|
||||
make
|
||||
</pre>
|
||||
<p>
|
||||
This always builds a native binary, depending on the host OS
|
||||
you're running this command on. Check the section on
|
||||
<a href="#cross">cross-compilation</a> for more options.
|
||||
</p>
|
||||
<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 macOS: you <b>must</b> set the <tt>MACOSX_DEPLOYMENT_TARGET</tt>
|
||||
environment variable to a value supported by your toolchain:
|
||||
</p>
|
||||
<pre class="code">
|
||||
MACOSX_DEPLOYMENT_TARGET=XX.YY make
|
||||
</pre>
|
||||
<h3>Installing LuaJIT</h3>
|
||||
<p>
|
||||
The top-level Makefile installs LuaJIT by default under
|
||||
<tt>/usr/local</tt>, i.e. the executable ends up in
|
||||
<tt>/usr/local/bin</tt> and so on. You need root privileges
|
||||
to write to this path. So, assuming sudo is installed on your system,
|
||||
run the following command and enter your sudo password:
|
||||
</p>
|
||||
<pre class="code">
|
||||
sudo make install
|
||||
</pre>
|
||||
<p>
|
||||
Otherwise specify the directory prefix as an absolute path, e.g.:
|
||||
</p>
|
||||
<pre class="code">
|
||||
make install PREFIX=/home/myself/lj2
|
||||
</pre>
|
||||
<p>
|
||||
Obviously the prefixes given during build and installation need to be the same.
|
||||
</p>
|
||||
|
||||
<h2 id="windows">Windows Systems</h2>
|
||||
<h3>Prerequisites</h3>
|
||||
<p>
|
||||
Either install one of the open source SDKs
|
||||
(<a href="http://mingw.org/"><span class="ext">»</span> MinGW</a> or
|
||||
<a href="https://www.cygwin.com/"><span class="ext">»</span> Cygwin</a>), which come with a modified
|
||||
GCC plus the required development headers.
|
||||
Or install Microsoft's Visual Studio (MSVC).
|
||||
</p>
|
||||
<h3>Building with MSVC</h3>
|
||||
<p>
|
||||
Open a "Visual Studio Command Prompt" (x86, x64 or ARM64), <tt>cd</tt> to the
|
||||
directory with the source code and run these commands:
|
||||
</p>
|
||||
<pre class="code">
|
||||
cd src
|
||||
msvcbuild
|
||||
</pre>
|
||||
<p>
|
||||
Check the <tt>msvcbuild.bat</tt> file for more options.
|
||||
Then follow the installation instructions below.
|
||||
</p>
|
||||
<p>
|
||||
For an x64 to ARM64 cross-build run this first: <tt>vcvarsall.bat x64_arm64</tt>
|
||||
</p>
|
||||
<h3>Building with MinGW or Cygwin</h3>
|
||||
<p>
|
||||
Open a command prompt window and make sure the MinGW or Cygwin programs
|
||||
are in your path. Then <tt>cd</tt> to the directory of the git repository.
|
||||
Then run this command for MinGW:
|
||||
</p>
|
||||
<pre class="code">
|
||||
mingw32-make
|
||||
</pre>
|
||||
<p>
|
||||
Or this command for Cygwin:
|
||||
</p>
|
||||
<pre class="code">
|
||||
make
|
||||
</pre>
|
||||
<p>
|
||||
Then follow the installation instructions below.
|
||||
</p>
|
||||
<h3>Installing LuaJIT</h3>
|
||||
<p>
|
||||
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>src\jit</tt> directory of the distribution
|
||||
to the latter directory.
|
||||
</p>
|
||||
<p>
|
||||
There are no hardcoded
|
||||
absolute path names — all modules are loaded relative to the
|
||||
directory where <tt>luajit.exe</tt> is installed
|
||||
(see <tt>src/luaconf.h</tt>).
|
||||
</p>
|
||||
|
||||
<h2 id="cross">Cross-compiling LuaJIT</h2>
|
||||
<p>
|
||||
First, let's clear up some terminology:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Host: This is your development system, usually based on a x64 or x86 CPU.</li>
|
||||
<li>Target: This is the target system you want LuaJIT to run on, e.g. Android/ARM.</li>
|
||||
<li>Toolchain: This comprises a C compiler, linker, assembler and a matching C library.</li>
|
||||
<li>Host (or system) toolchain: This is the toolchain used to build native binaries for your host system.</li>
|
||||
<li>Cross-compile toolchain: This is the toolchain used to build binaries for the target system. They can only be run on the target system.</li>
|
||||
</ul>
|
||||
<p>
|
||||
The GNU Makefile-based build system allows cross-compiling on any host
|
||||
for any supported target:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Yes, you need a toolchain for both your host <em>and</em> your target!</li>
|
||||
<li>Both host and target architectures must have the same pointer size.</li>
|
||||
<li>E.g. if you want to cross-compile to a 32 bit target on a 64 bit host, you need to install the multilib development package (e.g. <tt>libc6-dev-i386</tt> on Debian/Ubuntu) and build a 32 bit host part (<tt>HOST_CC="gcc -m32"</tt>).</li>
|
||||
<li>On some distro versions, multilib conflicts with cross-compilers. The workaround is to install the x86 cross-compiler package <tt>gcc-i686-linux-gnu</tt> and use it to build the host part (<tt>HOST_CC=i686-linux-gnu-gcc</tt>).</li>
|
||||
<li>64 bit targets always require compilation on a 64 bit host.</li>
|
||||
</ul>
|
||||
<p>
|
||||
You need to specify <tt>TARGET_SYS</tt> whenever the host OS and the
|
||||
target OS differ, or you'll get assembler or linker errors:
|
||||
</p>
|
||||
<ul>
|
||||
<li>E.g. if you're compiling on a Windows or macOS host for embedded Linux or Android, you need to add <tt>TARGET_SYS=Linux</tt> to the examples below.</li>
|
||||
<li>For a minimal target OS, you may need to disable the built-in allocator in <tt>src/Makefile</tt> and use <tt>TARGET_SYS=Other</tt>.</li>
|
||||
<li>Don't forget to specify the same <tt>TARGET_SYS</tt> for the install step, too.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Here are some examples where host and target have the same CPU:
|
||||
</p>
|
||||
<pre class="code">
|
||||
# Cross-compile to a 32 bit binary on a multilib x64 OS
|
||||
make CC="gcc -m32"
|
||||
|
||||
# Cross-compile on Debian/Ubuntu for Windows (mingw32 package)
|
||||
make HOST_CC="gcc -m32" CROSS=i586-mingw32msvc- TARGET_SYS=Windows
|
||||
</pre>
|
||||
<p id="cross2">
|
||||
The <tt>CROSS</tt> prefix allows specifying a standard GNU cross-compile
|
||||
toolchain (Binutils, GCC and a matching libc). The prefix may vary
|
||||
depending on the <tt>--target</tt> the toolchain was built for (note the
|
||||
<tt>CROSS</tt> prefix has a trailing <tt>"-"</tt>). The examples below
|
||||
use the canonical toolchain triplets for Linux.
|
||||
</p>
|
||||
<p>
|
||||
Since there's often no easy way to detect CPU features at runtime, it's
|
||||
important to compile with the proper CPU or architecture settings:
|
||||
</o>
|
||||
<ul>
|
||||
<li>The best way to get consistent results is to specify the correct settings when building the toolchain yourself.</li>
|
||||
<li>For a pre-built, generic toolchain add <tt>-mcpu=...</tt> or <tt>-march=...</tt> and other necessary flags to <tt>TARGET_CFLAGS</tt>.</li>
|
||||
<li>For ARM it's important to have the correct <tt>-mfloat-abi=...</tt> setting, too. Otherwise LuaJIT may not run at the full performance of your target CPU.</li>
|
||||
<li>For MIPS it's important to select a supported ABI (o32 on MIPS32, n64 on MIPS64) and consistently compile your project either with hard-float or soft-float compiler settings.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Here are some examples for targets with a different CPU than the host:
|
||||
</p>
|
||||
<pre class="code">
|
||||
# ARM soft-float
|
||||
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
|
||||
TARGET_CFLAGS="-mfloat-abi=soft"
|
||||
|
||||
# ARM soft-float ABI with VFP (example for Cortex-A9)
|
||||
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
|
||||
TARGET_CFLAGS="-mcpu=cortex-a9 -mfloat-abi=softfp"
|
||||
|
||||
# ARM hard-float ABI with VFP (armhf, most modern toolchains)
|
||||
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabihf-
|
||||
|
||||
# ARM64
|
||||
make CROSS=aarch64-linux-gnu-
|
||||
|
||||
# PPC
|
||||
make HOST_CC="gcc -m32" CROSS=powerpc-linux-gnu-
|
||||
|
||||
# MIPS32 big-endian
|
||||
make HOST_CC="gcc -m32" CROSS=mips-linux-gnu-
|
||||
# MIPS32 little-endian
|
||||
make HOST_CC="gcc -m32" CROSS=mipsel-linux-gnu-
|
||||
|
||||
# MIPS64 big-endian
|
||||
make CROSS=mips-linux- TARGET_CFLAGS="-mips64r2 -mabi=64"
|
||||
# MIPS64 little-endian
|
||||
make CROSS=mipsel-linux- TARGET_CFLAGS="-mips64r2 -mabi=64"
|
||||
</pre>
|
||||
<p>
|
||||
You can cross-compile for <b id="android">Android</b> using the <a href="https://developer.android.com/ndk/"><span class="ext">»</span> Android NDK</a>.
|
||||
Please adapt the environment variables to match the install locations and the
|
||||
desired target platform. E.g. Android 4.1 corresponds to ABI level 16.
|
||||
</p>
|
||||
<pre class="code">
|
||||
# Android/ARM64, aarch64, Android 5.0+ (L)
|
||||
NDKDIR=/opt/android/ndk
|
||||
NDKBIN=$NDKDIR/toolchains/llvm/prebuilt/linux-x86_64/bin
|
||||
NDKCROSS=$NDKBIN/aarch64-linux-android-
|
||||
NDKCC=$NDKBIN/aarch64-linux-android21-clang
|
||||
make CROSS=$NDKCROSS \
|
||||
STATIC_CC=$NDKCC DYNAMIC_CC="$NDKCC -fPIC" \
|
||||
TARGET_LD=$NDKCC TARGET_AR="$NDKBIN/llvm-ar rcus" \
|
||||
TARGET_STRIP=$NDKBIN/llvm-strip
|
||||
|
||||
# Android/ARM, armeabi-v7a (ARMv7 VFP), Android 4.1+ (JB)
|
||||
NDKDIR=/opt/android/ndk
|
||||
NDKBIN=$NDKDIR/toolchains/llvm/prebuilt/linux-x86_64/bin
|
||||
NDKCROSS=$NDKBIN/arm-linux-androideabi-
|
||||
NDKCC=$NDKBIN/armv7a-linux-androideabi16-clang
|
||||
make HOST_CC="gcc -m32" CROSS=$NDKCROSS \
|
||||
STATIC_CC=$NDKCC DYNAMIC_CC="$NDKCC -fPIC" \
|
||||
TARGET_LD=$NDKCC TARGET_AR="$NDKBIN/llvm-ar rcus" \
|
||||
TARGET_STRIP=$NDKBIN/llvm-strip
|
||||
</pre>
|
||||
<p>
|
||||
You can cross-compile for <b id="ios">iOS 3.0+</b> (iPhone/iPad) using the <a href="https://developer.apple.com/ios/"><span class="ext">»</span> iOS SDK</a>:
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
Note: <b>the JIT compiler is disabled for iOS</b>, because regular iOS Apps
|
||||
are not allowed to generate code at runtime. You'll only get the performance
|
||||
of the LuaJIT interpreter on iOS. This is still faster than plain Lua, but
|
||||
much slower than the JIT compiler. Please complain to Apple, not me.
|
||||
Or use Android. :-p
|
||||
</p>
|
||||
<pre class="code">
|
||||
# iOS/ARM64
|
||||
ISDKP=$(xcrun --sdk iphoneos --show-sdk-path)
|
||||
ICC=$(xcrun --sdk iphoneos --find clang)
|
||||
ISDKF="-arch arm64 -isysroot $ISDKP"
|
||||
make DEFAULT_CC=clang CROSS="$(dirname $ICC)/" \
|
||||
TARGET_FLAGS="$ISDKF" TARGET_SYS=iOS
|
||||
</pre>
|
||||
|
||||
<h3 id="consoles">Cross-compiling for consoles</h3>
|
||||
<p>
|
||||
Building LuaJIT for consoles requires both a supported host compiler
|
||||
(x86 or x64) and a cross-compiler from the official console SDK.
|
||||
</p>
|
||||
<p>
|
||||
Due to restrictions on consoles, the JIT compiler is disabled and only
|
||||
the fast interpreter is built. This is still faster than plain Lua,
|
||||
but much slower than the JIT compiler. The FFI is disabled, too, since
|
||||
it's not very useful in such an environment.
|
||||
</p>
|
||||
<p>
|
||||
The following commands build a static library <tt>libluajit.a</tt>,
|
||||
which can be linked against your game, just like the Lua library.
|
||||
</p>
|
||||
<p>
|
||||
To cross-compile for <b id="ps3">PS3</b> from a Linux host (requires
|
||||
32 bit GCC, i.e. multilib Linux/x64) or a Windows host (requires
|
||||
32 bit MinGW), run this command:
|
||||
</p>
|
||||
<pre class="code">
|
||||
make HOST_CC="gcc -m32" CROSS=ppu-lv2-
|
||||
</pre>
|
||||
<p>
|
||||
To cross-compile for the other consoles from a Windows host, open a
|
||||
"Native Tools Command Prompt for VS". You need to choose either the 32
|
||||
or the 64 bit version of the host compiler to match the target.
|
||||
Then <tt>cd</tt> to the <tt>src</tt> directory below the source code
|
||||
and run the build command given in the table:
|
||||
</p>
|
||||
<table class="compat">
|
||||
<tr class="compathead">
|
||||
<td class="compatname">Console</td>
|
||||
<td class="compatbits">Bits</td>
|
||||
<td class="compatx">Build Command</td>
|
||||
</tr>
|
||||
<tr class="odd separate">
|
||||
<td class="compatname"><b id="ps4">PS4</b></td>
|
||||
<td class="compatbits">64</td>
|
||||
<td class="compatx"><tt>ps4build</tt></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td class="compatname"><b id="ps5">PS5</b></td>
|
||||
<td class="compatbits">64</td>
|
||||
<td class="compatx"><tt>ps5build</tt></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td class="compatname"><b id="psvita">PS Vita</b></td>
|
||||
<td class="compatbits">32</td>
|
||||
<td class="compatx"><tt>psvitabuild</tt></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td class="compatname"><b id="xbox360">Xbox 360</b></td>
|
||||
<td class="compatbits">32</td>
|
||||
<td class="compatx"><tt>xedkbuild</tt></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td class="compatname"><b id="xboxone">Xbox One</b></td>
|
||||
<td class="compatbits">64</td>
|
||||
<td class="compatx"><tt>xb1build</tt></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td class="compatname"><b id="nx32">Nintendo Switch NX32</b></td>
|
||||
<td class="compatbits">32</td>
|
||||
<td class="compatx"><tt>nxbuild</tt></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td class="compatname"><b id="nx64">Nintendo Switch NX64</b></td>
|
||||
<td class="compatbits">64</td>
|
||||
<td class="compatx"><tt>nxbuild</tt></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Please check out the comments in the corresponding <tt>*.bat</tt>
|
||||
file for more options.
|
||||
</p>
|
||||
|
||||
<h2 id="embed">Embedding LuaJIT</h2>
|
||||
<p>
|
||||
LuaJIT is API-compatible with Lua 5.1. If you've already embedded Lua
|
||||
into your application, you probably don't need to do anything to switch
|
||||
to LuaJIT, except link with a different library:
|
||||
</p>
|
||||
<ul>
|
||||
<li>It's strongly suggested to build LuaJIT separately using the supplied
|
||||
build system. Please do <em>not</em> attempt to integrate the individual
|
||||
source files into your build tree. You'll most likely get the internal build
|
||||
dependencies wrong or mess up the compiler flags. Treat LuaJIT like any
|
||||
other external library and link your application with either the dynamic
|
||||
or static library, depending on your needs.</li>
|
||||
<li>If you want to load C modules compiled for plain Lua
|
||||
with <tt>require()</tt>, you need to make sure the public symbols
|
||||
(e.g. <tt>lua_pushnumber</tt>) are exported, too:
|
||||
<ul><li>On POSIX systems you can either link to the shared library
|
||||
or link the static library into your application. In the latter case
|
||||
you'll need to export all public symbols from your main executable
|
||||
(e.g. <tt>-Wl,-E</tt> on Linux) and add the external dependencies
|
||||
(e.g. <tt>-lm -ldl</tt> on Linux).</li>
|
||||
<li>Since Windows symbols are bound to a specific DLL name, you need to
|
||||
link to the <tt>lua51.dll</tt> created by the LuaJIT build (do not rename
|
||||
the DLL). You may link LuaJIT statically on Windows only if you don't
|
||||
intend to load Lua/C modules at runtime.
|
||||
</li></ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Additional hints for initializing LuaJIT using the C API functions:</p>
|
||||
<ul>
|
||||
<li>Here's a
|
||||
<a href="http://lua-users.org/wiki/SimpleLuaApiExample"><span class="ext">»</span> simple example</a>
|
||||
for embedding Lua or LuaJIT into your application.</li>
|
||||
<li>Make sure you use <tt>luaL_newstate</tt>. Avoid using
|
||||
<tt>lua_newstate</tt>, since this uses the (slower) default memory
|
||||
allocator from your system (no support for this on 64 bit architectures).</li>
|
||||
<li>Make sure you use <tt>luaL_openlibs</tt> and not the old Lua 5.0 style
|
||||
of calling <tt>luaopen_base</tt> etc. directly.</li>
|
||||
<li>To change or extend the list of standard libraries to load, copy
|
||||
<tt>src/lib_init.c</tt> to your project and modify it accordingly.
|
||||
Make sure the <tt>jit</tt> library is loaded, or the JIT compiler
|
||||
will not be activated.</li>
|
||||
<li>The <tt>bit.*</tt> module for bitwise operations
|
||||
is already built-in. There's no need to statically link
|
||||
<a href="https://bitop.luajit.org/"><span class="ext">»</span> Lua BitOp</a> to your application.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="distro">Hints for Distribution Maintainers</h2>
|
||||
<p>
|
||||
The LuaJIT build system has extra provisions for the needs of most
|
||||
POSIX-based distributions. If you're a package maintainer for
|
||||
a distribution, <em>please</em> make use of these features and
|
||||
avoid patching, subverting, autotoolizing or messing up the build system
|
||||
in unspeakable ways.
|
||||
</p>
|
||||
<p>
|
||||
There should be absolutely no need to patch <tt>luaconf.h</tt> or any
|
||||
of the Makefiles. And please do not hand-pick files for your packages —
|
||||
simply use whatever <tt>make install</tt> creates. There's a reason
|
||||
for all the files <em>and</em> directories it creates.
|
||||
</p>
|
||||
<p>
|
||||
The build system uses GNU make and auto-detects most settings based on
|
||||
the host you're building it on. This should work fine for native builds,
|
||||
even when sandboxed. You may need to pass some of the following flags to
|
||||
<em>both</em> the <tt>make</tt> and the <tt>make install</tt> command lines
|
||||
for a regular distribution build:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>PREFIX</tt> overrides the installation path and should usually
|
||||
be set to <tt>/usr</tt>. Setting this also changes the module paths and
|
||||
the paths needed to locate the shared library.</li>
|
||||
<li><tt>DESTDIR</tt> is an absolute path which allows you to install
|
||||
to a shadow tree instead of the root tree of the build system.</li>
|
||||
<li><tt>MULTILIB</tt> sets the architecture-specific library path component
|
||||
for multilib systems. The default is <tt>lib</tt>.</li>
|
||||
<li>Have a look at the top-level <tt>Makefile</tt> and <tt>src/Makefile</tt>
|
||||
for additional variables to tweak. The following variables <em>may</em> be
|
||||
overridden, but it's <em>not</em> recommended, except for special needs
|
||||
like cross-builds:
|
||||
<tt>BUILDMODE, CC, HOST_CC, STATIC_CC, DYNAMIC_CC, CFLAGS, HOST_CFLAGS,
|
||||
TARGET_CFLAGS, LDFLAGS, HOST_LDFLAGS, TARGET_LDFLAGS, TARGET_SHLDFLAGS,
|
||||
TARGET_FLAGS, LIBS, HOST_LIBS, TARGET_LIBS, CROSS, HOST_SYS, TARGET_SYS
|
||||
</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The build system has a special target for an amalgamated build, i.e.
|
||||
<tt>make amalg</tt>. This compiles the LuaJIT core as one huge C file
|
||||
and allows GCC to generate faster and shorter code. Alas, this requires
|
||||
lots of memory during the build. This may be a problem for some users,
|
||||
that's why it's not enabled by default. But it shouldn't be a problem for
|
||||
most build farms. It's recommended that binary distributions use this
|
||||
target for their LuaJIT builds.
|
||||
</p>
|
||||
<p>
|
||||
The tl;dr version of the above:
|
||||
</p>
|
||||
<pre class="code">
|
||||
make amalg PREFIX=/usr && \
|
||||
make install PREFIX=/usr DESTDIR=/tmp/buildroot
|
||||
</pre>
|
||||
<p>
|
||||
Finally, if you encounter any difficulties, please
|
||||
<a href="contact.html">contact me</a> first, instead of releasing a broken
|
||||
package onto unsuspecting users. Because they'll usually gonna complain
|
||||
to me (the upstream) and not you (the package maintainer), anyway.
|
||||
</p>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
203
thirdPart/luajit/doc/luajit.html
Normal file
203
thirdPart/luajit/doc/luajit.html
Normal file
@@ -0,0 +1,203 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>LuaJIT</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
<meta name="description" content="LuaJIT is a Just-In-Time (JIT) compiler for the Lua language.">
|
||||
<style type="text/css">
|
||||
table.feature {
|
||||
width: inherit;
|
||||
line-height: 1.2;
|
||||
margin: 0;
|
||||
}
|
||||
table.feature td {
|
||||
width: 80px;
|
||||
height: 40px;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
border: 4px solid #e6ecff;
|
||||
border-radius: 12px;
|
||||
}
|
||||
table.os td {
|
||||
background: #7080d0;
|
||||
background-image: linear-gradient(#4060c0 10%, #b0b0ff 95%);
|
||||
background-image: -moz-linear-gradient(#4060c0 10%, #b0b0ff 95%);
|
||||
background-image: -webkit-linear-gradient(#4060c0 10%, #b0b0ff 95%);
|
||||
background-image: -o-linear-gradient(#4060c0 10%, #b0b0ff 95%);
|
||||
background-image: -ms-linear-gradient(#4060c0 10%, #b0b0ff 95%);
|
||||
}
|
||||
table.os1 td {
|
||||
color: #ffff80;
|
||||
}
|
||||
table.os2 td {
|
||||
color: #ffa040;
|
||||
}
|
||||
table.os3 td {
|
||||
color: #40ffff;
|
||||
}
|
||||
table.compiler td {
|
||||
color: #2080ff;
|
||||
background: #62bf41;
|
||||
background-image: linear-gradient(#62bf41 10%, #b0ffb0 95%);
|
||||
background-image: -moz-linear-gradient(#62bf41 10%, #b0ffb0 95%);
|
||||
background-image: -webkit-linear-gradient(#62bf41 10%, #b0ffb0 95%);
|
||||
background-image: -o-linear-gradient(#62bf41 10%, #b0ffb0 95%);
|
||||
background-image: -ms-linear-gradient(#62bf41 10%, #b0ffb0 95%);
|
||||
}
|
||||
table.cpu td {
|
||||
color: #ffff00;
|
||||
background: #cf7251;
|
||||
background-image: linear-gradient(#bf6241 10%, #ffb0b0 95%);
|
||||
background-image: -moz-linear-gradient(#bf6241 10%, #ffb0b0 95%);
|
||||
background-image: -webkit-linear-gradient(#bf6241 10%, #ffb0b0 95%);
|
||||
background-image: -o-linear-gradient(#bf6241 10%, #ffb0b0 95%);
|
||||
background-image: -ms-linear-gradient(#bf6241 10%, #ffb0b0 95%);
|
||||
}
|
||||
table.fcompat td {
|
||||
color: #2060e0;
|
||||
background: #61cfcf;
|
||||
background-image: linear-gradient(#41bfbf 10%, #b0ffff 95%);
|
||||
background-image: -moz-linear-gradient(#41bfbf 10%, #b0ffff 95%);
|
||||
background-image: -webkit-linear-gradient(#41bfbf 10%, #b0ffff 95%);
|
||||
background-image: -o-linear-gradient(#41bfbf 10%, #b0ffff 95%);
|
||||
background-image: -ms-linear-gradient(#41bfbf 10%, #b0ffff 95%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1>LuaJIT</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a class="current" href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
<p>
|
||||
LuaJIT is a <b>Just-In-Time Compiler</b> (JIT) for the
|
||||
<a href="https://www.lua.org/"><span class="ext">»</span> Lua</a> programming language.
|
||||
Lua is a powerful, dynamic and light-weight programming language.
|
||||
It may be embedded or used as a general-purpose, stand-alone language.
|
||||
</p>
|
||||
<p>
|
||||
LuaJIT is Copyright © 2005-2023 Mike Pall, released under the
|
||||
<a href="https://www.opensource.org/licenses/mit-license.php"><span class="ext">»</span> MIT open source license</a>.
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
|
||||
<h2>Compatibility</h2>
|
||||
<table class="feature os os1">
|
||||
<tr><td>Windows</td><td>Linux</td><td>BSD</td><td>macOS</td><td>POSIX</td></tr>
|
||||
</table>
|
||||
<table class="feature os os2">
|
||||
<tr><td><span style="font-size:90%;">Embedded</span></td><td>Android</td><td>iOS</td></tr>
|
||||
</table>
|
||||
<table class="feature os os3">
|
||||
<tr><td>PS3</td><td>PS4<br>PS5</td><td>PS Vita</td><td>Xbox 360</td><td>Xbox One</td><td>Nintendo<br>Switch</td></tr>
|
||||
</table>
|
||||
<table class="feature compiler">
|
||||
<tr><td>GCC</td><td>Clang<br>LLVM</td><td>MSVC</td></tr>
|
||||
</table>
|
||||
<table class="feature cpu">
|
||||
<tr><td>x86<br>x64</td><td>ARM<br>ARM64</td><td>PPC</td><td>MIPS32<br>MIPS64</td></tr>
|
||||
</table>
|
||||
<table class="feature fcompat">
|
||||
<tr><td>Lua 5.1<br>API+ABI</td><td>+ JIT</td><td>+ BitOp</td><td>+ FFI</td><td>Drop-in<br>DLL/.so</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>Overview</h2>
|
||||
<p style="margin-top: 1em;">
|
||||
LuaJIT has been successfully used as a <b>scripting middleware</b> in
|
||||
games, appliances, network and graphics apps, numerical simulations,
|
||||
trading platforms and many other specialty applications.
|
||||
</p>
|
||||
<p>
|
||||
LuaJIT is part of a hundred million web sites, huge SaaS installations,
|
||||
network switches, set-top boxes and other embedded devices. You've probably
|
||||
already used LuaJIT without knowing about it.
|
||||
</p>
|
||||
<p>
|
||||
LuaJIT scales from embedded devices, smartphones, desktops up to server
|
||||
farms. It combines high flexibility with high performance and an unmatched
|
||||
<b>low memory footprint</b>.
|
||||
</p>
|
||||
<p>
|
||||
LuaJIT has been in continuous development since 2005. It's widely
|
||||
considered to be <b>one of the fastest dynamic language
|
||||
implementations</b>. It has outperformed other dynamic languages on many
|
||||
cross-language benchmarks since its first release — often by a
|
||||
substantial margin.
|
||||
</p>
|
||||
<p>
|
||||
For <b>LuaJIT 2.0</b>, the whole VM has been rewritten from the ground up
|
||||
and relentlessly optimized for performance. It combines a <b>high-speed
|
||||
interpreter</b>, written in assembler, with a <b>state-of-the-art JIT
|
||||
compiler</b>.
|
||||
</p>
|
||||
<p>
|
||||
An innovative <b>trace compiler</b> is integrated with advanced,
|
||||
SSA-based optimizations and highly tuned code generation backends.
|
||||
A substantial reduction of the overhead associated with dynamic languages
|
||||
allows it to break into the performance range traditionally reserved for
|
||||
offline, static language compilers.
|
||||
</p>
|
||||
|
||||
<h2>More ...</h2>
|
||||
<p>
|
||||
Please select a sub-topic in the navigation bar to learn more about LuaJIT.
|
||||
</p>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
317
thirdPart/luajit/doc/running.html
Normal file
317
thirdPart/luajit/doc/running.html
Normal file
@@ -0,0 +1,317 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Running LuaJIT</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
||||
<meta name="Language" content="en">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
||||
<style type="text/css">
|
||||
table.opt {
|
||||
line-height: 1.2;
|
||||
}
|
||||
tr.opthead td {
|
||||
font-weight: bold;
|
||||
}
|
||||
td.flag_name {
|
||||
width: 4em;
|
||||
}
|
||||
td.flag_level {
|
||||
width: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
td.param_name {
|
||||
width: 6em;
|
||||
}
|
||||
td.param_default {
|
||||
width: 4em;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="site">
|
||||
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
||||
</div>
|
||||
<div id="head">
|
||||
<h1>Running LuaJIT</h1>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul><li>
|
||||
<a href="luajit.html">LuaJIT</a>
|
||||
<ul><li>
|
||||
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="install.html">Installation</a>
|
||||
</li><li>
|
||||
<a class="current" href="running.html">Running</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="extensions.html">Extensions</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi.html">FFI Library</a>
|
||||
<ul><li>
|
||||
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="ext_buffer.html">String Buffers</a>
|
||||
</li><li>
|
||||
<a href="ext_jit.html">jit.* Library</a>
|
||||
</li><li>
|
||||
<a href="ext_c_api.html">Lua/C API</a>
|
||||
</li><li>
|
||||
<a href="ext_profiler.html">Profiler</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
||||
</li><li>
|
||||
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
||||
</li></ul>
|
||||
</div>
|
||||
<div id="main">
|
||||
|
||||
<p>
|
||||
LuaJIT has only a single stand-alone executable, called <tt>luajit</tt> on
|
||||
POSIX systems or <tt>luajit.exe</tt> on Windows. It can be used to run simple
|
||||
Lua statements or whole Lua applications from the command line. It has an
|
||||
interactive mode, too.
|
||||
</p>
|
||||
|
||||
<h2 id="options">Command Line Options</h2>
|
||||
<p>
|
||||
The <tt>luajit</tt> stand-alone executable is just a slightly modified
|
||||
version of the regular <tt>lua</tt> stand-alone executable.
|
||||
It supports the same basic options, too. <tt>luajit -h</tt>
|
||||
prints a short list of the available options. Please have a look at the
|
||||
<a href="https://www.lua.org/manual/5.1/manual.html#6"><span class="ext">»</span> Lua manual</a>
|
||||
for details.
|
||||
</p>
|
||||
<p>
|
||||
LuaJIT has some additional options:
|
||||
</p>
|
||||
|
||||
<h3 id="opt_b"><tt>-b[options] input output</tt></h3>
|
||||
<p>
|
||||
This option saves or lists bytecode. The following additional options
|
||||
are accepted:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>-l</tt> — Only list bytecode.</li>
|
||||
<li><tt>-s</tt> — Strip debug info (this is the default).</li>
|
||||
<li><tt>-g</tt> — Keep debug info.</li>
|
||||
<li><tt>-W</tt> — Generate 32 bit (non-GC64) bytecode.</li>
|
||||
<li><tt>-X</tt> — Generate 64 bit (GC64) bytecode.</li>
|
||||
<li><tt>-d</tt> — Generate bytecode in deterministic manner.</li>
|
||||
<li><tt>-n name</tt> — Set module name (default: auto-detect from input name)</li>
|
||||
<li><tt>-t type</tt> — Set output file type (default: auto-detect from output name).</li>
|
||||
<li><tt>-a arch</tt> — Override architecture for object files (default: native).</li>
|
||||
<li><tt>-o os</tt> — Override OS for object files (default: native).</li>
|
||||
<li><tt>-F name</tt> — Override filename (default: input filename).</li>
|
||||
<li><tt>-e chunk</tt> — Use chunk string as input.</li>
|
||||
<li><tt>-</tt> (a single minus sign) — Use stdin as input and/or stdout as output.</li>
|
||||
</ul>
|
||||
<p>
|
||||
The output file type is auto-detected from the extension of the output
|
||||
file name:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>c</tt> — C source file, exported bytecode data.</li>
|
||||
<li><tt>cc</tt> — C++ source file, exported bytecode data.</li>
|
||||
<li><tt>h</tt> — C/C++ header file, static bytecode data.</li>
|
||||
<li><tt>obj</tt> or <tt>o</tt> — Object file, exported bytecode data
|
||||
(OS- and architecture-specific).</li>
|
||||
<li><tt>raw</tt> or any other extension — Raw bytecode file (portable).
|
||||
</ul>
|
||||
<p>
|
||||
Notes:
|
||||
</p>
|
||||
<ul>
|
||||
<li>See also <a href="extensions.html#string_dump">string.dump()</a>
|
||||
for information on bytecode portability and compatibility.</li>
|
||||
<li>A file in raw bytecode format is auto-detected and can be loaded like
|
||||
any Lua source file. E.g. directly from the command line or with
|
||||
<tt>loadfile()</tt>, <tt>dofile()</tt> etc.</li>
|
||||
<li>To statically embed the bytecode of a module in your application,
|
||||
generate an object file and just link it with your application.</li>
|
||||
<li>On most ELF-based systems (e.g. Linux) you need to explicitly export the
|
||||
global symbols when linking your application, e.g. with: <tt>-Wl,-E</tt></li>
|
||||
<li><tt>require()</tt> tries to load embedded bytecode data from exported
|
||||
symbols (in <tt>*.exe</tt> or <tt>lua51.dll</tt> on Windows) and from
|
||||
shared libraries in <tt>package.cpath</tt>.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Typical usage examples:
|
||||
</p>
|
||||
<pre class="code">
|
||||
luajit -b test.lua test.out # Save bytecode to test.out
|
||||
luajit -bg test.lua test.out # Keep debug info
|
||||
luajit -be "print('hello world')" test.out # Save cmdline script
|
||||
|
||||
luajit -bl test.lua # List to stdout
|
||||
luajit -bl test.lua test.txt # List to test.txt
|
||||
luajit -ble "print('hello world')" # List cmdline script
|
||||
|
||||
luajit -b test.lua test.obj # Generate object file
|
||||
# Link test.obj with your application and load it with require("test")
|
||||
</pre>
|
||||
|
||||
<h3 id="opt_j"><tt>-j cmd[=arg[,arg...]]</tt></h3>
|
||||
<p>
|
||||
This option performs a LuaJIT control command or activates one of the
|
||||
loadable extension modules. The command is first looked up in the
|
||||
<tt>jit.*</tt> library. If no matching function is found, a module
|
||||
named <tt>jit.<cmd></tt> is loaded and the <tt>start()</tt>
|
||||
function of the module is called with the specified arguments (if
|
||||
any). The space between <tt>-j</tt> and <tt>cmd</tt> is optional.
|
||||
</p>
|
||||
<p>
|
||||
Here are the available LuaJIT control commands:
|
||||
</p>
|
||||
<ul>
|
||||
<li id="j_on"><tt>-jon</tt> — Turns the JIT compiler on (default).</li>
|
||||
<li id="j_off"><tt>-joff</tt> — Turns the JIT compiler off (only use the interpreter).</li>
|
||||
<li id="j_flush"><tt>-jflush</tt> — Flushes the whole cache of compiled code.</li>
|
||||
<li id="j_v"><tt>-jv</tt> — Shows verbose information about the progress of the JIT compiler.</li>
|
||||
<li id="j_dump"><tt>-jdump</tt> — Dumps the code and structures used in various compiler stages.</li>
|
||||
<li id="j_p"><tt>-jp</tt> — Start the <a href="ext_profiler.html">integrated profiler</a>.</li>
|
||||
</ul>
|
||||
<p>
|
||||
The <tt>-jv</tt> and <tt>-jdump</tt> commands are extension modules
|
||||
written in Lua. They are mainly used for debugging the JIT compiler
|
||||
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-XX.YY.ZZ>/jit</tt> on POSIX
|
||||
systems (replace XX.YY.ZZ by the installed version).
|
||||
</p>
|
||||
|
||||
<h3 id="opt_O"><tt>-O[level]</tt><br>
|
||||
<tt>-O[+]flag</tt> <tt>-O-flag</tt><br>
|
||||
<tt>-Oparam=value</tt></h3>
|
||||
<p>
|
||||
This options allows fine-tuned control of the optimizations used by
|
||||
the JIT compiler. This is mainly intended for debugging LuaJIT itself.
|
||||
Please note that the JIT compiler is extremely fast (we are talking
|
||||
about the microsecond to millisecond range). Disabling optimizations
|
||||
doesn't have any visible impact on its overhead, but usually generates
|
||||
code that runs slower.
|
||||
</p>
|
||||
<p>
|
||||
The first form sets an optimization level — this enables a
|
||||
specific mix of optimization flags. <tt>-O0</tt> turns off all
|
||||
optimizations and higher numbers enable more optimizations. Omitting
|
||||
the level (i.e. just <tt>-O</tt>) sets the default optimization level,
|
||||
which is <tt>-O3</tt> in the current version.
|
||||
</p>
|
||||
<p>
|
||||
The second form adds or removes individual optimization flags.
|
||||
The third form sets a parameter for the VM or the JIT compiler
|
||||
to a specific value.
|
||||
</p>
|
||||
<p>
|
||||
You can either use this option multiple times (like <tt>-Ocse
|
||||
-O-dce -Ohotloop=10</tt>) or separate several settings with a comma
|
||||
(like <tt>-O+cse,-dce,hotloop=10</tt>). The settings are applied from
|
||||
left to right, and later settings override earlier ones. You can freely
|
||||
mix the three forms, but note that setting an optimization level
|
||||
overrides all earlier flags.
|
||||
</p>
|
||||
<p>
|
||||
Note that <tt>-Ofma</tt> is not enabled by default at any level,
|
||||
because it affects floating-point result accuracy. Only enable this,
|
||||
if you fully understand the trade-offs of FMA for performance (higher),
|
||||
determinism (lower) and numerical accuracy (higher).
|
||||
</p>
|
||||
<p>
|
||||
Here are the available flags and at what optimization levels they
|
||||
are enabled:
|
||||
</p>
|
||||
<table class="opt">
|
||||
<tr class="opthead">
|
||||
<td class="flag_name">Flag</td>
|
||||
<td class="flag_level">-O1</td>
|
||||
<td class="flag_level">-O2</td>
|
||||
<td class="flag_level">-O3</td>
|
||||
<td class="flag_desc"> </td>
|
||||
</tr>
|
||||
<tr class="odd separate">
|
||||
<td class="flag_name">fold</td><td class="flag_level">•</td><td class="flag_level">•</td><td class="flag_level">•</td><td class="flag_desc">Constant Folding, Simplifications and Reassociation</td></tr>
|
||||
<tr class="even">
|
||||
<td class="flag_name">cse</td><td class="flag_level">•</td><td class="flag_level">•</td><td class="flag_level">•</td><td class="flag_desc">Common-Subexpression Elimination</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="flag_name">dce</td><td class="flag_level">•</td><td class="flag_level">•</td><td class="flag_level">•</td><td class="flag_desc">Dead-Code Elimination</td></tr>
|
||||
<tr class="even">
|
||||
<td class="flag_name">narrow</td><td class="flag_level"> </td><td class="flag_level">•</td><td class="flag_level">•</td><td class="flag_desc">Narrowing of numbers to integers</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="flag_name">loop</td><td class="flag_level"> </td><td class="flag_level">•</td><td class="flag_level">•</td><td class="flag_desc">Loop Optimizations (code hoisting)</td></tr>
|
||||
<tr class="even">
|
||||
<td class="flag_name">fwd</td><td class="flag_level"> </td><td class="flag_level"> </td><td class="flag_level">•</td><td class="flag_desc">Load Forwarding (L2L) and Store Forwarding (S2L)</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="flag_name">dse</td><td class="flag_level"> </td><td class="flag_level"> </td><td class="flag_level">•</td><td class="flag_desc">Dead-Store Elimination</td></tr>
|
||||
<tr class="even">
|
||||
<td class="flag_name">abc</td><td class="flag_level"> </td><td class="flag_level"> </td><td class="flag_level">•</td><td class="flag_desc">Array Bounds Check Elimination</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="flag_name">sink</td><td class="flag_level"> </td><td class="flag_level"> </td><td class="flag_level">•</td><td class="flag_desc">Allocation/Store Sinking</td></tr>
|
||||
<tr class="even">
|
||||
<td class="flag_name">fuse</td><td class="flag_level"> </td><td class="flag_level"> </td><td class="flag_level">•</td><td class="flag_desc">Fusion of operands into instructions</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="flag_name">fma </td><td class="flag_level"> </td><td class="flag_level"> </td><td class="flag_level"> </td><td class="flag_desc">Fused multiply-add</td></tr>
|
||||
</table>
|
||||
<p>
|
||||
Here are the parameters and their default settings:
|
||||
</p>
|
||||
<table class="opt">
|
||||
<tr class="opthead">
|
||||
<td class="param_name">Parameter</td>
|
||||
<td class="param_default">Default</td>
|
||||
<td class="param_desc"> </td>
|
||||
</tr>
|
||||
<tr class="odd separate">
|
||||
<td class="param_name">maxtrace</td><td class="param_default">1000</td><td class="param_desc">Max. number of traces in the cache</td></tr>
|
||||
<tr class="even">
|
||||
<td class="param_name">maxrecord</td><td class="param_default">4000</td><td class="param_desc">Max. number of recorded IR instructions</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="param_name">maxirconst</td><td class="param_default">500</td><td class="param_desc">Max. number of IR constants of a trace</td></tr>
|
||||
<tr class="even">
|
||||
<td class="param_name">maxside</td><td class="param_default">100</td><td class="param_desc">Max. number of side traces of a root trace</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="param_name">maxsnap</td><td class="param_default">500</td><td class="param_desc">Max. number of snapshots for a trace</td></tr>
|
||||
<tr class="even separate">
|
||||
<td class="param_name">hotloop</td><td class="param_default">56</td><td class="param_desc">Number of iterations to detect a hot loop or hot call</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="param_name">hotexit</td><td class="param_default">10</td><td class="param_desc">Number of taken exits to start a side trace</td></tr>
|
||||
<tr class="even">
|
||||
<td class="param_name">tryside</td><td class="param_default">4</td><td class="param_desc">Number of attempts to compile a side trace</td></tr>
|
||||
<tr class="odd separate">
|
||||
<td class="param_name">instunroll</td><td class="param_default">4</td><td class="param_desc">Max. unroll factor for instable loops</td></tr>
|
||||
<tr class="even">
|
||||
<td class="param_name">loopunroll</td><td class="param_default">15</td><td class="param_desc">Max. unroll factor for loop ops in side traces</td></tr>
|
||||
<tr class="odd">
|
||||
<td class="param_name">callunroll</td><td class="param_default">3</td><td class="param_desc">Max. unroll factor for pseudo-recursive calls</td></tr>
|
||||
<tr class="even">
|
||||
<td class="param_name">recunroll</td><td class="param_default">2</td><td class="param_desc">Min. unroll factor for true recursion</td></tr>
|
||||
<tr class="odd separate">
|
||||
<td class="param_name">sizemcode</td><td class="param_default">32</td><td class="param_desc">Size of each machine code area in KBytes (Windows: 64K)</td></tr>
|
||||
<tr class="even">
|
||||
<td class="param_name">maxmcode</td><td class="param_default">512</td><td class="param_desc">Max. total size of all machine code areas in KBytes</td></tr>
|
||||
</table>
|
||||
<br class="flush">
|
||||
</div>
|
||||
<div id="foot">
|
||||
<hr class="hide">
|
||||
Copyright © 2005-2023
|
||||
<span class="noprint">
|
||||
·
|
||||
<a href="contact.html">Contact</a>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
456
thirdPart/luajit/dynasm/dasm_arm.h
Normal file
456
thirdPart/luajit/dynasm/dasm_arm.h
Normal file
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
** DynASM ARM encoding engine.
|
||||
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
** Released under the MIT 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_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8,
|
||||
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. */
|
||||
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;
|
||||
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;
|
||||
memset((void *)D->sections, 0, maxsection * sizeof(dasm_Section));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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].rbuf = D->sections[i].buf - D->sections[i].pos;
|
||||
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;
|
||||
/* Bkwd rel or global. */
|
||||
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
|
||||
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:
|
||||
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_IMMV8:
|
||||
CK((n & 3) == 0, RANGE_I);
|
||||
n >>= 2;
|
||||
/* fallthrough */
|
||||
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 = 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) {
|
||||
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: case DASM_IMM12: case DASM_IMM16:
|
||||
case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: 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:
|
||||
if (n < 0) {
|
||||
n = (int)((ptrdiff_t)D->globals[-n-10] - (ptrdiff_t)cp - 4);
|
||||
goto patchrel;
|
||||
}
|
||||
/* fallthrough */
|
||||
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 if ((ins & 0x2000) == 0) {
|
||||
CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL);
|
||||
goto patchimml;
|
||||
} else {
|
||||
CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL);
|
||||
n >>= 2;
|
||||
goto patchimml;
|
||||
}
|
||||
break;
|
||||
case DASM_LABEL_LG:
|
||||
ins &= 2047; if (ins >= 20) D->globals[ins-20] = (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;
|
||||
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: case DASM_IMMV8: patchimml:
|
||||
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
|
||||
|
||||
1125
thirdPart/luajit/dynasm/dasm_arm.lua
Normal file
1125
thirdPart/luajit/dynasm/dasm_arm.lua
Normal file
File diff suppressed because it is too large
Load Diff
558
thirdPart/luajit/dynasm/dasm_arm64.h
Normal file
558
thirdPart/luajit/dynasm/dasm_arm64.h
Normal file
@@ -0,0 +1,558 @@
|
||||
/*
|
||||
** DynASM ARM64 encoding engine.
|
||||
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
** Released under the MIT license. See dynasm.lua for full copyright notice.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DASM_ARCH "arm64"
|
||||
|
||||
#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_REL_A,
|
||||
DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML,
|
||||
DASM_IMMV, DASM_VREG,
|
||||
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_RANGE_VREG 0x16000000
|
||||
#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. */
|
||||
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;
|
||||
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;
|
||||
memset((void *)D->sections, 0, maxsection * sizeof(dasm_Section));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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].rbuf = D->sections[i].buf - D->sections[i].pos;
|
||||
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
|
||||
|
||||
static int dasm_imm12(unsigned int n)
|
||||
{
|
||||
if ((n >> 12) == 0)
|
||||
return n;
|
||||
else if ((n & 0xff000fff) == 0)
|
||||
return (n >> 12) | 0x1000;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dasm_ffs(unsigned long long x)
|
||||
{
|
||||
int n = -1;
|
||||
while (x) { x >>= 1; n++; }
|
||||
return n;
|
||||
}
|
||||
|
||||
static int dasm_imm13(int lo, int hi)
|
||||
{
|
||||
int inv = 0, w = 64, s = 0xfff, xa, xb;
|
||||
unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo;
|
||||
unsigned long long m = 1ULL, a, b, c;
|
||||
if (n & 1) { n = ~n; inv = 1; }
|
||||
a = n & (unsigned long long)-(long long)n;
|
||||
b = (n+a)&(unsigned long long)-(long long)(n+a);
|
||||
c = (n+a-b)&(unsigned long long)-(long long)(n+a-b);
|
||||
xa = dasm_ffs(a); xb = dasm_ffs(b);
|
||||
if (c) {
|
||||
w = dasm_ffs(c) - xa;
|
||||
if (w == 32) m = 0x0000000100000001UL;
|
||||
else if (w == 16) m = 0x0001000100010001UL;
|
||||
else if (w == 8) m = 0x0101010101010101UL;
|
||||
else if (w == 4) m = 0x1111111111111111UL;
|
||||
else if (w == 2) m = 0x5555555555555555UL;
|
||||
else return -1;
|
||||
s = (-2*w & 0x3f) - 1;
|
||||
} else if (!a) {
|
||||
return -1;
|
||||
} else if (xb == -1) {
|
||||
xb = 64;
|
||||
}
|
||||
if ((b-a) * m != n) return -1;
|
||||
if (inv) {
|
||||
return ((w - xb) << 6) | (s+w+xa-xb);
|
||||
} else {
|
||||
return ((w - xa) << 6) | (s+xb-xa);
|
||||
}
|
||||
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: if ((ins & 0x8000)) ofs += 8; break;
|
||||
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
|
||||
case DASM_REL_LG:
|
||||
n = (ins & 2047) - 10; pl = D->lglabels + n;
|
||||
/* Bkwd rel or global. */
|
||||
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
|
||||
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++;
|
||||
if ((ins & 0x8000)) ofs += 8;
|
||||
break;
|
||||
case DASM_REL_A:
|
||||
b[pos++] = n;
|
||||
b[pos++] = va_arg(ap, int);
|
||||
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:
|
||||
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
|
||||
n >>= ((ins>>10)&31);
|
||||
#ifdef DASM_CHECKS
|
||||
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_IMM6:
|
||||
CK((n >> 6) == 0, RANGE_I);
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_IMM12:
|
||||
CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_IMM13W:
|
||||
CK(dasm_imm13(n, n) != -1, RANGE_I);
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_IMM13X: {
|
||||
int m = va_arg(ap, int);
|
||||
CK(dasm_imm13(n, m) != -1, RANGE_I);
|
||||
b[pos++] = n;
|
||||
b[pos++] = m;
|
||||
break;
|
||||
}
|
||||
case DASM_IMML: {
|
||||
#ifdef DASM_CHECKS
|
||||
int scale = (ins & 3);
|
||||
CK((!(n & ((1<<scale)-1)) && (unsigned int)(n>>scale) < 4096) ||
|
||||
(unsigned int)(n+256) < 512, RANGE_I);
|
||||
#endif
|
||||
b[pos++] = n;
|
||||
break;
|
||||
}
|
||||
case DASM_IMMV:
|
||||
ofs += 4;
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_VREG:
|
||||
CK(n < 32, RANGE_VREG);
|
||||
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 = 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) {
|
||||
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: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W:
|
||||
case DASM_IMML: case DASM_IMMV: case DASM_VREG: pos++; break;
|
||||
case DASM_IMM13X: case DASM_REL_A: pos += 2; 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|(int)(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++ = 0xd503201f;
|
||||
break;
|
||||
case DASM_REL_LG:
|
||||
if (n < 0) {
|
||||
ptrdiff_t na = (ptrdiff_t)D->globals[-n-10] - (ptrdiff_t)cp + 4;
|
||||
n = (int)na;
|
||||
CK((ptrdiff_t)n == na, RANGE_REL);
|
||||
goto patchrel;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DASM_REL_PC:
|
||||
CK(n >= 0, UNDEF_PC);
|
||||
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4;
|
||||
patchrel:
|
||||
if (!(ins & 0xf800)) { /* B, BL */
|
||||
CK((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, RANGE_REL);
|
||||
cp[-1] |= ((n >> 2) & 0x03ffffff);
|
||||
} else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */
|
||||
CK((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, RANGE_REL);
|
||||
cp[-1] |= ((n << 3) & 0x00ffffe0);
|
||||
} else if ((ins & 0x3000) == 0x2000) { /* ADR */
|
||||
CK(((n+0x00100000) >> 21) == 0, RANGE_REL);
|
||||
cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29);
|
||||
} else if ((ins & 0x3000) == 0x3000) { /* ADRP */
|
||||
cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29);
|
||||
} else if ((ins & 0x1000)) { /* TBZ, TBNZ */
|
||||
CK((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, RANGE_REL);
|
||||
cp[-1] |= ((n << 3) & 0x0007ffe0);
|
||||
} else if ((ins & 0x8000)) { /* absolute */
|
||||
cp[0] = (unsigned int)((ptrdiff_t)cp - 4 + n);
|
||||
cp[1] = (unsigned int)(((ptrdiff_t)cp - 4 + n) >> 32);
|
||||
cp += 2;
|
||||
}
|
||||
break;
|
||||
case DASM_REL_A: {
|
||||
ptrdiff_t na = (((ptrdiff_t)(*b++) << 32) | (unsigned int)n);
|
||||
if ((ins & 0x3000) == 0x3000) { /* ADRP */
|
||||
ins &= ~0x1000;
|
||||
na = (na >> 12) - (((ptrdiff_t)cp - 4) >> 12);
|
||||
} else {
|
||||
na = na - (ptrdiff_t)cp + 4;
|
||||
}
|
||||
n = (int)na;
|
||||
CK((ptrdiff_t)n == na, RANGE_REL);
|
||||
goto patchrel;
|
||||
}
|
||||
case DASM_LABEL_LG:
|
||||
ins &= 2047; if (ins >= 20) D->globals[ins-20] = (void *)(base + n);
|
||||
break;
|
||||
case DASM_LABEL_PC: break;
|
||||
case DASM_IMM:
|
||||
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
|
||||
break;
|
||||
case DASM_IMM6:
|
||||
cp[-1] |= ((n&31) << 19) | ((n&32) << 26);
|
||||
break;
|
||||
case DASM_IMM12:
|
||||
cp[-1] |= (dasm_imm12((unsigned int)n) << 10);
|
||||
break;
|
||||
case DASM_IMM13W:
|
||||
cp[-1] |= (dasm_imm13(n, n) << 10);
|
||||
break;
|
||||
case DASM_IMM13X:
|
||||
cp[-1] |= (dasm_imm13(n, *b++) << 10);
|
||||
break;
|
||||
case DASM_IMML: {
|
||||
int scale = (ins & 3);
|
||||
cp[-1] |= (!(n & ((1<<scale)-1)) && (unsigned int)(n>>scale) < 4096) ?
|
||||
((n << (10-scale)) | 0x01000000) : ((n & 511) << 12);
|
||||
break;
|
||||
}
|
||||
case DASM_IMMV:
|
||||
*cp++ = n;
|
||||
break;
|
||||
case DASM_VREG:
|
||||
cp[-1] |= (n & 0x1f) << (ins & 0x1f);
|
||||
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|(int)(D->section-D->sections);
|
||||
return D->status;
|
||||
}
|
||||
#endif
|
||||
|
||||
1226
thirdPart/luajit/dynasm/dasm_arm64.lua
Normal file
1226
thirdPart/luajit/dynasm/dasm_arm64.lua
Normal file
File diff suppressed because it is too large
Load Diff
419
thirdPart/luajit/dynasm/dasm_mips.h
Normal file
419
thirdPart/luajit/dynasm/dasm_mips.h
Normal file
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
** DynASM MIPS encoding engine.
|
||||
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
** Released under the MIT license. See dynasm.lua for full copyright notice.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DASM_ARCH "mips"
|
||||
|
||||
#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_IMMS,
|
||||
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. */
|
||||
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;
|
||||
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;
|
||||
memset((void *)D->sections, 0, maxsection * sizeof(dasm_Section));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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].rbuf = D->sections[i].buf - D->sections[i].pos;
|
||||
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;
|
||||
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) - 0xff00;
|
||||
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;
|
||||
/* Bkwd rel or global. */
|
||||
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
|
||||
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: case DASM_IMMS:
|
||||
#ifdef DASM_CHECKS
|
||||
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
|
||||
#endif
|
||||
n >>= ((ins>>10)&31);
|
||||
#ifdef DASM_CHECKS
|
||||
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 = 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) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16) - 0xff00;
|
||||
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: case DASM_IMMS: 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|(int)(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) - 0xff00;
|
||||
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:
|
||||
if (n < 0) {
|
||||
n = (int)((ptrdiff_t)D->globals[-n-10] - (ptrdiff_t)cp);
|
||||
goto patchrel;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DASM_REL_PC:
|
||||
CK(n >= 0, UNDEF_PC);
|
||||
n = *DASM_POS2PTR(D, n);
|
||||
if (ins & 2048)
|
||||
n = (n + (int)(size_t)base) & 0x0fffffff;
|
||||
else
|
||||
n = n - (int)((char *)cp - base);
|
||||
patchrel: {
|
||||
unsigned int e = 16 + ((ins >> 12) & 15);
|
||||
CK((n & 3) == 0 &&
|
||||
((n + ((ins & 2048) ? 0 : (1<<(e+1)))) >> (e+2)) == 0, RANGE_REL);
|
||||
cp[-1] |= ((n>>2) & ((1<<e)-1));
|
||||
}
|
||||
break;
|
||||
case DASM_LABEL_LG:
|
||||
ins &= 2047; if (ins >= 20) D->globals[ins-20] = (void *)(base + n);
|
||||
break;
|
||||
case DASM_LABEL_PC: break;
|
||||
case DASM_IMMS:
|
||||
cp[-1] |= ((n>>3) & 4); n &= 0x1f;
|
||||
/* fallthrough */
|
||||
case DASM_IMM:
|
||||
cp[-1] |= (n & ((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|(int)(D->section-D->sections);
|
||||
return D->status;
|
||||
}
|
||||
#endif
|
||||
|
||||
1181
thirdPart/luajit/dynasm/dasm_mips.lua
Normal file
1181
thirdPart/luajit/dynasm/dasm_mips.lua
Normal file
File diff suppressed because it is too large
Load Diff
12
thirdPart/luajit/dynasm/dasm_mips64.lua
Normal file
12
thirdPart/luajit/dynasm/dasm_mips64.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- DynASM MIPS64 module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- See dynasm.lua for full copyright notice.
|
||||
------------------------------------------------------------------------------
|
||||
-- This module just sets 64 bit mode for the combined MIPS/MIPS64 module.
|
||||
-- All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
mips64 = true -- Using a global is an ugly, but effective solution.
|
||||
return require("dasm_mips")
|
||||
418
thirdPart/luajit/dynasm/dasm_ppc.h
Normal file
418
thirdPart/luajit/dynasm/dasm_ppc.h
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
** DynASM PPC/PPC64 encoding engine.
|
||||
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
** Released under the MIT 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_IMMSH,
|
||||
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. */
|
||||
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;
|
||||
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;
|
||||
memset((void *)D->sections, 0, maxsection * sizeof(dasm_Section));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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].rbuf = D->sections[i].buf - D->sections[i].pos;
|
||||
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;
|
||||
/* Bkwd rel or global. */
|
||||
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
|
||||
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);
|
||||
#endif
|
||||
n >>= ((ins>>10)&31);
|
||||
#ifdef DASM_CHECKS
|
||||
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_IMMSH:
|
||||
CK((n >> 6) == 0, 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 = 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) {
|
||||
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: case DASM_IMMSH: 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) - 4;
|
||||
goto patchrel;
|
||||
case DASM_ALIGN:
|
||||
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
|
||||
break;
|
||||
case DASM_REL_LG:
|
||||
if (n < 0) {
|
||||
n = (int)((ptrdiff_t)D->globals[-n-10] - (ptrdiff_t)cp);
|
||||
goto patchrel;
|
||||
}
|
||||
/* fallthrough */
|
||||
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-20] = (void *)(base + n);
|
||||
break;
|
||||
case DASM_LABEL_PC: break;
|
||||
case DASM_IMM:
|
||||
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
|
||||
break;
|
||||
case DASM_IMMSH:
|
||||
cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32);
|
||||
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
|
||||
|
||||
1919
thirdPart/luajit/dynasm/dasm_ppc.lua
Normal file
1919
thirdPart/luajit/dynasm/dasm_ppc.lua
Normal file
File diff suppressed because it is too large
Load Diff
83
thirdPart/luajit/dynasm/dasm_proto.h
Normal file
83
thirdPart/luajit/dynasm/dasm_proto.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
** DynASM encoding engine prototypes.
|
||||
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
** Released under the MIT 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.5.0"
|
||||
#define DASM_VERSION 10500 /* 1.5.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 */
|
||||
12
thirdPart/luajit/dynasm/dasm_x64.lua
Normal file
12
thirdPart/luajit/dynasm/dasm_x64.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- DynASM x64 module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 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")
|
||||
523
thirdPart/luajit/dynasm/dasm_x86.h
Normal file
523
thirdPart/luajit/dynasm/dasm_x86.h
Normal file
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
** DynASM x86 encoding engine.
|
||||
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
** Released under the MIT 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. */
|
||||
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;
|
||||
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;
|
||||
memset((void *)D->sections, 0, maxsection * sizeof(dasm_Section));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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].rbuf = D->sections[i].buf - D->sections[i].pos;
|
||||
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 = -1;
|
||||
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 < 0) mrm = p[-2]; if ((mrm&7) != 5) break; }
|
||||
/* fallthrough */
|
||||
case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */
|
||||
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; /* fallthrough */
|
||||
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&-16) == 0 && (n != 4 || (*p>>5) != 2), RANGE_VREG);
|
||||
if (*p < 0x40 && p[1] == DASM_DISP) mrm = n;
|
||||
if (*p < 0x20 && (n&7) == 4) ofs++;
|
||||
switch ((*p++ >> 3) & 3) {
|
||||
case 3: n |= b[pos-3]; /* fallthrough */
|
||||
case 2: n |= b[pos-2]; /* fallthrough */
|
||||
case 1: if (n <= 7) { b[pos-1] |= 0x10; ofs--; }
|
||||
}
|
||||
continue;
|
||||
}
|
||||
mrm = -1;
|
||||
} else {
|
||||
int *pl, n;
|
||||
switch (action) {
|
||||
case DASM_REL_LG:
|
||||
case DASM_IMM_LG:
|
||||
n = *p++; pl = D->lglabels + n;
|
||||
/* Bkwd rel or global. */
|
||||
if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
|
||||
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. */
|
||||
} else if (sizeof(ptrdiff_t) == 8) {
|
||||
ofs += 4;
|
||||
}
|
||||
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++];
|
||||
int op = 0;
|
||||
while (1) {
|
||||
int action = *p++;
|
||||
switch (action) {
|
||||
case DASM_REL_LG: p++;
|
||||
/* fallthrough */
|
||||
case DASM_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;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++;
|
||||
/* fallthrough */
|
||||
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++;
|
||||
/* fallthrough */
|
||||
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: op = *p++; break;
|
||||
case DASM_MARK: break;
|
||||
case DASM_SECTION: case DASM_STOP: goto stop;
|
||||
default: op = action; 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;
|
||||
}
|
||||
|
||||
#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)
|
||||
#define dasmq(x) \
|
||||
do { *((unsigned long long *)cp) = (unsigned long long)(x); cp+=8; } 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)
|
||||
#define dasmq(x) do { dasmd(x); dasmd((x)>>32); } while (0)
|
||||
#endif
|
||||
static unsigned char *dasma_(unsigned char *cp, ptrdiff_t x)
|
||||
{
|
||||
if (sizeof(ptrdiff_t) == 8)
|
||||
dasmq((unsigned long long)x);
|
||||
else
|
||||
dasmd((unsigned int)x);
|
||||
return cp;
|
||||
}
|
||||
#define dasma(x) (cp = dasma_(cp, (x)))
|
||||
|
||||
/* 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;
|
||||
}
|
||||
/* fallthrough */
|
||||
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;
|
||||
/* fallthrough */
|
||||
case DASM_IMM_D: wd: dasmd(n); break;
|
||||
case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL;
|
||||
/* fallthrough */
|
||||
case DASM_IMM_W: dasmw(n); break;
|
||||
case DASM_VREG: {
|
||||
int t = *p++;
|
||||
unsigned char *ex = cp - (t&7);
|
||||
if ((n & 8) && t < 0xa0) {
|
||||
if (*ex & 0x80) ex[1] ^= 0x20 << (t>>6); else *ex ^= 1 << (t>>6);
|
||||
n &= 7;
|
||||
} else if (n & 0x10) {
|
||||
if (*ex & 0x80) {
|
||||
*ex = 0xc5; ex[1] = (ex[1] & 0x80) | ex[2]; ex += 2;
|
||||
}
|
||||
while (++ex < cp) ex[-1] = *ex;
|
||||
if (mark) mark--;
|
||||
cp--;
|
||||
n &= 7;
|
||||
}
|
||||
if (t >= 0xc0) n <<= 4;
|
||||
else if (t >= 0x40) n <<= 3;
|
||||
else if (n == 4 && t < 0x20) { cp[-1] ^= n; *cp++ = 0x20; }
|
||||
cp[-1] ^= n;
|
||||
break;
|
||||
}
|
||||
case DASM_REL_LG: p++; if (n >= 0) goto rel_pc;
|
||||
b++; n = (int)(ptrdiff_t)D->globals[-n-10];
|
||||
/* fallthrough */
|
||||
case DASM_REL_A: rel_a:
|
||||
n -= (unsigned 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) { dasma((ptrdiff_t)D->globals[-n-10]); break; }
|
||||
/* fallthrough */
|
||||
case DASM_IMM_PC: {
|
||||
int *pb = DASM_POS2PTR(D, n);
|
||||
dasma(*pb < 0 ? (ptrdiff_t)pb[1] : (*pb + (ptrdiff_t)base));
|
||||
break;
|
||||
}
|
||||
case DASM_LABEL_LG: {
|
||||
int idx = *p++;
|
||||
if (idx >= 10)
|
||||
D->globals[idx-10] = (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++;
|
||||
/* fallthrough */
|
||||
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
|
||||
|
||||
2394
thirdPart/luajit/dynasm/dasm_x86.lua
Normal file
2394
thirdPart/luajit/dynasm/dasm_x86.lua
Normal file
File diff suppressed because it is too large
Load Diff
1095
thirdPart/luajit/dynasm/dynasm.lua
Normal file
1095
thirdPart/luajit/dynasm/dynasm.lua
Normal file
File diff suppressed because it is too large
Load Diff
88
thirdPart/luajit/etc/luajit.1
Normal file
88
thirdPart/luajit/etc/luajit.1
Normal file
@@ -0,0 +1,88 @@
|
||||
.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 https://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 "\-b " ...
|
||||
Save or list bytecode. Run without arguments to get help on options.
|
||||
.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 "\-E"
|
||||
Ignore environment variables.
|
||||
.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-2023 Mike Pall.
|
||||
.br
|
||||
\fBLuaJIT\fR is open source software, released under the MIT license.
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
More details in the provided HTML docs or at:
|
||||
.IR https://luajit.org
|
||||
.br
|
||||
More about the Lua language can be found at:
|
||||
.IR https://lua.org/docs.html
|
||||
.PP
|
||||
lua(1)
|
||||
25
thirdPart/luajit/etc/luajit.pc
Normal file
25
thirdPart/luajit/etc/luajit.pc
Normal file
@@ -0,0 +1,25 @@
|
||||
# Package information for LuaJIT to be used by pkg-config.
|
||||
majver=2
|
||||
minver=1
|
||||
relver=ROLLING
|
||||
version=${majver}.${minver}.${relver}
|
||||
abiver=5.1
|
||||
|
||||
prefix=/usr/local
|
||||
multilib=lib
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/${multilib}
|
||||
libname=luajit-${abiver}
|
||||
includedir=${prefix}/include/luajit-${majver}.${minver}
|
||||
|
||||
INSTALL_LMOD=${prefix}/share/lua/${abiver}
|
||||
INSTALL_CMOD=${prefix}/${multilib}/lua/${abiver}
|
||||
|
||||
Name: LuaJIT
|
||||
Description: Just-in-time compiler for Lua
|
||||
URL: https://luajit.org
|
||||
Version: ${version}
|
||||
Requires:
|
||||
Libs: -L${libdir} -l${libname}
|
||||
Libs.private: -Wl,-E -lm -ldl
|
||||
Cflags: -I${includedir}
|
||||
9
thirdPart/luajit/src/.gitignore
vendored
Normal file
9
thirdPart/luajit/src/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
luajit
|
||||
luajit.h
|
||||
luajit_relver.txt
|
||||
lj_bcdef.h
|
||||
lj_ffdef.h
|
||||
lj_libdef.h
|
||||
lj_recdef.h
|
||||
lj_folddef.h
|
||||
lj_vm.[sS]
|
||||
743
thirdPart/luajit/src/Makefile
Normal file
743
thirdPart/luajit/src/Makefile
Normal file
@@ -0,0 +1,743 @@
|
||||
##############################################################################
|
||||
# LuaJIT Makefile. Requires GNU Make.
|
||||
#
|
||||
# Please read doc/install.html before changing any variables!
|
||||
#
|
||||
# Suitable for POSIX platforms (Linux, *BSD, OSX etc.).
|
||||
# Also works with MinGW and Cygwin on Windows.
|
||||
# Please check msvcbuild.bat for building with MSVC on Windows.
|
||||
#
|
||||
# Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
##############################################################################
|
||||
|
||||
MAJVER= 2
|
||||
MINVER= 1
|
||||
ABIVER= 5.1
|
||||
NODOTABIVER= 51
|
||||
|
||||
##############################################################################
|
||||
############################# COMPILER OPTIONS #############################
|
||||
##############################################################################
|
||||
# These options mainly affect 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. Make sure you force a full recompile
|
||||
# with "make clean", followed by "make" if you change any options.
|
||||
#
|
||||
DEFAULT_CC = gcc
|
||||
#
|
||||
# LuaJIT builds as a native 32 or 64 bit binary by default.
|
||||
CC= $(DEFAULT_CC)
|
||||
#
|
||||
# Use this if you want to force a 32 bit build on a 64 bit multilib OS.
|
||||
#CC= $(DEFAULT_CC) -m32
|
||||
#
|
||||
# Since the assembler part does NOT maintain a frame pointer, it's pointless
|
||||
# to slow down the C part by not omitting it. Debugging, tracebacks and
|
||||
# unwinding are not affected -- the assembler part has frame unwind
|
||||
# information and GCC emits it where needed (x64) or with -g (see CCDEBUG).
|
||||
CCOPT= -O2 -fomit-frame-pointer
|
||||
# Use this if you want to generate a smaller binary (but it's slower):
|
||||
#CCOPT= -Os -fomit-frame-pointer
|
||||
# Note: it's no longer recommended to use -O3 with GCC 4.x.
|
||||
# The I-Cache bloat usually outweighs the benefits from aggressive inlining.
|
||||
#
|
||||
# Target-specific compiler options:
|
||||
#
|
||||
# x86/x64 only: For GCC 4.2 or higher and if you don't intend to distribute
|
||||
# the binaries to a different machine you could also use: -march=native
|
||||
#
|
||||
CCOPT_x86= -march=i686 -msse -msse2 -mfpmath=sse
|
||||
CCOPT_x64=
|
||||
CCOPT_arm=
|
||||
CCOPT_arm64=
|
||||
CCOPT_ppc=
|
||||
CCOPT_mips=
|
||||
#
|
||||
CCDEBUG=
|
||||
# Uncomment the next line to generate debug information:
|
||||
#CCDEBUG= -g
|
||||
#
|
||||
CCWARN= -Wall
|
||||
# Uncomment the next line to enable more warnings:
|
||||
#CCWARN+= -Wextra -Wdeclaration-after-statement -Wredundant-decls -Wshadow -Wpointer-arith
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
################################ BUILD MODE ################################
|
||||
##############################################################################
|
||||
# The default build mode 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
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
################################# FEATURES #################################
|
||||
##############################################################################
|
||||
# Enable/disable these features as needed, but make sure you force a full
|
||||
# recompile with "make clean", followed by "make".
|
||||
XCFLAGS=
|
||||
#
|
||||
# Permanently disable the FFI extension to reduce the size of the LuaJIT
|
||||
# executable. But please consider that the FFI library is compiled-in,
|
||||
# but NOT loaded by default. It only allocates any memory, if you actually
|
||||
# make use of it.
|
||||
#XCFLAGS+= -DLUAJIT_DISABLE_FFI
|
||||
#
|
||||
# Features from Lua 5.2 that are unlikely to break existing code are
|
||||
# enabled by default. Some other features that *might* break some existing
|
||||
# code (e.g. __pairs or os.execute() return values) can be enabled here.
|
||||
# Note: this does not provide full compatibility with Lua 5.2 at this time.
|
||||
#XCFLAGS+= -DLUAJIT_ENABLE_LUA52COMPAT
|
||||
#
|
||||
# Disable the JIT compiler, i.e. turn LuaJIT into a pure interpreter.
|
||||
#XCFLAGS+= -DLUAJIT_DISABLE_JIT
|
||||
#
|
||||
# Some architectures (e.g. PPC) can use either single-number (1) or
|
||||
# dual-number (2) mode. Uncomment one of these lines to override the
|
||||
# default mode. Please see LJ_ARCH_NUMMODE in lj_arch.h for details.
|
||||
#XCFLAGS+= -DLUAJIT_NUMMODE=1
|
||||
#XCFLAGS+= -DLUAJIT_NUMMODE=2
|
||||
#
|
||||
# Disable LJ_GC64 mode for x64.
|
||||
#XCFLAGS+= -DLUAJIT_DISABLE_GC64
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
############################ DEBUGGING SUPPORT #############################
|
||||
##############################################################################
|
||||
# Enable these options as needed, but make sure you force a full recompile
|
||||
# with "make clean", followed by "make".
|
||||
# Note that most of these are NOT suitable for benchmarking or release mode!
|
||||
#
|
||||
# Use the system provided memory allocator (realloc) instead of the
|
||||
# bundled memory allocator. This is slower, but sometimes helpful for
|
||||
# debugging. This option cannot be enabled on x64 without GC64, since
|
||||
# realloc usually doesn't return addresses in the right address range.
|
||||
# OTOH this option is mandatory for Valgrind's memcheck tool on x64 and
|
||||
# the only way to get useful results from it for all other architectures.
|
||||
#XCFLAGS+= -DLUAJIT_USE_SYSMALLOC
|
||||
#
|
||||
# This define is required to run LuaJIT under Valgrind. The Valgrind
|
||||
# header files must be installed. You should enable debug information, too.
|
||||
#XCFLAGS+= -DLUAJIT_USE_VALGRIND
|
||||
#
|
||||
# This is the client for the GDB JIT API. GDB 7.0 or higher is required
|
||||
# to make use of it. See lj_gdbjit.c for details. Enabling this causes
|
||||
# a non-negligible overhead, even when not running under GDB.
|
||||
#XCFLAGS+= -DLUAJIT_USE_GDBJIT
|
||||
#
|
||||
# Turn on assertions for the Lua/C API to debug problems with lua_* calls.
|
||||
# This is rather slow -- use only while developing C libraries/embeddings.
|
||||
#XCFLAGS+= -DLUA_USE_APICHECK
|
||||
#
|
||||
# Turn on assertions for the whole LuaJIT VM. This significantly slows down
|
||||
# everything. Use only if you suspect a problem with LuaJIT itself.
|
||||
#XCFLAGS+= -DLUA_USE_ASSERT
|
||||
#
|
||||
##############################################################################
|
||||
# You probably don't need to change anything below this line!
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Host system detection.
|
||||
##############################################################################
|
||||
|
||||
ifeq (Windows,$(findstring Windows,$(OS))$(MSYSTEM)$(TERM))
|
||||
HOST_SYS= Windows
|
||||
else
|
||||
HOST_SYS:= $(shell uname -s)
|
||||
ifneq (,$(findstring MINGW,$(HOST_SYS)))
|
||||
HOST_SYS= Windows
|
||||
HOST_MSYS= mingw
|
||||
endif
|
||||
ifneq (,$(findstring MSYS,$(HOST_SYS)))
|
||||
HOST_SYS= Windows
|
||||
HOST_MSYS= mingw
|
||||
endif
|
||||
ifneq (,$(findstring CYGWIN,$(HOST_SYS)))
|
||||
HOST_SYS= Windows
|
||||
HOST_MSYS= cygwin
|
||||
endif
|
||||
endif
|
||||
|
||||
##############################################################################
|
||||
# Flags and options for host and target.
|
||||
##############################################################################
|
||||
|
||||
# You can override the following variables at the make command line:
|
||||
# CC HOST_CC STATIC_CC DYNAMIC_CC
|
||||
# CFLAGS HOST_CFLAGS TARGET_CFLAGS
|
||||
# LDFLAGS HOST_LDFLAGS TARGET_LDFLAGS TARGET_SHLDFLAGS
|
||||
# LIBS HOST_LIBS TARGET_LIBS
|
||||
# CROSS HOST_SYS TARGET_SYS TARGET_FLAGS
|
||||
#
|
||||
# Cross-compilation examples:
|
||||
# make HOST_CC="gcc -m32" CROSS=i586-mingw32msvc- TARGET_SYS=Windows
|
||||
# make HOST_CC="gcc -m32" CROSS=powerpc-linux-gnu-
|
||||
|
||||
ASOPTIONS= $(CCOPT) $(CCWARN) $(XCFLAGS) $(CFLAGS)
|
||||
CCOPTIONS= $(CCDEBUG) $(ASOPTIONS)
|
||||
LDOPTIONS= $(CCDEBUG) $(LDFLAGS)
|
||||
|
||||
HOST_CC= $(CC)
|
||||
HOST_RM?= rm -f
|
||||
# If left blank, minilua is built and used. You can supply an installed
|
||||
# copy of (plain) Lua 5.1 or 5.2, plus Lua BitOp. E.g. with: HOST_LUA=lua
|
||||
HOST_LUA=
|
||||
|
||||
HOST_XCFLAGS= -I.
|
||||
HOST_XLDFLAGS=
|
||||
HOST_XLIBS=
|
||||
HOST_ACFLAGS= $(CCOPTIONS) $(HOST_XCFLAGS) $(TARGET_ARCH) $(HOST_CFLAGS)
|
||||
HOST_ALDFLAGS= $(LDOPTIONS) $(HOST_XLDFLAGS) $(HOST_LDFLAGS)
|
||||
HOST_ALIBS= $(HOST_XLIBS) $(LIBS) $(HOST_LIBS)
|
||||
|
||||
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_LIBPATH= $(or $(PREFIX),/usr/local)/$(or $(MULTILIB),lib)
|
||||
TARGET_SONAME= libluajit-$(ABIVER).so.$(MAJVER)
|
||||
TARGET_DYLIBNAME= libluajit-$(ABIVER).$(MAJVER).dylib
|
||||
TARGET_DYLIBPATH= $(TARGET_LIBPATH)/$(TARGET_DYLIBNAME)
|
||||
TARGET_DLLNAME= lua$(NODOTABIVER).dll
|
||||
TARGET_DLLDOTANAME= libluajit-$(ABIVER).dll.a
|
||||
TARGET_XSHLDFLAGS= -shared -fPIC -Wl,-soname,$(TARGET_SONAME)
|
||||
TARGET_DYNXLDOPTS=
|
||||
|
||||
TARGET_LFSFLAGS= -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
TARGET_XCFLAGS= $(TARGET_LFSFLAGS) -U_FORTIFY_SOURCE
|
||||
TARGET_XLDFLAGS=
|
||||
TARGET_XLIBS= -lm
|
||||
TARGET_TCFLAGS= $(CCOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS)
|
||||
TARGET_ACFLAGS= $(CCOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS)
|
||||
TARGET_ASFLAGS= $(ASOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS)
|
||||
TARGET_ALDFLAGS= $(LDOPTIONS) $(TARGET_XLDFLAGS) $(TARGET_FLAGS) $(TARGET_LDFLAGS)
|
||||
TARGET_ASHLDFLAGS= $(LDOPTIONS) $(TARGET_XSHLDFLAGS) $(TARGET_FLAGS) $(TARGET_SHLDFLAGS)
|
||||
TARGET_ALIBS= $(TARGET_XLIBS) $(LIBS) $(TARGET_LIBS)
|
||||
|
||||
TARGET_TESTARCH:=$(shell $(TARGET_CC) $(TARGET_TCFLAGS) -E lj_arch.h -dM)
|
||||
ifneq (,$(findstring LJ_TARGET_X64 ,$(TARGET_TESTARCH)))
|
||||
TARGET_LJARCH= x64
|
||||
else
|
||||
ifneq (,$(findstring LJ_TARGET_X86 ,$(TARGET_TESTARCH)))
|
||||
TARGET_LJARCH= x86
|
||||
else
|
||||
ifneq (,$(findstring LJ_TARGET_ARM ,$(TARGET_TESTARCH)))
|
||||
TARGET_LJARCH= arm
|
||||
else
|
||||
ifneq (,$(findstring LJ_TARGET_ARM64 ,$(TARGET_TESTARCH)))
|
||||
ifneq (,$(findstring __AARCH64EB__ ,$(TARGET_TESTARCH)))
|
||||
TARGET_ARCH= -D__AARCH64EB__=1
|
||||
endif
|
||||
TARGET_LJARCH= arm64
|
||||
else
|
||||
ifneq (,$(findstring LJ_TARGET_PPC ,$(TARGET_TESTARCH)))
|
||||
ifneq (,$(findstring LJ_LE 1,$(TARGET_TESTARCH)))
|
||||
TARGET_ARCH= -DLJ_ARCH_ENDIAN=LUAJIT_LE
|
||||
else
|
||||
TARGET_ARCH= -DLJ_ARCH_ENDIAN=LUAJIT_BE
|
||||
endif
|
||||
TARGET_LJARCH= ppc
|
||||
else
|
||||
ifneq (,$(findstring LJ_TARGET_MIPS ,$(TARGET_TESTARCH)))
|
||||
ifneq (,$(findstring MIPSEL ,$(TARGET_TESTARCH)))
|
||||
TARGET_ARCH= -D__MIPSEL__=1
|
||||
endif
|
||||
ifneq (,$(findstring LJ_TARGET_MIPS64 ,$(TARGET_TESTARCH)))
|
||||
TARGET_LJARCH= mips64
|
||||
else
|
||||
TARGET_LJARCH= mips
|
||||
endif
|
||||
else
|
||||
$(error Unsupported target architecture)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring LJ_TARGET_PS3 1,$(TARGET_TESTARCH)))
|
||||
TARGET_SYS= PS3
|
||||
TARGET_ARCH+= -D__CELLOS_LV2__
|
||||
TARGET_XCFLAGS+= -DLUAJIT_USE_SYSMALLOC
|
||||
TARGET_XLIBS+= -lpthread
|
||||
endif
|
||||
|
||||
TARGET_XCFLAGS+= $(CCOPT_$(TARGET_LJARCH))
|
||||
TARGET_ARCH+= $(patsubst %,-DLUAJIT_TARGET=LUAJIT_ARCH_%,$(TARGET_LJARCH))
|
||||
|
||||
ifneq (,$(PREFIX))
|
||||
ifneq (/usr/local,$(PREFIX))
|
||||
TARGET_XCFLAGS+= -DLUA_ROOT=\"$(PREFIX)\"
|
||||
ifneq (/usr,$(PREFIX))
|
||||
TARGET_DYNXLDOPTS= -Wl,-rpath,$(TARGET_LIBPATH)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(MULTILIB))
|
||||
TARGET_XCFLAGS+= -DLUA_MULTILIB=\"$(MULTILIB)\"
|
||||
endif
|
||||
ifneq (,$(LMULTILIB))
|
||||
TARGET_XCFLAGS+= -DLUA_LMULTILIB=\"$(LMULTILIB)\"
|
||||
endif
|
||||
|
||||
##############################################################################
|
||||
# Target system detection.
|
||||
##############################################################################
|
||||
|
||||
TARGET_SYS?= $(HOST_SYS)
|
||||
ifeq (Windows,$(TARGET_SYS))
|
||||
TARGET_STRIP+= --strip-unneeded
|
||||
TARGET_XSHLDFLAGS= -shared -Wl,--out-implib,$(TARGET_DLLDOTANAME)
|
||||
TARGET_DYNXLDOPTS=
|
||||
else
|
||||
TARGET_AR+= 2>/dev/null
|
||||
ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1))
|
||||
TARGET_XCFLAGS+= -fno-stack-protector
|
||||
endif
|
||||
ifeq (Darwin,$(TARGET_SYS))
|
||||
ifeq (,$(MACOSX_DEPLOYMENT_TARGET))
|
||||
$(error missing: export MACOSX_DEPLOYMENT_TARGET=XX.YY)
|
||||
endif
|
||||
TARGET_STRIP+= -x
|
||||
TARGET_XCFLAGS+= -DLUAJIT_UNWIND_EXTERNAL
|
||||
TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC
|
||||
TARGET_DYNXLDOPTS=
|
||||
TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).255
|
||||
else
|
||||
ifeq (iOS,$(TARGET_SYS))
|
||||
TARGET_STRIP+= -x
|
||||
TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC
|
||||
TARGET_DYNXLDOPTS=
|
||||
TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).255
|
||||
ifeq (arm64,$(TARGET_LJARCH))
|
||||
TARGET_XCFLAGS+= -fno-omit-frame-pointer
|
||||
endif
|
||||
else
|
||||
ifeq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH)))
|
||||
# Find out whether the target toolchain always generates unwind tables.
|
||||
TARGET_TESTUNWIND=$(shell exec 2>/dev/null; echo 'extern void b(void);int a(void){b();return 0;}' | $(TARGET_CC) -c -x c - -o tmpunwind.o && { grep -qa -e eh_frame -e __unwind_info tmpunwind.o || grep -qU -e eh_frame -e __unwind_info tmpunwind.o; } && echo E; rm -f tmpunwind.o)
|
||||
ifneq (,$(findstring E,$(TARGET_TESTUNWIND)))
|
||||
TARGET_XCFLAGS+= -DLUAJIT_UNWIND_EXTERNAL
|
||||
endif
|
||||
endif
|
||||
ifneq (SunOS,$(TARGET_SYS))
|
||||
ifneq (PS3,$(TARGET_SYS))
|
||||
TARGET_XLDFLAGS+= -Wl,-E
|
||||
endif
|
||||
endif
|
||||
ifeq (Linux,$(TARGET_SYS))
|
||||
TARGET_XLIBS+= -ldl
|
||||
endif
|
||||
ifeq (GNU/kFreeBSD,$(TARGET_SYS))
|
||||
TARGET_XLIBS+= -ldl
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(HOST_SYS),$(TARGET_SYS))
|
||||
ifeq (Windows,$(TARGET_SYS))
|
||||
HOST_XCFLAGS+= -malign-double -DLUAJIT_OS=LUAJIT_OS_WINDOWS
|
||||
else
|
||||
ifeq (Linux,$(TARGET_SYS))
|
||||
HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_LINUX
|
||||
else
|
||||
ifeq (Darwin,$(TARGET_SYS))
|
||||
HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OSX
|
||||
else
|
||||
ifeq (iOS,$(TARGET_SYS))
|
||||
HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OSX -DTARGET_OS_IPHONE=1
|
||||
else
|
||||
HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OTHER
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(CCDEBUG))
|
||||
TARGET_STRIP= @:
|
||||
endif
|
||||
|
||||
##############################################################################
|
||||
# Files and pathnames.
|
||||
##############################################################################
|
||||
|
||||
MINILUA_O= host/minilua.o
|
||||
MINILUA_LIBS= -lm
|
||||
MINILUA_T= host/minilua
|
||||
MINILUA_X= $(MINILUA_T)
|
||||
MINILUA_DEP=
|
||||
|
||||
ifeq (,$(HOST_LUA))
|
||||
HOST_LUA= $(MINILUA_X)
|
||||
MINILUA_DEP= $(MINILUA_T)
|
||||
endif
|
||||
|
||||
DASM_DIR= ../dynasm
|
||||
DASM= $(HOST_LUA) $(DASM_DIR)/dynasm.lua
|
||||
DASM_XFLAGS=
|
||||
DASM_AFLAGS=
|
||||
DASM_ARCH= $(TARGET_LJARCH)
|
||||
|
||||
ifneq (,$(findstring LJ_LE 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D ENDIAN_LE
|
||||
else
|
||||
DASM_AFLAGS+= -D ENDIAN_BE
|
||||
endif
|
||||
ifneq (,$(findstring LJ_ARCH_BITS 64,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D P64
|
||||
endif
|
||||
ifneq (,$(findstring LJ_HASJIT 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D JIT
|
||||
endif
|
||||
ifneq (,$(findstring LJ_HASFFI 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D FFI
|
||||
endif
|
||||
ifneq (,$(findstring LJ_DUALNUM 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D DUALNUM
|
||||
endif
|
||||
ifneq (,$(findstring LJ_ARCH_HASFPU 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D FPU
|
||||
TARGET_ARCH+= -DLJ_ARCH_HASFPU=1
|
||||
else
|
||||
TARGET_ARCH+= -DLJ_ARCH_HASFPU=0
|
||||
endif
|
||||
ifeq (,$(findstring LJ_ABI_SOFTFP 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D HFABI
|
||||
TARGET_ARCH+= -DLJ_ABI_SOFTFP=0
|
||||
else
|
||||
TARGET_ARCH+= -DLJ_ABI_SOFTFP=1
|
||||
endif
|
||||
ifneq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D NO_UNWIND
|
||||
TARGET_ARCH+= -DLUAJIT_NO_UNWIND
|
||||
endif
|
||||
ifneq (,$(findstring LJ_ABI_PAUTH 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D PAUTH
|
||||
TARGET_ARCH+= -DLJ_ABI_PAUTH=1
|
||||
endif
|
||||
DASM_AFLAGS+= -D VER=$(subst LJ_ARCH_VERSION_,,$(filter LJ_ARCH_VERSION_%,$(subst LJ_ARCH_VERSION ,LJ_ARCH_VERSION_,$(TARGET_TESTARCH))))
|
||||
ifeq (Windows,$(TARGET_SYS))
|
||||
DASM_AFLAGS+= -D WIN
|
||||
endif
|
||||
ifeq (x64,$(TARGET_LJARCH))
|
||||
ifeq (,$(findstring LJ_FR2 1,$(TARGET_TESTARCH)))
|
||||
DASM_ARCH= x86
|
||||
endif
|
||||
else
|
||||
ifeq (arm,$(TARGET_LJARCH))
|
||||
ifeq (iOS,$(TARGET_SYS))
|
||||
DASM_AFLAGS+= -D IOS
|
||||
endif
|
||||
else
|
||||
ifneq (,$(findstring LJ_TARGET_MIPSR6 ,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D MIPSR6
|
||||
endif
|
||||
ifeq (ppc,$(TARGET_LJARCH))
|
||||
ifneq (,$(findstring LJ_ARCH_SQRT 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D SQRT
|
||||
endif
|
||||
ifneq (,$(findstring LJ_ARCH_ROUND 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D ROUND
|
||||
endif
|
||||
ifneq (,$(findstring LJ_ARCH_PPC32ON64 1,$(TARGET_TESTARCH)))
|
||||
DASM_AFLAGS+= -D GPR64
|
||||
endif
|
||||
ifeq (PS3,$(TARGET_SYS))
|
||||
DASM_AFLAGS+= -D PPE -D TOC
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
DASM_FLAGS= $(DASM_XFLAGS) $(DASM_AFLAGS)
|
||||
DASM_DASC= vm_$(DASM_ARCH).dasc
|
||||
|
||||
GIT= git
|
||||
ifeq (Windows,$(HOST_SYS)$(HOST_MSYS))
|
||||
GIT_RELVER= if exist ..\.git ( $(GIT) show -s --format=%%ct >luajit_relver.txt ) else ( type ..\.relver >luajit_relver.txt )
|
||||
else
|
||||
GIT_RELVER= [ -e ../.git ] && $(GIT) show -s --format=%ct >luajit_relver.txt 2>/dev/null || cat ../.relver >luajit_relver.txt 2>/dev/null || :
|
||||
endif
|
||||
GIT_DEP= $(wildcard ../.git/HEAD ../.git/refs/heads/*)
|
||||
|
||||
BUILDVM_O= host/buildvm.o host/buildvm_asm.o host/buildvm_peobj.o \
|
||||
host/buildvm_lib.o host/buildvm_fold.o
|
||||
BUILDVM_T= host/buildvm
|
||||
BUILDVM_X= $(BUILDVM_T)
|
||||
|
||||
HOST_O= $(MINILUA_O) $(BUILDVM_O)
|
||||
HOST_T= $(MINILUA_T) $(BUILDVM_T)
|
||||
|
||||
LJVM_S= lj_vm.S
|
||||
LJVM_O= lj_vm.o
|
||||
LJVM_BOUT= $(LJVM_S)
|
||||
LJVM_MODE= elfasm
|
||||
|
||||
LJLIB_O= lib_base.o lib_math.o lib_bit.o lib_string.o lib_table.o \
|
||||
lib_io.o lib_os.o lib_package.o lib_debug.o lib_jit.o lib_ffi.o \
|
||||
lib_buffer.o
|
||||
LJLIB_C= $(LJLIB_O:.o=.c)
|
||||
|
||||
LJCORE_O= lj_assert.o lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \
|
||||
lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
|
||||
lj_prng.o lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o \
|
||||
lj_strscan.o lj_strfmt.o lj_strfmt_num.o lj_serialize.o \
|
||||
lj_api.o lj_profile.o \
|
||||
lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \
|
||||
lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
|
||||
lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \
|
||||
lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \
|
||||
lj_asm.o lj_trace.o lj_gdbjit.o \
|
||||
lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_ccallback.o \
|
||||
lj_carith.o lj_clib.o lj_cparse.o \
|
||||
lj_lib.o lj_alloc.o lib_aux.o \
|
||||
$(LJLIB_O) lib_init.o
|
||||
|
||||
LJVMCORE_O= $(LJVM_O) $(LJCORE_O)
|
||||
LJVMCORE_DYNO= $(LJVMCORE_O:.o=_dyn.o)
|
||||
|
||||
LIB_VMDEF= jit/vmdef.lua
|
||||
LIB_VMDEFP= $(LIB_VMDEF)
|
||||
|
||||
LUAJIT_O= luajit.o
|
||||
LUAJIT_A= libluajit.a
|
||||
LUAJIT_SO= libluajit.so
|
||||
LUAJIT_T= luajit
|
||||
|
||||
ALL_T= $(LUAJIT_T) $(LUAJIT_A) $(LUAJIT_SO) $(HOST_T)
|
||||
ALL_HDRGEN= lj_bcdef.h lj_ffdef.h lj_libdef.h lj_recdef.h lj_folddef.h \
|
||||
host/buildvm_arch.h luajit.h
|
||||
ALL_GEN= $(LJVM_S) $(ALL_HDRGEN) luajit_relver.txt $(LIB_VMDEFP)
|
||||
WIN_RM= *.obj *.lib *.exp *.dll *.exe *.manifest *.pdb *.ilk
|
||||
ALL_RM= $(ALL_T) $(ALL_GEN) *.o host/*.o $(WIN_RM)
|
||||
|
||||
##############################################################################
|
||||
# Build mode handling.
|
||||
##############################################################################
|
||||
|
||||
# Mixed mode defaults.
|
||||
TARGET_O= $(LUAJIT_A)
|
||||
TARGET_T= $(LUAJIT_T) $(LUAJIT_SO)
|
||||
TARGET_DEP= $(LIB_VMDEF) $(LUAJIT_SO)
|
||||
|
||||
ifeq (Windows,$(TARGET_SYS))
|
||||
TARGET_DYNCC= $(STATIC_CC)
|
||||
LJVM_MODE= peobj
|
||||
LJVM_BOUT= $(LJVM_O)
|
||||
LUAJIT_T= luajit.exe
|
||||
ifeq (cygwin,$(HOST_MSYS))
|
||||
LUAJIT_SO= cyg$(TARGET_DLLNAME)
|
||||
else
|
||||
LUAJIT_SO= $(TARGET_DLLNAME)
|
||||
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 (Darwin,$(TARGET_SYS))
|
||||
LJVM_MODE= machasm
|
||||
endif
|
||||
ifeq (iOS,$(TARGET_SYS))
|
||||
LJVM_MODE= machasm
|
||||
endif
|
||||
ifeq (SunOS,$(TARGET_SYS))
|
||||
BUILDMODE= static
|
||||
endif
|
||||
ifeq (PS3,$(TARGET_SYS))
|
||||
BUILDMODE= static
|
||||
endif
|
||||
|
||||
ifeq (Windows,$(HOST_SYS))
|
||||
MINILUA_T= host/minilua.exe
|
||||
BUILDVM_T= host/buildvm.exe
|
||||
ifeq (,$(HOST_MSYS))
|
||||
MINILUA_X= host\minilua
|
||||
BUILDVM_X= host\buildvm
|
||||
ALL_RM:= $(subst /,\,$(ALL_RM))
|
||||
HOST_RM= del
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (static,$(BUILDMODE))
|
||||
TARGET_DYNCC= @:
|
||||
TARGET_T= $(LUAJIT_T)
|
||||
TARGET_DEP= $(LIB_VMDEF)
|
||||
else
|
||||
ifeq (dynamic,$(BUILDMODE))
|
||||
ifneq (Windows,$(TARGET_SYS))
|
||||
TARGET_CC= $(DYNAMIC_CC)
|
||||
endif
|
||||
TARGET_DYNCC= @:
|
||||
LJVMCORE_DYNO= $(LJVMCORE_O)
|
||||
TARGET_O= $(LUAJIT_SO)
|
||||
TARGET_XLDFLAGS+= $(TARGET_DYNXLDOPTS)
|
||||
else
|
||||
ifeq (Darwin,$(TARGET_SYS))
|
||||
TARGET_DYNCC= @:
|
||||
LJVMCORE_DYNO= $(LJVMCORE_O)
|
||||
endif
|
||||
ifeq (iOS,$(TARGET_SYS))
|
||||
TARGET_DYNCC= @:
|
||||
LJVMCORE_DYNO= $(LJVMCORE_O)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
Q= @
|
||||
E= @echo
|
||||
#Q=
|
||||
#E= @:
|
||||
|
||||
##############################################################################
|
||||
# Make targets.
|
||||
##############################################################################
|
||||
|
||||
default all: $(TARGET_T)
|
||||
|
||||
amalg:
|
||||
$(MAKE) all "LJCORE_O=ljamalg.o"
|
||||
|
||||
clean:
|
||||
$(HOST_RM) $(ALL_RM)
|
||||
|
||||
libbc:
|
||||
./$(LUAJIT_T) host/genlibbc.lua -o host/buildvm_libbc.h $(LJLIB_C)
|
||||
$(MAKE) all
|
||||
|
||||
depend:
|
||||
@for file in $(ALL_HDRGEN); do \
|
||||
test -f $$file || touch $$file; \
|
||||
done
|
||||
@$(HOST_CC) $(HOST_ACFLAGS) -MM *.c host/*.c | \
|
||||
sed -e "s| [^ ]*/dasm_\S*\.h||g" \
|
||||
-e "s|^\([^l ]\)|host/\1|" \
|
||||
-e "s| lj_target_\S*\.h| lj_target_*.h|g" \
|
||||
-e "s| lj_emit_\S*\.h| lj_emit_*.h|g" \
|
||||
-e "s| lj_asm_\S*\.h| lj_asm_*.h|g" >Makefile.dep
|
||||
@for file in $(ALL_HDRGEN); do \
|
||||
test -s $$file || $(HOST_RM) $$file; \
|
||||
done
|
||||
|
||||
.PHONY: default all amalg clean libbc depend
|
||||
|
||||
##############################################################################
|
||||
# Rules for generated files.
|
||||
##############################################################################
|
||||
|
||||
$(MINILUA_T): $(MINILUA_O)
|
||||
$(E) "HOSTLINK $@"
|
||||
$(Q)$(HOST_CC) $(HOST_ALDFLAGS) -o $@ $(MINILUA_O) $(MINILUA_LIBS) $(HOST_ALIBS)
|
||||
|
||||
luajit.h: $(MINILUA_DEP) $(GIT_DEP) luajit_rolling.h
|
||||
$(E) "VERSION $@"
|
||||
$(Q)$(GIT_RELVER)
|
||||
$(Q)$(HOST_LUA) host/genversion.lua
|
||||
|
||||
host/buildvm_arch.h: $(DASM_DASC) $(MINILUA_DEP) lj_arch.h lua.h luaconf.h
|
||||
$(E) "DYNASM $@"
|
||||
$(Q)$(DASM) $(DASM_FLAGS) -o $@ $(DASM_DASC)
|
||||
|
||||
host/buildvm.o: $(DASM_DIR)/dasm_*.h
|
||||
|
||||
$(BUILDVM_T): $(BUILDVM_O)
|
||||
$(E) "HOSTLINK $@"
|
||||
$(Q)$(HOST_CC) $(HOST_ALDFLAGS) -o $@ $(BUILDVM_O) $(HOST_ALIBS)
|
||||
|
||||
$(LJVM_BOUT): $(BUILDVM_T)
|
||||
$(E) "BUILDVM $@"
|
||||
$(Q)$(BUILDVM_X) -m $(LJVM_MODE) -o $@
|
||||
|
||||
lj_bcdef.h: $(BUILDVM_T) $(LJLIB_C)
|
||||
$(E) "BUILDVM $@"
|
||||
$(Q)$(BUILDVM_X) -m bcdef -o $@ $(LJLIB_C)
|
||||
|
||||
lj_ffdef.h: $(BUILDVM_T) $(LJLIB_C)
|
||||
$(E) "BUILDVM $@"
|
||||
$(Q)$(BUILDVM_X) -m ffdef -o $@ $(LJLIB_C)
|
||||
|
||||
lj_libdef.h: $(BUILDVM_T) $(LJLIB_C)
|
||||
$(E) "BUILDVM $@"
|
||||
$(Q)$(BUILDVM_X) -m libdef -o $@ $(LJLIB_C)
|
||||
|
||||
lj_recdef.h: $(BUILDVM_T) $(LJLIB_C)
|
||||
$(E) "BUILDVM $@"
|
||||
$(Q)$(BUILDVM_X) -m recdef -o $@ $(LJLIB_C)
|
||||
|
||||
$(LIB_VMDEF): $(BUILDVM_T) $(LJLIB_C)
|
||||
$(E) "BUILDVM $@"
|
||||
$(Q)$(BUILDVM_X) -m vmdef -o $(LIB_VMDEFP) $(LJLIB_C)
|
||||
|
||||
lj_folddef.h: $(BUILDVM_T) lj_opt_fold.c
|
||||
$(E) "BUILDVM $@"
|
||||
$(Q)$(BUILDVM_X) -m folddef -o $@ lj_opt_fold.c
|
||||
|
||||
##############################################################################
|
||||
# Object file rules.
|
||||
##############################################################################
|
||||
|
||||
%.o: %.c
|
||||
$(E) "CC $@"
|
||||
$(Q)$(TARGET_DYNCC) $(TARGET_ACFLAGS) -c -o $(@:.o=_dyn.o) $<
|
||||
$(Q)$(TARGET_CC) $(TARGET_ACFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.S
|
||||
$(E) "ASM $@"
|
||||
$(Q)$(TARGET_DYNCC) $(TARGET_ASFLAGS) -c -o $(@:.o=_dyn.o) $<
|
||||
$(Q)$(TARGET_CC) $(TARGET_ASFLAGS) -c -o $@ $<
|
||||
|
||||
$(LUAJIT_O):
|
||||
$(E) "CC $@"
|
||||
$(Q)$(TARGET_STCC) $(TARGET_ACFLAGS) -c -o $@ $<
|
||||
|
||||
$(HOST_O): %.o: %.c
|
||||
$(E) "HOSTCC $@"
|
||||
$(Q)$(HOST_CC) $(HOST_ACFLAGS) -c -o $@ $<
|
||||
|
||||
include Makefile.dep
|
||||
|
||||
##############################################################################
|
||||
# Target file rules.
|
||||
##############################################################################
|
||||
|
||||
$(LUAJIT_A): $(LJVMCORE_O)
|
||||
$(E) "AR $@"
|
||||
$(Q)$(TARGET_AR) $@ $(LJVMCORE_O)
|
||||
|
||||
# The dependency on _O, but linking with _DYNO is intentional.
|
||||
$(LUAJIT_SO): $(LJVMCORE_O)
|
||||
$(E) "DYNLINK $@"
|
||||
$(Q)$(TARGET_LD) $(TARGET_ASHLDFLAGS) -o $@ $(LJVMCORE_DYNO) $(TARGET_ALIBS)
|
||||
$(Q)$(TARGET_STRIP) $@
|
||||
|
||||
$(LUAJIT_T): $(TARGET_O) $(LUAJIT_O) $(TARGET_DEP)
|
||||
$(E) "LINK $@"
|
||||
$(Q)$(TARGET_LD) $(TARGET_ALDFLAGS) -o $@ $(LUAJIT_O) $(TARGET_O) $(TARGET_ALIBS)
|
||||
$(Q)$(TARGET_STRIP) $@
|
||||
$(E) "OK Successfully built LuaJIT"
|
||||
|
||||
##############################################################################
|
||||
259
thirdPart/luajit/src/Makefile.dep
Normal file
259
thirdPart/luajit/src/Makefile.dep
Normal file
@@ -0,0 +1,259 @@
|
||||
lib_aux.o: lib_aux.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
|
||||
lj_arch.h lj_err.h lj_errmsg.h lj_state.h lj_trace.h lj_jit.h lj_ir.h \
|
||||
lj_dispatch.h lj_bc.h lj_traceerr.h lj_lib.h lj_vmevent.h
|
||||
lib_base.o: lib_base.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_debug.h lj_buf.h \
|
||||
lj_str.h lj_tab.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h \
|
||||
lj_cconv.h lj_ff.h lj_ffdef.h lj_dispatch.h lj_jit.h lj_ir.h lj_char.h \
|
||||
lj_strscan.h lj_strfmt.h lj_lib.h lj_libdef.h
|
||||
lib_bit.o: lib_bit.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_buf.h lj_gc.h lj_str.h lj_strscan.h \
|
||||
lj_strfmt.h lj_ctype.h lj_cdata.h lj_cconv.h lj_carith.h lj_ff.h \
|
||||
lj_ffdef.h lj_lib.h lj_libdef.h
|
||||
lib_buffer.o: lib_buffer.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_buf.h lj_str.h \
|
||||
lj_tab.h lj_udata.h lj_meta.h lj_ctype.h lj_cdata.h lj_cconv.h \
|
||||
lj_strfmt.h lj_serialize.h lj_lib.h lj_libdef.h
|
||||
lib_debug.o: lib_debug.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_debug.h lj_lib.h \
|
||||
lj_libdef.h
|
||||
lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
||||
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h \
|
||||
lj_ctype.h lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h \
|
||||
lj_ccallback.h lj_clib.h lj_strfmt.h lj_ff.h lj_ffdef.h lj_lib.h \
|
||||
lj_libdef.h
|
||||
lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
|
||||
lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
||||
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_state.h \
|
||||
lj_strfmt.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
|
||||
lib_jit.o: lib_jit.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_debug.h lj_str.h lj_tab.h \
|
||||
lj_state.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \
|
||||
lj_target.h lj_target_*.h lj_trace.h lj_dispatch.h lj_traceerr.h \
|
||||
lj_vm.h lj_vmevent.h lj_lib.h luajit.h lj_libdef.h
|
||||
lib_math.o: lib_math.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
|
||||
lj_def.h lj_arch.h lj_lib.h lj_vm.h lj_prng.h lj_libdef.h
|
||||
lib_os.o: lib_os.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_buf.h lj_str.h lj_lib.h \
|
||||
lj_libdef.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_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h \
|
||||
lj_tab.h lj_meta.h lj_state.h lj_ff.h lj_ffdef.h lj_bcdump.h lj_lex.h \
|
||||
lj_char.h lj_strfmt.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_buf.h lj_str.h \
|
||||
lj_tab.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
|
||||
lj_alloc.o: lj_alloc.c lj_def.h lua.h luaconf.h lj_arch.h lj_alloc.h \
|
||||
lj_prng.h
|
||||
lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_func.h lj_udata.h \
|
||||
lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \
|
||||
lj_dispatch.h lj_traceerr.h lj_vm.h lj_strscan.h lj_strfmt.h
|
||||
lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_buf.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h \
|
||||
lj_jit.h lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h \
|
||||
lj_traceerr.h lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h \
|
||||
lj_prng.h lj_emit_*.h lj_asm_*.h
|
||||
lj_assert.o: lj_assert.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h
|
||||
lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
|
||||
lj_bcdef.h
|
||||
lj_bcread.o: lj_bcread.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_bc.h \
|
||||
lj_ctype.h lj_cdata.h lualib.h lj_lex.h lj_bcdump.h lj_state.h \
|
||||
lj_strfmt.h
|
||||
lj_bcwrite.o: lj_bcwrite.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_buf.h lj_str.h lj_bc.h lj_ctype.h lj_dispatch.h lj_jit.h \
|
||||
lj_ir.h lj_strfmt.h lj_bcdump.h lj_lex.h lj_err.h lj_errmsg.h lj_vm.h
|
||||
lj_buf.o: lj_buf.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_strfmt.h
|
||||
lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_meta.h lj_ir.h lj_ctype.h \
|
||||
lj_cconv.h lj_cdata.h lj_carith.h lj_strscan.h
|
||||
lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_cconv.h lj_cdata.h \
|
||||
lj_ccall.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \
|
||||
lj_traceerr.h
|
||||
lj_ccallback.o: lj_ccallback.c lj_obj.h lua.h luaconf.h lj_def.h \
|
||||
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_state.h lj_frame.h \
|
||||
lj_bc.h lj_ctype.h lj_cconv.h lj_ccall.h lj_ccallback.h lj_target.h \
|
||||
lj_target_*.h lj_mcode.h lj_jit.h lj_ir.h lj_trace.h lj_dispatch.h \
|
||||
lj_traceerr.h lj_vm.h
|
||||
lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h lj_ctype.h \
|
||||
lj_cdata.h lj_cconv.h lj_ccallback.h
|
||||
lj_cdata.o: lj_cdata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_cconv.h lj_cdata.h
|
||||
lj_char.o: lj_char.c lj_char.h lj_def.h lua.h luaconf.h
|
||||
lj_clib.o: lj_clib.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_err.h lj_errmsg.h lj_tab.h lj_str.h lj_udata.h lj_ctype.h lj_cconv.h \
|
||||
lj_cdata.h lj_clib.h lj_strfmt.h
|
||||
lj_cparse.o: lj_cparse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_ctype.h lj_cparse.h \
|
||||
lj_frame.h lj_bc.h lj_vm.h lj_char.h lj_strscan.h lj_strfmt.h
|
||||
lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_err.h lj_errmsg.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_gc.h \
|
||||
lj_cdata.h lj_cparse.h lj_cconv.h lj_carith.h lj_clib.h lj_ccall.h \
|
||||
lj_ff.h lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_trace.h \
|
||||
lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h lj_snap.h \
|
||||
lj_crecord.h lj_strfmt.h
|
||||
lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_strfmt.h lj_ctype.h \
|
||||
lj_ccallback.h lj_buf.h
|
||||
lj_debug.o: lj_debug.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \
|
||||
lj_state.h lj_frame.h lj_bc.h lj_strfmt.h lj_jit.h lj_ir.h
|
||||
lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_func.h lj_tab.h \
|
||||
lj_meta.h lj_debug.h lj_state.h lj_frame.h lj_bc.h lj_ff.h lj_ffdef.h \
|
||||
lj_strfmt.h lj_jit.h lj_ir.h lj_ccallback.h lj_ctype.h lj_trace.h \
|
||||
lj_dispatch.h lj_traceerr.h lj_profile.h lj_vm.h luajit.h
|
||||
lj_err.o: lj_err.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_err.h \
|
||||
lj_errmsg.h lj_debug.h lj_str.h lj_func.h lj_state.h lj_frame.h lj_bc.h \
|
||||
lj_ff.h lj_ffdef.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \
|
||||
lj_traceerr.h lj_vm.h lj_strfmt.h
|
||||
lj_ffrecord.o: lj_ffrecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h lj_frame.h \
|
||||
lj_bc.h lj_ff.h lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \
|
||||
lj_trace.h lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h \
|
||||
lj_crecord.h lj_vm.h lj_strscan.h lj_strfmt.h lj_serialize.h lj_recdef.h
|
||||
lj_func.o: lj_func.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_func.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \
|
||||
lj_traceerr.h lj_vm.h
|
||||
lj_gc.o: lj_gc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_func.h lj_udata.h \
|
||||
lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cdata.h lj_trace.h \
|
||||
lj_jit.h lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_vmevent.h
|
||||
lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_frame.h lj_bc.h lj_buf.h \
|
||||
lj_str.h lj_strfmt.h lj_jit.h lj_ir.h lj_dispatch.h
|
||||
lj_ir.o: lj_ir.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_buf.h lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \
|
||||
lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h lj_cdata.h \
|
||||
lj_carith.h lj_vm.h lj_strscan.h lj_serialize.h lj_strfmt.h lj_prng.h
|
||||
lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_ctype.h lj_cdata.h \
|
||||
lualib.h lj_state.h lj_lex.h lj_parse.h lj_char.h lj_strscan.h \
|
||||
lj_strfmt.h
|
||||
lj_lib.o: lj_lib.c lauxlib.h lua.h luaconf.h lj_obj.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_bc.h \
|
||||
lj_dispatch.h lj_jit.h lj_ir.h lj_ctype.h lj_vm.h lj_strscan.h \
|
||||
lj_strfmt.h lj_lex.h lj_bcdump.h lj_lib.h
|
||||
lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
|
||||
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_func.h \
|
||||
lj_frame.h lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h
|
||||
lj_mcode.o: lj_mcode.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_jit.h lj_ir.h lj_mcode.h lj_trace.h \
|
||||
lj_dispatch.h lj_bc.h lj_traceerr.h lj_prng.h lj_vm.h
|
||||
lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_meta.h lj_frame.h \
|
||||
lj_bc.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lib.h
|
||||
lj_obj.o: lj_obj.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h
|
||||
lj_opt_dce.o: lj_opt_dce.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_ir.h lj_jit.h lj_iropt.h
|
||||
lj_opt_fold.o: lj_opt_fold.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_buf.h lj_gc.h lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h \
|
||||
lj_iropt.h lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h \
|
||||
lj_carith.h lj_vm.h lj_strscan.h lj_strfmt.h lj_folddef.h
|
||||
lj_opt_loop.o: lj_opt_loop.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_ir.h lj_jit.h \
|
||||
lj_iropt.h lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_snap.h \
|
||||
lj_vm.h
|
||||
lj_opt_mem.o: lj_opt_mem.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_tab.h lj_ir.h lj_jit.h lj_iropt.h lj_ircall.h lj_dispatch.h lj_bc.h
|
||||
lj_opt_narrow.o: lj_opt_narrow.c lj_obj.h lua.h luaconf.h lj_def.h \
|
||||
lj_arch.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h lj_trace.h lj_dispatch.h \
|
||||
lj_traceerr.h lj_vm.h lj_strscan.h
|
||||
lj_opt_sink.o: lj_opt_sink.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_ir.h lj_jit.h lj_iropt.h lj_target.h lj_target_*.h
|
||||
lj_opt_split.o: lj_opt_split.c lj_obj.h lua.h luaconf.h lj_def.h \
|
||||
lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_ir.h \
|
||||
lj_jit.h lj_ircall.h lj_iropt.h lj_dispatch.h lj_bc.h lj_vm.h
|
||||
lj_parse.o: lj_parse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_str.h lj_tab.h \
|
||||
lj_func.h lj_state.h lj_bc.h lj_ctype.h lj_strfmt.h lj_lex.h lj_parse.h \
|
||||
lj_vm.h lj_vmevent.h
|
||||
lj_prng.o: lj_prng.c lj_def.h lua.h luaconf.h lj_arch.h lj_prng.h
|
||||
lj_profile.o: lj_profile.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_buf.h lj_gc.h lj_str.h lj_frame.h lj_bc.h lj_debug.h lj_dispatch.h \
|
||||
lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h
|
||||
lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \
|
||||
lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_debug.h lj_ir.h lj_jit.h \
|
||||
lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h \
|
||||
lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h lj_prng.h
|
||||
lj_serialize.o: lj_serialize.c lj_obj.h lua.h luaconf.h lj_def.h \
|
||||
lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \
|
||||
lj_udata.h lj_ctype.h lj_cdata.h lj_ir.h lj_serialize.h
|
||||
lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \
|
||||
lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \
|
||||
lj_target_*.h lj_ctype.h lj_cdata.h
|
||||
lj_state.o: lj_state.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_func.h \
|
||||
lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_trace.h lj_jit.h \
|
||||
lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_prng.h lj_lex.h \
|
||||
lj_alloc.h luajit.h
|
||||
lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_err.h lj_errmsg.h lj_str.h lj_char.h lj_prng.h
|
||||
lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_meta.h lj_state.h \
|
||||
lj_char.h lj_strfmt.h lj_ctype.h lj_lib.h
|
||||
lj_strfmt_num.o: lj_strfmt_num.c lj_obj.h lua.h luaconf.h lj_def.h \
|
||||
lj_arch.h lj_buf.h lj_gc.h lj_str.h lj_strfmt.h
|
||||
lj_strscan.o: lj_strscan.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_char.h lj_strscan.h
|
||||
lj_tab.o: lj_tab.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||
lj_err.h lj_errmsg.h lj_tab.h
|
||||
lj_trace.o: lj_trace.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_frame.h lj_bc.h \
|
||||
lj_state.h lj_ir.h lj_jit.h lj_iropt.h lj_mcode.h lj_trace.h \
|
||||
lj_dispatch.h lj_traceerr.h lj_snap.h lj_gdbjit.h lj_record.h lj_asm.h \
|
||||
lj_vm.h lj_vmevent.h lj_target.h lj_target_*.h lj_prng.h
|
||||
lj_udata.o: lj_udata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_gc.h lj_err.h lj_errmsg.h lj_udata.h
|
||||
lj_vmevent.o: lj_vmevent.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_str.h lj_tab.h lj_state.h lj_dispatch.h lj_bc.h lj_jit.h lj_ir.h \
|
||||
lj_vm.h lj_vmevent.h
|
||||
lj_vmmath.o: lj_vmmath.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||
lj_ir.h lj_vm.h
|
||||
ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_assert.c lj_obj.h \
|
||||
lj_def.h lj_arch.h lj_gc.c lj_gc.h lj_err.h lj_errmsg.h lj_buf.h \
|
||||
lj_str.h lj_tab.h lj_func.h lj_udata.h lj_meta.h lj_state.h lj_frame.h \
|
||||
lj_bc.h lj_ctype.h lj_cdata.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \
|
||||
lj_traceerr.h lj_vm.h lj_vmevent.h lj_err.c lj_debug.h lj_ff.h \
|
||||
lj_ffdef.h lj_strfmt.h lj_char.c lj_char.h lj_bc.c lj_bcdef.h lj_obj.c \
|
||||
lj_buf.c lj_str.c lj_prng.h lj_tab.c lj_func.c lj_udata.c lj_meta.c \
|
||||
lj_strscan.h lj_lib.h lj_debug.c lj_prng.c lj_state.c lj_lex.h \
|
||||
lj_alloc.h luajit.h lj_dispatch.c lj_ccallback.h lj_profile.h \
|
||||
lj_vmevent.c lj_vmmath.c lj_strscan.c lj_strfmt.c lj_strfmt_num.c \
|
||||
lj_serialize.c lj_serialize.h lj_api.c lj_profile.c lj_lex.c lualib.h \
|
||||
lj_parse.h lj_parse.c lj_bcread.c lj_bcdump.h lj_bcwrite.c lj_load.c \
|
||||
lj_ctype.c lj_cdata.c lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h \
|
||||
lj_ccallback.c lj_target.h lj_target_*.h lj_mcode.h lj_carith.c \
|
||||
lj_carith.h lj_clib.c lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_ir.c \
|
||||
lj_ircall.h lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h \
|
||||
lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_opt_split.c \
|
||||
lj_opt_sink.c lj_mcode.c lj_snap.c lj_record.c lj_record.h lj_ffrecord.h \
|
||||
lj_crecord.c lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h \
|
||||
lj_emit_*.h lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c \
|
||||
lib_aux.c lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c \
|
||||
lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c \
|
||||
lib_ffi.c lib_buffer.c lib_init.c
|
||||
luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h
|
||||
host/buildvm.o: host/buildvm.c host/buildvm.h lj_def.h lua.h luaconf.h \
|
||||
lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_gc.h lj_obj.h lj_bc.h lj_ir.h \
|
||||
lj_ircall.h lj_ir.h lj_jit.h lj_frame.h lj_bc.h lj_dispatch.h lj_ctype.h \
|
||||
lj_gc.h lj_ccall.h lj_ctype.h luajit.h \
|
||||
host/buildvm_arch.h lj_traceerr.h
|
||||
host/buildvm_asm.o: host/buildvm_asm.c host/buildvm.h lj_def.h lua.h luaconf.h \
|
||||
lj_arch.h lj_bc.h lj_def.h lj_arch.h
|
||||
host/buildvm_fold.o: host/buildvm_fold.c host/buildvm.h lj_def.h lua.h \
|
||||
luaconf.h lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_ir.h lj_obj.h
|
||||
host/buildvm_lib.o: host/buildvm_lib.c host/buildvm.h lj_def.h lua.h luaconf.h \
|
||||
lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_bc.h lj_lib.h lj_obj.h \
|
||||
host/buildvm_libbc.h
|
||||
host/buildvm_peobj.o: host/buildvm_peobj.c host/buildvm.h lj_def.h lua.h \
|
||||
luaconf.h lj_arch.h lj_bc.h lj_def.h lj_arch.h
|
||||
host/minilua.o: host/minilua.c
|
||||
3
thirdPart/luajit/src/host/.gitignore
vendored
Normal file
3
thirdPart/luajit/src/host/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
minilua
|
||||
buildvm
|
||||
buildvm_arch.h
|
||||
4
thirdPart/luajit/src/host/README
Normal file
4
thirdPart/luajit/src/host/README
Normal file
@@ -0,0 +1,4 @@
|
||||
The files in this directory are only used during the build process of LuaJIT.
|
||||
For cross-compilation, they must be executed on the host, not on the target.
|
||||
|
||||
These files should NOT be installed!
|
||||
529
thirdPart/luajit/src/host/buildvm.c
Normal file
529
thirdPart/luajit/src/host/buildvm.c
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
** LuaJIT VM builder.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** This is a tool to build the hand-tuned assembler code required for
|
||||
** LuaJIT's bytecode interpreter. It supports a variety of output formats
|
||||
** to feed different toolchains (see usage() below).
|
||||
**
|
||||
** This tool is not particularly optimized because it's only used while
|
||||
** _building_ LuaJIT. There's no point in distributing or installing it.
|
||||
** Only the object code generated by this tool is linked into LuaJIT.
|
||||
**
|
||||
** Caveat: some memory is not free'd, error handling is lazy.
|
||||
** It's a one-shot tool -- any effort fixing this would be wasted.
|
||||
*/
|
||||
|
||||
#include "buildvm.h"
|
||||
#include "lj_obj.h"
|
||||
#include "lj_gc.h"
|
||||
#include "lj_bc.h"
|
||||
#if LJ_HASJIT
|
||||
#include "lj_ir.h"
|
||||
#include "lj_ircall.h"
|
||||
#endif
|
||||
#include "lj_frame.h"
|
||||
#include "lj_dispatch.h"
|
||||
#if LJ_HASFFI
|
||||
#include "lj_ctype.h"
|
||||
#include "lj_ccall.h"
|
||||
#endif
|
||||
#include "luajit.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* DynASM glue definitions. */
|
||||
#define Dst ctx
|
||||
#define Dst_DECL BuildCtx *ctx
|
||||
#define Dst_REF (ctx->D)
|
||||
#define DASM_CHECKS 1
|
||||
|
||||
#include "../dynasm/dasm_proto.h"
|
||||
|
||||
/* Glue macros for DynASM. */
|
||||
static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type);
|
||||
|
||||
#define DASM_EXTERN(ctx, addr, idx, type) \
|
||||
collect_reloc(ctx, addr, idx, type)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Avoid trouble if cross-compiling for an x86 target. Speed doesn't matter. */
|
||||
#define DASM_ALIGNED_WRITES 1
|
||||
|
||||
/* Embed architecture-specific DynASM encoder. */
|
||||
#if LJ_TARGET_X86ORX64
|
||||
#include "../dynasm/dasm_x86.h"
|
||||
#elif LJ_TARGET_ARM
|
||||
#include "../dynasm/dasm_arm.h"
|
||||
#elif LJ_TARGET_ARM64
|
||||
#include "../dynasm/dasm_arm64.h"
|
||||
#elif LJ_TARGET_PPC
|
||||
#include "../dynasm/dasm_ppc.h"
|
||||
#elif LJ_TARGET_MIPS
|
||||
#include "../dynasm/dasm_mips.h"
|
||||
#else
|
||||
#error "No support for this architecture (yet)"
|
||||
#endif
|
||||
|
||||
/* Embed generated architecture-specific backend. */
|
||||
#include "buildvm_arch.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
void owrite(BuildCtx *ctx, const void *ptr, size_t sz)
|
||||
{
|
||||
if (fwrite(ptr, 1, sz, ctx->fp) != sz) {
|
||||
fprintf(stderr, "Error: cannot write to output file: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Emit code as raw bytes. Only used for DynASM debugging. */
|
||||
static void emit_raw(BuildCtx *ctx)
|
||||
{
|
||||
owrite(ctx, ctx->code, ctx->codesz);
|
||||
}
|
||||
|
||||
/* -- Build machine code -------------------------------------------------- */
|
||||
|
||||
static const char *sym_decorate(BuildCtx *ctx,
|
||||
const char *prefix, const char *suffix)
|
||||
{
|
||||
char name[256];
|
||||
char *p;
|
||||
#if LJ_64
|
||||
const char *symprefix = ctx->mode == BUILD_machasm ? "_" : "";
|
||||
#elif LJ_TARGET_XBOX360
|
||||
const char *symprefix = "";
|
||||
#else
|
||||
const char *symprefix = ctx->mode != BUILD_elfasm ? "_" : "";
|
||||
#endif
|
||||
sprintf(name, "%s%s%s", symprefix, prefix, suffix);
|
||||
p = strchr(name, '@');
|
||||
if (p) {
|
||||
#if LJ_TARGET_X86ORX64
|
||||
if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj))
|
||||
name[0] = name[1] == 'R' ? '_' : '@'; /* Just for _RtlUnwind@16. */
|
||||
else
|
||||
*p = '\0';
|
||||
#elif LJ_TARGET_PPC && !LJ_TARGET_CONSOLE
|
||||
/* Keep @plt etc. */
|
||||
#else
|
||||
*p = '\0';
|
||||
#endif
|
||||
}
|
||||
p = (char *)malloc(strlen(name)+1); /* MSVC doesn't like strdup. */
|
||||
strcpy(p, name);
|
||||
return p;
|
||||
}
|
||||
|
||||
#define NRELOCSYM (sizeof(extnames)/sizeof(extnames[0])-1)
|
||||
|
||||
static int relocmap[NRELOCSYM];
|
||||
|
||||
/* Collect external relocations. */
|
||||
static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type)
|
||||
{
|
||||
if (ctx->nreloc >= BUILD_MAX_RELOC) {
|
||||
fprintf(stderr, "Error: too many relocations, increase BUILD_MAX_RELOC.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (relocmap[idx] < 0) {
|
||||
relocmap[idx] = ctx->nrelocsym;
|
||||
ctx->relocsym[ctx->nrelocsym] = sym_decorate(ctx, "", extnames[idx]);
|
||||
ctx->nrelocsym++;
|
||||
}
|
||||
ctx->reloc[ctx->nreloc].ofs = (int32_t)(addr - ctx->code);
|
||||
ctx->reloc[ctx->nreloc].sym = relocmap[idx];
|
||||
ctx->reloc[ctx->nreloc].type = type;
|
||||
ctx->nreloc++;
|
||||
#if LJ_TARGET_XBOX360
|
||||
return (int)(ctx->code - addr) + 4; /* Encode symbol offset of .text. */
|
||||
#else
|
||||
return 0; /* Encode symbol offset of 0. */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Naive insertion sort. Performance doesn't matter here. */
|
||||
static void sym_insert(BuildCtx *ctx, int32_t ofs,
|
||||
const char *prefix, const char *suffix)
|
||||
{
|
||||
ptrdiff_t i = ctx->nsym++;
|
||||
while (i > 0) {
|
||||
if (ctx->sym[i-1].ofs <= ofs)
|
||||
break;
|
||||
ctx->sym[i] = ctx->sym[i-1];
|
||||
i--;
|
||||
}
|
||||
ctx->sym[i].ofs = ofs;
|
||||
ctx->sym[i].name = sym_decorate(ctx, prefix, suffix);
|
||||
}
|
||||
|
||||
/* Build the machine code. */
|
||||
static int build_code(BuildCtx *ctx)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
|
||||
/* Initialize DynASM structures. */
|
||||
ctx->nglob = GLOB__MAX;
|
||||
ctx->glob = (void **)malloc(ctx->nglob*sizeof(void *));
|
||||
memset(ctx->glob, 0, ctx->nglob*sizeof(void *));
|
||||
ctx->nreloc = 0;
|
||||
|
||||
ctx->globnames = globnames;
|
||||
ctx->extnames = extnames;
|
||||
ctx->relocsym = (const char **)malloc(NRELOCSYM*sizeof(const char *));
|
||||
ctx->nrelocsym = 0;
|
||||
for (i = 0; i < (int)NRELOCSYM; i++) relocmap[i] = -1;
|
||||
|
||||
ctx->dasm_ident = DASM_IDENT;
|
||||
ctx->dasm_arch = DASM_ARCH;
|
||||
|
||||
dasm_init(Dst, DASM_MAXSECTION);
|
||||
dasm_setupglobal(Dst, ctx->glob, ctx->nglob);
|
||||
dasm_setup(Dst, build_actionlist);
|
||||
|
||||
/* Call arch-specific backend to emit the code. */
|
||||
ctx->npc = build_backend(ctx);
|
||||
|
||||
/* Finalize the code. */
|
||||
(void)dasm_checkstep(Dst, -1);
|
||||
if ((status = dasm_link(Dst, &ctx->codesz))) return status;
|
||||
ctx->code = (uint8_t *)malloc(ctx->codesz);
|
||||
if ((status = dasm_encode(Dst, (void *)ctx->code))) return status;
|
||||
|
||||
/* Allocate symbol table and bytecode offsets. */
|
||||
ctx->beginsym = sym_decorate(ctx, "", LABEL_PREFIX "vm_asm_begin");
|
||||
ctx->sym = (BuildSym *)malloc((ctx->npc+ctx->nglob+1)*sizeof(BuildSym));
|
||||
ctx->nsym = 0;
|
||||
ctx->bc_ofs = (int32_t *)malloc(ctx->npc*sizeof(int32_t));
|
||||
|
||||
/* Collect the opcodes (PC labels). */
|
||||
for (i = 0; i < ctx->npc; i++) {
|
||||
int32_t ofs = dasm_getpclabel(Dst, i);
|
||||
if (ofs < 0) return 0x22000000|i;
|
||||
ctx->bc_ofs[i] = ofs;
|
||||
if ((LJ_HASJIT ||
|
||||
!(i == BC_JFORI || i == BC_JFORL || i == BC_JITERL || i == BC_JLOOP ||
|
||||
i == BC_IFORL || i == BC_IITERL || i == BC_ILOOP)) &&
|
||||
(LJ_HASFFI || i != BC_KCDATA))
|
||||
sym_insert(ctx, ofs, LABEL_PREFIX_BC, bc_names[i]);
|
||||
}
|
||||
|
||||
/* Collect the globals (named labels). */
|
||||
for (i = 0; i < ctx->nglob; i++) {
|
||||
const char *gl = globnames[i];
|
||||
int len = (int)strlen(gl);
|
||||
if (!ctx->glob[i]) {
|
||||
fprintf(stderr, "Error: undefined global %s\n", gl);
|
||||
exit(2);
|
||||
}
|
||||
/* Skip the _Z symbols. */
|
||||
if (!(len >= 2 && gl[len-2] == '_' && gl[len-1] == 'Z'))
|
||||
sym_insert(ctx, (int32_t)((uint8_t *)(ctx->glob[i]) - ctx->code),
|
||||
LABEL_PREFIX, globnames[i]);
|
||||
}
|
||||
|
||||
/* Close the address range. */
|
||||
sym_insert(ctx, (int32_t)ctx->codesz, "", "");
|
||||
ctx->nsym--;
|
||||
|
||||
dasm_free(Dst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -- Generate VM enums --------------------------------------------------- */
|
||||
|
||||
const char *const bc_names[] = {
|
||||
#define BCNAME(name, ma, mb, mc, mt) #name,
|
||||
BCDEF(BCNAME)
|
||||
#undef BCNAME
|
||||
NULL
|
||||
};
|
||||
|
||||
#if LJ_HASJIT
|
||||
const char *const ir_names[] = {
|
||||
#define IRNAME(name, m, m1, m2) #name,
|
||||
IRDEF(IRNAME)
|
||||
#undef IRNAME
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *const irt_names[] = {
|
||||
#define IRTNAME(name, size) #name,
|
||||
IRTDEF(IRTNAME)
|
||||
#undef IRTNAME
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *const irfpm_names[] = {
|
||||
#define FPMNAME(name) #name,
|
||||
IRFPMDEF(FPMNAME)
|
||||
#undef FPMNAME
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *const irfield_names[] = {
|
||||
#define FLNAME(name, ofs) #name,
|
||||
IRFLDEF(FLNAME)
|
||||
#undef FLNAME
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *const ircall_names[] = {
|
||||
#define IRCALLNAME(cond, name, nargs, kind, type, flags) #name,
|
||||
IRCALLDEF(IRCALLNAME)
|
||||
#undef IRCALLNAME
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const trace_errors[] = {
|
||||
#define TREDEF(name, msg) msg,
|
||||
#include "lj_traceerr.h"
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
#if LJ_HASJIT
|
||||
static const char *lower(char *buf, const char *s)
|
||||
{
|
||||
char *p = buf;
|
||||
while (*s) {
|
||||
*p++ = (*s >= 'A' && *s <= 'Z') ? *s+0x20 : *s;
|
||||
s++;
|
||||
}
|
||||
*p = '\0';
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Emit C source code for bytecode-related definitions. */
|
||||
static void emit_bcdef(BuildCtx *ctx)
|
||||
{
|
||||
int i;
|
||||
fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
|
||||
fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_ofs[] = {\n");
|
||||
for (i = 0; i < ctx->npc; i++) {
|
||||
if (i != 0)
|
||||
fprintf(ctx->fp, ",\n");
|
||||
fprintf(ctx->fp, "%d", ctx->bc_ofs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit VM definitions as Lua code for debug modules. */
|
||||
static void emit_vmdef(BuildCtx *ctx)
|
||||
{
|
||||
#if LJ_HASJIT
|
||||
char buf[80];
|
||||
#endif
|
||||
int i;
|
||||
fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n");
|
||||
fprintf(ctx->fp, "assert(require(\"jit\").version == \"%s\", \"LuaJIT core/library version mismatch\")\n\n", LUAJIT_VERSION);
|
||||
fprintf(ctx->fp, "return {\n\n");
|
||||
|
||||
fprintf(ctx->fp, "bcnames = \"");
|
||||
for (i = 0; bc_names[i]; i++) fprintf(ctx->fp, "%-6s", bc_names[i]);
|
||||
fprintf(ctx->fp, "\",\n\n");
|
||||
|
||||
#if LJ_HASJIT
|
||||
fprintf(ctx->fp, "irnames = \"");
|
||||
for (i = 0; ir_names[i]; i++) fprintf(ctx->fp, "%-6s", ir_names[i]);
|
||||
fprintf(ctx->fp, "\",\n\n");
|
||||
|
||||
fprintf(ctx->fp, "irfpm = { [0]=");
|
||||
for (i = 0; irfpm_names[i]; i++)
|
||||
fprintf(ctx->fp, "\"%s\", ", lower(buf, irfpm_names[i]));
|
||||
fprintf(ctx->fp, "},\n\n");
|
||||
|
||||
fprintf(ctx->fp, "irfield = { [0]=");
|
||||
for (i = 0; irfield_names[i]; i++) {
|
||||
char *p;
|
||||
lower(buf, irfield_names[i]);
|
||||
p = strchr(buf, '_');
|
||||
if (p) *p = '.';
|
||||
fprintf(ctx->fp, "\"%s\", ", buf);
|
||||
}
|
||||
fprintf(ctx->fp, "},\n\n");
|
||||
|
||||
fprintf(ctx->fp, "ircall = {\n[0]=");
|
||||
for (i = 0; ircall_names[i]; i++)
|
||||
fprintf(ctx->fp, "\"%s\",\n", ircall_names[i]);
|
||||
fprintf(ctx->fp, "},\n\n");
|
||||
|
||||
fprintf(ctx->fp, "traceerr = {\n[0]=");
|
||||
for (i = 0; trace_errors[i]; i++)
|
||||
fprintf(ctx->fp, "\"%s\",\n", trace_errors[i]);
|
||||
fprintf(ctx->fp, "},\n\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* -- Argument parsing ---------------------------------------------------- */
|
||||
|
||||
/* Build mode names. */
|
||||
static const char *const modenames[] = {
|
||||
#define BUILDNAME(name) #name,
|
||||
BUILDDEF(BUILDNAME)
|
||||
#undef BUILDNAME
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Print usage information and exit. */
|
||||
static void usage(void)
|
||||
{
|
||||
int i;
|
||||
fprintf(stderr, LUAJIT_VERSION " VM builder.\n");
|
||||
fprintf(stderr, LUAJIT_COPYRIGHT ", " LUAJIT_URL "\n");
|
||||
fprintf(stderr, "Target architecture: " LJ_ARCH_NAME "\n\n");
|
||||
fprintf(stderr, "Usage: buildvm -m mode [-o outfile] [infiles...]\n\n");
|
||||
fprintf(stderr, "Available modes:\n");
|
||||
for (i = 0; i < BUILD__MAX; i++)
|
||||
fprintf(stderr, " %s\n", modenames[i]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Parse the output mode name. */
|
||||
static BuildMode parsemode(const char *mode)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; modenames[i]; i++)
|
||||
if (!strcmp(mode, modenames[i]))
|
||||
return (BuildMode)i;
|
||||
usage();
|
||||
return (BuildMode)-1;
|
||||
}
|
||||
|
||||
/* Parse arguments. */
|
||||
static void parseargs(BuildCtx *ctx, char **argv)
|
||||
{
|
||||
const char *a;
|
||||
int i;
|
||||
ctx->mode = (BuildMode)-1;
|
||||
ctx->outname = "-";
|
||||
for (i = 1; (a = argv[i]) != NULL; i++) {
|
||||
if (a[0] != '-')
|
||||
break;
|
||||
switch (a[1]) {
|
||||
case '-':
|
||||
if (a[2]) goto err;
|
||||
i++;
|
||||
goto ok;
|
||||
case '\0':
|
||||
goto ok;
|
||||
case 'm':
|
||||
i++;
|
||||
if (a[2] || argv[i] == NULL) goto err;
|
||||
ctx->mode = parsemode(argv[i]);
|
||||
break;
|
||||
case 'o':
|
||||
i++;
|
||||
if (a[2] || argv[i] == NULL) goto err;
|
||||
ctx->outname = argv[i];
|
||||
break;
|
||||
default: err:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok:
|
||||
ctx->args = argv+i;
|
||||
if (ctx->mode == (BuildMode)-1) goto err;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
BuildCtx ctx_;
|
||||
BuildCtx *ctx = &ctx_;
|
||||
int status, binmode;
|
||||
|
||||
if (sizeof(void *) != 4*LJ_32+8*LJ_64) {
|
||||
fprintf(stderr,"Error: pointer size mismatch in cross-build.\n");
|
||||
fprintf(stderr,"Try: make HOST_CC=\"gcc -m32\" CROSS=...\n\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
UNUSED(argc);
|
||||
parseargs(ctx, argv);
|
||||
|
||||
if ((status = build_code(ctx))) {
|
||||
fprintf(stderr,"Error: DASM error %08x\n", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (ctx->mode) {
|
||||
case BUILD_peobj:
|
||||
case BUILD_raw:
|
||||
binmode = 1;
|
||||
break;
|
||||
default:
|
||||
binmode = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx->outname[0] == '-' && ctx->outname[1] == '\0') {
|
||||
ctx->fp = stdout;
|
||||
#if defined(_WIN32)
|
||||
if (binmode)
|
||||
_setmode(_fileno(stdout), _O_BINARY); /* Yuck. */
|
||||
#endif
|
||||
} else if (!(ctx->fp = fopen(ctx->outname, binmode ? "wb" : "w"))) {
|
||||
fprintf(stderr, "Error: cannot open output file '%s': %s\n",
|
||||
ctx->outname, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch (ctx->mode) {
|
||||
case BUILD_elfasm:
|
||||
case BUILD_coffasm:
|
||||
case BUILD_machasm:
|
||||
emit_asm(ctx);
|
||||
emit_asm_debug(ctx);
|
||||
break;
|
||||
case BUILD_peobj:
|
||||
emit_peobj(ctx);
|
||||
break;
|
||||
case BUILD_raw:
|
||||
emit_raw(ctx);
|
||||
break;
|
||||
case BUILD_bcdef:
|
||||
emit_bcdef(ctx);
|
||||
emit_lib(ctx);
|
||||
break;
|
||||
case BUILD_vmdef:
|
||||
emit_vmdef(ctx);
|
||||
emit_lib(ctx);
|
||||
fprintf(ctx->fp, "}\n\n");
|
||||
break;
|
||||
case BUILD_ffdef:
|
||||
case BUILD_libdef:
|
||||
case BUILD_recdef:
|
||||
emit_lib(ctx);
|
||||
break;
|
||||
case BUILD_folddef:
|
||||
emit_fold(ctx);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fflush(ctx->fp);
|
||||
if (ferror(ctx->fp)) {
|
||||
fprintf(stderr, "Error: cannot write to output file: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
fclose(ctx->fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
105
thirdPart/luajit/src/host/buildvm.h
Normal file
105
thirdPart/luajit/src/host/buildvm.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
** LuaJIT VM builder.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#ifndef _BUILDVM_H
|
||||
#define _BUILDVM_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lj_def.h"
|
||||
#include "lj_arch.h"
|
||||
|
||||
/* Hardcoded limits. Increase as needed. */
|
||||
#define BUILD_MAX_RELOC 200 /* Max. number of relocations. */
|
||||
#define BUILD_MAX_FOLD 4096 /* Max. number of fold rules. */
|
||||
|
||||
/* Prefix for scanned library definitions. */
|
||||
#define LIBDEF_PREFIX "LJLIB_"
|
||||
|
||||
/* Prefix for scanned fold definitions. */
|
||||
#define FOLDDEF_PREFIX "LJFOLD"
|
||||
|
||||
/* Prefixes for generated labels. */
|
||||
#define LABEL_PREFIX "lj_"
|
||||
#define LABEL_PREFIX_BC LABEL_PREFIX "BC_"
|
||||
#define LABEL_PREFIX_FF LABEL_PREFIX "ff_"
|
||||
#define LABEL_PREFIX_CF LABEL_PREFIX "cf_"
|
||||
#define LABEL_PREFIX_FFH LABEL_PREFIX "ffh_"
|
||||
#define LABEL_PREFIX_LIBCF LABEL_PREFIX "lib_cf_"
|
||||
#define LABEL_PREFIX_LIBINIT LABEL_PREFIX "lib_init_"
|
||||
|
||||
/* Forward declaration. */
|
||||
struct dasm_State;
|
||||
|
||||
/* Build modes. */
|
||||
#define BUILDDEF(_) \
|
||||
_(elfasm) _(coffasm) _(machasm) _(peobj) _(raw) \
|
||||
_(bcdef) _(ffdef) _(libdef) _(recdef) _(vmdef) \
|
||||
_(folddef)
|
||||
|
||||
typedef enum {
|
||||
#define BUILDENUM(name) BUILD_##name,
|
||||
BUILDDEF(BUILDENUM)
|
||||
#undef BUILDENUM
|
||||
BUILD__MAX
|
||||
} BuildMode;
|
||||
|
||||
/* Code relocation. */
|
||||
typedef struct BuildReloc {
|
||||
int32_t ofs;
|
||||
int sym;
|
||||
int type;
|
||||
} BuildReloc;
|
||||
|
||||
typedef struct BuildSym {
|
||||
const char *name;
|
||||
int32_t ofs;
|
||||
} BuildSym;
|
||||
|
||||
/* Build context structure. */
|
||||
typedef struct BuildCtx {
|
||||
/* DynASM state pointer. Should be first member. */
|
||||
struct dasm_State *D;
|
||||
/* Parsed command line. */
|
||||
BuildMode mode;
|
||||
FILE *fp;
|
||||
const char *outname;
|
||||
char **args;
|
||||
/* Code and symbols generated by DynASM. */
|
||||
uint8_t *code;
|
||||
size_t codesz;
|
||||
int npc, nglob, nsym, nreloc, nrelocsym;
|
||||
void **glob;
|
||||
BuildSym *sym;
|
||||
const char **relocsym;
|
||||
int32_t *bc_ofs;
|
||||
const char *beginsym;
|
||||
/* Strings generated by DynASM. */
|
||||
const char *const *globnames;
|
||||
const char *const *extnames;
|
||||
const char *dasm_ident;
|
||||
const char *dasm_arch;
|
||||
/* Relocations. */
|
||||
BuildReloc reloc[BUILD_MAX_RELOC];
|
||||
} BuildCtx;
|
||||
|
||||
extern void owrite(BuildCtx *ctx, const void *ptr, size_t sz);
|
||||
extern void emit_asm(BuildCtx *ctx);
|
||||
extern void emit_peobj(BuildCtx *ctx);
|
||||
extern void emit_lib(BuildCtx *ctx);
|
||||
extern void emit_fold(BuildCtx *ctx);
|
||||
|
||||
extern const char *const bc_names[];
|
||||
extern const char *const ir_names[];
|
||||
extern const char *const irt_names[];
|
||||
extern const char *const irfpm_names[];
|
||||
extern const char *const irfield_names[];
|
||||
extern const char *const ircall_names[];
|
||||
|
||||
#endif
|
||||
351
thirdPart/luajit/src/host/buildvm_asm.c
Normal file
351
thirdPart/luajit/src/host/buildvm_asm.c
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
** LuaJIT VM builder: Assembler source code emitter.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#include "buildvm.h"
|
||||
#include "lj_bc.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if LJ_TARGET_X86ORX64
|
||||
/* Emit bytes piecewise as assembler text. */
|
||||
static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
if ((i & 15) == 0)
|
||||
fprintf(ctx->fp, "\t.byte %d", p[i]);
|
||||
else
|
||||
fprintf(ctx->fp, ",%d", p[i]);
|
||||
if ((i & 15) == 15) putc('\n', ctx->fp);
|
||||
}
|
||||
if ((n & 15) != 0) putc('\n', ctx->fp);
|
||||
}
|
||||
|
||||
/* Emit relocation */
|
||||
static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym)
|
||||
{
|
||||
switch (ctx->mode) {
|
||||
case BUILD_elfasm:
|
||||
if (type)
|
||||
fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
|
||||
else
|
||||
fprintf(ctx->fp, "\t.long %s\n", sym);
|
||||
break;
|
||||
case BUILD_coffasm:
|
||||
fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", sym);
|
||||
if (type)
|
||||
fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
|
||||
else
|
||||
fprintf(ctx->fp, "\t.long %s\n", sym);
|
||||
break;
|
||||
default: /* BUILD_machasm for relative relocations handled below. */
|
||||
fprintf(ctx->fp, "\t.long %s\n", sym);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const jccnames[] = {
|
||||
"jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja",
|
||||
"js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg"
|
||||
};
|
||||
|
||||
/* Emit x86/x64 text relocations. */
|
||||
static void emit_asm_reloc_text(BuildCtx *ctx, uint8_t *cp, int n,
|
||||
const char *sym)
|
||||
{
|
||||
const char *opname = NULL;
|
||||
if (--n < 0) goto err;
|
||||
if (cp[n] == 0xe8) {
|
||||
opname = "call";
|
||||
} else if (cp[n] == 0xe9) {
|
||||
opname = "jmp";
|
||||
} else if (cp[n] >= 0x80 && cp[n] <= 0x8f && n > 0 && cp[n-1] == 0x0f) {
|
||||
opname = jccnames[cp[n]-0x80];
|
||||
n--;
|
||||
} else {
|
||||
err:
|
||||
fprintf(stderr, "Error: unsupported opcode for %s symbol relocation.\n",
|
||||
sym);
|
||||
exit(1);
|
||||
}
|
||||
emit_asm_bytes(ctx, cp, n);
|
||||
if (strncmp(sym+(*sym == '_'), LABEL_PREFIX, sizeof(LABEL_PREFIX)-1)) {
|
||||
/* Various fixups for external symbols outside of our binary. */
|
||||
if (ctx->mode == BUILD_elfasm) {
|
||||
if (LJ_32)
|
||||
fprintf(ctx->fp, "#if __PIC__\n\t%s lj_wrap_%s\n#else\n", opname, sym);
|
||||
fprintf(ctx->fp, "\t%s %s@PLT\n", opname, sym);
|
||||
if (LJ_32)
|
||||
fprintf(ctx->fp, "#endif\n");
|
||||
return;
|
||||
} else if (LJ_32 && ctx->mode == BUILD_machasm) {
|
||||
fprintf(ctx->fp, "\t%s L%s$stub\n", opname, sym);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(ctx->fp, "\t%s %s\n", opname, sym);
|
||||
}
|
||||
#else
|
||||
/* Emit words piecewise as assembler text. */
|
||||
static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i += 4) {
|
||||
uint32_t ins = *(uint32_t *)(p+i);
|
||||
#if LJ_TARGET_ARM64 && LJ_BE
|
||||
ins = lj_bswap(ins); /* ARM64 instructions are always little-endian. */
|
||||
#endif
|
||||
if ((i & 15) == 0)
|
||||
fprintf(ctx->fp, "\t.long 0x%08x", ins);
|
||||
else
|
||||
fprintf(ctx->fp, ",0x%08x", ins);
|
||||
if ((i & 15) == 12) putc('\n', ctx->fp);
|
||||
}
|
||||
if ((n & 15) != 0) putc('\n', ctx->fp);
|
||||
}
|
||||
|
||||
/* Emit relocation as part of an instruction. */
|
||||
static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
|
||||
const char *sym)
|
||||
{
|
||||
uint32_t ins;
|
||||
emit_asm_words(ctx, p, n-4);
|
||||
ins = *(uint32_t *)(p+n-4);
|
||||
#if LJ_TARGET_ARM
|
||||
if ((ins & 0xff000000u) == 0xfa000000u) {
|
||||
fprintf(ctx->fp, "\tblx %s\n", sym);
|
||||
} else if ((ins & 0x0e000000u) == 0x0a000000u) {
|
||||
fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b",
|
||||
&"eqnecsccmiplvsvchilsgeltgtle"[2*(ins >> 28)], sym);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Error: unsupported opcode %08x for %s symbol relocation.\n",
|
||||
ins, sym);
|
||||
exit(1);
|
||||
}
|
||||
#elif LJ_TARGET_ARM64
|
||||
if ((ins >> 26) == 0x25u) {
|
||||
fprintf(ctx->fp, "\tbl %s\n", sym);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Error: unsupported opcode %08x for %s symbol relocation.\n",
|
||||
ins, sym);
|
||||
exit(1);
|
||||
}
|
||||
#elif LJ_TARGET_PPC
|
||||
#if LJ_TARGET_PS3
|
||||
#define TOCPREFIX "."
|
||||
#else
|
||||
#define TOCPREFIX ""
|
||||
#endif
|
||||
if ((ins >> 26) == 16) {
|
||||
fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n",
|
||||
(ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
|
||||
} else if ((ins >> 26) == 18) {
|
||||
fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Error: unsupported opcode %08x for %s symbol relocation.\n",
|
||||
ins, sym);
|
||||
exit(1);
|
||||
}
|
||||
#elif LJ_TARGET_MIPS
|
||||
fprintf(stderr,
|
||||
"Error: unsupported opcode %08x for %s symbol relocation.\n",
|
||||
ins, sym);
|
||||
exit(1);
|
||||
#else
|
||||
#error "missing relocation support for this architecture"
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LJ_TARGET_ARM
|
||||
#define ELFASM_PX "%%"
|
||||
#else
|
||||
#define ELFASM_PX "@"
|
||||
#endif
|
||||
|
||||
/* Emit an assembler label. */
|
||||
static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
|
||||
{
|
||||
switch (ctx->mode) {
|
||||
case BUILD_elfasm:
|
||||
#if LJ_TARGET_PS3
|
||||
if (!strncmp(name, "lj_vm_", 6) &&
|
||||
strcmp(name, ctx->beginsym) &&
|
||||
!strstr(name, "hook")) {
|
||||
fprintf(ctx->fp,
|
||||
"\n\t.globl %s\n"
|
||||
"\t.section \".opd\",\"aw\"\n"
|
||||
"%s:\n"
|
||||
"\t.long .%s,.TOC.@tocbase32\n"
|
||||
"\t.size %s,8\n"
|
||||
"\t.previous\n"
|
||||
"\t.globl .%s\n"
|
||||
"\t.hidden .%s\n"
|
||||
"\t.type .%s, " ELFASM_PX "function\n"
|
||||
"\t.size .%s, %d\n"
|
||||
".%s:\n",
|
||||
name, name, name, name, name, name, name, name, size, name);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
fprintf(ctx->fp,
|
||||
"\n\t.globl %s\n"
|
||||
"\t.hidden %s\n"
|
||||
"\t.type %s, " ELFASM_PX "%s\n"
|
||||
"\t.size %s, %d\n"
|
||||
"%s:\n",
|
||||
name, name, name, isfunc ? "function" : "object", name, size, name);
|
||||
break;
|
||||
case BUILD_coffasm:
|
||||
fprintf(ctx->fp, "\n\t.globl %s\n", name);
|
||||
if (isfunc)
|
||||
fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
|
||||
fprintf(ctx->fp, "%s:\n", name);
|
||||
break;
|
||||
case BUILD_machasm:
|
||||
fprintf(ctx->fp,
|
||||
"\n\t.private_extern %s\n"
|
||||
"\t.no_dead_strip %s\n"
|
||||
"%s:\n", name, name, name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit alignment. */
|
||||
static void emit_asm_align(BuildCtx *ctx, int bits)
|
||||
{
|
||||
switch (ctx->mode) {
|
||||
case BUILD_elfasm:
|
||||
case BUILD_coffasm:
|
||||
fprintf(ctx->fp, "\t.p2align %d\n", bits);
|
||||
break;
|
||||
case BUILD_machasm:
|
||||
fprintf(ctx->fp, "\t.align %d\n", bits);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Emit assembler source code. */
|
||||
void emit_asm(BuildCtx *ctx)
|
||||
{
|
||||
int i, rel;
|
||||
|
||||
fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
|
||||
fprintf(ctx->fp, "\t.text\n");
|
||||
#if LJ_TARGET_MIPS32 && !LJ_ABI_SOFTFP
|
||||
fprintf(ctx->fp, "\t.module fp=32\n");
|
||||
#endif
|
||||
#if LJ_TARGET_MIPS
|
||||
fprintf(ctx->fp, "\t.set nomips16\n\t.abicalls\n\t.set noreorder\n\t.set nomacro\n");
|
||||
#endif
|
||||
emit_asm_align(ctx, 4);
|
||||
|
||||
#if LJ_TARGET_PS3
|
||||
emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0);
|
||||
#else
|
||||
emit_asm_label(ctx, ctx->beginsym, 0, 0);
|
||||
#endif
|
||||
if (ctx->mode != BUILD_machasm)
|
||||
fprintf(ctx->fp, ".Lbegin:\n");
|
||||
|
||||
#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
|
||||
/* This should really be moved into buildvm_arm.dasc. */
|
||||
#if LJ_ARCH_HASFPU
|
||||
fprintf(ctx->fp,
|
||||
".fnstart\n"
|
||||
".save {r5, r6, r7, r8, r9, r10, r11, lr}\n"
|
||||
".vsave {d8-d15}\n"
|
||||
".save {r4}\n"
|
||||
".pad #28\n");
|
||||
#else
|
||||
fprintf(ctx->fp,
|
||||
".fnstart\n"
|
||||
".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
|
||||
".pad #28\n");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for (i = rel = 0; i < ctx->nsym; i++) {
|
||||
int32_t ofs = ctx->sym[i].ofs;
|
||||
int32_t next = ctx->sym[i+1].ofs;
|
||||
#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI
|
||||
if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
|
||||
fprintf(ctx->fp,
|
||||
".globl lj_err_unwind_arm\n"
|
||||
".personality lj_err_unwind_arm\n"
|
||||
".fnend\n"
|
||||
".fnstart\n"
|
||||
".save {r4, r5, r11, lr}\n"
|
||||
".setfp r11, sp\n");
|
||||
#endif
|
||||
emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
|
||||
while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
|
||||
BuildReloc *r = &ctx->reloc[rel];
|
||||
int n = r->ofs - ofs;
|
||||
#if LJ_TARGET_X86ORX64
|
||||
if (r->type != 0 &&
|
||||
(ctx->mode == BUILD_elfasm || ctx->mode == BUILD_machasm)) {
|
||||
emit_asm_reloc_text(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
|
||||
} else {
|
||||
emit_asm_bytes(ctx, ctx->code+ofs, n);
|
||||
emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
|
||||
}
|
||||
ofs += n+4;
|
||||
#else
|
||||
emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
|
||||
ofs += n;
|
||||
#endif
|
||||
rel++;
|
||||
}
|
||||
#if LJ_TARGET_X86ORX64
|
||||
emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
|
||||
#else
|
||||
emit_asm_words(ctx, ctx->code+ofs, next-ofs);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
|
||||
fprintf(ctx->fp,
|
||||
#if !LJ_HASFFI
|
||||
".globl lj_err_unwind_arm\n"
|
||||
".personality lj_err_unwind_arm\n"
|
||||
#endif
|
||||
".fnend\n");
|
||||
#endif
|
||||
|
||||
fprintf(ctx->fp, "\n");
|
||||
switch (ctx->mode) {
|
||||
case BUILD_elfasm:
|
||||
#if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA)
|
||||
fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
|
||||
#endif
|
||||
#if LJ_TARGET_PPC && !LJ_TARGET_PS3 && !LJ_ABI_SOFTFP
|
||||
/* Hard-float ABI. */
|
||||
fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
|
||||
#endif
|
||||
/* fallthrough */
|
||||
case BUILD_coffasm:
|
||||
fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
|
||||
break;
|
||||
case BUILD_machasm:
|
||||
fprintf(ctx->fp,
|
||||
"\t.cstring\n"
|
||||
"\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fprintf(ctx->fp, "\n");
|
||||
}
|
||||
|
||||
236
thirdPart/luajit/src/host/buildvm_fold.c
Normal file
236
thirdPart/luajit/src/host/buildvm_fold.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
** LuaJIT VM builder: IR folding hash table generator.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#include "buildvm.h"
|
||||
#include "lj_obj.h"
|
||||
#if LJ_HASJIT
|
||||
#include "lj_ir.h"
|
||||
|
||||
/* Context for the folding hash table generator. */
|
||||
static int lineno;
|
||||
static uint32_t funcidx;
|
||||
static uint32_t foldkeys[BUILD_MAX_FOLD];
|
||||
static uint32_t nkeys;
|
||||
|
||||
/* Try to fill the hash table with keys using the hash parameters. */
|
||||
static int tryhash(uint32_t *htab, uint32_t sz, uint32_t r, int dorol)
|
||||
{
|
||||
uint32_t i;
|
||||
if (dorol && ((r & 31) == 0 || (r>>5) == 0))
|
||||
return 0; /* Avoid zero rotates. */
|
||||
memset(htab, 0xff, (sz+1)*sizeof(uint32_t));
|
||||
for (i = 0; i < nkeys; i++) {
|
||||
uint32_t key = foldkeys[i];
|
||||
uint32_t k = key & 0xffffff;
|
||||
uint32_t h = (dorol ? lj_rol(lj_rol(k, r>>5) - k, r&31) :
|
||||
(((k << (r>>5)) - k) << (r&31))) % sz;
|
||||
if (htab[h] != 0xffffffff) { /* Collision on primary slot. */
|
||||
if (htab[h+1] != 0xffffffff) { /* Collision on secondary slot. */
|
||||
/* Try to move the colliding key, if possible. */
|
||||
if (h < sz-1 && htab[h+2] == 0xffffffff) {
|
||||
uint32_t k2 = htab[h+1] & 0xffffff;
|
||||
uint32_t h2 = (dorol ? lj_rol(lj_rol(k2, r>>5) - k2, r&31) :
|
||||
(((k2 << (r>>5)) - k2) << (r&31))) % sz;
|
||||
if (h2 != h+1) return 0; /* Cannot resolve collision. */
|
||||
htab[h+2] = htab[h+1]; /* Move colliding key to secondary slot. */
|
||||
} else {
|
||||
return 0; /* Collision. */
|
||||
}
|
||||
}
|
||||
htab[h+1] = key;
|
||||
} else {
|
||||
htab[h] = key;
|
||||
}
|
||||
}
|
||||
return 1; /* Success, all keys could be stored. */
|
||||
}
|
||||
|
||||
/* Print the generated hash table. */
|
||||
static void printhash(BuildCtx *ctx, uint32_t *htab, uint32_t sz)
|
||||
{
|
||||
uint32_t i;
|
||||
fprintf(ctx->fp, "static const uint32_t fold_hash[%d] = {\n0x%08x",
|
||||
sz+1, htab[0]);
|
||||
for (i = 1; i < sz+1; i++)
|
||||
fprintf(ctx->fp, ",\n0x%08x", htab[i]);
|
||||
fprintf(ctx->fp, "\n};\n\n");
|
||||
}
|
||||
|
||||
/* Exhaustive search for the shortest semi-perfect hash table. */
|
||||
static void makehash(BuildCtx *ctx)
|
||||
{
|
||||
uint32_t htab[BUILD_MAX_FOLD*2+1];
|
||||
uint32_t sz, r;
|
||||
/* Search for the smallest hash table with an odd size. */
|
||||
for (sz = (nkeys|1); sz < BUILD_MAX_FOLD*2; sz += 2) {
|
||||
/* First try all shift hash combinations. */
|
||||
for (r = 0; r < 32*32; r++) {
|
||||
if (tryhash(htab, sz, r, 0)) {
|
||||
printhash(ctx, htab, sz);
|
||||
fprintf(ctx->fp,
|
||||
"#define fold_hashkey(k)\t(((((k)<<%u)-(k))<<%u)%%%u)\n\n",
|
||||
r>>5, r&31, sz);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Then try all rotate hash combinations. */
|
||||
for (r = 0; r < 32*32; r++) {
|
||||
if (tryhash(htab, sz, r, 1)) {
|
||||
printhash(ctx, htab, sz);
|
||||
fprintf(ctx->fp,
|
||||
"#define fold_hashkey(k)\t(lj_rol(lj_rol((k),%u)-(k),%u)%%%u)\n\n",
|
||||
r>>5, r&31, sz);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Error: search for perfect hash failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Parse one token of a fold rule. */
|
||||
static uint32_t nexttoken(char **pp, int allowlit, int allowany)
|
||||
{
|
||||
char *p = *pp;
|
||||
if (p) {
|
||||
uint32_t i;
|
||||
char *q = strchr(p, ' ');
|
||||
if (q) *q++ = '\0';
|
||||
*pp = q;
|
||||
if (allowlit && !strncmp(p, "IRFPM_", 6)) {
|
||||
for (i = 0; irfpm_names[i]; i++)
|
||||
if (!strcmp(irfpm_names[i], p+6))
|
||||
return i;
|
||||
} else if (allowlit && !strncmp(p, "IRFL_", 5)) {
|
||||
for (i = 0; irfield_names[i]; i++)
|
||||
if (!strcmp(irfield_names[i], p+5))
|
||||
return i;
|
||||
} else if (allowlit && !strncmp(p, "IRCALL_", 7)) {
|
||||
for (i = 0; ircall_names[i]; i++)
|
||||
if (!strcmp(ircall_names[i], p+7))
|
||||
return i;
|
||||
} else if (allowlit && !strncmp(p, "IRCONV_", 7)) {
|
||||
for (i = 0; irt_names[i]; i++) {
|
||||
const char *r = strchr(p+7, '_');
|
||||
if (r && !strncmp(irt_names[i], p+7, r-(p+7))) {
|
||||
uint32_t j;
|
||||
for (j = 0; irt_names[j]; j++)
|
||||
if (!strcmp(irt_names[j], r+1))
|
||||
return (i << 5) + j;
|
||||
}
|
||||
}
|
||||
} else if (allowlit && *p >= '0' && *p <= '9') {
|
||||
for (i = 0; *p >= '0' && *p <= '9'; p++)
|
||||
i = i*10 + (*p - '0');
|
||||
if (*p == '\0')
|
||||
return i;
|
||||
} else if (allowany && !strcmp("any", p)) {
|
||||
return allowany;
|
||||
} else {
|
||||
for (i = 0; ir_names[i]; i++)
|
||||
if (!strcmp(ir_names[i], p))
|
||||
return i;
|
||||
}
|
||||
fprintf(stderr, "Error: bad fold definition token \"%s\" at line %d\n", p, lineno);
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse a fold rule. */
|
||||
static void foldrule(char *p)
|
||||
{
|
||||
uint32_t op = nexttoken(&p, 0, 0);
|
||||
uint32_t left = nexttoken(&p, 0, 0x7f);
|
||||
uint32_t right = nexttoken(&p, 1, 0x3ff);
|
||||
uint32_t key = (funcidx << 24) | (op << 17) | (left << 10) | right;
|
||||
uint32_t i;
|
||||
if (nkeys >= BUILD_MAX_FOLD) {
|
||||
fprintf(stderr, "Error: too many fold rules, increase BUILD_MAX_FOLD.\n");
|
||||
exit(1);
|
||||
}
|
||||
/* Simple insertion sort to detect duplicates. */
|
||||
for (i = nkeys; i > 0; i--) {
|
||||
if ((foldkeys[i-1]&0xffffff) < (key & 0xffffff))
|
||||
break;
|
||||
if ((foldkeys[i-1]&0xffffff) == (key & 0xffffff)) {
|
||||
fprintf(stderr, "Error: duplicate fold definition at line %d\n", lineno);
|
||||
exit(1);
|
||||
}
|
||||
foldkeys[i] = foldkeys[i-1];
|
||||
}
|
||||
foldkeys[i] = key;
|
||||
nkeys++;
|
||||
}
|
||||
|
||||
/* Emit C source code for IR folding hash table. */
|
||||
void emit_fold(BuildCtx *ctx)
|
||||
{
|
||||
char buf[256]; /* We don't care about analyzing lines longer than that. */
|
||||
const char *fname = ctx->args[0];
|
||||
FILE *fp;
|
||||
|
||||
if (fname == NULL) {
|
||||
fprintf(stderr, "Error: missing input filename\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (fname[0] == '-' && fname[1] == '\0') {
|
||||
fp = stdin;
|
||||
} else {
|
||||
fp = fopen(fname, "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Error: cannot open input file '%s': %s\n",
|
||||
fname, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
|
||||
fprintf(ctx->fp, "static const FoldFunc fold_func[] = {\n");
|
||||
|
||||
lineno = 0;
|
||||
funcidx = 0;
|
||||
nkeys = 0;
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
lineno++;
|
||||
/* The prefix must be at the start of a line, otherwise it's ignored. */
|
||||
if (!strncmp(buf, FOLDDEF_PREFIX, sizeof(FOLDDEF_PREFIX)-1)) {
|
||||
char *p = buf+sizeof(FOLDDEF_PREFIX)-1;
|
||||
char *q = strchr(p, ')');
|
||||
if (p[0] == '(' && q) {
|
||||
p++;
|
||||
*q = '\0';
|
||||
foldrule(p);
|
||||
} else if ((p[0] == 'F' || p[0] == 'X') && p[1] == '(' && q) {
|
||||
p += 2;
|
||||
*q = '\0';
|
||||
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';
|
||||
fprintf(stderr, "Error: unknown fold definition tag %s%s at line %d\n",
|
||||
FOLDDEF_PREFIX, p, lineno);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
fprintf(ctx->fp, "\n};\n\n");
|
||||
|
||||
makehash(ctx);
|
||||
}
|
||||
#else
|
||||
void emit_fold(BuildCtx *ctx)
|
||||
{
|
||||
UNUSED(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
466
thirdPart/luajit/src/host/buildvm_lib.c
Normal file
466
thirdPart/luajit/src/host/buildvm_lib.c
Normal file
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
** LuaJIT VM builder: library definition compiler.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#include "buildvm.h"
|
||||
#include "lj_obj.h"
|
||||
#include "lj_bc.h"
|
||||
#include "lj_lib.h"
|
||||
#include "buildvm_libbc.h"
|
||||
|
||||
/* Context for library definitions. */
|
||||
static uint8_t obuf[8192];
|
||||
static uint8_t *optr;
|
||||
static char modname[80];
|
||||
static size_t modnamelen;
|
||||
static char funcname[80];
|
||||
static int modstate, regfunc;
|
||||
static int ffid, recffid, ffasmfunc;
|
||||
|
||||
enum {
|
||||
REGFUNC_OK,
|
||||
REGFUNC_NOREG,
|
||||
REGFUNC_NOREGUV
|
||||
};
|
||||
|
||||
static void libdef_name(const char *p, int kind)
|
||||
{
|
||||
size_t n = strlen(p);
|
||||
if (kind != LIBINIT_STRING) {
|
||||
if (n > modnamelen && p[modnamelen] == '_' &&
|
||||
!strncmp(p, modname, modnamelen)) {
|
||||
p += modnamelen+1;
|
||||
n -= modnamelen+1;
|
||||
}
|
||||
}
|
||||
if (n > LIBINIT_MAXSTR) {
|
||||
fprintf(stderr, "Error: string too long: '%s'\n", p);
|
||||
exit(1);
|
||||
}
|
||||
if (optr+1+n+2 > obuf+sizeof(obuf)) { /* +2 for caller. */
|
||||
fprintf(stderr, "Error: output buffer overflow\n");
|
||||
exit(1);
|
||||
}
|
||||
*optr++ = (uint8_t)(n | kind);
|
||||
memcpy(optr, p, n);
|
||||
optr += n;
|
||||
}
|
||||
|
||||
static void libdef_endmodule(BuildCtx *ctx)
|
||||
{
|
||||
if (modstate != 0) {
|
||||
char line[80];
|
||||
const uint8_t *p;
|
||||
int n;
|
||||
if (modstate == 1)
|
||||
fprintf(ctx->fp, " (lua_CFunction)0");
|
||||
fprintf(ctx->fp, "\n};\n");
|
||||
fprintf(ctx->fp, "static const uint8_t %s%s[] = {\n",
|
||||
LABEL_PREFIX_LIBINIT, modname);
|
||||
line[0] = '\0';
|
||||
for (n = 0, p = obuf; p < optr; p++) {
|
||||
n += sprintf(line+n, "%d,", *p);
|
||||
if (n >= 75) {
|
||||
fprintf(ctx->fp, "%s\n", line);
|
||||
n = 0;
|
||||
line[0] = '\0';
|
||||
}
|
||||
}
|
||||
fprintf(ctx->fp, "%s%d\n};\n#endif\n\n", line, LIBINIT_END);
|
||||
}
|
||||
}
|
||||
|
||||
static void libdef_module(BuildCtx *ctx, char *p, int arg)
|
||||
{
|
||||
UNUSED(arg);
|
||||
if (ctx->mode == BUILD_libdef) {
|
||||
libdef_endmodule(ctx);
|
||||
optr = obuf;
|
||||
*optr++ = (uint8_t)ffid;
|
||||
*optr++ = (uint8_t)ffasmfunc;
|
||||
*optr++ = 0; /* Hash table size. */
|
||||
modstate = 1;
|
||||
fprintf(ctx->fp, "#ifdef %sMODULE_%s\n", LIBDEF_PREFIX, p);
|
||||
fprintf(ctx->fp, "#undef %sMODULE_%s\n", LIBDEF_PREFIX, p);
|
||||
fprintf(ctx->fp, "static const lua_CFunction %s%s[] = {\n",
|
||||
LABEL_PREFIX_LIBCF, p);
|
||||
}
|
||||
modnamelen = strlen(p);
|
||||
if (modnamelen > sizeof(modname)-1) {
|
||||
fprintf(stderr, "Error: module name too long: '%s'\n", p);
|
||||
exit(1);
|
||||
}
|
||||
strcpy(modname, p);
|
||||
}
|
||||
|
||||
static int find_ffofs(BuildCtx *ctx, const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ctx->nglob; i++) {
|
||||
const char *gl = ctx->globnames[i];
|
||||
if (gl[0] == 'f' && gl[1] == 'f' && gl[2] == '_' && !strcmp(gl+3, name)) {
|
||||
return (int)((uint8_t *)ctx->glob[i] - ctx->code);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Error: undefined fast function %s%s\n",
|
||||
LABEL_PREFIX_FF, name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void libdef_func(BuildCtx *ctx, char *p, int arg)
|
||||
{
|
||||
if (arg != LIBINIT_CF)
|
||||
ffasmfunc++;
|
||||
if (ctx->mode == BUILD_libdef) {
|
||||
if (modstate == 0) {
|
||||
fprintf(stderr, "Error: no module for function definition %s\n", p);
|
||||
exit(1);
|
||||
}
|
||||
if (regfunc == REGFUNC_NOREG) {
|
||||
if (optr+1 > obuf+sizeof(obuf)) {
|
||||
fprintf(stderr, "Error: output buffer overflow\n");
|
||||
exit(1);
|
||||
}
|
||||
*optr++ = LIBINIT_FFID;
|
||||
} else {
|
||||
if (arg != LIBINIT_ASM_) {
|
||||
if (modstate != 1) fprintf(ctx->fp, ",\n");
|
||||
modstate = 2;
|
||||
fprintf(ctx->fp, " %s%s", arg ? LABEL_PREFIX_FFH : LABEL_PREFIX_CF, p);
|
||||
}
|
||||
if (regfunc != REGFUNC_NOREGUV) obuf[2]++; /* Bump hash table size. */
|
||||
libdef_name(regfunc == REGFUNC_NOREGUV ? "" : p, arg);
|
||||
}
|
||||
} else if (ctx->mode == BUILD_ffdef) {
|
||||
fprintf(ctx->fp, "FFDEF(%s)\n", p);
|
||||
} else if (ctx->mode == BUILD_recdef) {
|
||||
if (strlen(p) > sizeof(funcname)-1) {
|
||||
fprintf(stderr, "Error: function name too long: '%s'\n", p);
|
||||
exit(1);
|
||||
}
|
||||
strcpy(funcname, p);
|
||||
} else if (ctx->mode == BUILD_vmdef) {
|
||||
int i;
|
||||
for (i = 1; p[i] && modname[i-1]; i++)
|
||||
if (p[i] == '_') p[i] = '.';
|
||||
fprintf(ctx->fp, "\"%s\",\n", p);
|
||||
} else if (ctx->mode == BUILD_bcdef) {
|
||||
if (arg != LIBINIT_CF)
|
||||
fprintf(ctx->fp, ",\n%d", find_ffofs(ctx, p));
|
||||
}
|
||||
ffid++;
|
||||
regfunc = REGFUNC_OK;
|
||||
}
|
||||
|
||||
static uint8_t *libdef_uleb128(uint8_t *p, uint32_t *vv)
|
||||
{
|
||||
uint32_t v = *p++;
|
||||
if (v >= 0x80) {
|
||||
int sh = 0; v &= 0x7f;
|
||||
do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80);
|
||||
}
|
||||
*vv = v;
|
||||
return p;
|
||||
}
|
||||
|
||||
static void libdef_fixupbc(uint8_t *p)
|
||||
{
|
||||
uint32_t i, sizebc;
|
||||
p += 4;
|
||||
p = libdef_uleb128(p, &sizebc);
|
||||
p = libdef_uleb128(p, &sizebc);
|
||||
p = libdef_uleb128(p, &sizebc);
|
||||
for (i = 0; i < sizebc; i++, p += 4) {
|
||||
uint8_t op = p[libbc_endian ? 3 : 0];
|
||||
uint8_t ra = p[libbc_endian ? 2 : 1];
|
||||
uint8_t rc = p[libbc_endian ? 1 : 2];
|
||||
uint8_t rb = p[libbc_endian ? 0 : 3];
|
||||
if (!LJ_DUALNUM && op == BC_ISTYPE && rc == ~LJ_TNUMX+1) {
|
||||
op = BC_ISNUM; rc++;
|
||||
}
|
||||
p[LJ_ENDIAN_SELECT(0, 3)] = op;
|
||||
p[LJ_ENDIAN_SELECT(1, 2)] = ra;
|
||||
p[LJ_ENDIAN_SELECT(2, 1)] = rc;
|
||||
p[LJ_ENDIAN_SELECT(3, 0)] = rb;
|
||||
}
|
||||
}
|
||||
|
||||
static void libdef_lua(BuildCtx *ctx, char *p, int arg)
|
||||
{
|
||||
UNUSED(arg);
|
||||
if (ctx->mode == BUILD_libdef) {
|
||||
int i;
|
||||
for (i = 0; libbc_map[i].name != NULL; i++) {
|
||||
if (!strcmp(libbc_map[i].name, p)) {
|
||||
int ofs = libbc_map[i].ofs;
|
||||
int len = libbc_map[i+1].ofs - ofs;
|
||||
obuf[2]++; /* Bump hash table size. */
|
||||
*optr++ = LIBINIT_LUA;
|
||||
libdef_name(p, 0);
|
||||
memcpy(optr, libbc_code + ofs, len);
|
||||
libdef_fixupbc(optr);
|
||||
optr += len;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Error: missing libbc definition for %s\n", p);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t find_rec(char *name)
|
||||
{
|
||||
char *p = (char *)obuf;
|
||||
uint32_t n;
|
||||
for (n = 2; *p; n++) {
|
||||
if (strcmp(p, name) == 0)
|
||||
return n;
|
||||
p += strlen(p)+1;
|
||||
}
|
||||
if (p+strlen(name)+1 >= (char *)obuf+sizeof(obuf)) {
|
||||
fprintf(stderr, "Error: output buffer overflow\n");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(p, name);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void libdef_rec(BuildCtx *ctx, char *p, int arg)
|
||||
{
|
||||
UNUSED(arg);
|
||||
if (ctx->mode == BUILD_recdef) {
|
||||
char *q;
|
||||
uint32_t n;
|
||||
for (; recffid+1 < ffid; recffid++)
|
||||
fprintf(ctx->fp, ",\n0");
|
||||
recffid = ffid;
|
||||
if (*p == '.') p = funcname;
|
||||
q = strchr(p, ' ');
|
||||
if (q) *q++ = '\0';
|
||||
n = find_rec(p);
|
||||
if (q)
|
||||
fprintf(ctx->fp, ",\n0x%02x00+(%s)", n, q);
|
||||
else
|
||||
fprintf(ctx->fp, ",\n0x%02x00", n);
|
||||
}
|
||||
}
|
||||
|
||||
static void memcpy_endian(void *dst, void *src, size_t n)
|
||||
{
|
||||
union { uint8_t b; uint32_t u; } host_endian;
|
||||
host_endian.u = 1;
|
||||
if (host_endian.b == LJ_ENDIAN_SELECT(1, 0)) {
|
||||
memcpy(dst, src, n);
|
||||
} else {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++)
|
||||
((uint8_t *)dst)[i] = ((uint8_t *)src)[n-i-1];
|
||||
}
|
||||
}
|
||||
|
||||
static void libdef_push(BuildCtx *ctx, char *p, int arg)
|
||||
{
|
||||
UNUSED(arg);
|
||||
if (ctx->mode == BUILD_libdef) {
|
||||
int len = (int)strlen(p);
|
||||
if (*p == '"') {
|
||||
if (len > 1 && p[len-1] == '"') {
|
||||
p[len-1] = '\0';
|
||||
libdef_name(p+1, LIBINIT_STRING);
|
||||
return;
|
||||
}
|
||||
} else if (*p >= '0' && *p <= '9') {
|
||||
char *ep;
|
||||
double d = strtod(p, &ep);
|
||||
if (*ep == '\0') {
|
||||
if (optr+1+sizeof(double) > obuf+sizeof(obuf)) {
|
||||
fprintf(stderr, "Error: output buffer overflow\n");
|
||||
exit(1);
|
||||
}
|
||||
*optr++ = LIBINIT_NUMBER;
|
||||
memcpy_endian(optr, &d, sizeof(double));
|
||||
optr += sizeof(double);
|
||||
return;
|
||||
}
|
||||
} else if (!strcmp(p, "lastcl")) {
|
||||
if (optr+1 > obuf+sizeof(obuf)) {
|
||||
fprintf(stderr, "Error: output buffer overflow\n");
|
||||
exit(1);
|
||||
}
|
||||
*optr++ = LIBINIT_LASTCL;
|
||||
return;
|
||||
} else if (len > 4 && !strncmp(p, "top-", 4)) {
|
||||
if (optr+2 > obuf+sizeof(obuf)) {
|
||||
fprintf(stderr, "Error: output buffer overflow\n");
|
||||
exit(1);
|
||||
}
|
||||
*optr++ = LIBINIT_COPY;
|
||||
*optr++ = (uint8_t)atoi(p+4);
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "Error: bad value for %sPUSH(%s)\n", LIBDEF_PREFIX, p);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void libdef_set(BuildCtx *ctx, char *p, int arg)
|
||||
{
|
||||
UNUSED(arg);
|
||||
if (ctx->mode == BUILD_libdef) {
|
||||
if (p[0] == '!' && p[1] == '\0') p[0] = '\0'; /* Set env. */
|
||||
libdef_name(p, LIBINIT_STRING);
|
||||
*optr++ = LIBINIT_SET;
|
||||
obuf[2]++; /* Bump hash table size. */
|
||||
}
|
||||
}
|
||||
|
||||
static void libdef_regfunc(BuildCtx *ctx, char *p, int arg)
|
||||
{
|
||||
UNUSED(ctx); UNUSED(p);
|
||||
regfunc = arg;
|
||||
}
|
||||
|
||||
typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg);
|
||||
|
||||
typedef struct LibDefHandler {
|
||||
const char *suffix;
|
||||
const char *stop;
|
||||
const LibDefFunc func;
|
||||
const int arg;
|
||||
} LibDefHandler;
|
||||
|
||||
static const LibDefHandler libdef_handlers[] = {
|
||||
{ "MODULE_", " \t\r\n", libdef_module, 0 },
|
||||
{ "CF(", ")", libdef_func, LIBINIT_CF },
|
||||
{ "ASM(", ")", libdef_func, LIBINIT_ASM },
|
||||
{ "ASM_(", ")", libdef_func, LIBINIT_ASM_ },
|
||||
{ "LUA(", ")", libdef_lua, 0 },
|
||||
{ "REC(", ")", libdef_rec, 0 },
|
||||
{ "PUSH(", ")", libdef_push, 0 },
|
||||
{ "SET(", ")", libdef_set, 0 },
|
||||
{ "NOREGUV", NULL, libdef_regfunc, REGFUNC_NOREGUV },
|
||||
{ "NOREG", NULL, libdef_regfunc, REGFUNC_NOREG },
|
||||
{ NULL, NULL, (LibDefFunc)0, 0 }
|
||||
};
|
||||
|
||||
/* Emit C source code for library function definitions. */
|
||||
void emit_lib(BuildCtx *ctx)
|
||||
{
|
||||
const char *fname;
|
||||
|
||||
if (ctx->mode == BUILD_ffdef || ctx->mode == BUILD_libdef ||
|
||||
ctx->mode == BUILD_recdef)
|
||||
fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
|
||||
else if (ctx->mode == BUILD_vmdef)
|
||||
fprintf(ctx->fp, "ffnames = {\n[0]=\"Lua\",\n\"C\",\n");
|
||||
if (ctx->mode == BUILD_recdef)
|
||||
fprintf(ctx->fp, "static const uint16_t recff_idmap[] = {\n0,\n0x0100");
|
||||
recffid = ffid = FF_C+1;
|
||||
ffasmfunc = 0;
|
||||
|
||||
while ((fname = *ctx->args++)) {
|
||||
char buf[256]; /* We don't care about analyzing lines longer than that. */
|
||||
FILE *fp;
|
||||
if (fname[0] == '-' && fname[1] == '\0') {
|
||||
fp = stdin;
|
||||
} else {
|
||||
fp = fopen(fname, "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Error: cannot open input file '%s': %s\n",
|
||||
fname, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
modstate = 0;
|
||||
regfunc = REGFUNC_OK;
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
char *p;
|
||||
/* Simplistic pre-processor. Only handles top-level #if/#endif. */
|
||||
if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') {
|
||||
int ok = 1;
|
||||
size_t len = strlen(buf);
|
||||
if (buf[len-1] == '\n') {
|
||||
buf[len-1] = 0;
|
||||
if (buf[len-2] == '\r') {
|
||||
buf[len-2] = 0;
|
||||
}
|
||||
}
|
||||
if (!strcmp(buf, "#if LJ_52"))
|
||||
ok = LJ_52;
|
||||
else if (!strcmp(buf, "#if LJ_HASJIT"))
|
||||
ok = LJ_HASJIT;
|
||||
else if (!strcmp(buf, "#if LJ_HASFFI"))
|
||||
ok = LJ_HASFFI;
|
||||
else if (!strcmp(buf, "#if LJ_HASBUFFER"))
|
||||
ok = LJ_HASBUFFER;
|
||||
if (!ok) {
|
||||
int lvl = 1;
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
if (buf[0] == '#' && buf[1] == 'e' && buf[2] == 'n') {
|
||||
if (--lvl == 0) break;
|
||||
} else if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') {
|
||||
lvl++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (p = buf; (p = strstr(p, LIBDEF_PREFIX)) != NULL; ) {
|
||||
const LibDefHandler *ldh;
|
||||
p += sizeof(LIBDEF_PREFIX)-1;
|
||||
for (ldh = libdef_handlers; ldh->suffix != NULL; ldh++) {
|
||||
size_t n, len = strlen(ldh->suffix);
|
||||
if (!strncmp(p, ldh->suffix, len)) {
|
||||
p += len;
|
||||
n = ldh->stop ? strcspn(p, ldh->stop) : 0;
|
||||
if (!p[n]) break;
|
||||
p[n] = '\0';
|
||||
ldh->func(ctx, p, ldh->arg);
|
||||
p += n+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ldh->suffix == NULL) {
|
||||
buf[strlen(buf)-1] = '\0';
|
||||
fprintf(stderr, "Error: unknown library definition tag %s%s\n",
|
||||
LIBDEF_PREFIX, p);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
if (ctx->mode == BUILD_libdef) {
|
||||
libdef_endmodule(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->mode == BUILD_ffdef) {
|
||||
fprintf(ctx->fp, "\n#undef FFDEF\n\n");
|
||||
fprintf(ctx->fp,
|
||||
"#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n",
|
||||
ffasmfunc);
|
||||
} else if (ctx->mode == BUILD_vmdef) {
|
||||
fprintf(ctx->fp, "},\n\n");
|
||||
} else if (ctx->mode == BUILD_bcdef) {
|
||||
int i;
|
||||
fprintf(ctx->fp, "\n};\n\n");
|
||||
fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_mode[] = {\n");
|
||||
fprintf(ctx->fp, "BCDEF(BCMODE)\n");
|
||||
for (i = ffasmfunc-1; i > 0; i--)
|
||||
fprintf(ctx->fp, "BCMODE_FF,\n");
|
||||
fprintf(ctx->fp, "BCMODE_FF\n};\n\n");
|
||||
} else if (ctx->mode == BUILD_recdef) {
|
||||
char *p = (char *)obuf;
|
||||
fprintf(ctx->fp, "\n};\n\n");
|
||||
fprintf(ctx->fp, "static const RecordFunc recff_func[] = {\n"
|
||||
"recff_nyi,\n"
|
||||
"recff_c");
|
||||
while (*p) {
|
||||
fprintf(ctx->fp, ",\nrecff_%s", p);
|
||||
p += strlen(p)+1;
|
||||
}
|
||||
fprintf(ctx->fp, "\n};\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
81
thirdPart/luajit/src/host/buildvm_libbc.h
Normal file
81
thirdPart/luajit/src/host/buildvm_libbc.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/* This is a generated file. DO NOT EDIT! */
|
||||
|
||||
static const int libbc_endian = 0;
|
||||
|
||||
static const uint8_t libbc_code[] = {
|
||||
#if LJ_FR2
|
||||
/* math.deg */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,241,135,158,166,3,
|
||||
220,203,178,130,4,
|
||||
/* math.rad */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,243,244,148,165,20,
|
||||
198,190,199,252,3,
|
||||
/* string.len */ 0,1,2,0,0,0,3,BC_ISTYPE,0,5,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
|
||||
/* table.foreachi */ 0,2,10,0,0,0,15,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,
|
||||
BC_KSHORT,2,1,0,BC_LEN,3,0,0,BC_KSHORT,4,1,0,BC_FORI,2,8,128,BC_MOV,6,1,0,
|
||||
BC_MOV,8,5,0,BC_TGETR,9,5,0,BC_CALL,6,3,2,BC_ISEQP,6,0,0,BC_JMP,7,1,128,
|
||||
BC_RET1,6,2,0,BC_FORL,2,248,127,BC_RET0,0,1,0,
|
||||
/* table.foreach */ 0,2,11,0,0,1,16,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,BC_KPRI,
|
||||
2,0,0,BC_MOV,3,0,0,BC_KNUM,4,0,0,BC_JMP,5,7,128,BC_MOV,7,1,0,BC_MOV,9,5,0,
|
||||
BC_MOV,10,6,0,BC_CALL,7,3,2,BC_ISEQP,7,0,0,BC_JMP,8,1,128,BC_RET1,7,2,0,
|
||||
BC_ITERN,5,3,3,BC_ITERL,5,247,127,BC_RET0,0,1,0,1,255,255,249,255,15,
|
||||
/* table.getn */ 0,1,2,0,0,0,3,BC_ISTYPE,0,12,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
|
||||
/* table.remove */ 0,2,10,0,0,2,30,BC_ISTYPE,0,12,0,BC_LEN,2,0,0,BC_ISNEP,1,0,
|
||||
0,BC_JMP,3,7,128,BC_ISEQN,2,0,0,BC_JMP,3,23,128,BC_TGETR,3,2,0,BC_KPRI,4,0,0,
|
||||
BC_TSETR,4,2,0,BC_RET1,3,2,0,BC_JMP,3,18,128,BC_ISTYPE,1,14,0,BC_KSHORT,3,1,0,
|
||||
BC_ISGT,3,1,0,BC_JMP,3,14,128,BC_ISGT,1,2,0,BC_JMP,3,12,128,BC_TGETR,3,1,0,
|
||||
BC_ADDVN,4,1,1,BC_MOV,5,2,0,BC_KSHORT,6,1,0,BC_FORI,4,4,128,BC_SUBVN,8,1,7,
|
||||
BC_TGETR,9,7,0,BC_TSETR,9,8,0,BC_FORL,4,252,127,BC_KPRI,4,0,0,BC_TSETR,4,2,0,
|
||||
BC_RET1,3,2,0,BC_RET0,0,1,0,0,2,
|
||||
/* table.move */ 0,5,12,0,0,0,35,BC_ISTYPE,0,12,0,BC_ISTYPE,1,14,0,BC_ISTYPE,
|
||||
2,14,0,BC_ISTYPE,3,14,0,BC_ISNEP,4,0,0,BC_JMP,5,1,128,BC_MOV,4,0,0,BC_ISTYPE,
|
||||
4,12,0,BC_ISGT,1,2,0,BC_JMP,5,24,128,BC_SUBVV,5,1,3,BC_ISLT,2,3,0,BC_JMP,6,4,
|
||||
128,BC_ISLE,3,1,0,BC_JMP,6,2,128,BC_ISEQV,4,0,0,BC_JMP,6,9,128,BC_MOV,6,1,0,
|
||||
BC_MOV,7,2,0,BC_KSHORT,8,1,0,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,
|
||||
BC_TSETR,11,10,4,BC_FORL,6,252,127,BC_JMP,6,8,128,BC_MOV,6,2,0,BC_MOV,7,1,0,
|
||||
BC_KSHORT,8,255,255,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,BC_TSETR,
|
||||
11,10,4,BC_FORL,6,252,127,BC_RET1,4,2,0,
|
||||
#else
|
||||
/* math.deg */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,241,135,158,166,3,
|
||||
220,203,178,130,4,
|
||||
/* math.rad */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,243,244,148,165,20,
|
||||
198,190,199,252,3,
|
||||
/* string.len */ 0,1,2,0,0,0,3,BC_ISTYPE,0,5,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
|
||||
/* table.foreachi */ 0,2,9,0,0,0,15,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,
|
||||
BC_KSHORT,2,1,0,BC_LEN,3,0,0,BC_KSHORT,4,1,0,BC_FORI,2,8,128,BC_MOV,6,1,0,
|
||||
BC_MOV,7,5,0,BC_TGETR,8,5,0,BC_CALL,6,3,2,BC_ISEQP,6,0,0,BC_JMP,7,1,128,
|
||||
BC_RET1,6,2,0,BC_FORL,2,248,127,BC_RET0,0,1,0,
|
||||
/* table.foreach */ 0,2,10,0,0,1,16,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,BC_KPRI,
|
||||
2,0,0,BC_MOV,3,0,0,BC_KNUM,4,0,0,BC_JMP,5,7,128,BC_MOV,7,1,0,BC_MOV,8,5,0,
|
||||
BC_MOV,9,6,0,BC_CALL,7,3,2,BC_ISEQP,7,0,0,BC_JMP,8,1,128,BC_RET1,7,2,0,
|
||||
BC_ITERN,5,3,3,BC_ITERL,5,247,127,BC_RET0,0,1,0,1,255,255,249,255,15,
|
||||
/* table.getn */ 0,1,2,0,0,0,3,BC_ISTYPE,0,12,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
|
||||
/* table.remove */ 0,2,10,0,0,2,30,BC_ISTYPE,0,12,0,BC_LEN,2,0,0,BC_ISNEP,1,0,
|
||||
0,BC_JMP,3,7,128,BC_ISEQN,2,0,0,BC_JMP,3,23,128,BC_TGETR,3,2,0,BC_KPRI,4,0,0,
|
||||
BC_TSETR,4,2,0,BC_RET1,3,2,0,BC_JMP,3,18,128,BC_ISTYPE,1,14,0,BC_KSHORT,3,1,0,
|
||||
BC_ISGT,3,1,0,BC_JMP,3,14,128,BC_ISGT,1,2,0,BC_JMP,3,12,128,BC_TGETR,3,1,0,
|
||||
BC_ADDVN,4,1,1,BC_MOV,5,2,0,BC_KSHORT,6,1,0,BC_FORI,4,4,128,BC_SUBVN,8,1,7,
|
||||
BC_TGETR,9,7,0,BC_TSETR,9,8,0,BC_FORL,4,252,127,BC_KPRI,4,0,0,BC_TSETR,4,2,0,
|
||||
BC_RET1,3,2,0,BC_RET0,0,1,0,0,2,
|
||||
/* table.move */ 0,5,12,0,0,0,35,BC_ISTYPE,0,12,0,BC_ISTYPE,1,14,0,BC_ISTYPE,
|
||||
2,14,0,BC_ISTYPE,3,14,0,BC_ISNEP,4,0,0,BC_JMP,5,1,128,BC_MOV,4,0,0,BC_ISTYPE,
|
||||
4,12,0,BC_ISGT,1,2,0,BC_JMP,5,24,128,BC_SUBVV,5,1,3,BC_ISLT,2,3,0,BC_JMP,6,4,
|
||||
128,BC_ISLE,3,1,0,BC_JMP,6,2,128,BC_ISEQV,4,0,0,BC_JMP,6,9,128,BC_MOV,6,1,0,
|
||||
BC_MOV,7,2,0,BC_KSHORT,8,1,0,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,
|
||||
BC_TSETR,11,10,4,BC_FORL,6,252,127,BC_JMP,6,8,128,BC_MOV,6,2,0,BC_MOV,7,1,0,
|
||||
BC_KSHORT,8,255,255,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,BC_TSETR,
|
||||
11,10,4,BC_FORL,6,252,127,BC_RET1,4,2,0,
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
static const struct { const char *name; int ofs; } libbc_map[] = {
|
||||
{"math_deg",0},
|
||||
{"math_rad",25},
|
||||
{"string_len",50},
|
||||
{"table_foreachi",69},
|
||||
{"table_foreach",136},
|
||||
{"table_getn",213},
|
||||
{"table_remove",232},
|
||||
{"table_move",361},
|
||||
{NULL,508}
|
||||
};
|
||||
|
||||
473
thirdPart/luajit/src/host/buildvm_peobj.c
Normal file
473
thirdPart/luajit/src/host/buildvm_peobj.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
** LuaJIT VM builder: PE object emitter.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** Only used for building on Windows, since we cannot assume the presence
|
||||
** of a suitable assembler. The host and target byte order must match.
|
||||
*/
|
||||
|
||||
#include "buildvm.h"
|
||||
#include "lj_bc.h"
|
||||
|
||||
#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
|
||||
|
||||
/* Context for PE object emitter. */
|
||||
static char *strtab;
|
||||
static size_t strtabofs;
|
||||
|
||||
/* -- PE object definitions ----------------------------------------------- */
|
||||
|
||||
/* PE header. */
|
||||
typedef struct PEheader {
|
||||
uint16_t arch;
|
||||
uint16_t nsects;
|
||||
uint32_t time;
|
||||
uint32_t symtabofs;
|
||||
uint32_t nsyms;
|
||||
uint16_t opthdrsz;
|
||||
uint16_t flags;
|
||||
} PEheader;
|
||||
|
||||
/* PE section. */
|
||||
typedef struct PEsection {
|
||||
char name[8];
|
||||
uint32_t vsize;
|
||||
uint32_t vaddr;
|
||||
uint32_t size;
|
||||
uint32_t ofs;
|
||||
uint32_t relocofs;
|
||||
uint32_t lineofs;
|
||||
uint16_t nreloc;
|
||||
uint16_t nline;
|
||||
uint32_t flags;
|
||||
} PEsection;
|
||||
|
||||
/* PE relocation. */
|
||||
typedef struct PEreloc {
|
||||
uint32_t vaddr;
|
||||
uint32_t symidx;
|
||||
uint16_t type;
|
||||
} PEreloc;
|
||||
|
||||
/* Cannot use sizeof, because it pads up to the max. alignment. */
|
||||
#define PEOBJ_RELOC_SIZE (4+4+2)
|
||||
|
||||
/* PE symbol table entry. */
|
||||
typedef struct PEsym {
|
||||
union {
|
||||
char name[8];
|
||||
uint32_t nameref[2];
|
||||
} n;
|
||||
uint32_t value;
|
||||
int16_t sect;
|
||||
uint16_t type;
|
||||
uint8_t scl;
|
||||
uint8_t naux;
|
||||
} PEsym;
|
||||
|
||||
/* PE symbol table auxiliary entry for a section. */
|
||||
typedef struct PEsymaux {
|
||||
uint32_t size;
|
||||
uint16_t nreloc;
|
||||
uint16_t nline;
|
||||
uint32_t cksum;
|
||||
uint16_t assoc;
|
||||
uint8_t comdatsel;
|
||||
uint8_t unused[3];
|
||||
} PEsymaux;
|
||||
|
||||
/* Cannot use sizeof, because it pads up to the max. alignment. */
|
||||
#define PEOBJ_SYM_SIZE (8+4+2+2+1+1)
|
||||
|
||||
/* PE object CPU specific defines. */
|
||||
#if LJ_TARGET_X86
|
||||
#define PEOBJ_ARCH_TARGET 0x014c
|
||||
#define PEOBJ_RELOC_REL32 0x14 /* MS: REL32, GNU: DISP32. */
|
||||
#define PEOBJ_RELOC_DIR32 0x06
|
||||
#define PEOBJ_RELOC_OFS 0
|
||||
#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
|
||||
#elif LJ_TARGET_X64
|
||||
#define PEOBJ_ARCH_TARGET 0x8664
|
||||
#define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */
|
||||
#define PEOBJ_RELOC_DIR32 0x02
|
||||
#define PEOBJ_RELOC_ADDR32NB 0x03
|
||||
#define PEOBJ_RELOC_OFS 0
|
||||
#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
|
||||
#define PEOBJ_PDATA_NRELOC 6
|
||||
#define PEOBJ_XDATA_SIZE (8*2+4+6*2)
|
||||
#elif LJ_TARGET_ARM64
|
||||
#define PEOBJ_ARCH_TARGET 0xaa64
|
||||
#define PEOBJ_RELOC_REL32 0x03 /* MS: BRANCH26. */
|
||||
#define PEOBJ_RELOC_DIR32 0x01
|
||||
#define PEOBJ_RELOC_ADDR32NB 0x02
|
||||
#define PEOBJ_RELOC_OFS (-4)
|
||||
#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
|
||||
#define PEOBJ_PDATA_NRELOC 4
|
||||
#define PEOBJ_XDATA_SIZE (4+24+4 +4+8)
|
||||
#endif
|
||||
|
||||
/* Section numbers (0-based). */
|
||||
enum {
|
||||
PEOBJ_SECT_ABS = -2,
|
||||
PEOBJ_SECT_UNDEF = -1,
|
||||
PEOBJ_SECT_TEXT,
|
||||
#ifdef PEOBJ_PDATA_NRELOC
|
||||
PEOBJ_SECT_PDATA,
|
||||
PEOBJ_SECT_XDATA,
|
||||
#elif LJ_TARGET_X86
|
||||
PEOBJ_SECT_SXDATA,
|
||||
#endif
|
||||
PEOBJ_SECT_RDATA_Z,
|
||||
PEOBJ_NSECTIONS
|
||||
};
|
||||
|
||||
/* Symbol types. */
|
||||
#define PEOBJ_TYPE_NULL 0
|
||||
#define PEOBJ_TYPE_FUNC 0x20
|
||||
|
||||
/* Symbol storage class. */
|
||||
#define PEOBJ_SCL_EXTERN 2
|
||||
#define PEOBJ_SCL_STATIC 3
|
||||
|
||||
/* -- PE object emitter --------------------------------------------------- */
|
||||
|
||||
/* Emit PE object symbol. */
|
||||
static void emit_peobj_sym(BuildCtx *ctx, const char *name, uint32_t value,
|
||||
int sect, int type, int scl)
|
||||
{
|
||||
PEsym sym;
|
||||
size_t len = strlen(name);
|
||||
if (!strtab) { /* Pass 1: only calculate string table length. */
|
||||
if (len > 8) strtabofs += len+1;
|
||||
return;
|
||||
}
|
||||
if (len <= 8) {
|
||||
memcpy(sym.n.name, name, len);
|
||||
memset(sym.n.name+len, 0, 8-len);
|
||||
} else {
|
||||
sym.n.nameref[0] = 0;
|
||||
sym.n.nameref[1] = (uint32_t)strtabofs;
|
||||
memcpy(strtab + strtabofs, name, len);
|
||||
strtab[strtabofs+len] = 0;
|
||||
strtabofs += len+1;
|
||||
}
|
||||
sym.value = value;
|
||||
sym.sect = (int16_t)(sect+1); /* 1-based section number. */
|
||||
sym.type = (uint16_t)type;
|
||||
sym.scl = (uint8_t)scl;
|
||||
sym.naux = 0;
|
||||
owrite(ctx, &sym, PEOBJ_SYM_SIZE);
|
||||
}
|
||||
|
||||
/* Emit PE object section symbol. */
|
||||
static void emit_peobj_sym_sect(BuildCtx *ctx, PEsection *pesect, int sect)
|
||||
{
|
||||
PEsym sym;
|
||||
PEsymaux aux;
|
||||
if (!strtab) return; /* Pass 1: no output. */
|
||||
memcpy(sym.n.name, pesect[sect].name, 8);
|
||||
sym.value = 0;
|
||||
sym.sect = (int16_t)(sect+1); /* 1-based section number. */
|
||||
sym.type = PEOBJ_TYPE_NULL;
|
||||
sym.scl = PEOBJ_SCL_STATIC;
|
||||
sym.naux = 1;
|
||||
owrite(ctx, &sym, PEOBJ_SYM_SIZE);
|
||||
memset(&aux, 0, sizeof(PEsymaux));
|
||||
aux.size = pesect[sect].size;
|
||||
aux.nreloc = pesect[sect].nreloc;
|
||||
owrite(ctx, &aux, PEOBJ_SYM_SIZE);
|
||||
}
|
||||
|
||||
/* Emit Windows PE object file. */
|
||||
void emit_peobj(BuildCtx *ctx)
|
||||
{
|
||||
PEheader pehdr;
|
||||
PEsection pesect[PEOBJ_NSECTIONS];
|
||||
uint32_t sofs;
|
||||
int i, nrsym;
|
||||
union { uint8_t b; uint32_t u; } host_endian;
|
||||
#ifdef PEOBJ_PDATA_NRELOC
|
||||
uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
|
||||
#endif
|
||||
|
||||
sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection);
|
||||
|
||||
/* Fill in PE sections. */
|
||||
memset(&pesect, 0, PEOBJ_NSECTIONS*sizeof(PEsection));
|
||||
memcpy(pesect[PEOBJ_SECT_TEXT].name, ".text", sizeof(".text")-1);
|
||||
pesect[PEOBJ_SECT_TEXT].ofs = sofs;
|
||||
sofs += (pesect[PEOBJ_SECT_TEXT].size = (uint32_t)ctx->codesz);
|
||||
pesect[PEOBJ_SECT_TEXT].relocofs = sofs;
|
||||
sofs += (pesect[PEOBJ_SECT_TEXT].nreloc = (uint16_t)ctx->nreloc) * PEOBJ_RELOC_SIZE;
|
||||
/* Flags: 60 = read+execute, 50 = align16, 20 = code. */
|
||||
pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS;
|
||||
|
||||
#ifdef PEOBJ_PDATA_NRELOC
|
||||
memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
|
||||
pesect[PEOBJ_SECT_PDATA].ofs = sofs;
|
||||
sofs += (pesect[PEOBJ_SECT_PDATA].size = PEOBJ_PDATA_NRELOC*4);
|
||||
pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
|
||||
sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = PEOBJ_PDATA_NRELOC) * PEOBJ_RELOC_SIZE;
|
||||
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
|
||||
pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;
|
||||
|
||||
memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
|
||||
pesect[PEOBJ_SECT_XDATA].ofs = sofs;
|
||||
sofs += (pesect[PEOBJ_SECT_XDATA].size = PEOBJ_XDATA_SIZE); /* See below. */
|
||||
pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
|
||||
sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
|
||||
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
|
||||
pesect[PEOBJ_SECT_XDATA].flags = 0x40300040;
|
||||
#elif LJ_TARGET_X86
|
||||
memcpy(pesect[PEOBJ_SECT_SXDATA].name, ".sxdata", sizeof(".sxdata")-1);
|
||||
pesect[PEOBJ_SECT_SXDATA].ofs = sofs;
|
||||
sofs += (pesect[PEOBJ_SECT_SXDATA].size = 4);
|
||||
pesect[PEOBJ_SECT_SXDATA].relocofs = sofs;
|
||||
/* Flags: 40 = read, 30 = align4, 02 = lnk_info, 40 = initialized data. */
|
||||
pesect[PEOBJ_SECT_SXDATA].flags = 0x40300240;
|
||||
#endif
|
||||
|
||||
memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1);
|
||||
pesect[PEOBJ_SECT_RDATA_Z].ofs = sofs;
|
||||
sofs += (pesect[PEOBJ_SECT_RDATA_Z].size = (uint32_t)strlen(ctx->dasm_ident)+1);
|
||||
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
|
||||
pesect[PEOBJ_SECT_RDATA_Z].flags = 0x40300040;
|
||||
|
||||
/* Fill in PE header. */
|
||||
pehdr.arch = PEOBJ_ARCH_TARGET;
|
||||
pehdr.nsects = PEOBJ_NSECTIONS;
|
||||
pehdr.time = 0; /* Timestamp is optional. */
|
||||
pehdr.symtabofs = sofs;
|
||||
pehdr.opthdrsz = 0;
|
||||
pehdr.flags = 0;
|
||||
|
||||
/* Compute the size of the symbol table:
|
||||
** @feat.00 + nsections*2
|
||||
** + asm_start + nsym
|
||||
** + nrsym
|
||||
*/
|
||||
nrsym = ctx->nrelocsym;
|
||||
pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym;
|
||||
#ifdef PEOBJ_PDATA_NRELOC
|
||||
pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win. */
|
||||
#endif
|
||||
|
||||
/* Write PE object header and all sections. */
|
||||
owrite(ctx, &pehdr, sizeof(PEheader));
|
||||
owrite(ctx, &pesect, sizeof(PEsection)*PEOBJ_NSECTIONS);
|
||||
|
||||
/* Write .text section. */
|
||||
host_endian.u = 1;
|
||||
if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) {
|
||||
fprintf(stderr, "Error: different byte order for host and target\n");
|
||||
exit(1);
|
||||
}
|
||||
owrite(ctx, ctx->code, ctx->codesz);
|
||||
for (i = 0; i < ctx->nreloc; i++) {
|
||||
PEreloc reloc;
|
||||
reloc.vaddr = (uint32_t)ctx->reloc[i].ofs + PEOBJ_RELOC_OFS;
|
||||
reloc.symidx = 1+2+ctx->reloc[i].sym; /* Reloc syms are after .text sym. */
|
||||
reloc.type = ctx->reloc[i].type ? PEOBJ_RELOC_REL32 : PEOBJ_RELOC_DIR32;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
}
|
||||
|
||||
#if LJ_TARGET_X64
|
||||
{ /* Write .pdata section. */
|
||||
uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */
|
||||
PEreloc reloc;
|
||||
pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0;
|
||||
owrite(ctx, &pdata, sizeof(pdata));
|
||||
pdata[0] = fcofs; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 20;
|
||||
owrite(ctx, &pdata, sizeof(pdata));
|
||||
reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2+2+1;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2+2+1;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
reloc.vaddr = 16; reloc.symidx = 1+2+nrsym+2+2+1;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
reloc.vaddr = 20; reloc.symidx = 1+2+nrsym+2;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
}
|
||||
{ /* Write .xdata section. */
|
||||
uint16_t xdata[8+2+6];
|
||||
PEreloc reloc;
|
||||
xdata[0] = 0x01|0x08|0x10; /* Ver. 1, uhandler/ehandler, prolog size 0. */
|
||||
xdata[1] = 0x0005; /* Number of unwind codes, no frame pointer. */
|
||||
xdata[2] = 0x4200; /* Stack offset 4*8+8 = aword*5. */
|
||||
xdata[3] = 0x3000; /* Push rbx. */
|
||||
xdata[4] = 0x6000; /* Push rsi. */
|
||||
xdata[5] = 0x7000; /* Push rdi. */
|
||||
xdata[6] = 0x5000; /* Push rbp. */
|
||||
xdata[7] = 0; /* Alignment. */
|
||||
xdata[8] = xdata[9] = 0; /* Relocated address of exception handler. */
|
||||
xdata[10] = 0x01; /* Ver. 1, no handler, prolog size 0. */
|
||||
xdata[11] = 0x1504; /* Number of unwind codes, fp = rbp, fpofs = 16. */
|
||||
xdata[12] = 0x0300; /* set_fpreg. */
|
||||
xdata[13] = 0x0200; /* stack offset 0*8+8 = aword*1. */
|
||||
xdata[14] = 0x3000; /* Push rbx. */
|
||||
xdata[15] = 0x5000; /* Push rbp. */
|
||||
owrite(ctx, &xdata, sizeof(xdata));
|
||||
reloc.vaddr = 2*8; reloc.symidx = 1+2+nrsym+2+2;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
}
|
||||
#elif LJ_TARGET_ARM64
|
||||
/* https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling */
|
||||
{ /* Write .pdata section. */
|
||||
uint32_t pdata[4];
|
||||
PEreloc reloc;
|
||||
pdata[0] = 0;
|
||||
pdata[1] = 0;
|
||||
pdata[2] = fcofs;
|
||||
pdata[3] = 4+24+4;
|
||||
owrite(ctx, &pdata, sizeof(pdata));
|
||||
/* Start of .text and start of .xdata. */
|
||||
reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
/* Start of vm_ffi_call and start of second part of .xdata. */
|
||||
reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2+2+1;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
}
|
||||
{ /* Write .xdata section. */
|
||||
uint32_t u32;
|
||||
uint8_t *p, uwc[24];
|
||||
PEreloc reloc;
|
||||
|
||||
#define CBE16(x) (*p = ((x) >> 8) & 0xff, p[1] = (x) & 0xff, p += 2)
|
||||
#define CALLOC_S(s) (*p++ = ((s) >> 4)) /* s < 512 */
|
||||
#define CSAVE_FPLR(o) (*p++ = 0x40 | ((o) >> 3)) /* o <= 504 */
|
||||
#define CSAVE_REGP(r,o) CBE16(0xc800 | (((r) - 19) << 6) | ((o) >> 3))
|
||||
#define CSAVE_REGS(r1,r2,o1) do { \
|
||||
int r, o; for (r = r1, o = o1; r <= r2; r += 2, o -= 16) CSAVE_REGP(r, o); \
|
||||
} while (0)
|
||||
#define CSAVE_REGPX(r,o) CBE16(0xcc00 | (((r) - 19) << 6) | (~(o) >> 3))
|
||||
#define CSAVE_FREGP(r,o) CBE16(0xd800 | (((r) - 8) << 6) | ((o) >> 3))
|
||||
#define CSAVE_FREGS(r1,r2,o1) do { \
|
||||
int r, o; for (r = r1, o = o1; r <= r2; r += 2, o -= 16) CSAVE_FREGP(r, o); \
|
||||
} while (0)
|
||||
#define CADD_FP(s) CBE16(0xe200 | ((s) >> 3)) /* s < 8*256 */
|
||||
#define CODE_NOP 0xe3
|
||||
#define CODE_END 0xe4
|
||||
#define CEND_ALIGN do { \
|
||||
*p++ = CODE_END; \
|
||||
while ((p - uwc) & 3) *p++ = CODE_NOP; \
|
||||
} while (0)
|
||||
|
||||
/* Unwind codes for .text section with handler. */
|
||||
p = uwc;
|
||||
CADD_FP(192); /* +2 */
|
||||
CSAVE_REGS(19, 28, 176); /* +5*2 */
|
||||
CSAVE_FREGS(8, 15, 96); /* +4*2 */
|
||||
CSAVE_FPLR(192); /* +1 */
|
||||
CALLOC_S(208); /* +1 */
|
||||
CEND_ALIGN; /* +1 +1 -> 24 */
|
||||
|
||||
u32 = ((24u >> 2) << 27) | (1u << 20) | (fcofs >> 2);
|
||||
owrite(ctx, &u32, 4);
|
||||
owrite(ctx, &uwc, 24);
|
||||
|
||||
u32 = 0; /* Handler RVA to be relocated at 4 + 24. */
|
||||
owrite(ctx, &u32, 4);
|
||||
|
||||
/* Unwind codes for vm_ffi_call without handler. */
|
||||
p = uwc;
|
||||
CADD_FP(16); /* +2 */
|
||||
CSAVE_FPLR(16); /* +1 */
|
||||
CSAVE_REGPX(19, -32); /* +2 */
|
||||
CEND_ALIGN; /* +1 +2 -> 8 */
|
||||
|
||||
u32 = ((8u >> 2) << 27) | (((uint32_t)ctx->codesz - fcofs) >> 2);
|
||||
owrite(ctx, &u32, 4);
|
||||
owrite(ctx, &uwc, 8);
|
||||
|
||||
reloc.vaddr = 4 + 24; reloc.symidx = 1+2+nrsym+2+2;
|
||||
reloc.type = PEOBJ_RELOC_ADDR32NB;
|
||||
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
|
||||
}
|
||||
#elif LJ_TARGET_X86
|
||||
/* Write .sxdata section. */
|
||||
for (i = 0; i < nrsym; i++) {
|
||||
if (!strcmp(ctx->relocsym[i], "_lj_err_unwind_win")) {
|
||||
uint32_t symidx = 1+2+i;
|
||||
owrite(ctx, &symidx, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == nrsym) {
|
||||
fprintf(stderr, "Error: extern lj_err_unwind_win not used\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Write .rdata$Z section. */
|
||||
owrite(ctx, ctx->dasm_ident, strlen(ctx->dasm_ident)+1);
|
||||
|
||||
/* Write symbol table. */
|
||||
strtab = NULL; /* 1st pass: collect string sizes. */
|
||||
for (;;) {
|
||||
strtabofs = 4;
|
||||
/* Mark as SafeSEH compliant. */
|
||||
emit_peobj_sym(ctx, "@feat.00", 1,
|
||||
PEOBJ_SECT_ABS, PEOBJ_TYPE_NULL, PEOBJ_SCL_STATIC);
|
||||
|
||||
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_TEXT);
|
||||
for (i = 0; i < nrsym; i++)
|
||||
emit_peobj_sym(ctx, ctx->relocsym[i], 0,
|
||||
PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
|
||||
|
||||
#ifdef PEOBJ_PDATA_NRELOC
|
||||
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
|
||||
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
|
||||
emit_peobj_sym(ctx, "lj_err_unwind_win", 0,
|
||||
PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
|
||||
#elif LJ_TARGET_X86
|
||||
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_SXDATA);
|
||||
#endif
|
||||
|
||||
emit_peobj_sym(ctx, ctx->beginsym, 0,
|
||||
PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN);
|
||||
for (i = 0; i < ctx->nsym; i++)
|
||||
emit_peobj_sym(ctx, ctx->sym[i].name, (uint32_t)ctx->sym[i].ofs,
|
||||
PEOBJ_SECT_TEXT, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
|
||||
|
||||
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA_Z);
|
||||
|
||||
if (strtab)
|
||||
break;
|
||||
/* 2nd pass: alloc strtab, write syms and copy strings. */
|
||||
strtab = (char *)malloc(strtabofs);
|
||||
*(uint32_t *)strtab = (uint32_t)strtabofs;
|
||||
}
|
||||
|
||||
/* Write string table. */
|
||||
owrite(ctx, strtab, strtabofs);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void emit_peobj(BuildCtx *ctx)
|
||||
{
|
||||
UNUSED(ctx);
|
||||
fprintf(stderr, "Error: no PE object support for this target\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
234
thirdPart/luajit/src/host/genlibbc.lua
Normal file
234
thirdPart/luajit/src/host/genlibbc.lua
Normal file
@@ -0,0 +1,234 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- Lua script to dump the bytecode of the library functions written in Lua.
|
||||
-- The resulting 'buildvm_libbc.h' is used for the build process of LuaJIT.
|
||||
----------------------------------------------------------------------------
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
local ffi = require("ffi")
|
||||
local bit = require("bit")
|
||||
local vmdef = require("jit.vmdef")
|
||||
local bcnames = vmdef.bcnames
|
||||
|
||||
local format = string.format
|
||||
|
||||
local isbe = (string.byte(string.dump(function() end), 5) % 2 == 1)
|
||||
|
||||
local function usage(arg)
|
||||
io.stderr:write("Usage: ", arg and arg[0] or "genlibbc",
|
||||
" [-o buildvm_libbc.h] lib_*.c\n")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local function parse_arg(arg)
|
||||
local outfile = "-"
|
||||
if not (arg and arg[1]) then
|
||||
usage(arg)
|
||||
end
|
||||
if arg[1] == "-o" then
|
||||
outfile = arg[2]
|
||||
if not outfile then usage(arg) end
|
||||
table.remove(arg, 1)
|
||||
table.remove(arg, 1)
|
||||
end
|
||||
return outfile
|
||||
end
|
||||
|
||||
local function read_files(names)
|
||||
local src = ""
|
||||
for _,name in ipairs(names) do
|
||||
local fp = assert(io.open(name))
|
||||
src = src .. fp:read("*a")
|
||||
fp:close()
|
||||
end
|
||||
return src
|
||||
end
|
||||
|
||||
local function transform_lua(code)
|
||||
local fixup = {}
|
||||
local n = -30000
|
||||
code = string.gsub(code, "CHECK_(%w*)%((.-)%)", function(tp, var)
|
||||
n = n + 1
|
||||
fixup[n] = { "CHECK", tp }
|
||||
return format("%s=%d", var, n)
|
||||
end)
|
||||
code = string.gsub(code, "PAIRS%((.-)%)", function(var)
|
||||
fixup.PAIRS = true
|
||||
return format("nil, %s, 0x4dp80", var)
|
||||
end)
|
||||
return "return "..code, fixup
|
||||
end
|
||||
|
||||
local function read_uleb128(p)
|
||||
local v = p[0]; p = p + 1
|
||||
if v >= 128 then
|
||||
local sh = 7; v = v - 128
|
||||
repeat
|
||||
local r = p[0]
|
||||
v = v + bit.lshift(bit.band(r, 127), sh)
|
||||
sh = sh + 7
|
||||
p = p + 1
|
||||
until r < 128
|
||||
end
|
||||
return p, v
|
||||
end
|
||||
|
||||
-- ORDER LJ_T
|
||||
local name2itype = {
|
||||
str = 5, func = 9, tab = 12, int = 14, num = 15
|
||||
}
|
||||
|
||||
local BC, BCN = {}, {}
|
||||
for i=0,#bcnames/6-1 do
|
||||
local name = bcnames:sub(i*6+1, i*6+6):gsub(" ", "")
|
||||
BC[name] = i
|
||||
BCN[i] = name
|
||||
end
|
||||
local xop, xra = isbe and 3 or 0, isbe and 2 or 1
|
||||
local xrc, xrb = isbe and 1 or 2, isbe and 0 or 3
|
||||
|
||||
local function fixup_dump(dump, fixup)
|
||||
local buf = ffi.new("uint8_t[?]", #dump+1, dump)
|
||||
local p = buf+5
|
||||
local n, sizebc
|
||||
p, n = read_uleb128(p)
|
||||
local start = p
|
||||
p = p + 4
|
||||
p = read_uleb128(p)
|
||||
p = read_uleb128(p)
|
||||
p, sizebc = read_uleb128(p)
|
||||
local startbc = tonumber(p - start)
|
||||
local rawtab = {}
|
||||
for i=0,sizebc-1 do
|
||||
local op = p[xop]
|
||||
if op == BC.KSHORT then
|
||||
local rd = p[xrc] + 256*p[xrb]
|
||||
rd = bit.arshift(bit.lshift(rd, 16), 16)
|
||||
local f = fixup[rd]
|
||||
if f then
|
||||
if f[1] == "CHECK" then
|
||||
local tp = f[2]
|
||||
if tp == "tab" then rawtab[p[xra]] = true end
|
||||
p[xop] = tp == "num" and BC.ISNUM or BC.ISTYPE
|
||||
p[xrb] = 0
|
||||
p[xrc] = name2itype[tp]
|
||||
else
|
||||
error("unhandled fixup type: "..f[1])
|
||||
end
|
||||
end
|
||||
elseif op == BC.TGETV then
|
||||
if rawtab[p[xrb]] then
|
||||
p[xop] = BC.TGETR
|
||||
end
|
||||
elseif op == BC.TSETV then
|
||||
if rawtab[p[xrb]] then
|
||||
p[xop] = BC.TSETR
|
||||
end
|
||||
elseif op == BC.ITERC then
|
||||
if fixup.PAIRS then
|
||||
p[xop] = BC.ITERN
|
||||
end
|
||||
end
|
||||
p = p + 4
|
||||
end
|
||||
local ndump = ffi.string(start, n)
|
||||
-- Fixup hi-part of 0x4dp80 to LJ_KEYINDEX.
|
||||
ndump = ndump:gsub("\x80\x80\xcd\xaa\x04", "\xff\xff\xf9\xff\x0f")
|
||||
return { dump = ndump, startbc = startbc, sizebc = sizebc }
|
||||
end
|
||||
|
||||
local function find_defs(src, mode)
|
||||
local defs = {}
|
||||
for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do
|
||||
local tcode, fixup = transform_lua(code)
|
||||
local func = assert(load(tcode, "", mode))
|
||||
defs[name] = fixup_dump(string.dump(func, mode), fixup)
|
||||
defs[#defs+1] = name
|
||||
end
|
||||
return defs
|
||||
end
|
||||
|
||||
local function gen_header(defs32, defs64)
|
||||
local t = {}
|
||||
local function w(x) t[#t+1] = x end
|
||||
w("/* This is a generated file. DO NOT EDIT! */\n\n")
|
||||
w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n")
|
||||
for j,defs in ipairs{defs64, defs32} do
|
||||
local s, sb = "", ""
|
||||
for i,name in ipairs(defs) do
|
||||
local d = defs[name]
|
||||
s = s .. d.dump
|
||||
sb = sb .. string.char(i) .. ("\0"):rep(d.startbc - 1)
|
||||
.. (isbe and "\0\0\0\255" or "\255\0\0\0"):rep(d.sizebc)
|
||||
.. ("\0"):rep(#d.dump - d.startbc - d.sizebc*4)
|
||||
end
|
||||
if j == 1 then
|
||||
w("static const uint8_t libbc_code[] = {\n#if LJ_FR2\n")
|
||||
else
|
||||
w("\n#else\n")
|
||||
end
|
||||
local n = 0
|
||||
for i=1,#s do
|
||||
local x = string.byte(s, i)
|
||||
local xb = string.byte(sb, i)
|
||||
if xb == 255 then
|
||||
local name = BCN[x]
|
||||
local m = #name + 4
|
||||
if n + m > 78 then n = 0; w("\n") end
|
||||
n = n + m
|
||||
w("BC_"); w(name)
|
||||
else
|
||||
local m = x < 10 and 2 or (x < 100 and 3 or 4)
|
||||
if xb == 0 then
|
||||
if n + m > 78 then n = 0; w("\n") end
|
||||
else
|
||||
local name = defs[xb]:gsub("_", ".")
|
||||
if n ~= 0 then w("\n") end
|
||||
w("/* "); w(name); w(" */ ")
|
||||
n = #name + 7
|
||||
end
|
||||
n = n + m
|
||||
w(x)
|
||||
end
|
||||
w(",")
|
||||
end
|
||||
end
|
||||
w("\n#endif\n0\n};\n\n")
|
||||
w("static const struct { const char *name; int ofs; } libbc_map[] = {\n")
|
||||
local m32, m64 = 0, 0
|
||||
for i,name in ipairs(defs32) do
|
||||
assert(name == defs64[i])
|
||||
w('{"'); w(name); w('",'); w(m32) w('},\n')
|
||||
m32 = m32 + #defs32[name].dump
|
||||
m64 = m64 + #defs64[name].dump
|
||||
assert(m32 == m64)
|
||||
end
|
||||
w("{NULL,"); w(m32); w("}\n};\n\n")
|
||||
return table.concat(t)
|
||||
end
|
||||
|
||||
local function write_file(name, data)
|
||||
if name == "-" then
|
||||
assert(io.write(data))
|
||||
assert(io.flush())
|
||||
else
|
||||
local fp = io.open(name)
|
||||
if fp then
|
||||
local old = fp:read("*a")
|
||||
fp:close()
|
||||
if data == old then return end
|
||||
end
|
||||
fp = assert(io.open(name, "w"))
|
||||
assert(fp:write(data))
|
||||
assert(fp:close())
|
||||
end
|
||||
end
|
||||
|
||||
local outfile = parse_arg(arg)
|
||||
local src = read_files(arg)
|
||||
local defs32 = find_defs(src, "Wdts")
|
||||
local defs64 = find_defs(src, "Xdts")
|
||||
local hdr = gen_header(defs32, defs64)
|
||||
write_file(outfile, hdr)
|
||||
|
||||
436
thirdPart/luajit/src/host/genminilua.lua
Normal file
436
thirdPart/luajit/src/host/genminilua.lua
Normal file
@@ -0,0 +1,436 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- Lua script to generate a customized, minified version of Lua.
|
||||
-- The resulting 'minilua' is used for the build process of LuaJIT.
|
||||
----------------------------------------------------------------------------
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
local sub, match, gsub = string.sub, string.match, string.gsub
|
||||
|
||||
local LUA_VERSION = "5.1.5"
|
||||
local LUA_SOURCE
|
||||
|
||||
local function usage()
|
||||
io.stderr:write("Usage: ", arg and arg[0] or "genminilua",
|
||||
" lua-", LUA_VERSION, "-source-dir\n")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local function find_sources()
|
||||
LUA_SOURCE = arg and arg[1]
|
||||
if not LUA_SOURCE then usage() end
|
||||
if sub(LUA_SOURCE, -1) ~= "/" then LUA_SOURCE = LUA_SOURCE.."/" end
|
||||
local fp = io.open(LUA_SOURCE .. "lua.h")
|
||||
if not fp then
|
||||
LUA_SOURCE = LUA_SOURCE.."src/"
|
||||
fp = io.open(LUA_SOURCE .. "lua.h")
|
||||
if not fp then usage() end
|
||||
end
|
||||
local all = fp:read("*a")
|
||||
fp:close()
|
||||
if not match(all, 'LUA_RELEASE%s*"Lua '..LUA_VERSION..'"') then
|
||||
io.stderr:write("Error: version mismatch\n")
|
||||
usage()
|
||||
end
|
||||
end
|
||||
|
||||
local LUA_FILES = {
|
||||
"lmem.c", "lobject.c", "ltm.c", "lfunc.c", "ldo.c", "lstring.c", "ltable.c",
|
||||
"lgc.c", "lstate.c", "ldebug.c", "lzio.c", "lopcodes.c",
|
||||
"llex.c", "lcode.c", "lparser.c", "lvm.c", "lapi.c", "lauxlib.c",
|
||||
"lbaselib.c", "ltablib.c", "liolib.c", "loslib.c", "lstrlib.c", "linit.c",
|
||||
}
|
||||
|
||||
local REMOVE_LIB = {}
|
||||
gsub([[
|
||||
collectgarbage dofile gcinfo getfenv getmetatable load print rawequal rawset
|
||||
select tostring xpcall
|
||||
foreach foreachi getn maxn setn
|
||||
popen tmpfile seek setvbuf __tostring
|
||||
clock date difftime execute getenv rename setlocale time tmpname
|
||||
dump gfind len reverse
|
||||
LUA_LOADLIBNAME LUA_MATHLIBNAME LUA_DBLIBNAME
|
||||
]], "%S+", function(name)
|
||||
REMOVE_LIB[name] = true
|
||||
end)
|
||||
|
||||
local REMOVE_EXTINC = { ["<assert.h>"] = true, ["<locale.h>"] = true, }
|
||||
|
||||
local CUSTOM_MAIN = [[
|
||||
typedef unsigned int UB;
|
||||
static UB barg(lua_State *L,int idx){
|
||||
union{lua_Number n;U64 b;}bn;
|
||||
bn.n=lua_tonumber(L,idx)+6755399441055744.0;
|
||||
if (bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number");
|
||||
return(UB)bn.b;
|
||||
}
|
||||
#define BRET(b) lua_pushnumber(L,(lua_Number)(int)(b));return 1;
|
||||
static int tobit(lua_State *L){
|
||||
BRET(barg(L,1))}
|
||||
static int bnot(lua_State *L){
|
||||
BRET(~barg(L,1))}
|
||||
static int band(lua_State *L){
|
||||
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)}
|
||||
static int bor(lua_State *L){
|
||||
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)}
|
||||
static int bxor(lua_State *L){
|
||||
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)}
|
||||
static int lshift(lua_State *L){
|
||||
UB b=barg(L,1),n=barg(L,2)&31;BRET(b<<n)}
|
||||
static int rshift(lua_State *L){
|
||||
UB b=barg(L,1),n=barg(L,2)&31;BRET(b>>n)}
|
||||
static int arshift(lua_State *L){
|
||||
UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)}
|
||||
static int rol(lua_State *L){
|
||||
UB b=barg(L,1),n=barg(L,2)&31;BRET((b<<n)|(b>>(32-n)))}
|
||||
static int ror(lua_State *L){
|
||||
UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))}
|
||||
static int bswap(lua_State *L){
|
||||
UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)}
|
||||
static int tohex(lua_State *L){
|
||||
UB b=barg(L,1);
|
||||
int n=lua_isnone(L,2)?8:(int)barg(L,2);
|
||||
const char *hexdigits="0123456789abcdef";
|
||||
char buf[8];
|
||||
int i;
|
||||
if(n<0){n=-n;hexdigits="0123456789ABCDEF";}
|
||||
if(n>8)n=8;
|
||||
for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;}
|
||||
lua_pushlstring(L,buf,(size_t)n);
|
||||
return 1;
|
||||
}
|
||||
static const struct luaL_Reg bitlib[] = {
|
||||
{"tobit",tobit},
|
||||
{"bnot",bnot},
|
||||
{"band",band},
|
||||
{"bor",bor},
|
||||
{"bxor",bxor},
|
||||
{"lshift",lshift},
|
||||
{"rshift",rshift},
|
||||
{"arshift",arshift},
|
||||
{"rol",rol},
|
||||
{"ror",ror},
|
||||
{"bswap",bswap},
|
||||
{"tohex",tohex},
|
||||
{NULL,NULL}
|
||||
};
|
||||
int main(int argc, char **argv){
|
||||
lua_State *L = luaL_newstate();
|
||||
int i;
|
||||
luaL_openlibs(L);
|
||||
luaL_register(L, "bit", bitlib);
|
||||
if (argc < 2) return sizeof(void *);
|
||||
lua_createtable(L, 0, 1);
|
||||
lua_pushstring(L, argv[1]);
|
||||
lua_rawseti(L, -2, 0);
|
||||
lua_setglobal(L, "arg");
|
||||
if (luaL_loadfile(L, argv[1]))
|
||||
goto err;
|
||||
for (i = 2; i < argc; i++)
|
||||
lua_pushstring(L, argv[i]);
|
||||
if (lua_pcall(L, argc - 2, 0, 0)) {
|
||||
err:
|
||||
fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
|
||||
return 1;
|
||||
}
|
||||
lua_close(L);
|
||||
return 0;
|
||||
}
|
||||
]]
|
||||
|
||||
local function read_sources()
|
||||
local t = {}
|
||||
for i, name in ipairs(LUA_FILES) do
|
||||
local fp = assert(io.open(LUA_SOURCE..name, "r"))
|
||||
t[i] = fp:read("*a")
|
||||
assert(fp:close())
|
||||
end
|
||||
t[#t+1] = CUSTOM_MAIN
|
||||
return table.concat(t)
|
||||
end
|
||||
|
||||
local includes = {}
|
||||
|
||||
local function merge_includes(src)
|
||||
return gsub(src, '#include%s*"([^"]*)"%s*\n', function(name)
|
||||
if includes[name] then return "" end
|
||||
includes[name] = true
|
||||
local fp = assert(io.open(LUA_SOURCE..name, "r"))
|
||||
local inc = fp:read("*a")
|
||||
assert(fp:close())
|
||||
inc = gsub(inc, "#ifndef%s+%w+_h\n#define%s+%w+_h\n", "")
|
||||
inc = gsub(inc, "#endif%s*$", "")
|
||||
return merge_includes(inc)
|
||||
end)
|
||||
end
|
||||
|
||||
local function get_license(src)
|
||||
return match(src, "/%*+\n%* Copyright %(.-%*/\n")
|
||||
end
|
||||
|
||||
local function fold_lines(src)
|
||||
return gsub(src, "\\\n", " ")
|
||||
end
|
||||
|
||||
local strings = {}
|
||||
|
||||
local function save_str(str)
|
||||
local n = #strings+1
|
||||
strings[n] = str
|
||||
return "\1"..n.."\2"
|
||||
end
|
||||
|
||||
local function save_strings(src)
|
||||
src = gsub(src, '"[^"\n]*"', save_str)
|
||||
return gsub(src, "'[^'\n]*'", save_str)
|
||||
end
|
||||
|
||||
local function restore_strings(src)
|
||||
return gsub(src, "\1(%d+)\2", function(numstr)
|
||||
return strings[tonumber(numstr)]
|
||||
end)
|
||||
end
|
||||
|
||||
local function def_istrue(def)
|
||||
return def == "INT_MAX > 2147483640L" or
|
||||
def == "LUAI_BITSINT >= 32" or
|
||||
def == "SIZE_Bx < LUAI_BITSINT-1" or
|
||||
def == "cast" or
|
||||
def == "defined(LUA_CORE)" or
|
||||
def == "MINSTRTABSIZE" or
|
||||
def == "LUA_MINBUFFER" or
|
||||
def == "HARDSTACKTESTS" or
|
||||
def == "UNUSED"
|
||||
end
|
||||
|
||||
local head, defs = {[[
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned __int64 U64;
|
||||
#else
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
int _CRT_glob = 0;
|
||||
]]}, {}
|
||||
|
||||
local function preprocess(src)
|
||||
local t = { match(src, "^(.-)#") }
|
||||
local lvl, on, oldon = 0, true, {}
|
||||
for pp, def, txt in string.gmatch(src, "#(%w+) *([^\n]*)\n([^#]*)") do
|
||||
if pp == "if" or pp == "ifdef" or pp == "ifndef" then
|
||||
lvl = lvl + 1
|
||||
oldon[lvl] = on
|
||||
on = def_istrue(def)
|
||||
elseif pp == "else" then
|
||||
if oldon[lvl] then
|
||||
if on == false then on = true else on = false end
|
||||
end
|
||||
elseif pp == "elif" then
|
||||
if oldon[lvl] then
|
||||
on = def_istrue(def)
|
||||
end
|
||||
elseif pp == "endif" then
|
||||
on = oldon[lvl]
|
||||
lvl = lvl - 1
|
||||
elseif on then
|
||||
if pp == "include" then
|
||||
if not head[def] and not REMOVE_EXTINC[def] then
|
||||
head[def] = true
|
||||
head[#head+1] = "#include "..def.."\n"
|
||||
end
|
||||
elseif pp == "define" then
|
||||
local k, sp, v = match(def, "([%w_]+)(%s*)(.*)")
|
||||
if k and not (sp == "" and sub(v, 1, 1) == "(") then
|
||||
defs[k] = gsub(v, "%a[%w_]*", function(tok)
|
||||
return defs[tok] or tok
|
||||
end)
|
||||
else
|
||||
t[#t+1] = "#define "..def.."\n"
|
||||
end
|
||||
elseif pp ~= "undef" then
|
||||
error("unexpected directive: "..pp.." "..def)
|
||||
end
|
||||
end
|
||||
if on then t[#t+1] = txt end
|
||||
end
|
||||
return gsub(table.concat(t), "%a[%w_]*", function(tok)
|
||||
return defs[tok] or tok
|
||||
end)
|
||||
end
|
||||
|
||||
local function merge_header(src, license)
|
||||
local hdr = string.format([[
|
||||
/* This is a heavily customized and minimized copy of Lua %s. */
|
||||
/* It's only used to build LuaJIT. It does NOT have all standard functions! */
|
||||
]], LUA_VERSION)
|
||||
return hdr..license..table.concat(head)..src
|
||||
end
|
||||
|
||||
local function strip_unused1(src)
|
||||
return gsub(src, '( {"?([%w_]+)"?,%s+%a[%w_]*},\n)', function(line, func)
|
||||
return REMOVE_LIB[func] and "" or line
|
||||
end)
|
||||
end
|
||||
|
||||
local function strip_unused2(src)
|
||||
return gsub(src, "Symbolic Execution.-}=", "")
|
||||
end
|
||||
|
||||
local function strip_unused3(src)
|
||||
src = gsub(src, "extern", "static")
|
||||
src = gsub(src, "\nstatic([^\n]-)%(([^)]*)%)%(", "\nstatic%1 %2(")
|
||||
src = gsub(src, "#define lua_assert[^\n]*\n", "")
|
||||
src = gsub(src, "lua_assert%b();?", "")
|
||||
src = gsub(src, "default:\n}", "default:;\n}")
|
||||
src = gsub(src, "lua_lock%b();", "")
|
||||
src = gsub(src, "lua_unlock%b();", "")
|
||||
src = gsub(src, "luai_threadyield%b();", "")
|
||||
src = gsub(src, "luai_userstateopen%b();", "{}")
|
||||
src = gsub(src, "luai_userstate%w+%b();", "")
|
||||
src = gsub(src, "%(%(c==.*luaY_parser%)", "luaY_parser")
|
||||
src = gsub(src, "trydecpoint%(ls,seminfo%)",
|
||||
"luaX_lexerror(ls,\"malformed number\",TK_NUMBER)")
|
||||
src = gsub(src, "int c=luaZ_lookahead%b();", "")
|
||||
src = gsub(src, "luaL_register%(L,[^,]*,co_funcs%);\nreturn 2;",
|
||||
"return 1;")
|
||||
src = gsub(src, "getfuncname%b():", "NULL:")
|
||||
src = gsub(src, "getobjname%b():", "NULL:")
|
||||
src = gsub(src, "if%([^\n]*hookmask[^\n]*%)\n[^\n]*\n", "")
|
||||
src = gsub(src, "if%([^\n]*hookmask[^\n]*%)%b{}\n", "")
|
||||
src = gsub(src, "if%([^\n]*hookmask[^\n]*&&\n[^\n]*%b{}\n", "")
|
||||
src = gsub(src, "(twoto%b()%()", "%1(size_t)")
|
||||
src = gsub(src, "i<sizenode", "i<(int)sizenode")
|
||||
src = gsub(src, "cast%(unsigned int,key%-1%)", "cast(unsigned int,key)-1")
|
||||
return gsub(src, "\n\n+", "\n")
|
||||
end
|
||||
|
||||
local function strip_comments(src)
|
||||
return gsub(src, "/%*.-%*/", " ")
|
||||
end
|
||||
|
||||
local function strip_whitespace(src)
|
||||
src = gsub(src, "^%s+", "")
|
||||
src = gsub(src, "%s*\n%s*", "\n")
|
||||
src = gsub(src, "[ \t]+", " ")
|
||||
src = gsub(src, "(%W) ", "%1")
|
||||
return gsub(src, " (%W)", "%1")
|
||||
end
|
||||
|
||||
local function rename_tokens1(src)
|
||||
src = gsub(src, "getline", "getline_")
|
||||
src = gsub(src, "struct ([%w_]+)", "ZX%1")
|
||||
return gsub(src, "union ([%w_]+)", "ZY%1")
|
||||
end
|
||||
|
||||
local function rename_tokens2(src)
|
||||
src = gsub(src, "ZX([%w_]+)", "struct %1")
|
||||
return gsub(src, "ZY([%w_]+)", "union %1")
|
||||
end
|
||||
|
||||
local function fix_bugs_and_warnings(src)
|
||||
src = gsub(src, "(luaD_checkstack%(L,p%->maxstacksize)%)", "%1+p->numparams)")
|
||||
src = gsub(src, "if%(sep==%-1%)(return'%[';)\nelse (luaX_lexerror%b();)", "if (sep!=-1)%2\n%1")
|
||||
return gsub(src, "(default:{\nNode%*n=mainposition)", "/*fallthrough*/\n%1")
|
||||
end
|
||||
|
||||
local function func_gather(src)
|
||||
local nodes, list = {}, {}
|
||||
local pos, len = 1, #src
|
||||
while pos < len do
|
||||
local d, w = match(src, "^(#define ([%w_]+)[^\n]*\n)", pos)
|
||||
if d then
|
||||
local n = #list+1
|
||||
list[n] = d
|
||||
nodes[w] = n
|
||||
else
|
||||
local s
|
||||
d, w, s = match(src, "^(([%w_]+)[^\n]*([{;])\n)", pos)
|
||||
if not d then
|
||||
d, w, s = match(src, "^(([%w_]+)[^(]*%b()([{;])\n)", pos)
|
||||
if not d then d = match(src, "^[^\n]*\n", pos) end
|
||||
end
|
||||
if s == "{" then
|
||||
d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
|
||||
if sub(d, -2) == "{\n" then
|
||||
d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
|
||||
end
|
||||
end
|
||||
local k, v = nil, d
|
||||
if w == "typedef" then
|
||||
if match(d, "^typedef enum") then
|
||||
head[#head+1] = d
|
||||
else
|
||||
k = match(d, "([%w_]+);\n$")
|
||||
if not k then k = match(d, "^.-%(.-([%w_]+)%)%(") end
|
||||
end
|
||||
elseif w == "enum" then
|
||||
head[#head+1] = v
|
||||
elseif w ~= nil then
|
||||
k = match(d, "^[^\n]-([%w_]+)[(%[=]")
|
||||
if k then
|
||||
if w ~= "static" and k ~= "main" then v = "static "..d end
|
||||
else
|
||||
k = w
|
||||
end
|
||||
end
|
||||
if w and k then
|
||||
local o = nodes[k]
|
||||
if o then nodes["*"..k] = o end
|
||||
local n = #list+1
|
||||
list[n] = v
|
||||
nodes[k] = n
|
||||
end
|
||||
end
|
||||
pos = pos + #d
|
||||
end
|
||||
return nodes, list
|
||||
end
|
||||
|
||||
local function func_visit(nodes, list, used, n)
|
||||
local i = nodes[n]
|
||||
for m in string.gmatch(list[i], "[%w_]+") do
|
||||
if nodes[m] then
|
||||
local j = used[m]
|
||||
if not j then
|
||||
used[m] = i
|
||||
func_visit(nodes, list, used, m)
|
||||
elseif i < j then
|
||||
used[m] = i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function func_collect(src)
|
||||
local nodes, list = func_gather(src)
|
||||
local used = {}
|
||||
func_visit(nodes, list, used, "main")
|
||||
for n,i in pairs(nodes) do
|
||||
local j = used[n]
|
||||
if j and j < i then used["*"..n] = j end
|
||||
end
|
||||
for n,i in pairs(nodes) do
|
||||
if not used[n] then list[i] = "" end
|
||||
end
|
||||
return table.concat(list)
|
||||
end
|
||||
|
||||
find_sources()
|
||||
local src = read_sources()
|
||||
src = merge_includes(src)
|
||||
local license = get_license(src)
|
||||
src = fold_lines(src)
|
||||
src = strip_unused1(src)
|
||||
src = save_strings(src)
|
||||
src = strip_unused2(src)
|
||||
src = strip_comments(src)
|
||||
src = preprocess(src)
|
||||
src = strip_whitespace(src)
|
||||
src = strip_unused3(src)
|
||||
src = rename_tokens1(src)
|
||||
src = func_collect(src)
|
||||
src = rename_tokens2(src)
|
||||
src = restore_strings(src)
|
||||
src = fix_bugs_and_warnings(src)
|
||||
src = merge_header(src, license)
|
||||
io.write(src)
|
||||
45
thirdPart/luajit/src/host/genversion.lua
Normal file
45
thirdPart/luajit/src/host/genversion.lua
Normal file
@@ -0,0 +1,45 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- Lua script to embed the rolling release version in luajit.h.
|
||||
----------------------------------------------------------------------------
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
local arg = {...}
|
||||
local FILE_ROLLING_H = arg[1] or "luajit_rolling.h"
|
||||
local FILE_RELVER_TXT = arg[2] or "luajit_relver.txt"
|
||||
local FILE_LUAJIT_H = arg[3] or "luajit.h"
|
||||
|
||||
local function file_read(file)
|
||||
local fp = assert(io.open(file, "rb"), "run from the wrong directory")
|
||||
local data = assert(fp:read("*a"))
|
||||
fp:close()
|
||||
return data
|
||||
end
|
||||
|
||||
local function file_write_mod(file, data)
|
||||
local fp = io.open(file, "rb")
|
||||
if fp then
|
||||
local odata = assert(fp:read("*a"))
|
||||
fp:close()
|
||||
if odata == data then return end
|
||||
end
|
||||
fp = assert(io.open(file, "wb"))
|
||||
assert(fp:write(data))
|
||||
assert(fp:close())
|
||||
end
|
||||
|
||||
local text = file_read(FILE_ROLLING_H):gsub("#error.-\n", "")
|
||||
local relver = file_read(FILE_RELVER_TXT):match("(%d+)")
|
||||
|
||||
if relver then
|
||||
text = text:gsub("ROLLING", relver)
|
||||
else
|
||||
io.stderr:write([[
|
||||
**** WARNING Cannot determine rolling release version from git log.
|
||||
**** WARNING The 'git' command must be available during the build.
|
||||
]])
|
||||
file_write_mod(FILE_RELVER_TXT, "ROLLING\n") -- Fallback for install target.
|
||||
end
|
||||
|
||||
file_write_mod(FILE_LUAJIT_H, text)
|
||||
7771
thirdPart/luajit/src/host/minilua.c
Normal file
7771
thirdPart/luajit/src/host/minilua.c
Normal file
File diff suppressed because it is too large
Load Diff
1
thirdPart/luajit/src/jit/.gitignore
vendored
Normal file
1
thirdPart/luajit/src/jit/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
vmdef.lua
|
||||
189
thirdPart/luajit/src/jit/bc.lua
Normal file
189
thirdPart/luajit/src/jit/bc.lua
Normal file
@@ -0,0 +1,189 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT bytecode listing module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- This module lists the bytecode of a Lua function. If it's loaded by -jbc
|
||||
-- it hooks into the parser and lists all functions of a chunk as they
|
||||
-- are parsed.
|
||||
--
|
||||
-- Example usage:
|
||||
--
|
||||
-- luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)'
|
||||
-- luajit -jbc=- foo.lua
|
||||
-- luajit -jbc=foo.list foo.lua
|
||||
--
|
||||
-- Default output is to stderr. To redirect the output to a file, pass a
|
||||
-- filename as an argument (use '-' for stdout) or set the environment
|
||||
-- variable LUAJIT_LISTFILE. The file is overwritten every time the module
|
||||
-- is started.
|
||||
--
|
||||
-- This module can also be used programmatically:
|
||||
--
|
||||
-- local bc = require("jit.bc")
|
||||
--
|
||||
-- local function foo() print("hello") end
|
||||
--
|
||||
-- bc.dump(foo) --> -- BYTECODE -- [...]
|
||||
-- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello"
|
||||
--
|
||||
-- local out = {
|
||||
-- -- Do something with each line:
|
||||
-- write = function(t, ...) io.write(...) end,
|
||||
-- close = function(t) end,
|
||||
-- flush = function(t) end,
|
||||
-- }
|
||||
-- bc.dump(foo, out)
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Cache some library functions and objects.
|
||||
local jit = require("jit")
|
||||
local jutil = require("jit.util")
|
||||
local vmdef = require("jit.vmdef")
|
||||
local bit = require("bit")
|
||||
local sub, gsub, format = string.sub, string.gsub, string.format
|
||||
local byte, band, shr = string.byte, bit.band, bit.rshift
|
||||
local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck
|
||||
local funcuvname = jutil.funcuvname
|
||||
local bcnames = vmdef.bcnames
|
||||
local stdout, stderr = io.stdout, io.stderr
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local function ctlsub(c)
|
||||
if c == "\n" then return "\\n"
|
||||
elseif c == "\r" then return "\\r"
|
||||
elseif c == "\t" then return "\\t"
|
||||
else return format("\\%03d", byte(c))
|
||||
end
|
||||
end
|
||||
|
||||
-- Return one bytecode line.
|
||||
local function bcline(func, pc, prefix)
|
||||
local ins, m = funcbc(func, pc)
|
||||
if not ins then return end
|
||||
local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128)
|
||||
local a = band(shr(ins, 8), 0xff)
|
||||
local oidx = 6*band(ins, 0xff)
|
||||
local op = sub(bcnames, oidx+1, oidx+6)
|
||||
local s = format("%04d %s %-6s %3s ",
|
||||
pc, prefix or " ", op, ma == 0 and "" or a)
|
||||
local d = shr(ins, 16)
|
||||
if mc == 13*128 then -- BCMjump
|
||||
return format("%s=> %04d\n", s, pc+d-0x7fff)
|
||||
end
|
||||
if mb ~= 0 then
|
||||
d = band(d, 0xff)
|
||||
elseif mc == 0 then
|
||||
return s.."\n"
|
||||
end
|
||||
local kc
|
||||
if mc == 10*128 then -- BCMstr
|
||||
kc = funck(func, -d-1)
|
||||
kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub))
|
||||
elseif mc == 9*128 then -- BCMnum
|
||||
kc = funck(func, d)
|
||||
if op == "TSETM " then kc = kc - 2^52 end
|
||||
elseif mc == 12*128 then -- BCMfunc
|
||||
local fi = funcinfo(funck(func, -d-1))
|
||||
if fi.ffid then
|
||||
kc = vmdef.ffnames[fi.ffid]
|
||||
else
|
||||
kc = fi.loc
|
||||
end
|
||||
elseif mc == 5*128 then -- BCMuv
|
||||
kc = funcuvname(func, d)
|
||||
end
|
||||
if ma == 5 then -- BCMuv
|
||||
local ka = funcuvname(func, a)
|
||||
if kc then kc = ka.." ; "..kc else kc = ka end
|
||||
end
|
||||
if mb ~= 0 then
|
||||
local b = shr(ins, 24)
|
||||
if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end
|
||||
return format("%s%3d %3d\n", s, b, d)
|
||||
end
|
||||
if kc then return format("%s%3d ; %s\n", s, d, kc) end
|
||||
if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits
|
||||
return format("%s%3d\n", s, d)
|
||||
end
|
||||
|
||||
-- Collect branch targets of a function.
|
||||
local function bctargets(func)
|
||||
local target = {}
|
||||
for pc=1,1000000000 do
|
||||
local ins, m = funcbc(func, pc)
|
||||
if not ins then break end
|
||||
if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end
|
||||
end
|
||||
return target
|
||||
end
|
||||
|
||||
-- Dump bytecode instructions of a function.
|
||||
local function bcdump(func, out, all)
|
||||
if not out then out = stdout end
|
||||
local fi = funcinfo(func)
|
||||
if all and fi.children then
|
||||
for n=-1,-1000000000,-1 do
|
||||
local k = funck(func, n)
|
||||
if not k then break end
|
||||
if type(k) == "proto" then bcdump(k, out, true) end
|
||||
end
|
||||
end
|
||||
out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined))
|
||||
local target = bctargets(func)
|
||||
for pc=1,1000000000 do
|
||||
local s = bcline(func, pc, target[pc] and "=>")
|
||||
if not s then break end
|
||||
out:write(s)
|
||||
end
|
||||
out:write("\n")
|
||||
out:flush()
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Active flag and output file handle.
|
||||
local active, out
|
||||
|
||||
-- List handler.
|
||||
local function h_list(func)
|
||||
return bcdump(func, out)
|
||||
end
|
||||
|
||||
-- Detach list handler.
|
||||
local function bclistoff()
|
||||
if active then
|
||||
active = false
|
||||
jit.attach(h_list)
|
||||
if out and out ~= stdout and out ~= stderr then out:close() end
|
||||
out = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Open the output file and attach list handler.
|
||||
local function bcliston(outfile)
|
||||
if active then bclistoff() end
|
||||
if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end
|
||||
if outfile then
|
||||
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
|
||||
else
|
||||
out = stderr
|
||||
end
|
||||
jit.attach(h_list, "bc")
|
||||
active = true
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
return {
|
||||
line = bcline,
|
||||
dump = bcdump,
|
||||
targets = bctargets,
|
||||
on = bcliston,
|
||||
off = bclistoff,
|
||||
start = bcliston -- For -j command line option.
|
||||
}
|
||||
|
||||
629
thirdPart/luajit/src/jit/bcsave.lua
Normal file
629
thirdPart/luajit/src/jit/bcsave.lua
Normal file
@@ -0,0 +1,629 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT module to save/list bytecode.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- This module saves or lists the bytecode for an input file.
|
||||
-- It's run by the -b command line option.
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local jit = require("jit")
|
||||
assert(jit.version_num == 20199, "LuaJIT core/library version mismatch")
|
||||
local bit = require("bit")
|
||||
|
||||
-- Symbol name prefix for LuaJIT bytecode.
|
||||
local LJBC_PREFIX = "luaJIT_BC_"
|
||||
|
||||
local type, assert = type, assert
|
||||
local format = string.format
|
||||
local tremove, tconcat = table.remove, table.concat
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local function usage()
|
||||
io.stderr:write[[
|
||||
Save LuaJIT bytecode: luajit -b[options] input output
|
||||
-l Only list bytecode.
|
||||
-s Strip debug info (default).
|
||||
-g Keep debug info.
|
||||
-W Generate 32 bit (non-GC64) bytecode.
|
||||
-X Generate 64 bit (GC64) bytecode.
|
||||
-d Generate bytecode in deterministic manner.
|
||||
-n name Set module name (default: auto-detect from input name).
|
||||
-t type Set output file type (default: auto-detect from output name).
|
||||
-a arch Override architecture for object files (default: native).
|
||||
-o os Override OS for object files (default: native).
|
||||
-F name Override filename (default: input filename).
|
||||
-e chunk Use chunk string as input.
|
||||
-- Stop handling options.
|
||||
- Use stdin as input and/or stdout as output.
|
||||
|
||||
File types: c cc h obj o raw (default)
|
||||
]]
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local function check(ok, ...)
|
||||
if ok then return ok, ... end
|
||||
io.stderr:write("luajit: ", ...)
|
||||
io.stderr:write("\n")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local function readfile(ctx, input)
|
||||
if ctx.string then
|
||||
return check(loadstring(input, nil, ctx.mode))
|
||||
elseif ctx.filename then
|
||||
local data
|
||||
if input == "-" then
|
||||
data = io.stdin:read("*a")
|
||||
else
|
||||
local fp = assert(io.open(input, "rb"))
|
||||
data = assert(fp:read("*a"))
|
||||
assert(fp:close())
|
||||
end
|
||||
return check(load(data, ctx.filename, ctx.mode))
|
||||
else
|
||||
if input == "-" then input = nil end
|
||||
return check(loadfile(input, ctx.mode))
|
||||
end
|
||||
end
|
||||
|
||||
local function savefile(name, mode)
|
||||
if name == "-" then return io.stdout end
|
||||
return check(io.open(name, mode))
|
||||
end
|
||||
|
||||
local function set_stdout_binary(ffi)
|
||||
ffi.cdef[[int _setmode(int fd, int mode);]]
|
||||
ffi.C._setmode(1, 0x8000)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_type = {
|
||||
raw = "raw", c = "c", cc = "c", h = "h", o = "obj", obj = "obj",
|
||||
}
|
||||
|
||||
local map_arch = {
|
||||
x86 = { e = "le", b = 32, m = 3, p = 0x14c, },
|
||||
x64 = { e = "le", b = 64, m = 62, p = 0x8664, },
|
||||
arm = { e = "le", b = 32, m = 40, p = 0x1c0, },
|
||||
arm64 = { e = "le", b = 64, m = 183, p = 0xaa64, },
|
||||
arm64be = { e = "be", b = 64, m = 183, },
|
||||
ppc = { e = "be", b = 32, m = 20, },
|
||||
mips = { e = "be", b = 32, m = 8, f = 0x50001006, },
|
||||
mipsel = { e = "le", b = 32, m = 8, f = 0x50001006, },
|
||||
mips64 = { e = "be", b = 64, m = 8, f = 0x80000007, },
|
||||
mips64el = { e = "le", b = 64, m = 8, f = 0x80000007, },
|
||||
mips64r6 = { e = "be", b = 64, m = 8, f = 0xa0000407, },
|
||||
mips64r6el = { e = "le", b = 64, m = 8, f = 0xa0000407, },
|
||||
}
|
||||
|
||||
local map_os = {
|
||||
linux = true, windows = true, osx = true, freebsd = true, netbsd = true,
|
||||
openbsd = true, dragonfly = true, solaris = true,
|
||||
}
|
||||
|
||||
local function checkarg(str, map, err)
|
||||
str = str:lower()
|
||||
local s = check(map[str], "unknown ", err)
|
||||
return type(s) == "string" and s or str
|
||||
end
|
||||
|
||||
local function detecttype(str)
|
||||
local ext = str:lower():match("%.(%a+)$")
|
||||
return map_type[ext] or "raw"
|
||||
end
|
||||
|
||||
local function checkmodname(str)
|
||||
check(str:match("^[%w_.%-]+$"), "bad module name")
|
||||
return str:gsub("[%.%-]", "_")
|
||||
end
|
||||
|
||||
local function detectmodname(str)
|
||||
if type(str) == "string" then
|
||||
local tail = str:match("[^/\\]+$")
|
||||
if tail then str = tail end
|
||||
local head = str:match("^(.*)%.[^.]*$")
|
||||
if head then str = head end
|
||||
str = str:match("^[%w_.%-]+")
|
||||
else
|
||||
str = nil
|
||||
end
|
||||
check(str, "cannot derive module name, use -n name")
|
||||
return str:gsub("[%.%-]", "_")
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local function bcsave_tail(fp, output, s)
|
||||
local ok, err = fp:write(s)
|
||||
if ok and output ~= "-" then ok, err = fp:close() end
|
||||
check(ok, "cannot write ", output, ": ", err)
|
||||
end
|
||||
|
||||
local function bcsave_raw(output, s)
|
||||
if output == "-" and jit.os == "Windows" then
|
||||
local ok, ffi = pcall(require, "ffi")
|
||||
check(ok, "FFI library required to write binary file to stdout")
|
||||
set_stdout_binary(ffi)
|
||||
end
|
||||
local fp = savefile(output, "wb")
|
||||
bcsave_tail(fp, output, s)
|
||||
end
|
||||
|
||||
local function bcsave_c(ctx, output, s)
|
||||
local fp = savefile(output, "w")
|
||||
if ctx.type == "c" then
|
||||
fp:write(format([[
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
const unsigned char %s%s[] = {
|
||||
]], LJBC_PREFIX, ctx.modname))
|
||||
else
|
||||
fp:write(format([[
|
||||
#define %s%s_SIZE %d
|
||||
static const unsigned char %s%s[] = {
|
||||
]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname))
|
||||
end
|
||||
local t, n, m = {}, 0, 0
|
||||
for i=1,#s do
|
||||
local b = tostring(string.byte(s, i))
|
||||
m = m + #b + 1
|
||||
if m > 78 then
|
||||
fp:write(tconcat(t, ",", 1, n), ",\n")
|
||||
n, m = 0, #b + 1
|
||||
end
|
||||
n = n + 1
|
||||
t[n] = b
|
||||
end
|
||||
bcsave_tail(fp, output, tconcat(t, ",", 1, n).."\n};\n")
|
||||
end
|
||||
|
||||
local function bcsave_elfobj(ctx, output, s, ffi)
|
||||
ffi.cdef[[
|
||||
typedef struct {
|
||||
uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
|
||||
uint16_t type, machine;
|
||||
uint32_t version;
|
||||
uint32_t entry, phofs, shofs;
|
||||
uint32_t flags;
|
||||
uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
|
||||
} ELF32header;
|
||||
typedef struct {
|
||||
uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
|
||||
uint16_t type, machine;
|
||||
uint32_t version;
|
||||
uint64_t entry, phofs, shofs;
|
||||
uint32_t flags;
|
||||
uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
|
||||
} ELF64header;
|
||||
typedef struct {
|
||||
uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize;
|
||||
} ELF32sectheader;
|
||||
typedef struct {
|
||||
uint32_t name, type;
|
||||
uint64_t flags, addr, ofs, size;
|
||||
uint32_t link, info;
|
||||
uint64_t align, entsize;
|
||||
} ELF64sectheader;
|
||||
typedef struct {
|
||||
uint32_t name, value, size;
|
||||
uint8_t info, other;
|
||||
uint16_t sectidx;
|
||||
} ELF32symbol;
|
||||
typedef struct {
|
||||
uint32_t name;
|
||||
uint8_t info, other;
|
||||
uint16_t sectidx;
|
||||
uint64_t value, size;
|
||||
} ELF64symbol;
|
||||
typedef struct {
|
||||
ELF32header hdr;
|
||||
ELF32sectheader sect[6];
|
||||
ELF32symbol sym[2];
|
||||
uint8_t space[4096];
|
||||
} ELF32obj;
|
||||
typedef struct {
|
||||
ELF64header hdr;
|
||||
ELF64sectheader sect[6];
|
||||
ELF64symbol sym[2];
|
||||
uint8_t space[4096];
|
||||
} ELF64obj;
|
||||
]]
|
||||
local symname = LJBC_PREFIX..ctx.modname
|
||||
local ai = assert(map_arch[ctx.arch])
|
||||
local is64, isbe = ai.b == 64, ai.e == "be"
|
||||
|
||||
-- Handle different host/target endianess.
|
||||
local function f32(x) return x end
|
||||
local f16, fofs = f32, f32
|
||||
if ffi.abi("be") ~= isbe then
|
||||
f32 = bit.bswap
|
||||
function f16(x) return bit.rshift(bit.bswap(x), 16) end
|
||||
if is64 then
|
||||
local two32 = ffi.cast("int64_t", 2^32)
|
||||
function fofs(x) return bit.bswap(x)*two32 end
|
||||
else
|
||||
fofs = f32
|
||||
end
|
||||
end
|
||||
|
||||
-- Create ELF object and fill in header.
|
||||
local o = ffi.new(is64 and "ELF64obj" or "ELF32obj")
|
||||
local hdr = o.hdr
|
||||
if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi.
|
||||
local bf = assert(io.open("/bin/ls", "rb"))
|
||||
local bs = bf:read(9)
|
||||
bf:close()
|
||||
ffi.copy(o, bs, 9)
|
||||
check(hdr.emagic[0] == 127, "no support for writing native object files")
|
||||
else
|
||||
hdr.emagic = "\127ELF"
|
||||
hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0
|
||||
end
|
||||
hdr.eclass = is64 and 2 or 1
|
||||
hdr.eendian = isbe and 2 or 1
|
||||
hdr.eversion = 1
|
||||
hdr.type = f16(1)
|
||||
hdr.machine = f16(ai.m)
|
||||
hdr.flags = f32(ai.f or 0)
|
||||
hdr.version = f32(1)
|
||||
hdr.shofs = fofs(ffi.offsetof(o, "sect"))
|
||||
hdr.ehsize = f16(ffi.sizeof(hdr))
|
||||
hdr.shentsize = f16(ffi.sizeof(o.sect[0]))
|
||||
hdr.shnum = f16(6)
|
||||
hdr.shstridx = f16(2)
|
||||
|
||||
-- Fill in sections and symbols.
|
||||
local sofs, ofs = ffi.offsetof(o, "space"), 1
|
||||
for i,name in ipairs{
|
||||
".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack",
|
||||
} do
|
||||
local sect = o.sect[i]
|
||||
sect.align = fofs(1)
|
||||
sect.name = f32(ofs)
|
||||
ffi.copy(o.space+ofs, name)
|
||||
ofs = ofs + #name+1
|
||||
end
|
||||
o.sect[1].type = f32(2) -- .symtab
|
||||
o.sect[1].link = f32(3)
|
||||
o.sect[1].info = f32(1)
|
||||
o.sect[1].align = fofs(8)
|
||||
o.sect[1].ofs = fofs(ffi.offsetof(o, "sym"))
|
||||
o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0]))
|
||||
o.sect[1].size = fofs(ffi.sizeof(o.sym))
|
||||
o.sym[1].name = f32(1)
|
||||
o.sym[1].sectidx = f16(4)
|
||||
o.sym[1].size = fofs(#s)
|
||||
o.sym[1].info = 17
|
||||
o.sect[2].type = f32(3) -- .shstrtab
|
||||
o.sect[2].ofs = fofs(sofs)
|
||||
o.sect[2].size = fofs(ofs)
|
||||
o.sect[3].type = f32(3) -- .strtab
|
||||
o.sect[3].ofs = fofs(sofs + ofs)
|
||||
o.sect[3].size = fofs(#symname+2)
|
||||
ffi.copy(o.space+ofs+1, symname)
|
||||
ofs = ofs + #symname + 2
|
||||
o.sect[4].type = f32(1) -- .rodata
|
||||
o.sect[4].flags = fofs(2)
|
||||
o.sect[4].ofs = fofs(sofs + ofs)
|
||||
o.sect[4].size = fofs(#s)
|
||||
o.sect[5].type = f32(1) -- .note.GNU-stack
|
||||
o.sect[5].ofs = fofs(sofs + ofs + #s)
|
||||
|
||||
-- Write ELF object file.
|
||||
local fp = savefile(output, "wb")
|
||||
fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
|
||||
bcsave_tail(fp, output, s)
|
||||
end
|
||||
|
||||
local function bcsave_peobj(ctx, output, s, ffi)
|
||||
ffi.cdef[[
|
||||
typedef struct {
|
||||
uint16_t arch, nsects;
|
||||
uint32_t time, symtabofs, nsyms;
|
||||
uint16_t opthdrsz, flags;
|
||||
} PEheader;
|
||||
typedef struct {
|
||||
char name[8];
|
||||
uint32_t vsize, vaddr, size, ofs, relocofs, lineofs;
|
||||
uint16_t nreloc, nline;
|
||||
uint32_t flags;
|
||||
} PEsection;
|
||||
typedef struct __attribute((packed)) {
|
||||
union {
|
||||
char name[8];
|
||||
uint32_t nameref[2];
|
||||
};
|
||||
uint32_t value;
|
||||
int16_t sect;
|
||||
uint16_t type;
|
||||
uint8_t scl, naux;
|
||||
} PEsym;
|
||||
typedef struct __attribute((packed)) {
|
||||
uint32_t size;
|
||||
uint16_t nreloc, nline;
|
||||
uint32_t cksum;
|
||||
uint16_t assoc;
|
||||
uint8_t comdatsel, unused[3];
|
||||
} PEsymaux;
|
||||
typedef struct {
|
||||
PEheader hdr;
|
||||
PEsection sect[2];
|
||||
// Must be an even number of symbol structs.
|
||||
PEsym sym0;
|
||||
PEsymaux sym0aux;
|
||||
PEsym sym1;
|
||||
PEsymaux sym1aux;
|
||||
PEsym sym2;
|
||||
PEsym sym3;
|
||||
uint32_t strtabsize;
|
||||
uint8_t space[4096];
|
||||
} PEobj;
|
||||
]]
|
||||
local symname = LJBC_PREFIX..ctx.modname
|
||||
local ai = assert(map_arch[ctx.arch])
|
||||
local is64 = ai.b == 64
|
||||
local symexport = " /EXPORT:"..symname..",DATA "
|
||||
|
||||
-- The file format is always little-endian. Swap if the host is big-endian.
|
||||
local function f32(x) return x end
|
||||
local f16 = f32
|
||||
if ffi.abi("be") then
|
||||
f32 = bit.bswap
|
||||
function f16(x) return bit.rshift(bit.bswap(x), 16) end
|
||||
end
|
||||
|
||||
-- Create PE object and fill in header.
|
||||
local o = ffi.new("PEobj")
|
||||
local hdr = o.hdr
|
||||
hdr.arch = f16(assert(ai.p))
|
||||
hdr.nsects = f16(2)
|
||||
hdr.symtabofs = f32(ffi.offsetof(o, "sym0"))
|
||||
hdr.nsyms = f32(6)
|
||||
|
||||
-- Fill in sections and symbols.
|
||||
o.sect[0].name = ".drectve"
|
||||
o.sect[0].size = f32(#symexport)
|
||||
o.sect[0].flags = f32(0x00100a00)
|
||||
o.sym0.sect = f16(1)
|
||||
o.sym0.scl = 3
|
||||
o.sym0.name = ".drectve"
|
||||
o.sym0.naux = 1
|
||||
o.sym0aux.size = f32(#symexport)
|
||||
o.sect[1].name = ".rdata"
|
||||
o.sect[1].size = f32(#s)
|
||||
o.sect[1].flags = f32(0x40300040)
|
||||
o.sym1.sect = f16(2)
|
||||
o.sym1.scl = 3
|
||||
o.sym1.name = ".rdata"
|
||||
o.sym1.naux = 1
|
||||
o.sym1aux.size = f32(#s)
|
||||
o.sym2.sect = f16(2)
|
||||
o.sym2.scl = 2
|
||||
o.sym2.nameref[1] = f32(4)
|
||||
o.sym3.sect = f16(-1)
|
||||
o.sym3.scl = 2
|
||||
o.sym3.value = f32(1)
|
||||
o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant.
|
||||
ffi.copy(o.space, symname)
|
||||
local ofs = #symname + 1
|
||||
o.strtabsize = f32(ofs + 4)
|
||||
o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs)
|
||||
ffi.copy(o.space + ofs, symexport)
|
||||
ofs = ofs + #symexport
|
||||
o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs)
|
||||
|
||||
-- Write PE object file.
|
||||
local fp = savefile(output, "wb")
|
||||
fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
|
||||
bcsave_tail(fp, output, s)
|
||||
end
|
||||
|
||||
local function bcsave_machobj(ctx, output, s, ffi)
|
||||
ffi.cdef[[
|
||||
typedef struct
|
||||
{
|
||||
uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags;
|
||||
} mach_header;
|
||||
typedef struct
|
||||
{
|
||||
mach_header; uint32_t reserved;
|
||||
} mach_header_64;
|
||||
typedef struct {
|
||||
uint32_t cmd, cmdsize;
|
||||
char segname[16];
|
||||
uint64_t vmaddr, vmsize, fileoff, filesize;
|
||||
uint32_t maxprot, initprot, nsects, flags;
|
||||
} mach_segment_command_64;
|
||||
typedef struct {
|
||||
char sectname[16], segname[16];
|
||||
uint64_t addr, size;
|
||||
uint32_t offset, align, reloff, nreloc, flags;
|
||||
uint32_t reserved1, reserved2, reserved3;
|
||||
} mach_section_64;
|
||||
typedef struct {
|
||||
uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize;
|
||||
} mach_symtab_command;
|
||||
typedef struct {
|
||||
int32_t strx;
|
||||
uint8_t type, sect;
|
||||
uint16_t desc;
|
||||
uint64_t value;
|
||||
} mach_nlist_64;
|
||||
typedef struct {
|
||||
mach_header_64 hdr;
|
||||
mach_segment_command_64 seg;
|
||||
mach_section_64 sec;
|
||||
mach_symtab_command sym;
|
||||
mach_nlist_64 sym_entry;
|
||||
uint8_t space[4096];
|
||||
} mach_obj_64;
|
||||
]]
|
||||
local symname = '_'..LJBC_PREFIX..ctx.modname
|
||||
local cputype, cpusubtype = 0x01000007, 3
|
||||
if ctx.arch ~= "x64" then
|
||||
check(ctx.arch == "arm64", "unsupported architecture for OSX")
|
||||
cputype, cpusubtype = 0x0100000c, 0
|
||||
end
|
||||
local function aligned(v, a) return bit.band(v+a-1, -a) end
|
||||
|
||||
-- Create Mach-O object and fill in header.
|
||||
local o = ffi.new("mach_obj_64")
|
||||
local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, 8)
|
||||
|
||||
-- Fill in sections and symbols.
|
||||
o.hdr.magic = 0xfeedfacf
|
||||
o.hdr.cputype = cputype
|
||||
o.hdr.cpusubtype = cpusubtype
|
||||
o.hdr.filetype = 1
|
||||
o.hdr.ncmds = 2
|
||||
o.hdr.sizeofcmds = ffi.sizeof(o.seg)+ffi.sizeof(o.sec)+ffi.sizeof(o.sym)
|
||||
o.seg.cmd = 0x19
|
||||
o.seg.cmdsize = ffi.sizeof(o.seg)+ffi.sizeof(o.sec)
|
||||
o.seg.vmsize = #s
|
||||
o.seg.fileoff = mach_size
|
||||
o.seg.filesize = #s
|
||||
o.seg.maxprot = 1
|
||||
o.seg.initprot = 1
|
||||
o.seg.nsects = 1
|
||||
ffi.copy(o.sec.sectname, "__data")
|
||||
ffi.copy(o.sec.segname, "__DATA")
|
||||
o.sec.size = #s
|
||||
o.sec.offset = mach_size
|
||||
o.sym.cmd = 2
|
||||
o.sym.cmdsize = ffi.sizeof(o.sym)
|
||||
o.sym.symoff = ffi.offsetof(o, "sym_entry")
|
||||
o.sym.nsyms = 1
|
||||
o.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)
|
||||
o.sym.strsize = aligned(#symname+2, 8)
|
||||
o.sym_entry.type = 0xf
|
||||
o.sym_entry.sect = 1
|
||||
o.sym_entry.strx = 1
|
||||
ffi.copy(o.space+1, symname)
|
||||
|
||||
-- Write Macho-O object file.
|
||||
local fp = savefile(output, "wb")
|
||||
fp:write(ffi.string(o, mach_size))
|
||||
bcsave_tail(fp, output, s)
|
||||
end
|
||||
|
||||
local function bcsave_obj(ctx, output, s)
|
||||
local ok, ffi = pcall(require, "ffi")
|
||||
check(ok, "FFI library required to write this file type")
|
||||
if output == "-" and jit.os == "Windows" then
|
||||
set_stdout_binary(ffi)
|
||||
end
|
||||
if ctx.os == "windows" then
|
||||
return bcsave_peobj(ctx, output, s, ffi)
|
||||
elseif ctx.os == "osx" then
|
||||
return bcsave_machobj(ctx, output, s, ffi)
|
||||
else
|
||||
return bcsave_elfobj(ctx, output, s, ffi)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local function bclist(ctx, input, output)
|
||||
local f = readfile(ctx, input)
|
||||
require("jit.bc").dump(f, savefile(output, "w"), true)
|
||||
end
|
||||
|
||||
local function bcsave(ctx, input, output)
|
||||
local f = readfile(ctx, input)
|
||||
local s = string.dump(f, ctx.mode)
|
||||
local t = ctx.type
|
||||
if not t then
|
||||
t = detecttype(output)
|
||||
ctx.type = t
|
||||
end
|
||||
if t == "raw" then
|
||||
bcsave_raw(output, s)
|
||||
else
|
||||
if not ctx.modname then ctx.modname = detectmodname(input) end
|
||||
if t == "obj" then
|
||||
bcsave_obj(ctx, output, s)
|
||||
else
|
||||
bcsave_c(ctx, output, s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function docmd(...)
|
||||
local arg = {...}
|
||||
local n = 1
|
||||
local list = false
|
||||
local ctx = {
|
||||
mode = "bt", arch = jit.arch, os = jit.os:lower(),
|
||||
type = false, modname = false, string = false,
|
||||
}
|
||||
local strip = "s"
|
||||
local gc64 = ""
|
||||
while n <= #arg do
|
||||
local a = arg[n]
|
||||
if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
|
||||
tremove(arg, n)
|
||||
if a == "--" then break end
|
||||
for m=2,#a do
|
||||
local opt = a:sub(m, m)
|
||||
if opt == "l" then
|
||||
list = true
|
||||
elseif opt == "s" then
|
||||
strip = "s"
|
||||
elseif opt == "g" then
|
||||
strip = ""
|
||||
elseif opt == "W" or opt == "X" then
|
||||
gc64 = opt
|
||||
elseif opt == "d" then
|
||||
ctx.mode = ctx.mode .. opt
|
||||
else
|
||||
if arg[n] == nil or m ~= #a then usage() end
|
||||
if opt == "e" then
|
||||
if n ~= 1 then usage() end
|
||||
ctx.string = true
|
||||
elseif opt == "n" then
|
||||
ctx.modname = checkmodname(tremove(arg, n))
|
||||
elseif opt == "t" then
|
||||
ctx.type = checkarg(tremove(arg, n), map_type, "file type")
|
||||
elseif opt == "a" then
|
||||
ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
|
||||
elseif opt == "o" then
|
||||
ctx.os = checkarg(tremove(arg, n), map_os, "OS name")
|
||||
elseif opt == "F" then
|
||||
ctx.filename = "@"..tremove(arg, n)
|
||||
else
|
||||
usage()
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
ctx.mode = ctx.mode .. strip .. gc64
|
||||
if list then
|
||||
if #arg == 0 or #arg > 2 then usage() end
|
||||
bclist(ctx, arg[1], arg[2] or "-")
|
||||
else
|
||||
if #arg ~= 2 then usage() end
|
||||
bcsave(ctx, arg[1], arg[2])
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Public module functions.
|
||||
return {
|
||||
start = docmd -- Process -b command line option.
|
||||
}
|
||||
|
||||
689
thirdPart/luajit/src/jit/dis_arm.lua
Normal file
689
thirdPart/luajit/src/jit/dis_arm.lua
Normal file
@@ -0,0 +1,689 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT ARM disassembler module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This is a helper module used by the LuaJIT machine code dumper module.
|
||||
--
|
||||
-- It disassembles most user-mode ARMv7 instructions
|
||||
-- NYI: Advanced SIMD and VFP instructions.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
local sub, byte, format = string.sub, string.byte, string.format
|
||||
local match, gmatch = string.match, string.gmatch
|
||||
local concat = table.concat
|
||||
local bit = require("bit")
|
||||
local band, bor, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex
|
||||
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Opcode maps
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_loadc = {
|
||||
shift = 8, mask = 15,
|
||||
[10] = {
|
||||
shift = 20, mask = 1,
|
||||
[0] = {
|
||||
shift = 23, mask = 3,
|
||||
[0] = "vmovFmDN", "vstmFNdr",
|
||||
_ = {
|
||||
shift = 21, mask = 1,
|
||||
[0] = "vstrFdl",
|
||||
{ shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", }
|
||||
},
|
||||
},
|
||||
{
|
||||
shift = 23, mask = 3,
|
||||
[0] = "vmovFDNm",
|
||||
{ shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", },
|
||||
_ = {
|
||||
shift = 21, mask = 1,
|
||||
[0] = "vldrFdl", "vldmdbFNdr",
|
||||
},
|
||||
},
|
||||
},
|
||||
[11] = {
|
||||
shift = 20, mask = 1,
|
||||
[0] = {
|
||||
shift = 23, mask = 3,
|
||||
[0] = "vmovGmDN", "vstmGNdr",
|
||||
_ = {
|
||||
shift = 21, mask = 1,
|
||||
[0] = "vstrGdl",
|
||||
{ shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", }
|
||||
},
|
||||
},
|
||||
{
|
||||
shift = 23, mask = 3,
|
||||
[0] = "vmovGDNm",
|
||||
{ shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", },
|
||||
_ = {
|
||||
shift = 21, mask = 1,
|
||||
[0] = "vldrGdl", "vldmdbGNdr",
|
||||
},
|
||||
},
|
||||
},
|
||||
_ = {
|
||||
shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc.
|
||||
},
|
||||
}
|
||||
|
||||
local map_vfps = {
|
||||
shift = 6, mask = 0x2c001,
|
||||
[0] = "vmlaF.dnm", "vmlsF.dnm",
|
||||
[0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm",
|
||||
[0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm",
|
||||
[0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm",
|
||||
[0x20000] = "vdivF.dnm",
|
||||
[0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm",
|
||||
[0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm",
|
||||
[0x2c000] = "vmovF.dY",
|
||||
[0x2c001] = {
|
||||
shift = 7, mask = 0x1e01,
|
||||
[0] = "vmovF.dm", "vabsF.dm",
|
||||
[0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm",
|
||||
[0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm",
|
||||
[0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d",
|
||||
[0x0e01] = "vcvtG.dF.m",
|
||||
[0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm",
|
||||
[0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm",
|
||||
[0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm",
|
||||
},
|
||||
}
|
||||
|
||||
local map_vfpd = {
|
||||
shift = 6, mask = 0x2c001,
|
||||
[0] = "vmlaG.dnm", "vmlsG.dnm",
|
||||
[0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm",
|
||||
[0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm",
|
||||
[0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm",
|
||||
[0x20000] = "vdivG.dnm",
|
||||
[0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm",
|
||||
[0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm",
|
||||
[0x2c000] = "vmovG.dY",
|
||||
[0x2c001] = {
|
||||
shift = 7, mask = 0x1e01,
|
||||
[0] = "vmovG.dm", "vabsG.dm",
|
||||
[0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm",
|
||||
[0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm",
|
||||
[0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d",
|
||||
[0x0e01] = "vcvtF.dG.m",
|
||||
[0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm",
|
||||
[0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m",
|
||||
[0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m",
|
||||
},
|
||||
}
|
||||
|
||||
local map_datac = {
|
||||
shift = 24, mask = 1,
|
||||
[0] = {
|
||||
shift = 4, mask = 1,
|
||||
[0] = {
|
||||
shift = 8, mask = 15,
|
||||
[10] = map_vfps,
|
||||
[11] = map_vfpd,
|
||||
-- NYI cdp, mcr, mrc.
|
||||
},
|
||||
{
|
||||
shift = 8, mask = 15,
|
||||
[10] = {
|
||||
shift = 20, mask = 15,
|
||||
[0] = "vmovFnD", "vmovFDn",
|
||||
[14] = "vmsrD",
|
||||
[15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", },
|
||||
},
|
||||
},
|
||||
},
|
||||
"svcT",
|
||||
}
|
||||
|
||||
local map_loadcu = {
|
||||
shift = 0, mask = 0, -- NYI unconditional CP load/store.
|
||||
}
|
||||
|
||||
local map_datacu = {
|
||||
shift = 0, mask = 0, -- NYI unconditional CP data.
|
||||
}
|
||||
|
||||
local map_simddata = {
|
||||
shift = 0, mask = 0, -- NYI SIMD data.
|
||||
}
|
||||
|
||||
local map_simdload = {
|
||||
shift = 0, mask = 0, -- NYI SIMD load/store, preload.
|
||||
}
|
||||
|
||||
local map_preload = {
|
||||
shift = 0, mask = 0, -- NYI preload.
|
||||
}
|
||||
|
||||
local map_media = {
|
||||
shift = 20, mask = 31,
|
||||
[0] = false,
|
||||
{ --01
|
||||
shift = 5, mask = 7,
|
||||
[0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM",
|
||||
"sadd8DNM", false, false, "ssub8DNM",
|
||||
},
|
||||
{ --02
|
||||
shift = 5, mask = 7,
|
||||
[0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM",
|
||||
"qadd8DNM", false, false, "qsub8DNM",
|
||||
},
|
||||
{ --03
|
||||
shift = 5, mask = 7,
|
||||
[0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM",
|
||||
"shadd8DNM", false, false, "shsub8DNM",
|
||||
},
|
||||
false,
|
||||
{ --05
|
||||
shift = 5, mask = 7,
|
||||
[0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM",
|
||||
"uadd8DNM", false, false, "usub8DNM",
|
||||
},
|
||||
{ --06
|
||||
shift = 5, mask = 7,
|
||||
[0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM",
|
||||
"uqadd8DNM", false, false, "uqsub8DNM",
|
||||
},
|
||||
{ --07
|
||||
shift = 5, mask = 7,
|
||||
[0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM",
|
||||
"uhadd8DNM", false, false, "uhsub8DNM",
|
||||
},
|
||||
{ --08
|
||||
shift = 5, mask = 7,
|
||||
[0] = "pkhbtDNMU", false, "pkhtbDNMU",
|
||||
{ shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", },
|
||||
"pkhbtDNMU", "selDNM", "pkhtbDNMU",
|
||||
},
|
||||
false,
|
||||
{ --0a
|
||||
shift = 5, mask = 7,
|
||||
[0] = "ssatDxMu", "ssat16DxM", "ssatDxMu",
|
||||
{ shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", },
|
||||
"ssatDxMu", false, "ssatDxMu",
|
||||
},
|
||||
{ --0b
|
||||
shift = 5, mask = 7,
|
||||
[0] = "ssatDxMu", "revDM", "ssatDxMu",
|
||||
{ shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", },
|
||||
"ssatDxMu", "rev16DM", "ssatDxMu",
|
||||
},
|
||||
{ --0c
|
||||
shift = 5, mask = 7,
|
||||
[3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", },
|
||||
},
|
||||
false,
|
||||
{ --0e
|
||||
shift = 5, mask = 7,
|
||||
[0] = "usatDwMu", "usat16DwM", "usatDwMu",
|
||||
{ shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", },
|
||||
"usatDwMu", false, "usatDwMu",
|
||||
},
|
||||
{ --0f
|
||||
shift = 5, mask = 7,
|
||||
[0] = "usatDwMu", "rbitDM", "usatDwMu",
|
||||
{ shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", },
|
||||
"usatDwMu", "revshDM", "usatDwMu",
|
||||
},
|
||||
{ --10
|
||||
shift = 12, mask = 15,
|
||||
[15] = {
|
||||
shift = 5, mask = 7,
|
||||
"smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS",
|
||||
},
|
||||
_ = {
|
||||
shift = 5, mask = 7,
|
||||
[0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD",
|
||||
},
|
||||
},
|
||||
false, false, false,
|
||||
{ --14
|
||||
shift = 5, mask = 7,
|
||||
[0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS",
|
||||
},
|
||||
{ --15
|
||||
shift = 5, mask = 7,
|
||||
[0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", },
|
||||
{ shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", },
|
||||
false, false, false, false,
|
||||
"smmlsNMSD", "smmlsrNMSD",
|
||||
},
|
||||
false, false,
|
||||
{ --18
|
||||
shift = 5, mask = 7,
|
||||
[0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", },
|
||||
},
|
||||
false,
|
||||
{ --1a
|
||||
shift = 5, mask = 3, [2] = "sbfxDMvw",
|
||||
},
|
||||
{ --1b
|
||||
shift = 5, mask = 3, [2] = "sbfxDMvw",
|
||||
},
|
||||
{ --1c
|
||||
shift = 5, mask = 3,
|
||||
[0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
|
||||
},
|
||||
{ --1d
|
||||
shift = 5, mask = 3,
|
||||
[0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
|
||||
},
|
||||
{ --1e
|
||||
shift = 5, mask = 3, [2] = "ubfxDMvw",
|
||||
},
|
||||
{ --1f
|
||||
shift = 5, mask = 3, [2] = "ubfxDMvw",
|
||||
},
|
||||
}
|
||||
|
||||
local map_load = {
|
||||
shift = 21, mask = 9,
|
||||
{
|
||||
shift = 20, mask = 5,
|
||||
[0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL",
|
||||
},
|
||||
_ = {
|
||||
shift = 20, mask = 5,
|
||||
[0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL",
|
||||
}
|
||||
}
|
||||
|
||||
local map_load1 = {
|
||||
shift = 4, mask = 1,
|
||||
[0] = map_load, map_media,
|
||||
}
|
||||
|
||||
local map_loadm = {
|
||||
shift = 20, mask = 1,
|
||||
[0] = {
|
||||
shift = 23, mask = 3,
|
||||
[0] = "stmdaNR", "stmNR",
|
||||
{ shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR",
|
||||
},
|
||||
{
|
||||
shift = 23, mask = 3,
|
||||
[0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", },
|
||||
"ldmdbNR", "ldmibNR",
|
||||
},
|
||||
}
|
||||
|
||||
local map_data = {
|
||||
shift = 21, mask = 15,
|
||||
[0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs",
|
||||
"addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs",
|
||||
"tstNP", "teqNP", "cmpNP", "cmnNP",
|
||||
"orrDNPs", "movDPs", "bicDNPs", "mvnDPs",
|
||||
}
|
||||
|
||||
local map_mul = {
|
||||
shift = 21, mask = 7,
|
||||
[0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS",
|
||||
"umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs",
|
||||
}
|
||||
|
||||
local map_sync = {
|
||||
shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd.
|
||||
[0] = "swpDMN", false, false, false,
|
||||
"swpbDMN", false, false, false,
|
||||
"strexDMN", "ldrexDN", "strexdDN", "ldrexdDN",
|
||||
"strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN",
|
||||
}
|
||||
|
||||
local map_mulh = {
|
||||
shift = 21, mask = 3,
|
||||
[0] = { shift = 5, mask = 3,
|
||||
[0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", },
|
||||
{ shift = 5, mask = 3,
|
||||
[0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", },
|
||||
{ shift = 5, mask = 3,
|
||||
[0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", },
|
||||
{ shift = 5, mask = 3,
|
||||
[0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", },
|
||||
}
|
||||
|
||||
local map_misc = {
|
||||
shift = 4, mask = 7,
|
||||
-- NYI: decode PSR bits of msr.
|
||||
[0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", },
|
||||
{ shift = 21, mask = 3, "bxM", false, "clzDM", },
|
||||
{ shift = 21, mask = 3, "bxjM", },
|
||||
{ shift = 21, mask = 3, "blxM", },
|
||||
false,
|
||||
{ shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", },
|
||||
false,
|
||||
{ shift = 21, mask = 3, "bkptK", },
|
||||
}
|
||||
|
||||
local map_datar = {
|
||||
shift = 4, mask = 9,
|
||||
[9] = {
|
||||
shift = 5, mask = 3,
|
||||
[0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, },
|
||||
{ shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", },
|
||||
{ shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", },
|
||||
{ shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", },
|
||||
},
|
||||
_ = {
|
||||
shift = 20, mask = 25,
|
||||
[16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, },
|
||||
_ = {
|
||||
shift = 0, mask = 0xffffffff,
|
||||
[bor(0xe1a00000)] = "nop",
|
||||
_ = map_data,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
local map_datai = {
|
||||
shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12.
|
||||
[16] = "movwDW", [20] = "movtDW",
|
||||
[18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", },
|
||||
[22] = "msrNW",
|
||||
_ = map_data,
|
||||
}
|
||||
|
||||
local map_branch = {
|
||||
shift = 24, mask = 1,
|
||||
[0] = "bB", "blB"
|
||||
}
|
||||
|
||||
local map_condins = {
|
||||
[0] = map_datar, map_datai, map_load, map_load1,
|
||||
map_loadm, map_branch, map_loadc, map_datac
|
||||
}
|
||||
|
||||
-- NYI: setend.
|
||||
local map_uncondins = {
|
||||
[0] = false, map_simddata, map_simdload, map_preload,
|
||||
false, "blxB", map_loadcu, map_datacu,
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_gpr = {
|
||||
[0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
|
||||
}
|
||||
|
||||
local map_cond = {
|
||||
[0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt", "gt", "le", "al",
|
||||
}
|
||||
|
||||
local map_shift = { [0] = "lsl", "lsr", "asr", "ror", }
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Output a nicely formatted line with an opcode and operands.
|
||||
local function putop(ctx, text, operands)
|
||||
local pos = ctx.pos
|
||||
local extra = ""
|
||||
if ctx.rel then
|
||||
local sym = ctx.symtab[ctx.rel]
|
||||
if sym then
|
||||
extra = "\t->"..sym
|
||||
elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then
|
||||
extra = "\t; 0x"..tohex(ctx.rel)
|
||||
end
|
||||
end
|
||||
if ctx.hexdump > 0 then
|
||||
ctx.out(format("%08x %s %-5s %s%s\n",
|
||||
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
|
||||
else
|
||||
ctx.out(format("%08x %-5s %s%s\n",
|
||||
ctx.addr+pos, text, concat(operands, ", "), extra))
|
||||
end
|
||||
ctx.pos = pos + 4
|
||||
end
|
||||
|
||||
-- Fallback for unknown opcodes.
|
||||
local function unknown(ctx)
|
||||
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
|
||||
end
|
||||
|
||||
-- Format operand 2 of load/store opcodes.
|
||||
local function fmtload(ctx, op, pos)
|
||||
local base = map_gpr[band(rshift(op, 16), 15)]
|
||||
local x, ofs
|
||||
local ext = (band(op, 0x04000000) == 0)
|
||||
if not ext and band(op, 0x02000000) == 0 then
|
||||
ofs = band(op, 4095)
|
||||
if band(op, 0x00800000) == 0 then ofs = -ofs end
|
||||
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
|
||||
ofs = "#"..ofs
|
||||
elseif ext and band(op, 0x00400000) ~= 0 then
|
||||
ofs = band(op, 15) + band(rshift(op, 4), 0xf0)
|
||||
if band(op, 0x00800000) == 0 then ofs = -ofs end
|
||||
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
|
||||
ofs = "#"..ofs
|
||||
else
|
||||
ofs = map_gpr[band(op, 15)]
|
||||
if ext or band(op, 0xfe0) == 0 then
|
||||
elseif band(op, 0xfe0) == 0x60 then
|
||||
ofs = format("%s, rrx", ofs)
|
||||
else
|
||||
local sh = band(rshift(op, 7), 31)
|
||||
if sh == 0 then sh = 32 end
|
||||
ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh)
|
||||
end
|
||||
if band(op, 0x00800000) == 0 then ofs = "-"..ofs end
|
||||
end
|
||||
if ofs == "#0" then
|
||||
x = format("[%s]", base)
|
||||
elseif band(op, 0x01000000) == 0 then
|
||||
x = format("[%s], %s", base, ofs)
|
||||
else
|
||||
x = format("[%s, %s]", base, ofs)
|
||||
end
|
||||
if band(op, 0x01200000) == 0x01200000 then x = x.."!" end
|
||||
return x
|
||||
end
|
||||
|
||||
-- Format operand 2 of vector load/store opcodes.
|
||||
local function fmtvload(ctx, op, pos)
|
||||
local base = map_gpr[band(rshift(op, 16), 15)]
|
||||
local ofs = band(op, 255)*4
|
||||
if band(op, 0x00800000) == 0 then ofs = -ofs end
|
||||
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
|
||||
if ofs == 0 then
|
||||
return format("[%s]", base)
|
||||
else
|
||||
return format("[%s, #%d]", base, ofs)
|
||||
end
|
||||
end
|
||||
|
||||
local function fmtvr(op, vr, sh0, sh1)
|
||||
if vr == "s" then
|
||||
return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1))
|
||||
else
|
||||
return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16))
|
||||
end
|
||||
end
|
||||
|
||||
-- Disassemble a single instruction.
|
||||
local function disass_ins(ctx)
|
||||
local pos = ctx.pos
|
||||
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
|
||||
local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
|
||||
local operands = {}
|
||||
local suffix = ""
|
||||
local last, name, pat
|
||||
local vr
|
||||
ctx.op = op
|
||||
ctx.rel = nil
|
||||
|
||||
local cond = rshift(op, 28)
|
||||
local opat
|
||||
if cond == 15 then
|
||||
opat = map_uncondins[band(rshift(op, 25), 7)]
|
||||
else
|
||||
if cond ~= 14 then suffix = map_cond[cond] end
|
||||
opat = map_condins[band(rshift(op, 25), 7)]
|
||||
end
|
||||
while type(opat) ~= "string" do
|
||||
if not opat then return unknown(ctx) end
|
||||
opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
|
||||
end
|
||||
name, pat = match(opat, "^([a-z0-9]*)(.*)")
|
||||
if sub(pat, 1, 1) == "." then
|
||||
local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)")
|
||||
suffix = suffix..s2
|
||||
pat = p2
|
||||
end
|
||||
|
||||
for p in gmatch(pat, ".") do
|
||||
local x = nil
|
||||
if p == "D" then
|
||||
x = map_gpr[band(rshift(op, 12), 15)]
|
||||
elseif p == "N" then
|
||||
x = map_gpr[band(rshift(op, 16), 15)]
|
||||
elseif p == "S" then
|
||||
x = map_gpr[band(rshift(op, 8), 15)]
|
||||
elseif p == "M" then
|
||||
x = map_gpr[band(op, 15)]
|
||||
elseif p == "d" then
|
||||
x = fmtvr(op, vr, 12, 22)
|
||||
elseif p == "n" then
|
||||
x = fmtvr(op, vr, 16, 7)
|
||||
elseif p == "m" then
|
||||
x = fmtvr(op, vr, 0, 5)
|
||||
elseif p == "P" then
|
||||
if band(op, 0x02000000) ~= 0 then
|
||||
x = ror(band(op, 255), 2*band(rshift(op, 8), 15))
|
||||
else
|
||||
x = map_gpr[band(op, 15)]
|
||||
if band(op, 0xff0) ~= 0 then
|
||||
operands[#operands+1] = x
|
||||
local s = map_shift[band(rshift(op, 5), 3)]
|
||||
local r = nil
|
||||
if band(op, 0xf90) == 0 then
|
||||
if s == "ror" then s = "rrx" else r = "#32" end
|
||||
elseif band(op, 0x10) == 0 then
|
||||
r = "#"..band(rshift(op, 7), 31)
|
||||
else
|
||||
r = map_gpr[band(rshift(op, 8), 15)]
|
||||
end
|
||||
if name == "mov" then name = s; x = r
|
||||
elseif r then x = format("%s %s", s, r)
|
||||
else x = s end
|
||||
end
|
||||
end
|
||||
elseif p == "L" then
|
||||
x = fmtload(ctx, op, pos)
|
||||
elseif p == "l" then
|
||||
x = fmtvload(ctx, op, pos)
|
||||
elseif p == "B" then
|
||||
local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6)
|
||||
if cond == 15 then addr = addr + band(rshift(op, 23), 2) end
|
||||
ctx.rel = addr
|
||||
x = "0x"..tohex(addr)
|
||||
elseif p == "F" then
|
||||
vr = "s"
|
||||
elseif p == "G" then
|
||||
vr = "d"
|
||||
elseif p == "." then
|
||||
suffix = suffix..(vr == "s" and ".f32" or ".f64")
|
||||
elseif p == "R" then
|
||||
if band(op, 0x00200000) ~= 0 and #operands == 1 then
|
||||
operands[1] = operands[1].."!"
|
||||
end
|
||||
local t = {}
|
||||
for i=0,15 do
|
||||
if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end
|
||||
end
|
||||
x = "{"..concat(t, ", ").."}"
|
||||
elseif p == "r" then
|
||||
if band(op, 0x00200000) ~= 0 and #operands == 2 then
|
||||
operands[1] = operands[1].."!"
|
||||
end
|
||||
local s = tonumber(sub(last, 2))
|
||||
local n = band(op, 255)
|
||||
if vr == "d" then n = rshift(n, 1) end
|
||||
operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1)
|
||||
elseif p == "W" then
|
||||
x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000)
|
||||
elseif p == "T" then
|
||||
x = "#0x"..tohex(band(op, 0x00ffffff), 6)
|
||||
elseif p == "U" then
|
||||
x = band(rshift(op, 7), 31)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "u" then
|
||||
x = band(rshift(op, 7), 31)
|
||||
if band(op, 0x40) == 0 then
|
||||
if x == 0 then x = nil else x = "lsl #"..x end
|
||||
else
|
||||
if x == 0 then x = "asr #32" else x = "asr #"..x end
|
||||
end
|
||||
elseif p == "v" then
|
||||
x = band(rshift(op, 7), 31)
|
||||
elseif p == "w" then
|
||||
x = band(rshift(op, 16), 31)
|
||||
elseif p == "x" then
|
||||
x = band(rshift(op, 16), 31) + 1
|
||||
elseif p == "X" then
|
||||
x = band(rshift(op, 16), 31) - last + 1
|
||||
elseif p == "Y" then
|
||||
x = band(rshift(op, 12), 0xf0) + band(op, 0x0f)
|
||||
elseif p == "K" then
|
||||
x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4)
|
||||
elseif p == "s" then
|
||||
if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
if x then
|
||||
last = x
|
||||
if type(x) == "number" then x = "#"..x end
|
||||
operands[#operands+1] = x
|
||||
end
|
||||
end
|
||||
|
||||
return putop(ctx, name..suffix, operands)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Disassemble a block of code.
|
||||
local function disass_block(ctx, ofs, len)
|
||||
if not ofs then ofs = 0 end
|
||||
local stop = len and ofs+len or #ctx.code
|
||||
ctx.pos = ofs
|
||||
ctx.rel = nil
|
||||
while ctx.pos < stop do disass_ins(ctx) end
|
||||
end
|
||||
|
||||
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
|
||||
local function create(code, addr, out)
|
||||
local ctx = {}
|
||||
ctx.code = code
|
||||
ctx.addr = addr or 0
|
||||
ctx.out = out or io.write
|
||||
ctx.symtab = {}
|
||||
ctx.disass = disass_block
|
||||
ctx.hexdump = 8
|
||||
return ctx
|
||||
end
|
||||
|
||||
-- Simple API: disassemble code (a string) at address and output via out.
|
||||
local function disass(code, addr, out)
|
||||
create(code, addr, out):disass()
|
||||
end
|
||||
|
||||
-- Return register name for RID.
|
||||
local function regname(r)
|
||||
if r < 16 then return map_gpr[r] end
|
||||
return "d"..(r-16)
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
return {
|
||||
create = create,
|
||||
disass = disass,
|
||||
regname = regname
|
||||
}
|
||||
|
||||
1207
thirdPart/luajit/src/jit/dis_arm64.lua
Normal file
1207
thirdPart/luajit/src/jit/dis_arm64.lua
Normal file
File diff suppressed because it is too large
Load Diff
12
thirdPart/luajit/src/jit/dis_arm64be.lua
Normal file
12
thirdPart/luajit/src/jit/dis_arm64be.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT ARM64BE disassembler wrapper module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- ARM64 instructions are always little-endian. So just forward to the
|
||||
-- common ARM64 disassembler module. All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
return require((string.match(..., ".*%.") or "").."dis_arm64")
|
||||
|
||||
694
thirdPart/luajit/src/jit/dis_mips.lua
Normal file
694
thirdPart/luajit/src/jit/dis_mips.lua
Normal file
@@ -0,0 +1,694 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT MIPS disassembler module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT/X license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This is a helper module used by the LuaJIT machine code dumper module.
|
||||
--
|
||||
-- It disassembles all standard MIPS32R1/R2 instructions.
|
||||
-- Default mode is big-endian, but see: dis_mipsel.lua
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
local byte, format = string.byte, string.format
|
||||
local match, gmatch = string.match, string.gmatch
|
||||
local concat = table.concat
|
||||
local bit = require("bit")
|
||||
local band, bor, tohex = bit.band, bit.bor, bit.tohex
|
||||
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Extended opcode maps common to all MIPS releases
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
|
||||
local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
|
||||
|
||||
local map_cop0 = {
|
||||
shift = 25, mask = 1,
|
||||
[0] = {
|
||||
shift = 21, mask = 15,
|
||||
[0] = "mfc0TDW", [4] = "mtc0TDW",
|
||||
[10] = "rdpgprDT",
|
||||
[11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", },
|
||||
[14] = "wrpgprDT",
|
||||
}, {
|
||||
shift = 0, mask = 63,
|
||||
[1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
|
||||
[24] = "eret", [31] = "deret",
|
||||
[32] = "wait",
|
||||
},
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Primary and extended opcode maps for MIPS R1-R5
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
|
||||
|
||||
local map_special = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
|
||||
map_movci, map_srl, "sraDTA",
|
||||
"sllvDTS", false, map_srlv, "sravDTS",
|
||||
"jrS", "jalrD1S", "movzDST", "movnDST",
|
||||
"syscallY", "breakY", false, "sync",
|
||||
"mfhiD", "mthiS", "mfloD", "mtloS",
|
||||
"dsllvDST", false, "dsrlvDST", "dsravDST",
|
||||
"multST", "multuST", "divST", "divuST",
|
||||
"dmultST", "dmultuST", "ddivST", "ddivuST",
|
||||
"addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
|
||||
"andDST", "or|moveDST0", "xorDST", "nor|notDST0",
|
||||
false, false, "sltDST", "sltuDST",
|
||||
"daddDST", "dadduDST", "dsubDST", "dsubuDST",
|
||||
"tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
|
||||
"teqSTZ", false, "tneSTZ", false,
|
||||
"dsllDTA", false, "dsrlDTA", "dsraDTA",
|
||||
"dsll32DTA", false, "dsrl32DTA", "dsra32DTA",
|
||||
}
|
||||
|
||||
local map_special2 = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "maddST", "madduST", "mulDST", false,
|
||||
"msubST", "msubuST",
|
||||
[32] = "clzDS", [33] = "cloDS",
|
||||
[63] = "sdbbpY",
|
||||
}
|
||||
|
||||
local map_bshfl = {
|
||||
shift = 6, mask = 31,
|
||||
[2] = "wsbhDT",
|
||||
[16] = "sebDT",
|
||||
[24] = "sehDT",
|
||||
}
|
||||
|
||||
local map_dbshfl = {
|
||||
shift = 6, mask = 31,
|
||||
[2] = "dsbhDT",
|
||||
[5] = "dshdDT",
|
||||
}
|
||||
|
||||
local map_special3 = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
|
||||
[4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
|
||||
[32] = map_bshfl, [36] = map_dbshfl, [59] = "rdhwrTD",
|
||||
}
|
||||
|
||||
local map_regimm = {
|
||||
shift = 16, mask = 31,
|
||||
[0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB",
|
||||
false, false, false, false,
|
||||
"tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI",
|
||||
"teqiSI", false, "tneiSI", false,
|
||||
"bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB",
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, "synciSO",
|
||||
}
|
||||
|
||||
local map_cop1s = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
|
||||
"sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
|
||||
"round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
|
||||
"round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
|
||||
false,
|
||||
{ shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" },
|
||||
"movz.sFGT", "movn.sFGT",
|
||||
false, "recip.sFG", "rsqrt.sFG", false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, "cvt.d.sFG", false, false,
|
||||
"cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
"c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH",
|
||||
"c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH",
|
||||
"c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH",
|
||||
"c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH",
|
||||
}
|
||||
|
||||
local map_cop1d = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
|
||||
"sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
|
||||
"round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
|
||||
"round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
|
||||
false,
|
||||
{ shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" },
|
||||
"movz.dFGT", "movn.dFGT",
|
||||
false, "recip.dFG", "rsqrt.dFG", false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
"cvt.s.dFG", false, false, false,
|
||||
"cvt.w.dFG", "cvt.l.dFG", false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
"c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH",
|
||||
"c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH",
|
||||
"c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH",
|
||||
"c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH",
|
||||
}
|
||||
|
||||
local map_cop1ps = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false,
|
||||
false, "abs.psFG", "mov.psFG", "neg.psFG",
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false,
|
||||
{ shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" },
|
||||
"movz.psFGT", "movn.psFGT",
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
"cvt.s.puFG", false, false, false,
|
||||
false, false, false, false,
|
||||
"cvt.s.plFG", false, false, false,
|
||||
"pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH",
|
||||
"c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH",
|
||||
"c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH",
|
||||
"c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH",
|
||||
"c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH",
|
||||
}
|
||||
|
||||
local map_cop1w = {
|
||||
shift = 0, mask = 63,
|
||||
[32] = "cvt.s.wFG", [33] = "cvt.d.wFG",
|
||||
}
|
||||
|
||||
local map_cop1l = {
|
||||
shift = 0, mask = 63,
|
||||
[32] = "cvt.s.lFG", [33] = "cvt.d.lFG",
|
||||
}
|
||||
|
||||
local map_cop1bc = {
|
||||
shift = 16, mask = 3,
|
||||
[0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB",
|
||||
}
|
||||
|
||||
local map_cop1 = {
|
||||
shift = 21, mask = 31,
|
||||
[0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG",
|
||||
"mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG",
|
||||
map_cop1bc, false, false, false,
|
||||
false, false, false, false,
|
||||
map_cop1s, map_cop1d, false, false,
|
||||
map_cop1w, map_cop1l, map_cop1ps,
|
||||
}
|
||||
|
||||
local map_cop1x = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "lwxc1FSX", "ldxc1FSX", false, false,
|
||||
false, "luxc1FSX", false, false,
|
||||
"swxc1FSX", "sdxc1FSX", false, false,
|
||||
false, "suxc1FSX", false, "prefxMSX",
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, "alnv.psFGHS", false,
|
||||
"madd.sFRGH", "madd.dFRGH", false, false,
|
||||
false, false, "madd.psFRGH", false,
|
||||
"msub.sFRGH", "msub.dFRGH", false, false,
|
||||
false, false, "msub.psFRGH", false,
|
||||
"nmadd.sFRGH", "nmadd.dFRGH", false, false,
|
||||
false, false, "nmadd.psFRGH", false,
|
||||
"nmsub.sFRGH", "nmsub.dFRGH", false, false,
|
||||
false, false, "nmsub.psFRGH", false,
|
||||
}
|
||||
|
||||
local map_pri = {
|
||||
[0] = map_special, map_regimm, "jJ", "jalJ",
|
||||
"beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB",
|
||||
"addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI",
|
||||
"andiTSU", "ori|liTS0U", "xoriTSU", "luiTU",
|
||||
map_cop0, map_cop1, false, map_cop1x,
|
||||
"beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB",
|
||||
"daddiTSI", "daddiuTSI", false, false,
|
||||
map_special2, "jalxJ", false, map_special3,
|
||||
"lbTSO", "lhTSO", "lwlTSO", "lwTSO",
|
||||
"lbuTSO", "lhuTSO", "lwrTSO", false,
|
||||
"sbTSO", "shTSO", "swlTSO", "swTSO",
|
||||
false, false, "swrTSO", "cacheNSO",
|
||||
"llTSO", "lwc1HSO", "lwc2TSO", "prefNSO",
|
||||
false, "ldc1HSO", "ldc2TSO", "ldTSO",
|
||||
"scTSO", "swc1HSO", "swc2TSO", false,
|
||||
false, "sdc1HSO", "sdc2TSO", "sdTSO",
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Primary and extended opcode maps for MIPS R6
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_mul_r6 = { shift = 6, mask = 3, [2] = "mulDST", [3] = "muhDST" }
|
||||
local map_mulu_r6 = { shift = 6, mask = 3, [2] = "muluDST", [3] = "muhuDST" }
|
||||
local map_div_r6 = { shift = 6, mask = 3, [2] = "divDST", [3] = "modDST" }
|
||||
local map_divu_r6 = { shift = 6, mask = 3, [2] = "divuDST", [3] = "moduDST" }
|
||||
local map_dmul_r6 = { shift = 6, mask = 3, [2] = "dmulDST", [3] = "dmuhDST" }
|
||||
local map_dmulu_r6 = { shift = 6, mask = 3, [2] = "dmuluDST", [3] = "dmuhuDST" }
|
||||
local map_ddiv_r6 = { shift = 6, mask = 3, [2] = "ddivDST", [3] = "dmodDST" }
|
||||
local map_ddivu_r6 = { shift = 6, mask = 3, [2] = "ddivuDST", [3] = "dmoduDST" }
|
||||
|
||||
local map_special_r6 = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
|
||||
false, map_srl, "sraDTA",
|
||||
"sllvDTS", false, map_srlv, "sravDTS",
|
||||
"jrS", "jalrD1S", false, false,
|
||||
"syscallY", "breakY", false, "sync",
|
||||
"clzDS", "cloDS", "dclzDS", "dcloDS",
|
||||
"dsllvDST", "dlsaDSTA", "dsrlvDST", "dsravDST",
|
||||
map_mul_r6, map_mulu_r6, map_div_r6, map_divu_r6,
|
||||
map_dmul_r6, map_dmulu_r6, map_ddiv_r6, map_ddivu_r6,
|
||||
"addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
|
||||
"andDST", "or|moveDST0", "xorDST", "nor|notDST0",
|
||||
false, false, "sltDST", "sltuDST",
|
||||
"daddDST", "dadduDST", "dsubDST", "dsubuDST",
|
||||
"tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
|
||||
"teqSTZ", "seleqzDST", "tneSTZ", "selnezDST",
|
||||
"dsllDTA", false, "dsrlDTA", "dsraDTA",
|
||||
"dsll32DTA", false, "dsrl32DTA", "dsra32DTA",
|
||||
}
|
||||
|
||||
local map_bshfl_r6 = {
|
||||
shift = 9, mask = 3,
|
||||
[1] = "alignDSTa",
|
||||
_ = {
|
||||
shift = 6, mask = 31,
|
||||
[0] = "bitswapDT",
|
||||
[2] = "wsbhDT",
|
||||
[16] = "sebDT",
|
||||
[24] = "sehDT",
|
||||
}
|
||||
}
|
||||
|
||||
local map_dbshfl_r6 = {
|
||||
shift = 9, mask = 3,
|
||||
[1] = "dalignDSTa",
|
||||
_ = {
|
||||
shift = 6, mask = 31,
|
||||
[0] = "dbitswapDT",
|
||||
[2] = "dsbhDT",
|
||||
[5] = "dshdDT",
|
||||
}
|
||||
}
|
||||
|
||||
local map_special3_r6 = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
|
||||
[4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
|
||||
[32] = map_bshfl_r6, [36] = map_dbshfl_r6, [59] = "rdhwrTD",
|
||||
}
|
||||
|
||||
local map_regimm_r6 = {
|
||||
shift = 16, mask = 31,
|
||||
[0] = "bltzSB", [1] = "bgezSB",
|
||||
[6] = "dahiSI", [30] = "datiSI",
|
||||
[23] = "sigrieI", [31] = "synciSO",
|
||||
}
|
||||
|
||||
local map_pcrel_r6 = {
|
||||
shift = 19, mask = 3,
|
||||
[0] = "addiupcS2", "lwpcS2", "lwupcS2", {
|
||||
shift = 18, mask = 1,
|
||||
[0] = "ldpcS3", { shift = 16, mask = 3, [2] = "auipcSI", [3] = "aluipcSI" }
|
||||
}
|
||||
}
|
||||
|
||||
local map_cop1s_r6 = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
|
||||
"sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
|
||||
"round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
|
||||
"round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
|
||||
"sel.sFGH", false, false, false,
|
||||
"seleqz.sFGH", "recip.sFG", "rsqrt.sFG", "selnez.sFGH",
|
||||
"maddf.sFGH", "msubf.sFGH", "rint.sFG", "class.sFG",
|
||||
"min.sFGH", "mina.sFGH", "max.sFGH", "maxa.sFGH",
|
||||
false, "cvt.d.sFG", false, false,
|
||||
"cvt.w.sFG", "cvt.l.sFG",
|
||||
}
|
||||
|
||||
local map_cop1d_r6 = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
|
||||
"sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
|
||||
"round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
|
||||
"round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
|
||||
"sel.dFGH", false, false, false,
|
||||
"seleqz.dFGH", "recip.dFG", "rsqrt.dFG", "selnez.dFGH",
|
||||
"maddf.dFGH", "msubf.dFGH", "rint.dFG", "class.dFG",
|
||||
"min.dFGH", "mina.dFGH", "max.dFGH", "maxa.dFGH",
|
||||
"cvt.s.dFG", false, false, false,
|
||||
"cvt.w.dFG", "cvt.l.dFG",
|
||||
}
|
||||
|
||||
local map_cop1w_r6 = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "cmp.af.sFGH", "cmp.un.sFGH", "cmp.eq.sFGH", "cmp.ueq.sFGH",
|
||||
"cmp.lt.sFGH", "cmp.ult.sFGH", "cmp.le.sFGH", "cmp.ule.sFGH",
|
||||
"cmp.saf.sFGH", "cmp.sun.sFGH", "cmp.seq.sFGH", "cmp.sueq.sFGH",
|
||||
"cmp.slt.sFGH", "cmp.sult.sFGH", "cmp.sle.sFGH", "cmp.sule.sFGH",
|
||||
false, "cmp.or.sFGH", "cmp.une.sFGH", "cmp.ne.sFGH",
|
||||
false, false, false, false,
|
||||
false, "cmp.sor.sFGH", "cmp.sune.sFGH", "cmp.sne.sFGH",
|
||||
false, false, false, false,
|
||||
"cvt.s.wFG", "cvt.d.wFG",
|
||||
}
|
||||
|
||||
local map_cop1l_r6 = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "cmp.af.dFGH", "cmp.un.dFGH", "cmp.eq.dFGH", "cmp.ueq.dFGH",
|
||||
"cmp.lt.dFGH", "cmp.ult.dFGH", "cmp.le.dFGH", "cmp.ule.dFGH",
|
||||
"cmp.saf.dFGH", "cmp.sun.dFGH", "cmp.seq.dFGH", "cmp.sueq.dFGH",
|
||||
"cmp.slt.dFGH", "cmp.sult.dFGH", "cmp.sle.dFGH", "cmp.sule.dFGH",
|
||||
false, "cmp.or.dFGH", "cmp.une.dFGH", "cmp.ne.dFGH",
|
||||
false, false, false, false,
|
||||
false, "cmp.sor.dFGH", "cmp.sune.dFGH", "cmp.sne.dFGH",
|
||||
false, false, false, false,
|
||||
"cvt.s.lFG", "cvt.d.lFG",
|
||||
}
|
||||
|
||||
local map_cop1_r6 = {
|
||||
shift = 21, mask = 31,
|
||||
[0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG",
|
||||
"mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG",
|
||||
false, "bc1eqzHB", false, false,
|
||||
false, "bc1nezHB", false, false,
|
||||
map_cop1s_r6, map_cop1d_r6, false, false,
|
||||
map_cop1w_r6, map_cop1l_r6,
|
||||
}
|
||||
|
||||
local function maprs_popTS(rs, rt)
|
||||
if rt == 0 then return 0 elseif rs == 0 then return 1
|
||||
elseif rs == rt then return 2 else return 3 end
|
||||
end
|
||||
|
||||
local map_pop06_r6 = {
|
||||
maprs = maprs_popTS, [0] = "blezSB", "blezalcTB", "bgezalcTB", "bgeucSTB"
|
||||
}
|
||||
local map_pop07_r6 = {
|
||||
maprs = maprs_popTS, [0] = "bgtzSB", "bgtzalcTB", "bltzalcTB", "bltucSTB"
|
||||
}
|
||||
local map_pop26_r6 = {
|
||||
maprs = maprs_popTS, "blezcTB", "bgezcTB", "bgecSTB"
|
||||
}
|
||||
local map_pop27_r6 = {
|
||||
maprs = maprs_popTS, "bgtzcTB", "bltzcTB", "bltcSTB"
|
||||
}
|
||||
|
||||
local function maprs_popS(rs, rt)
|
||||
if rs == 0 then return 0 else return 1 end
|
||||
end
|
||||
|
||||
local map_pop66_r6 = {
|
||||
maprs = maprs_popS, [0] = "jicTI", "beqzcSb"
|
||||
}
|
||||
local map_pop76_r6 = {
|
||||
maprs = maprs_popS, [0] = "jialcTI", "bnezcSb"
|
||||
}
|
||||
|
||||
local function maprs_popST(rs, rt)
|
||||
if rs >= rt then return 0 elseif rs == 0 then return 1 else return 2 end
|
||||
end
|
||||
|
||||
local map_pop10_r6 = {
|
||||
maprs = maprs_popST, [0] = "bovcSTB", "beqzalcTB", "beqcSTB"
|
||||
}
|
||||
local map_pop30_r6 = {
|
||||
maprs = maprs_popST, [0] = "bnvcSTB", "bnezalcTB", "bnecSTB"
|
||||
}
|
||||
|
||||
local map_pri_r6 = {
|
||||
[0] = map_special_r6, map_regimm_r6, "jJ", "jalJ",
|
||||
"beq|beqz|bST00B", "bne|bnezST0B", map_pop06_r6, map_pop07_r6,
|
||||
map_pop10_r6, "addiu|liTS0I", "sltiTSI", "sltiuTSI",
|
||||
"andiTSU", "ori|liTS0U", "xoriTSU", "aui|luiTS0U",
|
||||
map_cop0, map_cop1_r6, false, false,
|
||||
false, false, map_pop26_r6, map_pop27_r6,
|
||||
map_pop30_r6, "daddiuTSI", false, false,
|
||||
false, "dauiTSI", false, map_special3_r6,
|
||||
"lbTSO", "lhTSO", false, "lwTSO",
|
||||
"lbuTSO", "lhuTSO", false, false,
|
||||
"sbTSO", "shTSO", false, "swTSO",
|
||||
false, false, false, false,
|
||||
false, "lwc1HSO", "bc#", false,
|
||||
false, "ldc1HSO", map_pop66_r6, "ldTSO",
|
||||
false, "swc1HSO", "balc#", map_pcrel_r6,
|
||||
false, "sdc1HSO", map_pop76_r6, "sdTSO",
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_gpr = {
|
||||
[0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra",
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Output a nicely formatted line with an opcode and operands.
|
||||
local function putop(ctx, text, operands)
|
||||
local pos = ctx.pos
|
||||
local extra = ""
|
||||
if ctx.rel then
|
||||
local sym = ctx.symtab[ctx.rel]
|
||||
if sym then extra = "\t->"..sym end
|
||||
end
|
||||
if ctx.hexdump > 0 then
|
||||
ctx.out(format("%08x %s %-7s %s%s\n",
|
||||
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
|
||||
else
|
||||
ctx.out(format("%08x %-7s %s%s\n",
|
||||
ctx.addr+pos, text, concat(operands, ", "), extra))
|
||||
end
|
||||
ctx.pos = pos + 4
|
||||
end
|
||||
|
||||
-- Fallback for unknown opcodes.
|
||||
local function unknown(ctx)
|
||||
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
|
||||
end
|
||||
|
||||
local function get_be(ctx)
|
||||
local pos = ctx.pos
|
||||
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
|
||||
return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
|
||||
end
|
||||
|
||||
local function get_le(ctx)
|
||||
local pos = ctx.pos
|
||||
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
|
||||
return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
|
||||
end
|
||||
|
||||
-- Disassemble a single instruction.
|
||||
local function disass_ins(ctx)
|
||||
local op = ctx:get()
|
||||
local operands = {}
|
||||
local last = nil
|
||||
ctx.op = op
|
||||
ctx.rel = nil
|
||||
|
||||
local opat = ctx.map_pri[rshift(op, 26)]
|
||||
while type(opat) ~= "string" do
|
||||
if not opat then return unknown(ctx) end
|
||||
if opat.maprs then
|
||||
opat = opat[opat.maprs(band(rshift(op,21),31), band(rshift(op,16),31))]
|
||||
else
|
||||
opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
|
||||
end
|
||||
end
|
||||
local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
|
||||
local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
|
||||
if altname then pat = pat2 end
|
||||
|
||||
for p in gmatch(pat, ".") do
|
||||
local x = nil
|
||||
if p == "S" then
|
||||
x = map_gpr[band(rshift(op, 21), 31)]
|
||||
elseif p == "T" then
|
||||
x = map_gpr[band(rshift(op, 16), 31)]
|
||||
elseif p == "D" then
|
||||
x = map_gpr[band(rshift(op, 11), 31)]
|
||||
elseif p == "F" then
|
||||
x = "f"..band(rshift(op, 6), 31)
|
||||
elseif p == "G" then
|
||||
x = "f"..band(rshift(op, 11), 31)
|
||||
elseif p == "H" then
|
||||
x = "f"..band(rshift(op, 16), 31)
|
||||
elseif p == "R" then
|
||||
x = "f"..band(rshift(op, 21), 31)
|
||||
elseif p == "A" then
|
||||
x = band(rshift(op, 6), 31)
|
||||
elseif p == "a" then
|
||||
x = band(rshift(op, 6), 7)
|
||||
elseif p == "E" then
|
||||
x = band(rshift(op, 6), 31) + 32
|
||||
elseif p == "M" then
|
||||
x = band(rshift(op, 11), 31)
|
||||
elseif p == "N" then
|
||||
x = band(rshift(op, 16), 31)
|
||||
elseif p == "C" then
|
||||
x = band(rshift(op, 18), 7)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "K" then
|
||||
x = band(rshift(op, 11), 31) + 1
|
||||
elseif p == "P" then
|
||||
x = band(rshift(op, 11), 31) + 33
|
||||
elseif p == "L" then
|
||||
x = band(rshift(op, 11), 31) - last + 1
|
||||
elseif p == "Q" then
|
||||
x = band(rshift(op, 11), 31) - last + 33
|
||||
elseif p == "I" then
|
||||
x = arshift(lshift(op, 16), 16)
|
||||
elseif p == "2" then
|
||||
x = arshift(lshift(op, 13), 11)
|
||||
elseif p == "3" then
|
||||
x = arshift(lshift(op, 14), 11)
|
||||
elseif p == "U" then
|
||||
x = band(op, 0xffff)
|
||||
elseif p == "O" then
|
||||
local disp = arshift(lshift(op, 16), 16)
|
||||
operands[#operands] = format("%d(%s)", disp, last)
|
||||
elseif p == "X" then
|
||||
local index = map_gpr[band(rshift(op, 16), 31)]
|
||||
operands[#operands] = format("%s(%s)", index, last)
|
||||
elseif p == "B" then
|
||||
x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 14) + 4
|
||||
ctx.rel = x
|
||||
x = format("0x%08x", x)
|
||||
elseif p == "b" then
|
||||
x = ctx.addr + ctx.pos + arshift(lshift(op, 11), 9) + 4
|
||||
ctx.rel = x
|
||||
x = format("0x%08x", x)
|
||||
elseif p == "#" then
|
||||
x = ctx.addr + ctx.pos + arshift(lshift(op, 6), 4) + 4
|
||||
ctx.rel = x
|
||||
x = format("0x%08x", x)
|
||||
elseif p == "J" then
|
||||
local a = ctx.addr + ctx.pos
|
||||
x = a - band(a, 0x0fffffff) + band(op, 0x03ffffff)*4
|
||||
ctx.rel = x
|
||||
x = format("0x%08x", x)
|
||||
elseif p == "V" then
|
||||
x = band(rshift(op, 8), 7)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "W" then
|
||||
x = band(op, 7)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "Y" then
|
||||
x = band(rshift(op, 6), 0x000fffff)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "Z" then
|
||||
x = band(rshift(op, 6), 1023)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "0" then
|
||||
if last == "r0" or last == 0 then
|
||||
local n = #operands
|
||||
operands[n] = nil
|
||||
last = operands[n-1]
|
||||
if altname then
|
||||
local a1, a2 = match(altname, "([^|]*)|(.*)")
|
||||
if a1 then name, altname = a1, a2
|
||||
else name = altname end
|
||||
end
|
||||
end
|
||||
elseif p == "1" then
|
||||
if last == "ra" then
|
||||
operands[#operands] = nil
|
||||
end
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
if x then operands[#operands+1] = x; last = x end
|
||||
end
|
||||
|
||||
return putop(ctx, name, operands)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Disassemble a block of code.
|
||||
local function disass_block(ctx, ofs, len)
|
||||
if not ofs then ofs = 0 end
|
||||
local stop = len and ofs+len or #ctx.code
|
||||
stop = stop - stop % 4
|
||||
ctx.pos = ofs - ofs % 4
|
||||
ctx.rel = nil
|
||||
while ctx.pos < stop do disass_ins(ctx) end
|
||||
end
|
||||
|
||||
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
|
||||
local function create(code, addr, out)
|
||||
local ctx = {}
|
||||
ctx.code = code
|
||||
ctx.addr = addr or 0
|
||||
ctx.out = out or io.write
|
||||
ctx.symtab = {}
|
||||
ctx.disass = disass_block
|
||||
ctx.hexdump = 8
|
||||
ctx.get = get_be
|
||||
ctx.map_pri = map_pri
|
||||
return ctx
|
||||
end
|
||||
|
||||
local function create_el(code, addr, out)
|
||||
local ctx = create(code, addr, out)
|
||||
ctx.get = get_le
|
||||
return ctx
|
||||
end
|
||||
|
||||
local function create_r6(code, addr, out)
|
||||
local ctx = create(code, addr, out)
|
||||
ctx.map_pri = map_pri_r6
|
||||
return ctx
|
||||
end
|
||||
|
||||
local function create_r6_el(code, addr, out)
|
||||
local ctx = create(code, addr, out)
|
||||
ctx.get = get_le
|
||||
ctx.map_pri = map_pri_r6
|
||||
return ctx
|
||||
end
|
||||
|
||||
-- Simple API: disassemble code (a string) at address and output via out.
|
||||
local function disass(code, addr, out)
|
||||
create(code, addr, out):disass()
|
||||
end
|
||||
|
||||
local function disass_el(code, addr, out)
|
||||
create_el(code, addr, out):disass()
|
||||
end
|
||||
|
||||
local function disass_r6(code, addr, out)
|
||||
create_r6(code, addr, out):disass()
|
||||
end
|
||||
|
||||
local function disass_r6_el(code, addr, out)
|
||||
create_r6_el(code, addr, out):disass()
|
||||
end
|
||||
|
||||
-- Return register name for RID.
|
||||
local function regname(r)
|
||||
if r < 32 then return map_gpr[r] end
|
||||
return "f"..(r-32)
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
return {
|
||||
create = create,
|
||||
create_el = create_el,
|
||||
create_r6 = create_r6,
|
||||
create_r6_el = create_r6_el,
|
||||
disass = disass,
|
||||
disass_el = disass_el,
|
||||
disass_r6 = disass_r6,
|
||||
disass_r6_el = disass_r6_el,
|
||||
regname = regname
|
||||
}
|
||||
|
||||
17
thirdPart/luajit/src/jit/dis_mips64.lua
Normal file
17
thirdPart/luajit/src/jit/dis_mips64.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT MIPS64 disassembler wrapper module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This module just exports the big-endian functions from the
|
||||
-- MIPS disassembler module. All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
|
||||
return {
|
||||
create = dis_mips.create,
|
||||
disass = dis_mips.disass,
|
||||
regname = dis_mips.regname
|
||||
}
|
||||
|
||||
17
thirdPart/luajit/src/jit/dis_mips64el.lua
Normal file
17
thirdPart/luajit/src/jit/dis_mips64el.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT MIPS64EL disassembler wrapper module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This module just exports the little-endian functions from the
|
||||
-- MIPS disassembler module. All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
|
||||
return {
|
||||
create = dis_mips.create_el,
|
||||
disass = dis_mips.disass_el,
|
||||
regname = dis_mips.regname
|
||||
}
|
||||
|
||||
17
thirdPart/luajit/src/jit/dis_mips64r6.lua
Normal file
17
thirdPart/luajit/src/jit/dis_mips64r6.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT MIPS64R6 disassembler wrapper module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This module just exports the r6 big-endian functions from the
|
||||
-- MIPS disassembler module. All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
|
||||
return {
|
||||
create = dis_mips.create_r6,
|
||||
disass = dis_mips.disass_r6,
|
||||
regname = dis_mips.regname
|
||||
}
|
||||
|
||||
17
thirdPart/luajit/src/jit/dis_mips64r6el.lua
Normal file
17
thirdPart/luajit/src/jit/dis_mips64r6el.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT MIPS64R6EL disassembler wrapper module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This module just exports the r6 little-endian functions from the
|
||||
-- MIPS disassembler module. All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
|
||||
return {
|
||||
create = dis_mips.create_r6_el,
|
||||
disass = dis_mips.disass_r6_el,
|
||||
regname = dis_mips.regname
|
||||
}
|
||||
|
||||
17
thirdPart/luajit/src/jit/dis_mipsel.lua
Normal file
17
thirdPart/luajit/src/jit/dis_mipsel.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT MIPSEL disassembler wrapper module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This module just exports the little-endian functions from the
|
||||
-- MIPS disassembler module. All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
|
||||
return {
|
||||
create = dis_mips.create_el,
|
||||
disass = dis_mips.disass_el,
|
||||
regname = dis_mips.regname
|
||||
}
|
||||
|
||||
591
thirdPart/luajit/src/jit/dis_ppc.lua
Normal file
591
thirdPart/luajit/src/jit/dis_ppc.lua
Normal file
@@ -0,0 +1,591 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT PPC disassembler module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT/X license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This is a helper module used by the LuaJIT machine code dumper module.
|
||||
--
|
||||
-- It disassembles all common, non-privileged 32/64 bit PowerPC instructions
|
||||
-- plus the e500 SPE instructions and some Cell/Xenon extensions.
|
||||
--
|
||||
-- NYI: VMX, VMX128
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
local byte, format = string.byte, string.format
|
||||
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
|
||||
local concat = table.concat
|
||||
local bit = require("bit")
|
||||
local band, bor, tohex = bit.band, bit.bor, bit.tohex
|
||||
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Primary and extended opcode maps
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_crops = {
|
||||
shift = 1, mask = 1023,
|
||||
[0] = "mcrfXX",
|
||||
[33] = "crnor|crnotCCC=", [129] = "crandcCCC",
|
||||
[193] = "crxor|crclrCCC%", [225] = "crnandCCC",
|
||||
[257] = "crandCCC", [289] = "creqv|crsetCCC%",
|
||||
[417] = "crorcCCC", [449] = "cror|crmoveCCC=",
|
||||
[16] = "b_lrKB", [528] = "b_ctrKB",
|
||||
[150] = "isync",
|
||||
}
|
||||
|
||||
local map_rlwinm = setmetatable({
|
||||
shift = 0, mask = -1,
|
||||
},
|
||||
{ __index = function(t, x)
|
||||
local rot = band(rshift(x, 11), 31)
|
||||
local mb = band(rshift(x, 6), 31)
|
||||
local me = band(rshift(x, 1), 31)
|
||||
if mb == 0 and me == 31-rot then
|
||||
return "slwiRR~A."
|
||||
elseif me == 31 and mb == 32-rot then
|
||||
return "srwiRR~-A."
|
||||
else
|
||||
return "rlwinmRR~AAA."
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
local map_rld = {
|
||||
shift = 2, mask = 7,
|
||||
[0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.",
|
||||
{
|
||||
shift = 1, mask = 1,
|
||||
[0] = "rldclRR~RM.", "rldcrRR~RM.",
|
||||
},
|
||||
}
|
||||
|
||||
local map_ext = setmetatable({
|
||||
shift = 1, mask = 1023,
|
||||
|
||||
[0] = "cmp_YLRR", [32] = "cmpl_YLRR",
|
||||
[4] = "twARR", [68] = "tdARR",
|
||||
|
||||
[8] = "subfcRRR.", [40] = "subfRRR.",
|
||||
[104] = "negRR.", [136] = "subfeRRR.",
|
||||
[200] = "subfzeRR.", [232] = "subfmeRR.",
|
||||
[520] = "subfcoRRR.", [552] = "subfoRRR.",
|
||||
[616] = "negoRR.", [648] = "subfeoRRR.",
|
||||
[712] = "subfzeoRR.", [744] = "subfmeoRR.",
|
||||
|
||||
[9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.",
|
||||
[457] = "divduRRR.", [489] = "divdRRR.",
|
||||
[745] = "mulldoRRR.",
|
||||
[969] = "divduoRRR.", [1001] = "divdoRRR.",
|
||||
|
||||
[10] = "addcRRR.", [138] = "addeRRR.",
|
||||
[202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.",
|
||||
[522] = "addcoRRR.", [650] = "addeoRRR.",
|
||||
[714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.",
|
||||
|
||||
[11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.",
|
||||
[459] = "divwuRRR.", [491] = "divwRRR.",
|
||||
[747] = "mullwoRRR.",
|
||||
[971] = "divwouRRR.", [1003] = "divwoRRR.",
|
||||
|
||||
[15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR",
|
||||
|
||||
[144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", },
|
||||
[19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", },
|
||||
[371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", },
|
||||
[339] = {
|
||||
shift = 11, mask = 1023,
|
||||
[32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR",
|
||||
},
|
||||
[467] = {
|
||||
shift = 11, mask = 1023,
|
||||
[32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR",
|
||||
},
|
||||
|
||||
[20] = "lwarxRR0R", [84] = "ldarxRR0R",
|
||||
|
||||
[21] = "ldxRR0R", [53] = "lduxRRR",
|
||||
[149] = "stdxRR0R", [181] = "stduxRRR",
|
||||
[341] = "lwaxRR0R", [373] = "lwauxRRR",
|
||||
|
||||
[23] = "lwzxRR0R", [55] = "lwzuxRRR",
|
||||
[87] = "lbzxRR0R", [119] = "lbzuxRRR",
|
||||
[151] = "stwxRR0R", [183] = "stwuxRRR",
|
||||
[215] = "stbxRR0R", [247] = "stbuxRRR",
|
||||
[279] = "lhzxRR0R", [311] = "lhzuxRRR",
|
||||
[343] = "lhaxRR0R", [375] = "lhauxRRR",
|
||||
[407] = "sthxRR0R", [439] = "sthuxRRR",
|
||||
|
||||
[54] = "dcbst-R0R", [86] = "dcbf-R0R",
|
||||
[150] = "stwcxRR0R.", [214] = "stdcxRR0R.",
|
||||
[246] = "dcbtst-R0R", [278] = "dcbt-R0R",
|
||||
[310] = "eciwxRR0R", [438] = "ecowxRR0R",
|
||||
[470] = "dcbi-RR",
|
||||
|
||||
[598] = {
|
||||
shift = 21, mask = 3,
|
||||
[0] = "sync", "lwsync", "ptesync",
|
||||
},
|
||||
[758] = "dcba-RR",
|
||||
[854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R",
|
||||
|
||||
[26] = "cntlzwRR~", [58] = "cntlzdRR~",
|
||||
[122] = "popcntbRR~",
|
||||
[154] = "prtywRR~", [186] = "prtydRR~",
|
||||
|
||||
[28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.",
|
||||
[284] = "eqvRR~R.", [316] = "xorRR~R.",
|
||||
[412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.",
|
||||
[508] = "cmpbRR~R",
|
||||
|
||||
[512] = "mcrxrX",
|
||||
|
||||
[532] = "ldbrxRR0R", [660] = "stdbrxRR0R",
|
||||
|
||||
[533] = "lswxRR0R", [597] = "lswiRR0A",
|
||||
[661] = "stswxRR0R", [725] = "stswiRR0A",
|
||||
|
||||
[534] = "lwbrxRR0R", [662] = "stwbrxRR0R",
|
||||
[790] = "lhbrxRR0R", [918] = "sthbrxRR0R",
|
||||
|
||||
[535] = "lfsxFR0R", [567] = "lfsuxFRR",
|
||||
[599] = "lfdxFR0R", [631] = "lfduxFRR",
|
||||
[663] = "stfsxFR0R", [695] = "stfsuxFRR",
|
||||
[727] = "stfdxFR0R", [759] = "stfduxFR0R",
|
||||
[855] = "lfiwaxFR0R",
|
||||
[983] = "stfiwxFR0R",
|
||||
|
||||
[24] = "slwRR~R.",
|
||||
|
||||
[27] = "sldRR~R.", [536] = "srwRR~R.",
|
||||
[792] = "srawRR~R.", [824] = "srawiRR~A.",
|
||||
|
||||
[794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.",
|
||||
[922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.",
|
||||
|
||||
[539] = "srdRR~R.",
|
||||
},
|
||||
{ __index = function(t, x)
|
||||
if band(x, 31) == 15 then return "iselRRRC" end
|
||||
end
|
||||
})
|
||||
|
||||
local map_ld = {
|
||||
shift = 0, mask = 3,
|
||||
[0] = "ldRRE", "lduRRE", "lwaRRE",
|
||||
}
|
||||
|
||||
local map_std = {
|
||||
shift = 0, mask = 3,
|
||||
[0] = "stdRRE", "stduRRE",
|
||||
}
|
||||
|
||||
local map_fps = {
|
||||
shift = 5, mask = 1,
|
||||
{
|
||||
shift = 1, mask = 15,
|
||||
[0] = false, false, "fdivsFFF.", false,
|
||||
"fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false,
|
||||
"fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false,
|
||||
"fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.",
|
||||
}
|
||||
}
|
||||
|
||||
local map_fpd = {
|
||||
shift = 5, mask = 1,
|
||||
[0] = {
|
||||
shift = 1, mask = 1023,
|
||||
[0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX",
|
||||
[38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>",
|
||||
[8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.",
|
||||
[136] = "fnabsF-F.", [264] = "fabsF-F.",
|
||||
[12] = "frspF-F.",
|
||||
[14] = "fctiwF-F.", [15] = "fctiwzF-F.",
|
||||
[583] = "mffsF.", [711] = "mtfsfZF.",
|
||||
[392] = "frinF-F.", [424] = "frizF-F.",
|
||||
[456] = "fripF-F.", [488] = "frimF-F.",
|
||||
[814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.",
|
||||
},
|
||||
{
|
||||
shift = 1, mask = 15,
|
||||
[0] = false, false, "fdivFFF.", false,
|
||||
"fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.",
|
||||
"freF-F.", "fmulFF-F.", "frsqrteF-F.", false,
|
||||
"fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.",
|
||||
}
|
||||
}
|
||||
|
||||
local map_spe = {
|
||||
shift = 0, mask = 2047,
|
||||
|
||||
[512] = "evaddwRRR", [514] = "evaddiwRAR~",
|
||||
[516] = "evsubwRRR~", [518] = "evsubiwRAR~",
|
||||
[520] = "evabsRR", [521] = "evnegRR",
|
||||
[522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR",
|
||||
[525] = "evcntlzwRR", [526] = "evcntlswRR",
|
||||
|
||||
[527] = "brincRRR",
|
||||
|
||||
[529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR",
|
||||
[535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=",
|
||||
[537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR",
|
||||
|
||||
[544] = "evsrwuRRR", [545] = "evsrwsRRR",
|
||||
[546] = "evsrwiuRRA", [547] = "evsrwisRRA",
|
||||
[548] = "evslwRRR", [550] = "evslwiRRA",
|
||||
[552] = "evrlwRRR", [553] = "evsplatiRS",
|
||||
[554] = "evrlwiRRA", [555] = "evsplatfiRS",
|
||||
[556] = "evmergehiRRR", [557] = "evmergeloRRR",
|
||||
[558] = "evmergehiloRRR", [559] = "evmergelohiRRR",
|
||||
|
||||
[560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR",
|
||||
[562] = "evcmpltuYRR", [563] = "evcmpltsYRR",
|
||||
[564] = "evcmpeqYRR",
|
||||
|
||||
[632] = "evselRRR", [633] = "evselRRRW",
|
||||
[634] = "evselRRRW", [635] = "evselRRRW",
|
||||
[636] = "evselRRRW", [637] = "evselRRRW",
|
||||
[638] = "evselRRRW", [639] = "evselRRRW",
|
||||
|
||||
[640] = "evfsaddRRR", [641] = "evfssubRRR",
|
||||
[644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR",
|
||||
[648] = "evfsmulRRR", [649] = "evfsdivRRR",
|
||||
[652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR",
|
||||
[656] = "evfscfuiR-R", [657] = "evfscfsiR-R",
|
||||
[658] = "evfscfufR-R", [659] = "evfscfsfR-R",
|
||||
[660] = "evfsctuiR-R", [661] = "evfsctsiR-R",
|
||||
[662] = "evfsctufR-R", [663] = "evfsctsfR-R",
|
||||
[664] = "evfsctuizR-R", [666] = "evfsctsizR-R",
|
||||
[668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR",
|
||||
|
||||
[704] = "efsaddRRR", [705] = "efssubRRR",
|
||||
[708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR",
|
||||
[712] = "efsmulRRR", [713] = "efsdivRRR",
|
||||
[716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR",
|
||||
[719] = "efscfdR-R",
|
||||
[720] = "efscfuiR-R", [721] = "efscfsiR-R",
|
||||
[722] = "efscfufR-R", [723] = "efscfsfR-R",
|
||||
[724] = "efsctuiR-R", [725] = "efsctsiR-R",
|
||||
[726] = "efsctufR-R", [727] = "efsctsfR-R",
|
||||
[728] = "efsctuizR-R", [730] = "efsctsizR-R",
|
||||
[732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR",
|
||||
|
||||
[736] = "efdaddRRR", [737] = "efdsubRRR",
|
||||
[738] = "efdcfuidR-R", [739] = "efdcfsidR-R",
|
||||
[740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR",
|
||||
[744] = "efdmulRRR", [745] = "efddivRRR",
|
||||
[746] = "efdctuidzR-R", [747] = "efdctsidzR-R",
|
||||
[748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR",
|
||||
[751] = "efdcfsR-R",
|
||||
[752] = "efdcfuiR-R", [753] = "efdcfsiR-R",
|
||||
[754] = "efdcfufR-R", [755] = "efdcfsfR-R",
|
||||
[756] = "efdctuiR-R", [757] = "efdctsiR-R",
|
||||
[758] = "efdctufR-R", [759] = "efdctsfR-R",
|
||||
[760] = "efdctuizR-R", [762] = "efdctsizR-R",
|
||||
[764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR",
|
||||
|
||||
[768] = "evlddxRR0R", [769] = "evlddRR8",
|
||||
[770] = "evldwxRR0R", [771] = "evldwRR8",
|
||||
[772] = "evldhxRR0R", [773] = "evldhRR8",
|
||||
[776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2",
|
||||
[780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2",
|
||||
[782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2",
|
||||
[784] = "evlwhexRR0R", [785] = "evlwheRR4",
|
||||
[788] = "evlwhouxRR0R", [789] = "evlwhouRR4",
|
||||
[790] = "evlwhosxRR0R", [791] = "evlwhosRR4",
|
||||
[792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4",
|
||||
[796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4",
|
||||
|
||||
[800] = "evstddxRR0R", [801] = "evstddRR8",
|
||||
[802] = "evstdwxRR0R", [803] = "evstdwRR8",
|
||||
[804] = "evstdhxRR0R", [805] = "evstdhRR8",
|
||||
[816] = "evstwhexRR0R", [817] = "evstwheRR4",
|
||||
[820] = "evstwhoxRR0R", [821] = "evstwhoRR4",
|
||||
[824] = "evstwwexRR0R", [825] = "evstwweRR4",
|
||||
[828] = "evstwwoxRR0R", [829] = "evstwwoRR4",
|
||||
|
||||
[1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR",
|
||||
[1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR",
|
||||
[1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR",
|
||||
[1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR",
|
||||
[1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR",
|
||||
[1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR",
|
||||
[1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR",
|
||||
[1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR",
|
||||
[1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR",
|
||||
[1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR",
|
||||
[1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR",
|
||||
[1147] = "evmwsmfaRRR",
|
||||
|
||||
[1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR",
|
||||
[1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR",
|
||||
[1220] = "evmraRR",
|
||||
[1222] = "evdivwsRRR", [1223] = "evdivwuRRR",
|
||||
[1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR",
|
||||
[1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR",
|
||||
|
||||
[1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR",
|
||||
[1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR",
|
||||
[1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR",
|
||||
[1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR",
|
||||
[1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR",
|
||||
[1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR",
|
||||
[1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR",
|
||||
[1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR",
|
||||
[1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR",
|
||||
[1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR",
|
||||
[1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR",
|
||||
[1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR",
|
||||
[1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR",
|
||||
[1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR",
|
||||
[1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR",
|
||||
[1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR",
|
||||
[1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR",
|
||||
[1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR",
|
||||
[1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR",
|
||||
[1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR",
|
||||
[1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR",
|
||||
[1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR",
|
||||
[1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR",
|
||||
[1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR",
|
||||
[1491] = "evmwssfanRRR", [1496] = "evmwumianRRR",
|
||||
[1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR",
|
||||
}
|
||||
|
||||
local map_pri = {
|
||||
[0] = false, false, "tdiARI", "twiARI",
|
||||
map_spe, false, false, "mulliRRI",
|
||||
"subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI",
|
||||
"addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I",
|
||||
"b_KBJ", "sc", "bKJ", map_crops,
|
||||
"rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.",
|
||||
"oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U",
|
||||
"andi.RR~U", "andis.RR~U", map_rld, map_ext,
|
||||
"lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD",
|
||||
"stwRRD", "stwuRRD", "stbRRD", "stbuRRD",
|
||||
"lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD",
|
||||
"sthRRD", "sthuRRD", "lmwRRD", "stmwRRD",
|
||||
"lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD",
|
||||
"stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD",
|
||||
false, false, map_ld, map_fps,
|
||||
false, false, map_std, map_fpd,
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_gpr = {
|
||||
[0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
|
||||
}
|
||||
|
||||
local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", }
|
||||
|
||||
-- Format a condition bit.
|
||||
local function condfmt(cond)
|
||||
if cond <= 3 then
|
||||
return map_cond[band(cond, 3)]
|
||||
else
|
||||
return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)])
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Output a nicely formatted line with an opcode and operands.
|
||||
local function putop(ctx, text, operands)
|
||||
local pos = ctx.pos
|
||||
local extra = ""
|
||||
if ctx.rel then
|
||||
local sym = ctx.symtab[ctx.rel]
|
||||
if sym then extra = "\t->"..sym end
|
||||
end
|
||||
if ctx.hexdump > 0 then
|
||||
ctx.out(format("%08x %s %-7s %s%s\n",
|
||||
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
|
||||
else
|
||||
ctx.out(format("%08x %-7s %s%s\n",
|
||||
ctx.addr+pos, text, concat(operands, ", "), extra))
|
||||
end
|
||||
ctx.pos = pos + 4
|
||||
end
|
||||
|
||||
-- Fallback for unknown opcodes.
|
||||
local function unknown(ctx)
|
||||
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
|
||||
end
|
||||
|
||||
-- Disassemble a single instruction.
|
||||
local function disass_ins(ctx)
|
||||
local pos = ctx.pos
|
||||
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
|
||||
local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
|
||||
local operands = {}
|
||||
local last = nil
|
||||
local rs = 21
|
||||
ctx.op = op
|
||||
ctx.rel = nil
|
||||
|
||||
local opat = map_pri[rshift(b0, 2)]
|
||||
while type(opat) ~= "string" do
|
||||
if not opat then return unknown(ctx) end
|
||||
opat = opat[band(rshift(op, opat.shift), opat.mask)]
|
||||
end
|
||||
local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
|
||||
local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)")
|
||||
if altname then pat = pat2 end
|
||||
|
||||
for p in gmatch(pat, ".") do
|
||||
local x = nil
|
||||
if p == "R" then
|
||||
x = map_gpr[band(rshift(op, rs), 31)]
|
||||
rs = rs - 5
|
||||
elseif p == "F" then
|
||||
x = "f"..band(rshift(op, rs), 31)
|
||||
rs = rs - 5
|
||||
elseif p == "A" then
|
||||
x = band(rshift(op, rs), 31)
|
||||
rs = rs - 5
|
||||
elseif p == "S" then
|
||||
x = arshift(lshift(op, 27-rs), 27)
|
||||
rs = rs - 5
|
||||
elseif p == "I" then
|
||||
x = arshift(lshift(op, 16), 16)
|
||||
elseif p == "U" then
|
||||
x = band(op, 0xffff)
|
||||
elseif p == "D" or p == "E" then
|
||||
local disp = arshift(lshift(op, 16), 16)
|
||||
if p == "E" then disp = band(disp, -4) end
|
||||
if last == "r0" then last = "0" end
|
||||
operands[#operands] = format("%d(%s)", disp, last)
|
||||
elseif p >= "2" and p <= "8" then
|
||||
local disp = band(rshift(op, rs), 31) * p
|
||||
if last == "r0" then last = "0" end
|
||||
operands[#operands] = format("%d(%s)", disp, last)
|
||||
elseif p == "H" then
|
||||
x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4)
|
||||
rs = rs - 5
|
||||
elseif p == "M" then
|
||||
x = band(rshift(op, rs), 31) + band(op, 0x20)
|
||||
elseif p == "C" then
|
||||
x = condfmt(band(rshift(op, rs), 31))
|
||||
rs = rs - 5
|
||||
elseif p == "B" then
|
||||
local bo = rshift(op, 21)
|
||||
local cond = band(rshift(op, 16), 31)
|
||||
local cn = ""
|
||||
rs = rs - 10
|
||||
if band(bo, 4) == 0 then
|
||||
cn = band(bo, 2) == 0 and "dnz" or "dz"
|
||||
if band(bo, 0x10) == 0 then
|
||||
cn = cn..(band(bo, 8) == 0 and "f" or "t")
|
||||
end
|
||||
if band(bo, 0x10) == 0 then x = condfmt(cond) end
|
||||
name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+")
|
||||
elseif band(bo, 0x10) == 0 then
|
||||
cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)]
|
||||
if cond > 3 then x = "cr"..rshift(cond, 2) end
|
||||
name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+")
|
||||
end
|
||||
name = gsub(name, "_", cn)
|
||||
elseif p == "J" then
|
||||
x = arshift(lshift(op, 27-rs), 29-rs)*4
|
||||
if band(op, 2) == 0 then x = ctx.addr + pos + x end
|
||||
ctx.rel = x
|
||||
x = "0x"..tohex(x)
|
||||
elseif p == "K" then
|
||||
if band(op, 1) ~= 0 then name = name.."l" end
|
||||
if band(op, 2) ~= 0 then name = name.."a" end
|
||||
elseif p == "X" or p == "Y" then
|
||||
x = band(rshift(op, rs+2), 7)
|
||||
if x == 0 and p == "Y" then x = nil else x = "cr"..x end
|
||||
rs = rs - 5
|
||||
elseif p == "W" then
|
||||
x = "cr"..band(op, 7)
|
||||
elseif p == "Z" then
|
||||
x = band(rshift(op, rs-4), 255)
|
||||
rs = rs - 10
|
||||
elseif p == ">" then
|
||||
operands[#operands] = rshift(operands[#operands], 1)
|
||||
elseif p == "0" then
|
||||
if last == "r0" then
|
||||
operands[#operands] = nil
|
||||
if altname then name = altname end
|
||||
end
|
||||
elseif p == "L" then
|
||||
name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w")
|
||||
elseif p == "." then
|
||||
if band(op, 1) == 1 then name = name.."." end
|
||||
elseif p == "N" then
|
||||
if op == 0x60000000 then name = "nop"; break end
|
||||
elseif p == "~" then
|
||||
local n = #operands
|
||||
operands[n-1], operands[n] = operands[n], operands[n-1]
|
||||
elseif p == "=" then
|
||||
local n = #operands
|
||||
if last == operands[n-1] then
|
||||
operands[n] = nil
|
||||
name = altname
|
||||
end
|
||||
elseif p == "%" then
|
||||
local n = #operands
|
||||
if last == operands[n-1] and last == operands[n-2] then
|
||||
operands[n] = nil
|
||||
operands[n-1] = nil
|
||||
name = altname
|
||||
end
|
||||
elseif p == "-" then
|
||||
rs = rs - 5
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
if x then operands[#operands+1] = x; last = x end
|
||||
end
|
||||
|
||||
return putop(ctx, name, operands)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Disassemble a block of code.
|
||||
local function disass_block(ctx, ofs, len)
|
||||
if not ofs then ofs = 0 end
|
||||
local stop = len and ofs+len or #ctx.code
|
||||
stop = stop - stop % 4
|
||||
ctx.pos = ofs - ofs % 4
|
||||
ctx.rel = nil
|
||||
while ctx.pos < stop do disass_ins(ctx) end
|
||||
end
|
||||
|
||||
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
|
||||
local function create(code, addr, out)
|
||||
local ctx = {}
|
||||
ctx.code = code
|
||||
ctx.addr = addr or 0
|
||||
ctx.out = out or io.write
|
||||
ctx.symtab = {}
|
||||
ctx.disass = disass_block
|
||||
ctx.hexdump = 8
|
||||
return ctx
|
||||
end
|
||||
|
||||
-- Simple API: disassemble code (a string) at address and output via out.
|
||||
local function disass(code, addr, out)
|
||||
create(code, addr, out):disass()
|
||||
end
|
||||
|
||||
-- Return register name for RID.
|
||||
local function regname(r)
|
||||
if r < 32 then return map_gpr[r] end
|
||||
return "f"..(r-32)
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
return {
|
||||
create = create,
|
||||
disass = disass,
|
||||
regname = regname
|
||||
}
|
||||
|
||||
17
thirdPart/luajit/src/jit/dis_x64.lua
Normal file
17
thirdPart/luajit/src/jit/dis_x64.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT x64 disassembler wrapper module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This module just exports the 64 bit functions from the combined
|
||||
-- x86/x64 disassembler module. All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local dis_x86 = require((string.match(..., ".*%.") or "").."dis_x86")
|
||||
return {
|
||||
create = dis_x86.create64,
|
||||
disass = dis_x86.disass64,
|
||||
regname = dis_x86.regname64
|
||||
}
|
||||
|
||||
953
thirdPart/luajit/src/jit/dis_x86.lua
Normal file
953
thirdPart/luajit/src/jit/dis_x86.lua
Normal file
@@ -0,0 +1,953 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT x86/x64 disassembler module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This is a helper module used by the LuaJIT machine code dumper module.
|
||||
--
|
||||
-- Sending small code snippets to an external disassembler and mixing the
|
||||
-- output with our own stuff was too fragile. So I had to bite the bullet
|
||||
-- and write yet another x86 disassembler. Oh well ...
|
||||
--
|
||||
-- The output format is very similar to what ndisasm generates. But it has
|
||||
-- been developed independently by looking at the opcode tables from the
|
||||
-- Intel and AMD manuals. The supported instruction set is quite extensive
|
||||
-- and reflects what a current generation Intel or AMD CPU implements in
|
||||
-- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3,
|
||||
-- SSE4.1, SSE4.2, SSE4a, AVX, AVX2 and even privileged and hypervisor
|
||||
-- (VMX/SVM) instructions.
|
||||
--
|
||||
-- Notes:
|
||||
-- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported.
|
||||
-- * No attempt at optimization has been made -- it's fast enough for my needs.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
local sub, byte, format = string.sub, string.byte, string.format
|
||||
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
|
||||
local lower, rep = string.lower, string.rep
|
||||
local bit = require("bit")
|
||||
local tohex = bit.tohex
|
||||
|
||||
-- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on.
|
||||
local map_opc1_32 = {
|
||||
--0x
|
||||
[0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es",
|
||||
"orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*",
|
||||
--1x
|
||||
"adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss",
|
||||
"sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds",
|
||||
--2x
|
||||
"andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa",
|
||||
"subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das",
|
||||
--3x
|
||||
"xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa",
|
||||
"cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas",
|
||||
--4x
|
||||
"incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR",
|
||||
"decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR",
|
||||
--5x
|
||||
"pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR",
|
||||
"popUR","popUR","popUR","popUR","popUR","popUR","popUR","popUR",
|
||||
--6x
|
||||
"sz*pushaw,pusha","sz*popaw,popa","boundVrm","arplWmr",
|
||||
"fs:seg","gs:seg","o16:","a16",
|
||||
"pushUi","imulVrmi","pushBs","imulVrms",
|
||||
"insb","insVS","outsb","outsVS",
|
||||
--7x
|
||||
"joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj",
|
||||
"jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj",
|
||||
--8x
|
||||
"arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms",
|
||||
"testBmr","testVmr","xchgBrm","xchgVrm",
|
||||
"movBmr","movVmr","movBrm","movVrm",
|
||||
"movVmg","leaVrm","movWgm","popUm",
|
||||
--9x
|
||||
"nop*xchgVaR|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR",
|
||||
"xchgVaR","xchgVaR","xchgVaR","xchgVaR",
|
||||
"sz*cbw,cwde,cdqe","sz*cwd,cdq,cqo","call farViw","wait",
|
||||
"sz*pushfw,pushf","sz*popfw,popf","sahf","lahf",
|
||||
--Ax
|
||||
"movBao","movVao","movBoa","movVoa",
|
||||
"movsb","movsVS","cmpsb","cmpsVS",
|
||||
"testBai","testVai","stosb","stosVS",
|
||||
"lodsb","lodsVS","scasb","scasVS",
|
||||
--Bx
|
||||
"movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi",
|
||||
"movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI",
|
||||
--Cx
|
||||
"shift!Bmu","shift!Vmu","retBw","ret","vex*3$lesVrm","vex*2$ldsVrm","movBmi","movVmi",
|
||||
"enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS",
|
||||
--Dx
|
||||
"shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb",
|
||||
"fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7",
|
||||
--Ex
|
||||
"loopneBj","loopeBj","loopBj","sz*jcxzBj,jecxzBj,jrcxzBj",
|
||||
"inBau","inVau","outBua","outVua",
|
||||
"callVj","jmpVj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda",
|
||||
--Fx
|
||||
"lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm",
|
||||
"clc","stc","cli","sti","cld","std","incb!Bm","incd!Vm",
|
||||
}
|
||||
assert(#map_opc1_32 == 255)
|
||||
|
||||
-- Map for 1st opcode byte in 64 bit mode (overrides only).
|
||||
local map_opc1_64 = setmetatable({
|
||||
[0x06]=false, [0x07]=false, [0x0e]=false,
|
||||
[0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false,
|
||||
[0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false,
|
||||
[0x60]=false, [0x61]=false, [0x62]=false, [0x63]="movsxdVrDmt", [0x67]="a32:",
|
||||
[0x40]="rex*", [0x41]="rex*b", [0x42]="rex*x", [0x43]="rex*xb",
|
||||
[0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb",
|
||||
[0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb",
|
||||
[0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb",
|
||||
[0x82]=false, [0x9a]=false, [0xc4]="vex*3", [0xc5]="vex*2", [0xce]=false,
|
||||
[0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false,
|
||||
}, { __index = map_opc1_32 })
|
||||
|
||||
-- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you.
|
||||
-- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2
|
||||
local map_opc2 = {
|
||||
--0x
|
||||
[0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret",
|
||||
"invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu",
|
||||
--1x
|
||||
"movupsXrm|movssXrvm|movupdXrm|movsdXrvm",
|
||||
"movupsXmr|movssXmvr|movupdXmr|movsdXmvr",
|
||||
"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm",
|
||||
"movlpsXmr||movlpdXmr",
|
||||
"unpcklpsXrvm||unpcklpdXrvm",
|
||||
"unpckhpsXrvm||unpckhpdXrvm",
|
||||
"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm",
|
||||
"movhpsXmr||movhpdXmr",
|
||||
"$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm",
|
||||
"hintnopVm","hintnopVm","hintnopVm","hintnopVm",
|
||||
--2x
|
||||
"movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil,
|
||||
"movapsXrm||movapdXrm",
|
||||
"movapsXmr||movapdXmr",
|
||||
"cvtpi2psXrMm|cvtsi2ssXrvVmt|cvtpi2pdXrMm|cvtsi2sdXrvVmt",
|
||||
"movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr",
|
||||
"cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm",
|
||||
"cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm",
|
||||
"ucomissXrm||ucomisdXrm",
|
||||
"comissXrm||comisdXrm",
|
||||
--3x
|
||||
"wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,"getsec",
|
||||
"opc3*38",nil,"opc3*3a",nil,nil,nil,nil,nil,
|
||||
--4x
|
||||
"cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm",
|
||||
"cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm",
|
||||
"cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm",
|
||||
"cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm",
|
||||
--5x
|
||||
"movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm",
|
||||
"rsqrtpsXrm|rsqrtssXrvm","rcppsXrm|rcpssXrvm",
|
||||
"andpsXrvm||andpdXrvm","andnpsXrvm||andnpdXrvm",
|
||||
"orpsXrvm||orpdXrvm","xorpsXrvm||xorpdXrvm",
|
||||
"addpsXrvm|addssXrvm|addpdXrvm|addsdXrvm","mulpsXrvm|mulssXrvm|mulpdXrvm|mulsdXrvm",
|
||||
"cvtps2pdXrm|cvtss2sdXrvm|cvtpd2psXrm|cvtsd2ssXrvm",
|
||||
"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm",
|
||||
"subpsXrvm|subssXrvm|subpdXrvm|subsdXrvm","minpsXrvm|minssXrvm|minpdXrvm|minsdXrvm",
|
||||
"divpsXrvm|divssXrvm|divpdXrvm|divsdXrvm","maxpsXrvm|maxssXrvm|maxpdXrvm|maxsdXrvm",
|
||||
--6x
|
||||
"punpcklbwPrvm","punpcklwdPrvm","punpckldqPrvm","packsswbPrvm",
|
||||
"pcmpgtbPrvm","pcmpgtwPrvm","pcmpgtdPrvm","packuswbPrvm",
|
||||
"punpckhbwPrvm","punpckhwdPrvm","punpckhdqPrvm","packssdwPrvm",
|
||||
"||punpcklqdqXrvm","||punpckhqdqXrvm",
|
||||
"movPrVSm","movqMrm|movdquXrm|movdqaXrm",
|
||||
--7x
|
||||
"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pvmu",
|
||||
"pshiftd!Pvmu","pshiftq!Mvmu||pshiftdq!Xvmu",
|
||||
"pcmpeqbPrvm","pcmpeqwPrvm","pcmpeqdPrvm","emms*|",
|
||||
"vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$",
|
||||
nil,nil,
|
||||
"||haddpdXrvm|haddpsXrvm","||hsubpdXrvm|hsubpsXrvm",
|
||||
"movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr",
|
||||
--8x
|
||||
"joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj",
|
||||
"jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj",
|
||||
--9x
|
||||
"setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm",
|
||||
"setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm",
|
||||
--Ax
|
||||
"push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil,
|
||||
"push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm",
|
||||
--Bx
|
||||
"cmpxchgBmr","cmpxchgVmr","$lssVrm","btrVmr",
|
||||
"$lfsVrm","$lgsVrm","movzxVrBmt","movzxVrWmt",
|
||||
"|popcntVrm","ud2Dp","bt!Vmu","btcVmr",
|
||||
"bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt",
|
||||
--Cx
|
||||
"xaddBmr","xaddVmr",
|
||||
"cmppsXrvmu|cmpssXrvmu|cmppdXrvmu|cmpsdXrvmu","$movntiVmr|",
|
||||
"pinsrwPrvWmu","pextrwDrPmu",
|
||||
"shufpsXrvmu||shufpdXrvmu","$cmpxchg!Qmp",
|
||||
"bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR",
|
||||
--Dx
|
||||
"||addsubpdXrvm|addsubpsXrvm","psrlwPrvm","psrldPrvm","psrlqPrvm",
|
||||
"paddqPrvm","pmullwPrvm",
|
||||
"|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm",
|
||||
"psubusbPrvm","psubuswPrvm","pminubPrvm","pandPrvm",
|
||||
"paddusbPrvm","padduswPrvm","pmaxubPrvm","pandnPrvm",
|
||||
--Ex
|
||||
"pavgbPrvm","psrawPrvm","psradPrvm","pavgwPrvm",
|
||||
"pmulhuwPrvm","pmulhwPrvm",
|
||||
"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr",
|
||||
"psubsbPrvm","psubswPrvm","pminswPrvm","porPrvm",
|
||||
"paddsbPrvm","paddswPrvm","pmaxswPrvm","pxorPrvm",
|
||||
--Fx
|
||||
"|||lddquXrm","psllwPrvm","pslldPrvm","psllqPrvm",
|
||||
"pmuludqPrvm","pmaddwdPrvm","psadbwPrvm","maskmovqMrm||maskmovdquXrm$",
|
||||
"psubbPrvm","psubwPrvm","psubdPrvm","psubqPrvm",
|
||||
"paddbPrvm","paddwPrvm","padddPrvm","ud",
|
||||
}
|
||||
assert(map_opc2[255] == "ud")
|
||||
|
||||
-- Map for three-byte opcodes. Can't wait for their next invention.
|
||||
local map_opc3 = {
|
||||
["38"] = { -- [66] 0f 38 xx
|
||||
--0x
|
||||
[0]="pshufbPrvm","phaddwPrvm","phadddPrvm","phaddswPrvm",
|
||||
"pmaddubswPrvm","phsubwPrvm","phsubdPrvm","phsubswPrvm",
|
||||
"psignbPrvm","psignwPrvm","psigndPrvm","pmulhrswPrvm",
|
||||
"||permilpsXrvm","||permilpdXrvm",nil,nil,
|
||||
--1x
|
||||
"||pblendvbXrma",nil,nil,nil,
|
||||
"||blendvpsXrma","||blendvpdXrma","||permpsXrvm","||ptestXrm",
|
||||
"||broadcastssXrm","||broadcastsdXrm","||broadcastf128XrlXm",nil,
|
||||
"pabsbPrm","pabswPrm","pabsdPrm",nil,
|
||||
--2x
|
||||
"||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm",
|
||||
"||pmovsxwqXrm","||pmovsxdqXrm",nil,nil,
|
||||
"||pmuldqXrvm","||pcmpeqqXrvm","||$movntdqaXrm","||packusdwXrvm",
|
||||
"||maskmovpsXrvm","||maskmovpdXrvm","||maskmovpsXmvr","||maskmovpdXmvr",
|
||||
--3x
|
||||
"||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm",
|
||||
"||pmovzxwqXrm","||pmovzxdqXrm","||permdXrvm","||pcmpgtqXrvm",
|
||||
"||pminsbXrvm","||pminsdXrvm","||pminuwXrvm","||pminudXrvm",
|
||||
"||pmaxsbXrvm","||pmaxsdXrvm","||pmaxuwXrvm","||pmaxudXrvm",
|
||||
--4x
|
||||
"||pmulddXrvm","||phminposuwXrm",nil,nil,
|
||||
nil,"||psrlvVSXrvm","||psravdXrvm","||psllvVSXrvm",
|
||||
--5x
|
||||
[0x58] = "||pbroadcastdXrlXm",[0x59] = "||pbroadcastqXrlXm",
|
||||
[0x5a] = "||broadcasti128XrlXm",
|
||||
--7x
|
||||
[0x78] = "||pbroadcastbXrlXm",[0x79] = "||pbroadcastwXrlXm",
|
||||
--8x
|
||||
[0x8c] = "||pmaskmovXrvVSm",
|
||||
[0x8e] = "||pmaskmovVSmXvr",
|
||||
--9x
|
||||
[0x96] = "||fmaddsub132pHXrvm",[0x97] = "||fmsubadd132pHXrvm",
|
||||
[0x98] = "||fmadd132pHXrvm",[0x99] = "||fmadd132sHXrvm",
|
||||
[0x9a] = "||fmsub132pHXrvm",[0x9b] = "||fmsub132sHXrvm",
|
||||
[0x9c] = "||fnmadd132pHXrvm",[0x9d] = "||fnmadd132sHXrvm",
|
||||
[0x9e] = "||fnmsub132pHXrvm",[0x9f] = "||fnmsub132sHXrvm",
|
||||
--Ax
|
||||
[0xa6] = "||fmaddsub213pHXrvm",[0xa7] = "||fmsubadd213pHXrvm",
|
||||
[0xa8] = "||fmadd213pHXrvm",[0xa9] = "||fmadd213sHXrvm",
|
||||
[0xaa] = "||fmsub213pHXrvm",[0xab] = "||fmsub213sHXrvm",
|
||||
[0xac] = "||fnmadd213pHXrvm",[0xad] = "||fnmadd213sHXrvm",
|
||||
[0xae] = "||fnmsub213pHXrvm",[0xaf] = "||fnmsub213sHXrvm",
|
||||
--Bx
|
||||
[0xb6] = "||fmaddsub231pHXrvm",[0xb7] = "||fmsubadd231pHXrvm",
|
||||
[0xb8] = "||fmadd231pHXrvm",[0xb9] = "||fmadd231sHXrvm",
|
||||
[0xba] = "||fmsub231pHXrvm",[0xbb] = "||fmsub231sHXrvm",
|
||||
[0xbc] = "||fnmadd231pHXrvm",[0xbd] = "||fnmadd231sHXrvm",
|
||||
[0xbe] = "||fnmsub231pHXrvm",[0xbf] = "||fnmsub231sHXrvm",
|
||||
--Dx
|
||||
[0xdc] = "||aesencXrvm", [0xdd] = "||aesenclastXrvm",
|
||||
[0xde] = "||aesdecXrvm", [0xdf] = "||aesdeclastXrvm",
|
||||
--Fx
|
||||
[0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt",
|
||||
[0xf7] = "| sarxVrmv| shlxVrmv| shrxVrmv",
|
||||
},
|
||||
|
||||
["3a"] = { -- [66] 0f 3a xx
|
||||
--0x
|
||||
[0x00]="||permqXrmu","||permpdXrmu","||pblenddXrvmu",nil,
|
||||
"||permilpsXrmu","||permilpdXrmu","||perm2f128Xrvmu",nil,
|
||||
"||roundpsXrmu","||roundpdXrmu","||roundssXrvmu","||roundsdXrvmu",
|
||||
"||blendpsXrvmu","||blendpdXrvmu","||pblendwXrvmu","palignrPrvmu",
|
||||
--1x
|
||||
nil,nil,nil,nil,
|
||||
"||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru",
|
||||
"||insertf128XrvlXmu","||extractf128XlXmYru",nil,nil,
|
||||
nil,nil,nil,nil,
|
||||
--2x
|
||||
"||pinsrbXrvVmu","||insertpsXrvmu","||pinsrXrvVmuS",nil,
|
||||
--3x
|
||||
[0x38] = "||inserti128Xrvmu",[0x39] = "||extracti128XlXmYru",
|
||||
--4x
|
||||
[0x40] = "||dppsXrvmu",
|
||||
[0x41] = "||dppdXrvmu",
|
||||
[0x42] = "||mpsadbwXrvmu",
|
||||
[0x44] = "||pclmulqdqXrvmu",
|
||||
[0x46] = "||perm2i128Xrvmu",
|
||||
[0x4a] = "||blendvpsXrvmb",[0x4b] = "||blendvpdXrvmb",
|
||||
[0x4c] = "||pblendvbXrvmb",
|
||||
--6x
|
||||
[0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu",
|
||||
[0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu",
|
||||
[0xdf] = "||aeskeygenassistXrmu",
|
||||
--Fx
|
||||
[0xf0] = "||| rorxVrmu",
|
||||
},
|
||||
}
|
||||
|
||||
-- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands).
|
||||
local map_opcvm = {
|
||||
[0xc1]="vmcall",[0xc2]="vmlaunch",[0xc3]="vmresume",[0xc4]="vmxoff",
|
||||
[0xc8]="monitor",[0xc9]="mwait",
|
||||
[0xd8]="vmrun",[0xd9]="vmmcall",[0xda]="vmload",[0xdb]="vmsave",
|
||||
[0xdc]="stgi",[0xdd]="clgi",[0xde]="skinit",[0xdf]="invlpga",
|
||||
[0xf8]="swapgs",[0xf9]="rdtscp",
|
||||
}
|
||||
|
||||
-- Map for FP opcodes. And you thought stack machines are simple?
|
||||
local map_opcfp = {
|
||||
-- D8-DF 00-BF: opcodes with a memory operand.
|
||||
-- D8
|
||||
[0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm",
|
||||
"fldFm",nil,"fstFm","fstpFm","fldenvVm","fldcwWm","fnstenvVm","fnstcwWm",
|
||||
-- DA
|
||||
"fiaddDm","fimulDm","ficomDm","ficompDm",
|
||||
"fisubDm","fisubrDm","fidivDm","fidivrDm",
|
||||
-- DB
|
||||
"fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp",
|
||||
-- DC
|
||||
"faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm",
|
||||
-- DD
|
||||
"fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm",
|
||||
-- DE
|
||||
"fiaddWm","fimulWm","ficomWm","ficompWm",
|
||||
"fisubWm","fisubrWm","fidivWm","fidivrWm",
|
||||
-- DF
|
||||
"fildWm","fisttpWm","fistWm","fistpWm",
|
||||
"fbld twordFmp","fildQm","fbstp twordFmp","fistpQm",
|
||||
-- xx C0-FF: opcodes with a pseudo-register operand.
|
||||
-- D8
|
||||
"faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf",
|
||||
-- D9
|
||||
"fldFf","fxchFf",{"fnop"},nil,
|
||||
{"fchs","fabs",nil,nil,"ftst","fxam"},
|
||||
{"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"},
|
||||
{"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"},
|
||||
{"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"},
|
||||
-- DA
|
||||
"fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil,
|
||||
-- DB
|
||||
"fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf",
|
||||
{nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil,
|
||||
-- DC
|
||||
"fadd toFf","fmul toFf",nil,nil,
|
||||
"fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf",
|
||||
-- DD
|
||||
"ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil,
|
||||
-- DE
|
||||
"faddpFf","fmulpFf",nil,{nil,"fcompp"},
|
||||
"fsubrpFf","fsubpFf","fdivrpFf","fdivpFf",
|
||||
-- DF
|
||||
nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil,
|
||||
}
|
||||
assert(map_opcfp[126] == "fcomipFf")
|
||||
|
||||
-- Map for opcode groups. The subkey is sp from the ModRM byte.
|
||||
local map_opcgroup = {
|
||||
arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" },
|
||||
shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" },
|
||||
testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" },
|
||||
testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" },
|
||||
incb = { "inc", "dec" },
|
||||
incd = { "inc", "dec", "callUmp", "$call farDmp",
|
||||
"jmpUmp", "$jmp farDmp", "pushUm" },
|
||||
sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" },
|
||||
sgdt = { "vm*$sgdt", "vm*$sidt", "$lgdt", "vm*$lidt",
|
||||
"smsw", nil, "lmsw", "vm*$invlpg" },
|
||||
bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" },
|
||||
cmpxchg = { nil, "sz*,cmpxchg8bQmp,cmpxchg16bXmp", nil, nil,
|
||||
nil, nil, "vmptrld|vmxon|vmclear", "vmptrst" },
|
||||
pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" },
|
||||
pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" },
|
||||
pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" },
|
||||
pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" },
|
||||
fxsave = { "$fxsave", "$fxrstor", "$ldmxcsr", "$stmxcsr",
|
||||
nil, "lfenceDp$", "mfenceDp$", "sfenceDp$clflush" },
|
||||
prefetch = { "prefetch", "prefetchw" },
|
||||
prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" },
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Maps for register names.
|
||||
local map_regs = {
|
||||
B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
|
||||
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
|
||||
B64 = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
|
||||
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
|
||||
W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
|
||||
"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" },
|
||||
D = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
|
||||
"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" },
|
||||
Q = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" },
|
||||
M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
|
||||
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext!
|
||||
X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
|
||||
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" },
|
||||
Y = { "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7",
|
||||
"ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15" },
|
||||
}
|
||||
local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" }
|
||||
|
||||
-- Maps for size names.
|
||||
local map_sz2n = {
|
||||
B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, Y = 32,
|
||||
}
|
||||
local map_sz2prefix = {
|
||||
B = "byte", W = "word", D = "dword",
|
||||
Q = "qword",
|
||||
M = "qword", X = "xword", Y = "yword",
|
||||
F = "dword", G = "qword", -- No need for sizes/register names for these two.
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Output a nicely formatted line with an opcode and operands.
|
||||
local function putop(ctx, text, operands)
|
||||
local code, pos, hex = ctx.code, ctx.pos, ""
|
||||
local hmax = ctx.hexdump
|
||||
if hmax > 0 then
|
||||
for i=ctx.start,pos-1 do
|
||||
hex = hex..format("%02X", byte(code, i, i))
|
||||
end
|
||||
if #hex > hmax then hex = sub(hex, 1, hmax)..". "
|
||||
else hex = hex..rep(" ", hmax-#hex+2) end
|
||||
end
|
||||
if operands then text = text.." "..operands end
|
||||
if ctx.o16 then text = "o16 "..text; ctx.o16 = false end
|
||||
if ctx.a32 then text = "a32 "..text; ctx.a32 = false end
|
||||
if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end
|
||||
if ctx.rex then
|
||||
local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "")..
|
||||
(ctx.rexx and "x" or "")..(ctx.rexb and "b" or "")..
|
||||
(ctx.vexl and "l" or "")
|
||||
if ctx.vexv and ctx.vexv ~= 0 then t = t.."v"..ctx.vexv end
|
||||
if t ~= "" then text = ctx.rex.."."..t.." "..gsub(text, "^ ", "")
|
||||
elseif ctx.rex == "vex" then text = gsub("v"..text, "^v ", "") end
|
||||
ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
|
||||
ctx.rex = false; ctx.vexl = false; ctx.vexv = false
|
||||
end
|
||||
if ctx.seg then
|
||||
local text2, n = gsub(text, "%[", "["..ctx.seg..":")
|
||||
if n == 0 then text = ctx.seg.." "..text else text = text2 end
|
||||
ctx.seg = false
|
||||
end
|
||||
if ctx.lock then text = "lock "..text; ctx.lock = false end
|
||||
local imm = ctx.imm
|
||||
if imm then
|
||||
local sym = ctx.symtab[imm]
|
||||
if sym then text = text.."\t->"..sym end
|
||||
end
|
||||
ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text))
|
||||
ctx.mrm = false
|
||||
ctx.vexv = false
|
||||
ctx.start = pos
|
||||
ctx.imm = nil
|
||||
end
|
||||
|
||||
-- Clear all prefix flags.
|
||||
local function clearprefixes(ctx)
|
||||
ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false
|
||||
ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
|
||||
ctx.rex = false; ctx.a32 = false; ctx.vexl = false
|
||||
end
|
||||
|
||||
-- Fallback for incomplete opcodes at the end.
|
||||
local function incomplete(ctx)
|
||||
ctx.pos = ctx.stop+1
|
||||
clearprefixes(ctx)
|
||||
return putop(ctx, "(incomplete)")
|
||||
end
|
||||
|
||||
-- Fallback for unknown opcodes.
|
||||
local function unknown(ctx)
|
||||
clearprefixes(ctx)
|
||||
return putop(ctx, "(unknown)")
|
||||
end
|
||||
|
||||
-- Return an immediate of the specified size.
|
||||
local function getimm(ctx, pos, n)
|
||||
if pos+n-1 > ctx.stop then return incomplete(ctx) end
|
||||
local code = ctx.code
|
||||
if n == 1 then
|
||||
local b1 = byte(code, pos, pos)
|
||||
return b1
|
||||
elseif n == 2 then
|
||||
local b1, b2 = byte(code, pos, pos+1)
|
||||
return b1+b2*256
|
||||
else
|
||||
local b1, b2, b3, b4 = byte(code, pos, pos+3)
|
||||
local imm = b1+b2*256+b3*65536+b4*16777216
|
||||
ctx.imm = imm
|
||||
return imm
|
||||
end
|
||||
end
|
||||
|
||||
-- Process pattern string and generate the operands.
|
||||
local function putpat(ctx, name, pat)
|
||||
local operands, regs, sz, mode, sp, rm, sc, rx, sdisp
|
||||
local code, pos, stop, vexl = ctx.code, ctx.pos, ctx.stop, ctx.vexl
|
||||
|
||||
-- Chars used: 1DFGHIMPQRSTUVWXYabcdfgijlmoprstuvwxyz
|
||||
for p in gmatch(pat, ".") do
|
||||
local x = nil
|
||||
if p == "V" or p == "U" then
|
||||
if ctx.rexw then sz = "Q"; ctx.rexw = false
|
||||
elseif ctx.o16 then sz = "W"; ctx.o16 = false
|
||||
elseif p == "U" and ctx.x64 then sz = "Q"
|
||||
else sz = "D" end
|
||||
regs = map_regs[sz]
|
||||
elseif p == "T" then
|
||||
if ctx.rexw then sz = "Q"; ctx.rexw = false else sz = "D" end
|
||||
regs = map_regs[sz]
|
||||
elseif p == "B" then
|
||||
sz = "B"
|
||||
regs = ctx.rex and map_regs.B64 or map_regs.B
|
||||
elseif match(p, "[WDQMXYFG]") then
|
||||
sz = p
|
||||
if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end
|
||||
regs = map_regs[sz]
|
||||
elseif p == "P" then
|
||||
sz = ctx.o16 and "X" or "M"; ctx.o16 = false
|
||||
if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end
|
||||
regs = map_regs[sz]
|
||||
elseif p == "H" then
|
||||
name = name..(ctx.rexw and "d" or "s")
|
||||
ctx.rexw = false
|
||||
elseif p == "S" then
|
||||
name = name..lower(sz)
|
||||
elseif p == "s" then
|
||||
local imm = getimm(ctx, pos, 1); if not imm then return end
|
||||
x = imm <= 127 and format("+0x%02x", imm)
|
||||
or format("-0x%02x", 256-imm)
|
||||
pos = pos+1
|
||||
elseif p == "u" then
|
||||
local imm = getimm(ctx, pos, 1); if not imm then return end
|
||||
x = format("0x%02x", imm)
|
||||
pos = pos+1
|
||||
elseif p == "b" then
|
||||
local imm = getimm(ctx, pos, 1); if not imm then return end
|
||||
x = regs[imm/16+1]
|
||||
pos = pos+1
|
||||
elseif p == "w" then
|
||||
local imm = getimm(ctx, pos, 2); if not imm then return end
|
||||
x = format("0x%x", imm)
|
||||
pos = pos+2
|
||||
elseif p == "o" then -- [offset]
|
||||
if ctx.x64 then
|
||||
local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
|
||||
local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
|
||||
x = format("[0x%08x%08x]", imm2, imm1)
|
||||
pos = pos+8
|
||||
else
|
||||
local imm = getimm(ctx, pos, 4); if not imm then return end
|
||||
x = format("[0x%08x]", imm)
|
||||
pos = pos+4
|
||||
end
|
||||
elseif p == "i" or p == "I" then
|
||||
local n = map_sz2n[sz]
|
||||
if n == 8 and ctx.x64 and p == "I" then
|
||||
local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
|
||||
local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
|
||||
x = format("0x%08x%08x", imm2, imm1)
|
||||
else
|
||||
if n == 8 then n = 4 end
|
||||
local imm = getimm(ctx, pos, n); if not imm then return end
|
||||
if sz == "Q" and (imm < 0 or imm > 0x7fffffff) then
|
||||
imm = (0xffffffff+1)-imm
|
||||
x = format(imm > 65535 and "-0x%08x" or "-0x%x", imm)
|
||||
else
|
||||
x = format(imm > 65535 and "0x%08x" or "0x%x", imm)
|
||||
end
|
||||
end
|
||||
pos = pos+n
|
||||
elseif p == "j" then
|
||||
local n = map_sz2n[sz]
|
||||
if n == 8 then n = 4 end
|
||||
local imm = getimm(ctx, pos, n); if not imm then return end
|
||||
if sz == "B" and imm > 127 then imm = imm-256
|
||||
elseif imm > 2147483647 then imm = imm-4294967296 end
|
||||
pos = pos+n
|
||||
imm = imm + pos + ctx.addr
|
||||
if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end
|
||||
ctx.imm = imm
|
||||
if sz == "W" then
|
||||
x = format("word 0x%04x", imm%65536)
|
||||
elseif ctx.x64 then
|
||||
local lo = imm % 0x1000000
|
||||
x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo)
|
||||
else
|
||||
x = "0x"..tohex(imm)
|
||||
end
|
||||
elseif p == "R" then
|
||||
local r = byte(code, pos-1, pos-1)%8
|
||||
if ctx.rexb then r = r + 8; ctx.rexb = false end
|
||||
x = regs[r+1]
|
||||
elseif p == "a" then x = regs[1]
|
||||
elseif p == "c" then x = "cl"
|
||||
elseif p == "d" then x = "dx"
|
||||
elseif p == "1" then x = "1"
|
||||
else
|
||||
if not mode then
|
||||
mode = ctx.mrm
|
||||
if not mode then
|
||||
if pos > stop then return incomplete(ctx) end
|
||||
mode = byte(code, pos, pos)
|
||||
pos = pos+1
|
||||
end
|
||||
rm = mode%8; mode = (mode-rm)/8
|
||||
sp = mode%8; mode = (mode-sp)/8
|
||||
sdisp = ""
|
||||
if mode < 3 then
|
||||
if rm == 4 then
|
||||
if pos > stop then return incomplete(ctx) end
|
||||
sc = byte(code, pos, pos)
|
||||
pos = pos+1
|
||||
rm = sc%8; sc = (sc-rm)/8
|
||||
rx = sc%8; sc = (sc-rx)/8
|
||||
if ctx.rexx then rx = rx + 8; ctx.rexx = false end
|
||||
if rx == 4 then rx = nil end
|
||||
end
|
||||
if mode > 0 or rm == 5 then
|
||||
local dsz = mode
|
||||
if dsz ~= 1 then dsz = 4 end
|
||||
local disp = getimm(ctx, pos, dsz); if not disp then return end
|
||||
if mode == 0 then rm = nil end
|
||||
if rm or rx or (not sc and ctx.x64 and not ctx.a32) then
|
||||
if dsz == 1 and disp > 127 then
|
||||
sdisp = format("-0x%x", 256-disp)
|
||||
elseif disp >= 0 and disp <= 0x7fffffff then
|
||||
sdisp = format("+0x%x", disp)
|
||||
else
|
||||
sdisp = format("-0x%x", (0xffffffff+1)-disp)
|
||||
end
|
||||
else
|
||||
sdisp = format(ctx.x64 and not ctx.a32 and
|
||||
not (disp >= 0 and disp <= 0x7fffffff)
|
||||
and "0xffffffff%08x" or "0x%08x", disp)
|
||||
end
|
||||
pos = pos+dsz
|
||||
end
|
||||
end
|
||||
if rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end
|
||||
if ctx.rexr then sp = sp + 8; ctx.rexr = false end
|
||||
end
|
||||
if p == "m" then
|
||||
if mode == 3 then x = regs[rm+1]
|
||||
else
|
||||
local aregs = ctx.a32 and map_regs.D or ctx.aregs
|
||||
local srm, srx = "", ""
|
||||
if rm then srm = aregs[rm+1]
|
||||
elseif not sc and ctx.x64 and not ctx.a32 then srm = "rip" end
|
||||
ctx.a32 = false
|
||||
if rx then
|
||||
if rm then srm = srm.."+" end
|
||||
srx = aregs[rx+1]
|
||||
if sc > 0 then srx = srx.."*"..(2^sc) end
|
||||
end
|
||||
x = format("[%s%s%s]", srm, srx, sdisp)
|
||||
end
|
||||
if mode < 3 and
|
||||
(not match(pat, "[aRrgp]") or match(pat, "t")) then -- Yuck.
|
||||
x = map_sz2prefix[sz].." "..x
|
||||
end
|
||||
elseif p == "r" then x = regs[sp+1]
|
||||
elseif p == "g" then x = map_segregs[sp+1]
|
||||
elseif p == "p" then -- Suppress prefix.
|
||||
elseif p == "f" then x = "st"..rm
|
||||
elseif p == "x" then
|
||||
if sp == 0 and ctx.lock and not ctx.x64 then
|
||||
x = "CR8"; ctx.lock = false
|
||||
else
|
||||
x = "CR"..sp
|
||||
end
|
||||
elseif p == "v" then
|
||||
if ctx.vexv then
|
||||
x = regs[ctx.vexv+1]; ctx.vexv = false
|
||||
end
|
||||
elseif p == "y" then x = "DR"..sp
|
||||
elseif p == "z" then x = "TR"..sp
|
||||
elseif p == "l" then vexl = false
|
||||
elseif p == "t" then
|
||||
else
|
||||
error("bad pattern `"..pat.."'")
|
||||
end
|
||||
end
|
||||
if x then operands = operands and operands..", "..x or x end
|
||||
end
|
||||
ctx.pos = pos
|
||||
return putop(ctx, name, operands)
|
||||
end
|
||||
|
||||
-- Forward declaration.
|
||||
local map_act
|
||||
|
||||
-- Fetch and cache MRM byte.
|
||||
local function getmrm(ctx)
|
||||
local mrm = ctx.mrm
|
||||
if not mrm then
|
||||
local pos = ctx.pos
|
||||
if pos > ctx.stop then return nil end
|
||||
mrm = byte(ctx.code, pos, pos)
|
||||
ctx.pos = pos+1
|
||||
ctx.mrm = mrm
|
||||
end
|
||||
return mrm
|
||||
end
|
||||
|
||||
-- Dispatch to handler depending on pattern.
|
||||
local function dispatch(ctx, opat, patgrp)
|
||||
if not opat then return unknown(ctx) end
|
||||
if match(opat, "%|") then -- MMX/SSE variants depending on prefix.
|
||||
local p
|
||||
if ctx.rep then
|
||||
p = ctx.rep=="rep" and "%|([^%|]*)" or "%|[^%|]*%|[^%|]*%|([^%|]*)"
|
||||
ctx.rep = false
|
||||
elseif ctx.o16 then p = "%|[^%|]*%|([^%|]*)"; ctx.o16 = false
|
||||
else p = "^[^%|]*" end
|
||||
opat = match(opat, p)
|
||||
if not opat then return unknown(ctx) end
|
||||
-- ctx.rep = false; ctx.o16 = false
|
||||
--XXX fails for 66 f2 0f 38 f1 06 crc32 eax,WORD PTR [esi]
|
||||
--XXX remove in branches?
|
||||
end
|
||||
if match(opat, "%$") then -- reg$mem variants.
|
||||
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
|
||||
opat = match(opat, mrm >= 192 and "^[^%$]*" or "%$(.*)")
|
||||
if opat == "" then return unknown(ctx) end
|
||||
end
|
||||
if opat == "" then return unknown(ctx) end
|
||||
local name, pat = match(opat, "^([a-z0-9 ]*)(.*)")
|
||||
if pat == "" and patgrp then pat = patgrp end
|
||||
return map_act[sub(pat, 1, 1)](ctx, name, pat)
|
||||
end
|
||||
|
||||
-- Get a pattern from an opcode map and dispatch to handler.
|
||||
local function dispatchmap(ctx, opcmap)
|
||||
local pos = ctx.pos
|
||||
local opat = opcmap[byte(ctx.code, pos, pos)]
|
||||
pos = pos + 1
|
||||
ctx.pos = pos
|
||||
return dispatch(ctx, opat)
|
||||
end
|
||||
|
||||
-- Map for action codes. The key is the first char after the name.
|
||||
map_act = {
|
||||
-- Simple opcodes without operands.
|
||||
[""] = function(ctx, name, pat)
|
||||
return putop(ctx, name)
|
||||
end,
|
||||
|
||||
-- Operand size chars fall right through.
|
||||
B = putpat, W = putpat, D = putpat, Q = putpat,
|
||||
V = putpat, U = putpat, T = putpat,
|
||||
M = putpat, X = putpat, P = putpat,
|
||||
F = putpat, G = putpat, Y = putpat,
|
||||
H = putpat,
|
||||
|
||||
-- Collect prefixes.
|
||||
[":"] = function(ctx, name, pat)
|
||||
ctx[pat == ":" and name or sub(pat, 2)] = name
|
||||
if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes.
|
||||
end,
|
||||
|
||||
-- Chain to special handler specified by name.
|
||||
["*"] = function(ctx, name, pat)
|
||||
return map_act[name](ctx, name, sub(pat, 2))
|
||||
end,
|
||||
|
||||
-- Use named subtable for opcode group.
|
||||
["!"] = function(ctx, name, pat)
|
||||
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
|
||||
return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2))
|
||||
end,
|
||||
|
||||
-- o16,o32[,o64] variants.
|
||||
sz = function(ctx, name, pat)
|
||||
if ctx.o16 then ctx.o16 = false
|
||||
else
|
||||
pat = match(pat, ",(.*)")
|
||||
if ctx.rexw then
|
||||
local p = match(pat, ",(.*)")
|
||||
if p then pat = p; ctx.rexw = false end
|
||||
end
|
||||
end
|
||||
pat = match(pat, "^[^,]*")
|
||||
return dispatch(ctx, pat)
|
||||
end,
|
||||
|
||||
-- Two-byte opcode dispatch.
|
||||
opc2 = function(ctx, name, pat)
|
||||
return dispatchmap(ctx, map_opc2)
|
||||
end,
|
||||
|
||||
-- Three-byte opcode dispatch.
|
||||
opc3 = function(ctx, name, pat)
|
||||
return dispatchmap(ctx, map_opc3[pat])
|
||||
end,
|
||||
|
||||
-- VMX/SVM dispatch.
|
||||
vm = function(ctx, name, pat)
|
||||
return dispatch(ctx, map_opcvm[ctx.mrm])
|
||||
end,
|
||||
|
||||
-- Floating point opcode dispatch.
|
||||
fp = function(ctx, name, pat)
|
||||
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
|
||||
local rm = mrm%8
|
||||
local idx = pat*8 + ((mrm-rm)/8)%8
|
||||
if mrm >= 192 then idx = idx + 64 end
|
||||
local opat = map_opcfp[idx]
|
||||
if type(opat) == "table" then opat = opat[rm+1] end
|
||||
return dispatch(ctx, opat)
|
||||
end,
|
||||
|
||||
-- REX prefix.
|
||||
rex = function(ctx, name, pat)
|
||||
if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.
|
||||
for p in gmatch(pat, ".") do ctx["rex"..p] = true end
|
||||
ctx.rex = "rex"
|
||||
end,
|
||||
|
||||
-- VEX prefix.
|
||||
vex = function(ctx, name, pat)
|
||||
if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.
|
||||
ctx.rex = "vex"
|
||||
local pos = ctx.pos
|
||||
if ctx.mrm then
|
||||
ctx.mrm = nil
|
||||
pos = pos-1
|
||||
end
|
||||
local b = byte(ctx.code, pos, pos)
|
||||
if not b then return incomplete(ctx) end
|
||||
pos = pos+1
|
||||
if b < 128 then ctx.rexr = true end
|
||||
local m = 1
|
||||
if pat == "3" then
|
||||
m = b%32; b = (b-m)/32
|
||||
local nb = b%2; b = (b-nb)/2
|
||||
if nb == 0 then ctx.rexb = true end
|
||||
local nx = b%2
|
||||
if nx == 0 then ctx.rexx = true end
|
||||
b = byte(ctx.code, pos, pos)
|
||||
if not b then return incomplete(ctx) end
|
||||
pos = pos+1
|
||||
if b >= 128 then ctx.rexw = true end
|
||||
end
|
||||
ctx.pos = pos
|
||||
local map
|
||||
if m == 1 then map = map_opc2
|
||||
elseif m == 2 then map = map_opc3["38"]
|
||||
elseif m == 3 then map = map_opc3["3a"]
|
||||
else return unknown(ctx) end
|
||||
local p = b%4; b = (b-p)/4
|
||||
if p == 1 then ctx.o16 = "o16"
|
||||
elseif p == 2 then ctx.rep = "rep"
|
||||
elseif p == 3 then ctx.rep = "repne" end
|
||||
local l = b%2; b = (b-l)/2
|
||||
if l ~= 0 then ctx.vexl = true end
|
||||
ctx.vexv = (-1-b)%16
|
||||
return dispatchmap(ctx, map)
|
||||
end,
|
||||
|
||||
-- Special case for nop with REX prefix.
|
||||
nop = function(ctx, name, pat)
|
||||
return dispatch(ctx, ctx.rex and pat or "nop")
|
||||
end,
|
||||
|
||||
-- Special case for 0F 77.
|
||||
emms = function(ctx, name, pat)
|
||||
if ctx.rex ~= "vex" then
|
||||
return putop(ctx, "emms")
|
||||
elseif ctx.vexl then
|
||||
ctx.vexl = false
|
||||
return putop(ctx, "zeroall")
|
||||
else
|
||||
return putop(ctx, "zeroupper")
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Disassemble a block of code.
|
||||
local function disass_block(ctx, ofs, len)
|
||||
if not ofs then ofs = 0 end
|
||||
local stop = len and ofs+len or #ctx.code
|
||||
ofs = ofs + 1
|
||||
ctx.start = ofs
|
||||
ctx.pos = ofs
|
||||
ctx.stop = stop
|
||||
ctx.imm = nil
|
||||
ctx.mrm = false
|
||||
clearprefixes(ctx)
|
||||
while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end
|
||||
if ctx.pos ~= ctx.start then incomplete(ctx) end
|
||||
end
|
||||
|
||||
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
|
||||
local function create(code, addr, out)
|
||||
local ctx = {}
|
||||
ctx.code = code
|
||||
ctx.addr = (addr or 0) - 1
|
||||
ctx.out = out or io.write
|
||||
ctx.symtab = {}
|
||||
ctx.disass = disass_block
|
||||
ctx.hexdump = 16
|
||||
ctx.x64 = false
|
||||
ctx.map1 = map_opc1_32
|
||||
ctx.aregs = map_regs.D
|
||||
return ctx
|
||||
end
|
||||
|
||||
local function create64(code, addr, out)
|
||||
local ctx = create(code, addr, out)
|
||||
ctx.x64 = true
|
||||
ctx.map1 = map_opc1_64
|
||||
ctx.aregs = map_regs.Q
|
||||
return ctx
|
||||
end
|
||||
|
||||
-- Simple API: disassemble code (a string) at address and output via out.
|
||||
local function disass(code, addr, out)
|
||||
create(code, addr, out):disass()
|
||||
end
|
||||
|
||||
local function disass64(code, addr, out)
|
||||
create64(code, addr, out):disass()
|
||||
end
|
||||
|
||||
-- Return register name for RID.
|
||||
local function regname(r)
|
||||
if r < 8 then return map_regs.D[r+1] end
|
||||
return map_regs.X[r-7]
|
||||
end
|
||||
|
||||
local function regname64(r)
|
||||
if r < 16 then return map_regs.Q[r+1] end
|
||||
return map_regs.X[r-15]
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
return {
|
||||
create = create,
|
||||
create64 = create64,
|
||||
disass = disass,
|
||||
disass64 = disass64,
|
||||
regname = regname,
|
||||
regname64 = regname64
|
||||
}
|
||||
|
||||
730
thirdPart/luajit/src/jit/dump.lua
Normal file
730
thirdPart/luajit/src/jit/dump.lua
Normal file
@@ -0,0 +1,730 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT compiler dump module.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- This module can be used to debug the JIT compiler itself. It dumps the
|
||||
-- code representations and structures used in various compiler stages.
|
||||
--
|
||||
-- Example usage:
|
||||
--
|
||||
-- luajit -jdump -e "local x=0; for i=1,1e6 do x=x+i end; print(x)"
|
||||
-- luajit -jdump=im -e "for i=1,1000 do for j=1,1000 do end end" | less -R
|
||||
-- luajit -jdump=is myapp.lua | less -R
|
||||
-- luajit -jdump=-b myapp.lua
|
||||
-- luajit -jdump=+aH,myapp.html myapp.lua
|
||||
-- luajit -jdump=ixT,myapp.dump myapp.lua
|
||||
--
|
||||
-- The first argument specifies the dump mode. The second argument gives
|
||||
-- the output file name. Default output is to stdout, unless the environment
|
||||
-- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the
|
||||
-- module is started.
|
||||
--
|
||||
-- Different features can be turned on or off with the dump mode. If the
|
||||
-- mode starts with a '+', the following features are added to the default
|
||||
-- set of features; a '-' removes them. Otherwise the features are replaced.
|
||||
--
|
||||
-- The following dump features are available (* marks the default):
|
||||
--
|
||||
-- * t Print a line for each started, ended or aborted trace (see also -jv).
|
||||
-- * b Dump the traced bytecode.
|
||||
-- * i Dump the IR (intermediate representation).
|
||||
-- r Augment the IR with register/stack slots.
|
||||
-- s Dump the snapshot map.
|
||||
-- * m Dump the generated machine code.
|
||||
-- x Print each taken trace exit.
|
||||
-- X Print each taken trace exit and the contents of all registers.
|
||||
-- a Print the IR of aborted traces, too.
|
||||
--
|
||||
-- The output format can be set with the following characters:
|
||||
--
|
||||
-- T Plain text output.
|
||||
-- A ANSI-colored text output
|
||||
-- H Colorized HTML + CSS output.
|
||||
--
|
||||
-- The default output format is plain text. It's set to ANSI-colored text
|
||||
-- if the COLORTERM variable is set. Note: this is independent of any output
|
||||
-- redirection, which is actually considered a feature.
|
||||
--
|
||||
-- You probably want to use less -R to enjoy viewing ANSI-colored text from
|
||||
-- a pipe or a file. Add this to your ~/.bashrc: export LESS="-R"
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Cache some library functions and objects.
|
||||
local jit = require("jit")
|
||||
local jutil = require("jit.util")
|
||||
local vmdef = require("jit.vmdef")
|
||||
local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc
|
||||
local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek
|
||||
local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap
|
||||
local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr
|
||||
local bit = require("bit")
|
||||
local band, shr, tohex = bit.band, bit.rshift, bit.tohex
|
||||
local sub, gsub, format = string.sub, string.gsub, string.format
|
||||
local byte, rep = string.byte, string.rep
|
||||
local type, tostring = type, tostring
|
||||
local stdout, stderr = io.stdout, io.stderr
|
||||
|
||||
-- Load other modules on-demand.
|
||||
local bcline, disass
|
||||
|
||||
-- Active flag, output file handle and dump mode.
|
||||
local active, out, dumpmode
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local symtabmt = { __index = false }
|
||||
local symtab = {}
|
||||
local nexitsym = 0
|
||||
|
||||
-- Fill nested symbol table with per-trace exit stub addresses.
|
||||
local function fillsymtab_tr(tr, nexit)
|
||||
local t = {}
|
||||
symtabmt.__index = t
|
||||
if jit.arch:sub(1, 4) == "mips" then
|
||||
t[traceexitstub(tr, 0)] = "exit"
|
||||
return
|
||||
end
|
||||
for i=0,nexit-1 do
|
||||
local addr = traceexitstub(tr, i)
|
||||
if addr < 0 then addr = addr + 2^32 end
|
||||
t[addr] = tostring(i)
|
||||
end
|
||||
local addr = traceexitstub(tr, nexit)
|
||||
if addr then t[addr] = "stack_check" end
|
||||
end
|
||||
|
||||
-- Fill symbol table with trace exit stub addresses.
|
||||
local function fillsymtab(tr, nexit)
|
||||
local t = symtab
|
||||
if nexitsym == 0 then
|
||||
local maskaddr = jit.arch == "arm" and -2
|
||||
local ircall = vmdef.ircall
|
||||
for i=0,#ircall do
|
||||
local addr = ircalladdr(i)
|
||||
if addr ~= 0 then
|
||||
if maskaddr then addr = band(addr, maskaddr) end
|
||||
if addr < 0 then addr = addr + 2^32 end
|
||||
t[addr] = ircall[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
if nexitsym == 1000000 then -- Per-trace exit stubs.
|
||||
fillsymtab_tr(tr, nexit)
|
||||
elseif nexit > nexitsym then -- Shared exit stubs.
|
||||
for i=nexitsym,nexit-1 do
|
||||
local addr = traceexitstub(i)
|
||||
if addr == nil then -- Fall back to per-trace exit stubs.
|
||||
fillsymtab_tr(tr, nexit)
|
||||
setmetatable(symtab, symtabmt)
|
||||
nexit = 1000000
|
||||
break
|
||||
end
|
||||
if addr < 0 then addr = addr + 2^32 end
|
||||
t[addr] = tostring(i)
|
||||
end
|
||||
nexitsym = nexit
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local function dumpwrite(s)
|
||||
out:write(s)
|
||||
end
|
||||
|
||||
-- Disassemble machine code.
|
||||
local function dump_mcode(tr)
|
||||
local info = traceinfo(tr)
|
||||
if not info then return end
|
||||
local mcode, addr, loop = tracemc(tr)
|
||||
if not mcode then return end
|
||||
if not disass then disass = require("jit.dis_"..jit.arch) end
|
||||
if addr < 0 then addr = addr + 2^32 end
|
||||
out:write("---- TRACE ", tr, " mcode ", #mcode, "\n")
|
||||
local ctx = disass.create(mcode, addr, dumpwrite)
|
||||
ctx.hexdump = 0
|
||||
ctx.symtab = fillsymtab(tr, info.nexit)
|
||||
if loop ~= 0 then
|
||||
symtab[addr+loop] = "LOOP"
|
||||
ctx:disass(0, loop)
|
||||
out:write("->LOOP:\n")
|
||||
ctx:disass(loop, #mcode-loop)
|
||||
symtab[addr+loop] = nil
|
||||
else
|
||||
ctx:disass(0, #mcode)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local irtype_text = {
|
||||
[0] = "nil",
|
||||
"fal",
|
||||
"tru",
|
||||
"lud",
|
||||
"str",
|
||||
"p32",
|
||||
"thr",
|
||||
"pro",
|
||||
"fun",
|
||||
"p64",
|
||||
"cdt",
|
||||
"tab",
|
||||
"udt",
|
||||
"flt",
|
||||
"num",
|
||||
"i8 ",
|
||||
"u8 ",
|
||||
"i16",
|
||||
"u16",
|
||||
"int",
|
||||
"u32",
|
||||
"i64",
|
||||
"u64",
|
||||
"sfp",
|
||||
}
|
||||
|
||||
local colortype_ansi = {
|
||||
[0] = "%s",
|
||||
"%s",
|
||||
"%s",
|
||||
"\027[36m%s\027[m",
|
||||
"\027[32m%s\027[m",
|
||||
"%s",
|
||||
"\027[1m%s\027[m",
|
||||
"%s",
|
||||
"\027[1m%s\027[m",
|
||||
"%s",
|
||||
"\027[33m%s\027[m",
|
||||
"\027[31m%s\027[m",
|
||||
"\027[36m%s\027[m",
|
||||
"\027[34m%s\027[m",
|
||||
"\027[34m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
}
|
||||
|
||||
local function colorize_text(s)
|
||||
return s
|
||||
end
|
||||
|
||||
local function colorize_ansi(s, t, extra)
|
||||
local out = format(colortype_ansi[t], s)
|
||||
if extra then out = "\027[3m"..out end
|
||||
return out
|
||||
end
|
||||
|
||||
local irtype_ansi = setmetatable({},
|
||||
{ __index = function(tab, t)
|
||||
local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end })
|
||||
|
||||
local html_escape = { ["<"] = "<", [">"] = ">", ["&"] = "&", }
|
||||
|
||||
local function colorize_html(s, t, extra)
|
||||
s = gsub(s, "[<>&]", html_escape)
|
||||
return format('<span class="irt_%s%s">%s</span>',
|
||||
irtype_text[t], extra and " irt_extra" or "", s)
|
||||
end
|
||||
|
||||
local irtype_html = setmetatable({},
|
||||
{ __index = function(tab, t)
|
||||
local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end })
|
||||
|
||||
local header_html = [[
|
||||
<style type="text/css">
|
||||
background { background: #ffffff; color: #000000; }
|
||||
pre.ljdump {
|
||||
font-size: 10pt;
|
||||
background: #f0f4ff;
|
||||
color: #000000;
|
||||
border: 1px solid #bfcfff;
|
||||
padding: 0.5em;
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
span.irt_str { color: #00a000; }
|
||||
span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; }
|
||||
span.irt_tab { color: #c00000; }
|
||||
span.irt_udt, span.irt_lud { color: #00c0c0; }
|
||||
span.irt_num { color: #4040c0; }
|
||||
span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; }
|
||||
span.irt_extra { font-style: italic; }
|
||||
</style>
|
||||
]]
|
||||
|
||||
local colorize, irtype
|
||||
|
||||
-- Lookup tables to convert some literals into names.
|
||||
local litname = {
|
||||
["SLOAD "] = setmetatable({}, { __index = function(t, mode)
|
||||
local s = ""
|
||||
if band(mode, 1) ~= 0 then s = s.."P" end
|
||||
if band(mode, 2) ~= 0 then s = s.."F" end
|
||||
if band(mode, 4) ~= 0 then s = s.."T" end
|
||||
if band(mode, 8) ~= 0 then s = s.."C" end
|
||||
if band(mode, 16) ~= 0 then s = s.."R" end
|
||||
if band(mode, 32) ~= 0 then s = s.."I" end
|
||||
if band(mode, 64) ~= 0 then s = s.."K" end
|
||||
t[mode] = s
|
||||
return s
|
||||
end}),
|
||||
["XLOAD "] = { [0] = "", "R", "V", "RV", "U", "RU", "VU", "RVU", },
|
||||
["CONV "] = setmetatable({}, { __index = function(t, mode)
|
||||
local s = irtype[band(mode, 31)]
|
||||
s = irtype[band(shr(mode, 5), 31)].."."..s
|
||||
if band(mode, 0x800) ~= 0 then s = s.." sext" end
|
||||
local c = shr(mode, 12)
|
||||
if c == 1 then s = s.." none"
|
||||
elseif c == 2 then s = s.." index"
|
||||
elseif c == 3 then s = s.." check" end
|
||||
t[mode] = s
|
||||
return s
|
||||
end}),
|
||||
["FLOAD "] = vmdef.irfield,
|
||||
["FREF "] = vmdef.irfield,
|
||||
["FPMATH"] = vmdef.irfpm,
|
||||
["TMPREF"] = { [0] = "", "IN", "OUT", "INOUT", "", "", "OUT2", "INOUT2" },
|
||||
["BUFHDR"] = { [0] = "RESET", "APPEND", "WRITE" },
|
||||
["TOSTR "] = { [0] = "INT", "NUM", "CHAR" },
|
||||
}
|
||||
|
||||
local function ctlsub(c)
|
||||
if c == "\n" then return "\\n"
|
||||
elseif c == "\r" then return "\\r"
|
||||
elseif c == "\t" then return "\\t"
|
||||
else return format("\\%03d", byte(c))
|
||||
end
|
||||
end
|
||||
|
||||
local function fmtfunc(func, pc)
|
||||
local fi = funcinfo(func, pc)
|
||||
if fi.loc then
|
||||
return fi.loc
|
||||
elseif fi.ffid then
|
||||
return vmdef.ffnames[fi.ffid]
|
||||
elseif fi.addr then
|
||||
return format("C:%x", fi.addr)
|
||||
else
|
||||
return "(?)"
|
||||
end
|
||||
end
|
||||
|
||||
local function formatk(tr, idx, sn)
|
||||
local k, t, slot = tracek(tr, idx)
|
||||
local tn = type(k)
|
||||
local s
|
||||
if tn == "number" then
|
||||
if t < 12 then
|
||||
s = k == 0 and "NULL" or format("[0x%08x]", k)
|
||||
elseif band(sn or 0, 0x30000) ~= 0 then
|
||||
s = band(sn, 0x20000) ~= 0 and "contpc" or "ftsz"
|
||||
elseif k == 2^52+2^51 then
|
||||
s = "bias"
|
||||
else
|
||||
s = format(0 < k and k < 0x1p-1026 and "%+a" or "%+.14g", k)
|
||||
end
|
||||
elseif tn == "string" then
|
||||
s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub))
|
||||
elseif tn == "function" then
|
||||
s = fmtfunc(k)
|
||||
elseif tn == "table" then
|
||||
s = format("{%p}", k)
|
||||
elseif tn == "userdata" then
|
||||
if t == 12 then
|
||||
s = format("userdata:%p", k)
|
||||
else
|
||||
s = format("[%p]", k)
|
||||
if s == "[NULL]" then s = "NULL" end
|
||||
end
|
||||
elseif t == 21 then -- int64_t
|
||||
s = sub(tostring(k), 1, -3)
|
||||
if sub(s, 1, 1) ~= "-" then s = "+"..s end
|
||||
elseif sn == 0x1057fff then -- SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL)
|
||||
return "----" -- Special case for LJ_FR2 slot 1.
|
||||
else
|
||||
s = tostring(k) -- For primitives.
|
||||
end
|
||||
s = colorize(format("%-4s", s), t, band(sn or 0, 0x100000) ~= 0)
|
||||
if slot then
|
||||
s = format("%s @%d", s, slot)
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
local function printsnap(tr, snap)
|
||||
local n = 2
|
||||
for s=0,snap[1]-1 do
|
||||
local sn = snap[n]
|
||||
if shr(sn, 24) == s then
|
||||
n = n + 1
|
||||
local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS
|
||||
if ref < 0 then
|
||||
out:write(formatk(tr, ref, sn))
|
||||
elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM
|
||||
out:write(colorize(format("%04d/%04d", ref, ref+1), 14))
|
||||
else
|
||||
local m, ot, op1, op2 = traceir(tr, ref)
|
||||
out:write(colorize(format("%04d", ref), band(ot, 31), band(sn, 0x100000) ~= 0))
|
||||
end
|
||||
out:write(band(sn, 0x10000) == 0 and " " or "|") -- SNAP_FRAME
|
||||
else
|
||||
out:write("---- ")
|
||||
end
|
||||
end
|
||||
out:write("]\n")
|
||||
end
|
||||
|
||||
-- Dump snapshots (not interleaved with IR).
|
||||
local function dump_snap(tr)
|
||||
out:write("---- TRACE ", tr, " snapshots\n")
|
||||
for i=0,1000000000 do
|
||||
local snap = tracesnap(tr, i)
|
||||
if not snap then break end
|
||||
out:write(format("#%-3d %04d [ ", i, snap[0]))
|
||||
printsnap(tr, snap)
|
||||
end
|
||||
end
|
||||
|
||||
-- Return a register name or stack slot for a rid/sp location.
|
||||
local function ridsp_name(ridsp, ins)
|
||||
if not disass then disass = require("jit.dis_"..jit.arch) end
|
||||
local rid, slot = band(ridsp, 0xff), shr(ridsp, 8)
|
||||
if rid == 253 or rid == 254 then
|
||||
return (slot == 0 or slot == 255) and " {sink" or format(" {%04d", ins-slot)
|
||||
end
|
||||
if ridsp > 255 then return format("[%x]", slot*4) end
|
||||
if rid < 128 then return disass.regname(rid) end
|
||||
return ""
|
||||
end
|
||||
|
||||
-- Dump CALL* function ref and return optional ctype.
|
||||
local function dumpcallfunc(tr, ins)
|
||||
local ctype
|
||||
if ins > 0 then
|
||||
local m, ot, op1, op2 = traceir(tr, ins)
|
||||
if band(ot, 31) == 0 then -- nil type means CARG(func, ctype).
|
||||
ins = op1
|
||||
ctype = formatk(tr, op2)
|
||||
end
|
||||
end
|
||||
if ins < 0 then
|
||||
out:write(format("[0x%x](", tonumber((tracek(tr, ins)))))
|
||||
else
|
||||
out:write(format("%04d (", ins))
|
||||
end
|
||||
return ctype
|
||||
end
|
||||
|
||||
-- Recursively gather CALL* args and dump them.
|
||||
local function dumpcallargs(tr, ins)
|
||||
if ins < 0 then
|
||||
out:write(formatk(tr, ins))
|
||||
else
|
||||
local m, ot, op1, op2 = traceir(tr, ins)
|
||||
local oidx = 6*shr(ot, 8)
|
||||
local op = sub(vmdef.irnames, oidx+1, oidx+6)
|
||||
if op == "CARG " then
|
||||
dumpcallargs(tr, op1)
|
||||
if op2 < 0 then
|
||||
out:write(" ", formatk(tr, op2))
|
||||
else
|
||||
out:write(" ", format("%04d", op2))
|
||||
end
|
||||
else
|
||||
out:write(format("%04d", ins))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Dump IR and interleaved snapshots.
|
||||
local function dump_ir(tr, dumpsnap, dumpreg)
|
||||
local info = traceinfo(tr)
|
||||
if not info then return end
|
||||
local nins = info.nins
|
||||
out:write("---- TRACE ", tr, " IR\n")
|
||||
local irnames = vmdef.irnames
|
||||
local snapref = 65536
|
||||
local snap, snapno
|
||||
if dumpsnap then
|
||||
snap = tracesnap(tr, 0)
|
||||
snapref = snap[0]
|
||||
snapno = 0
|
||||
end
|
||||
for ins=1,nins do
|
||||
if ins >= snapref then
|
||||
if dumpreg then
|
||||
out:write(format(".... SNAP #%-3d [ ", snapno))
|
||||
else
|
||||
out:write(format(".... SNAP #%-3d [ ", snapno))
|
||||
end
|
||||
printsnap(tr, snap)
|
||||
snapno = snapno + 1
|
||||
snap = tracesnap(tr, snapno)
|
||||
snapref = snap and snap[0] or 65536
|
||||
end
|
||||
local m, ot, op1, op2, ridsp = traceir(tr, ins)
|
||||
local oidx, t = 6*shr(ot, 8), band(ot, 31)
|
||||
local op = sub(irnames, oidx+1, oidx+6)
|
||||
if op == "LOOP " then
|
||||
if dumpreg then
|
||||
out:write(format("%04d ------------ LOOP ------------\n", ins))
|
||||
else
|
||||
out:write(format("%04d ------ LOOP ------------\n", ins))
|
||||
end
|
||||
elseif op ~= "NOP " and op ~= "CARG " and
|
||||
(dumpreg or op ~= "RENAME") then
|
||||
local rid = band(ridsp, 255)
|
||||
if dumpreg then
|
||||
out:write(format("%04d %-6s", ins, ridsp_name(ridsp, ins)))
|
||||
else
|
||||
out:write(format("%04d ", ins))
|
||||
end
|
||||
out:write(format("%s%s %s %s ",
|
||||
(rid == 254 or rid == 253) and "}" or
|
||||
(band(ot, 128) == 0 and " " or ">"),
|
||||
band(ot, 64) == 0 and " " or "+",
|
||||
irtype[t], op))
|
||||
local m1, m2 = band(m, 3), band(m, 3*4)
|
||||
if sub(op, 1, 4) == "CALL" then
|
||||
local ctype
|
||||
if m2 == 1*4 then -- op2 == IRMlit
|
||||
out:write(format("%-10s (", vmdef.ircall[op2]))
|
||||
else
|
||||
ctype = dumpcallfunc(tr, op2)
|
||||
end
|
||||
if op1 ~= -1 then dumpcallargs(tr, op1) end
|
||||
out:write(")")
|
||||
if ctype then out:write(" ctype ", ctype) end
|
||||
elseif op == "CNEW " and op2 == -1 then
|
||||
out:write(formatk(tr, op1))
|
||||
elseif m1 ~= 3 then -- op1 != IRMnone
|
||||
if op1 < 0 then
|
||||
out:write(formatk(tr, op1))
|
||||
else
|
||||
out:write(format(m1 == 0 and "%04d" or "#%-3d", op1))
|
||||
end
|
||||
if m2 ~= 3*4 then -- op2 != IRMnone
|
||||
if m2 == 1*4 then -- op2 == IRMlit
|
||||
local litn = litname[op]
|
||||
if litn and litn[op2] then
|
||||
out:write(" ", litn[op2])
|
||||
elseif op == "UREFO " or op == "UREFC " then
|
||||
out:write(format(" #%-3d", shr(op2, 8)))
|
||||
else
|
||||
out:write(format(" #%-3d", op2))
|
||||
end
|
||||
elseif op2 < 0 then
|
||||
out:write(" ", formatk(tr, op2))
|
||||
else
|
||||
out:write(format(" %04d", op2))
|
||||
end
|
||||
end
|
||||
end
|
||||
out:write("\n")
|
||||
end
|
||||
end
|
||||
if snap then
|
||||
if dumpreg then
|
||||
out:write(format(".... SNAP #%-3d [ ", snapno))
|
||||
else
|
||||
out:write(format(".... SNAP #%-3d [ ", snapno))
|
||||
end
|
||||
printsnap(tr, snap)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local recprefix = ""
|
||||
local recdepth = 0
|
||||
|
||||
-- Format trace error message.
|
||||
local function fmterr(err, info)
|
||||
if type(err) == "number" then
|
||||
if type(info) == "function" then info = fmtfunc(info) end
|
||||
local fmt = vmdef.traceerr[err]
|
||||
if fmt == "NYI: bytecode %s" then
|
||||
local oidx = 6 * info
|
||||
info = sub(vmdef.bcnames, oidx+1, oidx+6)
|
||||
end
|
||||
err = format(fmt, info)
|
||||
end
|
||||
return err
|
||||
end
|
||||
|
||||
-- Dump trace states.
|
||||
local function dump_trace(what, tr, func, pc, otr, oex)
|
||||
if what == "stop" or (what == "abort" and dumpmode.a) then
|
||||
if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == "stop")
|
||||
elseif dumpmode.s then dump_snap(tr) end
|
||||
if dumpmode.m then dump_mcode(tr) end
|
||||
end
|
||||
if what == "start" then
|
||||
if dumpmode.H then out:write('<pre class="ljdump">\n') end
|
||||
out:write("---- TRACE ", tr, " ", what)
|
||||
if otr then out:write(" ", otr, "/", oex == -1 and "stitch" or oex) end
|
||||
out:write(" ", fmtfunc(func, pc), "\n")
|
||||
elseif what == "stop" or what == "abort" then
|
||||
out:write("---- TRACE ", tr, " ", what)
|
||||
if what == "abort" then
|
||||
out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n")
|
||||
else
|
||||
local info = traceinfo(tr)
|
||||
local link, ltype = info.link, info.linktype
|
||||
if link == tr or link == 0 then
|
||||
out:write(" -> ", ltype, "\n")
|
||||
elseif ltype == "root" then
|
||||
out:write(" -> ", link, "\n")
|
||||
else
|
||||
out:write(" -> ", link, " ", ltype, "\n")
|
||||
end
|
||||
end
|
||||
if dumpmode.H then out:write("</pre>\n\n") else out:write("\n") end
|
||||
else
|
||||
if what == "flush" then symtab, nexitsym = {}, 0 end
|
||||
out:write("---- TRACE ", what, "\n\n")
|
||||
end
|
||||
out:flush()
|
||||
end
|
||||
|
||||
-- Dump recorded bytecode.
|
||||
local function dump_record(tr, func, pc, depth)
|
||||
if depth ~= recdepth then
|
||||
recdepth = depth
|
||||
recprefix = rep(" .", depth)
|
||||
end
|
||||
local line
|
||||
if pc >= 0 then
|
||||
line = bcline(func, pc, recprefix)
|
||||
if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end
|
||||
else
|
||||
line = "0000 "..recprefix.." FUNCC \n"
|
||||
end
|
||||
if pc <= 0 then
|
||||
out:write(sub(line, 1, -2), " ; ", fmtfunc(func), "\n")
|
||||
else
|
||||
out:write(line)
|
||||
end
|
||||
if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC
|
||||
out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond.
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local gpr64 = jit.arch:match("64")
|
||||
local fprmips32 = jit.arch == "mips" or jit.arch == "mipsel"
|
||||
|
||||
-- Dump taken trace exits.
|
||||
local function dump_texit(tr, ex, ngpr, nfpr, ...)
|
||||
out:write("---- TRACE ", tr, " exit ", ex, "\n")
|
||||
if dumpmode.X then
|
||||
local regs = {...}
|
||||
if gpr64 then
|
||||
for i=1,ngpr do
|
||||
out:write(format(" %016x", regs[i]))
|
||||
if i % 4 == 0 then out:write("\n") end
|
||||
end
|
||||
else
|
||||
for i=1,ngpr do
|
||||
out:write(" ", tohex(regs[i]))
|
||||
if i % 8 == 0 then out:write("\n") end
|
||||
end
|
||||
end
|
||||
if fprmips32 then
|
||||
for i=1,nfpr,2 do
|
||||
out:write(format(" %+17.14g", regs[ngpr+i]))
|
||||
if i % 8 == 7 then out:write("\n") end
|
||||
end
|
||||
else
|
||||
for i=1,nfpr do
|
||||
out:write(format(" %+17.14g", regs[ngpr+i]))
|
||||
if i % 4 == 0 then out:write("\n") end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Detach dump handlers.
|
||||
local function dumpoff()
|
||||
if active then
|
||||
active = false
|
||||
jit.attach(dump_texit)
|
||||
jit.attach(dump_record)
|
||||
jit.attach(dump_trace)
|
||||
if out and out ~= stdout and out ~= stderr then out:close() end
|
||||
out = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Open the output file and attach dump handlers.
|
||||
local function dumpon(opt, outfile)
|
||||
if active then dumpoff() end
|
||||
|
||||
local term = os.getenv("TERM")
|
||||
local colormode = (term and term:match("color") or os.getenv("COLORTERM")) and "A" or "T"
|
||||
if opt then
|
||||
opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end)
|
||||
end
|
||||
|
||||
local m = { t=true, b=true, i=true, m=true, }
|
||||
if opt and opt ~= "" then
|
||||
local o = sub(opt, 1, 1)
|
||||
if o ~= "+" and o ~= "-" then m = {} end
|
||||
for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end
|
||||
end
|
||||
dumpmode = m
|
||||
|
||||
if m.t or m.b or m.i or m.s or m.m then
|
||||
jit.attach(dump_trace, "trace")
|
||||
end
|
||||
if m.b then
|
||||
jit.attach(dump_record, "record")
|
||||
if not bcline then bcline = require("jit.bc").line end
|
||||
end
|
||||
if m.x or m.X then
|
||||
jit.attach(dump_texit, "texit")
|
||||
end
|
||||
|
||||
if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end
|
||||
if outfile then
|
||||
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
|
||||
else
|
||||
out = stdout
|
||||
end
|
||||
|
||||
m[colormode] = true
|
||||
if colormode == "A" then
|
||||
colorize = colorize_ansi
|
||||
irtype = irtype_ansi
|
||||
elseif colormode == "H" then
|
||||
colorize = colorize_html
|
||||
irtype = irtype_html
|
||||
out:write(header_html)
|
||||
else
|
||||
colorize = colorize_text
|
||||
irtype = irtype_text
|
||||
end
|
||||
|
||||
active = true
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
return {
|
||||
on = dumpon,
|
||||
off = dumpoff,
|
||||
start = dumpon -- For -j command line option.
|
||||
}
|
||||
|
||||
311
thirdPart/luajit/src/jit/p.lua
Normal file
311
thirdPart/luajit/src/jit/p.lua
Normal file
@@ -0,0 +1,311 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT profiler.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- This module is a simple command line interface to the built-in
|
||||
-- low-overhead profiler of LuaJIT.
|
||||
--
|
||||
-- The lower-level API of the profiler is accessible via the "jit.profile"
|
||||
-- module or the luaJIT_profile_* C API.
|
||||
--
|
||||
-- Example usage:
|
||||
--
|
||||
-- luajit -jp myapp.lua
|
||||
-- luajit -jp=s myapp.lua
|
||||
-- luajit -jp=-s myapp.lua
|
||||
-- luajit -jp=vl myapp.lua
|
||||
-- luajit -jp=G,profile.txt myapp.lua
|
||||
--
|
||||
-- The following dump features are available:
|
||||
--
|
||||
-- f Stack dump: function name, otherwise module:line. Default mode.
|
||||
-- F Stack dump: ditto, but always prepend module.
|
||||
-- l Stack dump: module:line.
|
||||
-- <number> stack dump depth (callee < caller). Default: 1.
|
||||
-- -<number> Inverse stack dump depth (caller > callee).
|
||||
-- s Split stack dump after first stack level. Implies abs(depth) >= 2.
|
||||
-- p Show full path for module names.
|
||||
-- v Show VM states. Can be combined with stack dumps, e.g. vf or fv.
|
||||
-- z Show zones. Can be combined with stack dumps, e.g. zf or fz.
|
||||
-- r Show raw sample counts. Default: show percentages.
|
||||
-- a Annotate excerpts from source code files.
|
||||
-- A Annotate complete source code files.
|
||||
-- G Produce raw output suitable for graphical tools (e.g. flame graphs).
|
||||
-- m<number> Minimum sample percentage to be shown. Default: 3.
|
||||
-- i<number> Sampling interval in milliseconds. Default: 10.
|
||||
--
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
-- Cache some library functions and objects.
|
||||
local jit = require("jit")
|
||||
local profile = require("jit.profile")
|
||||
local vmdef = require("jit.vmdef")
|
||||
local math = math
|
||||
local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor
|
||||
local sort, format = table.sort, string.format
|
||||
local stdout = io.stdout
|
||||
local zone -- Load jit.zone module on demand.
|
||||
|
||||
-- Output file handle.
|
||||
local out
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local prof_ud
|
||||
local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth
|
||||
local prof_ann, prof_count1, prof_count2, prof_samples
|
||||
|
||||
local map_vmmode = {
|
||||
N = "Compiled",
|
||||
I = "Interpreted",
|
||||
C = "C code",
|
||||
G = "Garbage Collector",
|
||||
J = "JIT Compiler",
|
||||
}
|
||||
|
||||
-- Profiler callback.
|
||||
local function prof_cb(th, samples, vmmode)
|
||||
prof_samples = prof_samples + samples
|
||||
local key_stack, key_stack2, key_state
|
||||
-- Collect keys for sample.
|
||||
if prof_states then
|
||||
if prof_states == "v" then
|
||||
key_state = map_vmmode[vmmode] or vmmode
|
||||
else
|
||||
key_state = zone:get() or "(none)"
|
||||
end
|
||||
end
|
||||
if prof_fmt then
|
||||
key_stack = profile.dumpstack(th, prof_fmt, prof_depth)
|
||||
key_stack = key_stack:gsub("%[builtin#(%d+)%]", function(x)
|
||||
return vmdef.ffnames[tonumber(x)]
|
||||
end)
|
||||
if prof_split == 2 then
|
||||
local k1, k2 = key_stack:match("(.-) [<>] (.*)")
|
||||
if k2 then key_stack, key_stack2 = k1, k2 end
|
||||
elseif prof_split == 3 then
|
||||
key_stack2 = profile.dumpstack(th, "l", 1)
|
||||
end
|
||||
end
|
||||
-- Order keys.
|
||||
local k1, k2
|
||||
if prof_split == 1 then
|
||||
if key_state then
|
||||
k1 = key_state
|
||||
if key_stack then k2 = key_stack end
|
||||
end
|
||||
elseif key_stack then
|
||||
k1 = key_stack
|
||||
if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end
|
||||
end
|
||||
-- Coalesce samples in one or two levels.
|
||||
if k1 then
|
||||
local t1 = prof_count1
|
||||
t1[k1] = (t1[k1] or 0) + samples
|
||||
if k2 then
|
||||
local t2 = prof_count2
|
||||
local t3 = t2[k1]
|
||||
if not t3 then t3 = {}; t2[k1] = t3 end
|
||||
t3[k2] = (t3[k2] or 0) + samples
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Show top N list.
|
||||
local function prof_top(count1, count2, samples, indent)
|
||||
local t, n = {}, 0
|
||||
for k in pairs(count1) do
|
||||
n = n + 1
|
||||
t[n] = k
|
||||
end
|
||||
sort(t, function(a, b) return count1[a] > count1[b] end)
|
||||
for i=1,n do
|
||||
local k = t[i]
|
||||
local v = count1[k]
|
||||
local pct = floor(v*100/samples + 0.5)
|
||||
if pct < prof_min then break end
|
||||
if not prof_raw then
|
||||
out:write(format("%s%2d%% %s\n", indent, pct, k))
|
||||
elseif prof_raw == "r" then
|
||||
out:write(format("%s%5d %s\n", indent, v, k))
|
||||
else
|
||||
out:write(format("%s %d\n", k, v))
|
||||
end
|
||||
if count2 then
|
||||
local r = count2[k]
|
||||
if r then
|
||||
prof_top(r, nil, v, (prof_split == 3 or prof_split == 1) and " -- " or
|
||||
(prof_depth < 0 and " -> " or " <- "))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Annotate source code
|
||||
local function prof_annotate(count1, samples)
|
||||
local files = {}
|
||||
local ms = 0
|
||||
for k, v in pairs(count1) do
|
||||
local pct = floor(v*100/samples + 0.5)
|
||||
ms = math.max(ms, v)
|
||||
if pct >= prof_min then
|
||||
local file, line = k:match("^(.*):(%d+)$")
|
||||
if not file then file = k; line = 0 end
|
||||
local fl = files[file]
|
||||
if not fl then fl = {}; files[file] = fl; files[#files+1] = file end
|
||||
line = tonumber(line)
|
||||
fl[line] = prof_raw and v or pct
|
||||
end
|
||||
end
|
||||
sort(files)
|
||||
local fmtv, fmtn = " %3d%% | %s\n", " | %s\n"
|
||||
if prof_raw then
|
||||
local n = math.max(5, math.ceil(math.log10(ms)))
|
||||
fmtv = "%"..n.."d | %s\n"
|
||||
fmtn = (" "):rep(n).." | %s\n"
|
||||
end
|
||||
local ann = prof_ann
|
||||
for _, file in ipairs(files) do
|
||||
local f0 = file:byte()
|
||||
if f0 == 40 or f0 == 91 then
|
||||
out:write(format("\n====== %s ======\n[Cannot annotate non-file]\n", file))
|
||||
break
|
||||
end
|
||||
local fp, err = io.open(file)
|
||||
if not fp then
|
||||
out:write(format("====== ERROR: %s: %s\n", file, err))
|
||||
break
|
||||
end
|
||||
out:write(format("\n====== %s ======\n", file))
|
||||
local fl = files[file]
|
||||
local n, show = 1, false
|
||||
if ann ~= 0 then
|
||||
for i=1,ann do
|
||||
if fl[i] then show = true; out:write("@@ 1 @@\n"); break end
|
||||
end
|
||||
end
|
||||
for line in fp:lines() do
|
||||
if line:byte() == 27 then
|
||||
out:write("[Cannot annotate bytecode file]\n")
|
||||
break
|
||||
end
|
||||
local v = fl[n]
|
||||
if ann ~= 0 then
|
||||
local v2 = fl[n+ann]
|
||||
if show then
|
||||
if v2 then show = n+ann elseif v then show = n
|
||||
elseif show+ann < n then show = false end
|
||||
elseif v2 then
|
||||
show = n+ann
|
||||
out:write(format("@@ %d @@\n", n))
|
||||
end
|
||||
if not show then goto next end
|
||||
end
|
||||
if v then
|
||||
out:write(format(fmtv, v, line))
|
||||
else
|
||||
out:write(format(fmtn, line))
|
||||
end
|
||||
::next::
|
||||
n = n + 1
|
||||
end
|
||||
fp:close()
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Finish profiling and dump result.
|
||||
local function prof_finish()
|
||||
if prof_ud then
|
||||
profile.stop()
|
||||
local samples = prof_samples
|
||||
if samples == 0 then
|
||||
if prof_raw ~= true then out:write("[No samples collected]\n") end
|
||||
return
|
||||
end
|
||||
if prof_ann then
|
||||
prof_annotate(prof_count1, samples)
|
||||
else
|
||||
prof_top(prof_count1, prof_count2, samples, "")
|
||||
end
|
||||
prof_count1 = nil
|
||||
prof_count2 = nil
|
||||
prof_ud = nil
|
||||
if out ~= stdout then out:close() end
|
||||
end
|
||||
end
|
||||
|
||||
-- Start profiling.
|
||||
local function prof_start(mode)
|
||||
local interval = ""
|
||||
mode = mode:gsub("i%d*", function(s) interval = s; return "" end)
|
||||
prof_min = 3
|
||||
mode = mode:gsub("m(%d+)", function(s) prof_min = tonumber(s); return "" end)
|
||||
prof_depth = 1
|
||||
mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end)
|
||||
local m = {}
|
||||
for c in mode:gmatch(".") do m[c] = c end
|
||||
prof_states = m.z or m.v
|
||||
if prof_states == "z" then zone = require("jit.zone") end
|
||||
local scope = m.l or m.f or m.F or (prof_states and "" or "f")
|
||||
local flags = (m.p or "")
|
||||
prof_raw = m.r
|
||||
if m.s then
|
||||
prof_split = 2
|
||||
if prof_depth == -1 or m["-"] then prof_depth = -2
|
||||
elseif prof_depth == 1 then prof_depth = 2 end
|
||||
elseif mode:find("[fF].*l") then
|
||||
scope = "l"
|
||||
prof_split = 3
|
||||
else
|
||||
prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
|
||||
end
|
||||
prof_ann = m.A and 0 or (m.a and 3)
|
||||
if prof_ann then
|
||||
scope = "l"
|
||||
prof_fmt = "pl"
|
||||
prof_split = 0
|
||||
prof_depth = 1
|
||||
elseif m.G and scope ~= "" then
|
||||
prof_fmt = flags..scope.."Z;"
|
||||
prof_depth = -100
|
||||
prof_raw = true
|
||||
prof_min = 0
|
||||
elseif scope == "" then
|
||||
prof_fmt = false
|
||||
else
|
||||
local sc = prof_split == 3 and m.f or m.F or scope
|
||||
prof_fmt = flags..sc..(prof_depth >= 0 and "Z < " or "Z > ")
|
||||
end
|
||||
prof_count1 = {}
|
||||
prof_count2 = {}
|
||||
prof_samples = 0
|
||||
profile.start(scope:lower()..interval, prof_cb)
|
||||
prof_ud = newproxy(true)
|
||||
getmetatable(prof_ud).__gc = prof_finish
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local function start(mode, outfile)
|
||||
if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end
|
||||
if outfile then
|
||||
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
|
||||
else
|
||||
out = stdout
|
||||
end
|
||||
prof_start(mode or "f")
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
return {
|
||||
start = start, -- For -j command line option.
|
||||
stop = prof_finish
|
||||
}
|
||||
|
||||
174
thirdPart/luajit/src/jit/v.lua
Normal file
174
thirdPart/luajit/src/jit/v.lua
Normal file
@@ -0,0 +1,174 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- Verbose mode of the LuaJIT compiler.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- This module shows verbose information about the progress of the
|
||||
-- JIT compiler. It prints one line for each generated trace. This module
|
||||
-- is useful to see which code has been compiled or where the compiler
|
||||
-- punts and falls back to the interpreter.
|
||||
--
|
||||
-- Example usage:
|
||||
--
|
||||
-- luajit -jv -e "for i=1,1000 do for j=1,1000 do end end"
|
||||
-- luajit -jv=myapp.out myapp.lua
|
||||
--
|
||||
-- Default output is to stderr. To redirect the output to a file, pass a
|
||||
-- filename as an argument (use '-' for stdout) or set the environment
|
||||
-- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the
|
||||
-- module is started.
|
||||
--
|
||||
-- The output from the first example should look like this:
|
||||
--
|
||||
-- [TRACE 1 (command line):1 loop]
|
||||
-- [TRACE 2 (1/3) (command line):1 -> 1]
|
||||
--
|
||||
-- The first number in each line is the internal trace number. Next are
|
||||
-- the file name ('(command line)') and the line number (':1') where the
|
||||
-- trace has started. Side traces also show the parent trace number and
|
||||
-- the exit number where they are attached to in parentheses ('(1/3)').
|
||||
-- An arrow at the end shows where the trace links to ('-> 1'), unless
|
||||
-- it loops to itself.
|
||||
--
|
||||
-- In this case the inner loop gets hot and is traced first, generating
|
||||
-- a root trace. Then the last exit from the 1st trace gets hot, too,
|
||||
-- and triggers generation of the 2nd trace. The side trace follows the
|
||||
-- path along the outer loop and *around* the inner loop, back to its
|
||||
-- start, and then links to the 1st trace. Yes, this may seem unusual,
|
||||
-- if you know how traditional compilers work. Trace compilers are full
|
||||
-- of surprises like this -- have fun! :-)
|
||||
--
|
||||
-- Aborted traces are shown like this:
|
||||
--
|
||||
-- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50]
|
||||
--
|
||||
-- Don't worry -- trace aborts are quite common, even in programs which
|
||||
-- can be fully compiled. The compiler may retry several times until it
|
||||
-- finds a suitable trace.
|
||||
--
|
||||
-- Of course this doesn't work with features that are not-yet-implemented
|
||||
-- (NYI error messages). The VM simply falls back to the interpreter. This
|
||||
-- may not matter at all if the particular trace is not very high up in
|
||||
-- the CPU usage profile. Oh, and the interpreter is quite fast, too.
|
||||
--
|
||||
-- Also check out the -jdump module, which prints all the gory details.
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Cache some library functions and objects.
|
||||
local jit = require("jit")
|
||||
local jutil = require("jit.util")
|
||||
local vmdef = require("jit.vmdef")
|
||||
local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo
|
||||
local type, sub, format = type, string.sub, string.format
|
||||
local stdout, stderr = io.stdout, io.stderr
|
||||
|
||||
-- Active flag and output file handle.
|
||||
local active, out
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local startloc, startex
|
||||
|
||||
local function fmtfunc(func, pc)
|
||||
local fi = funcinfo(func, pc)
|
||||
if fi.loc then
|
||||
return fi.loc
|
||||
elseif fi.ffid then
|
||||
return vmdef.ffnames[fi.ffid]
|
||||
elseif fi.addr then
|
||||
return format("C:%x", fi.addr)
|
||||
else
|
||||
return "(?)"
|
||||
end
|
||||
end
|
||||
|
||||
-- Format trace error message.
|
||||
local function fmterr(err, info)
|
||||
if type(err) == "number" then
|
||||
if type(info) == "function" then info = fmtfunc(info) end
|
||||
local fmt = vmdef.traceerr[err]
|
||||
if fmt == "NYI: bytecode %s" then
|
||||
local oidx = 6 * info
|
||||
info = sub(vmdef.bcnames, oidx+1, oidx+6)
|
||||
end
|
||||
err = format(fmt, info)
|
||||
end
|
||||
return err
|
||||
end
|
||||
|
||||
-- Dump trace states.
|
||||
local function dump_trace(what, tr, func, pc, otr, oex)
|
||||
if what == "start" then
|
||||
startloc = fmtfunc(func, pc)
|
||||
startex = otr and "("..otr.."/"..(oex == -1 and "stitch" or oex)..") " or ""
|
||||
else
|
||||
if what == "abort" then
|
||||
local loc = fmtfunc(func, pc)
|
||||
if loc ~= startloc then
|
||||
out:write(format("[TRACE --- %s%s -- %s at %s]\n",
|
||||
startex, startloc, fmterr(otr, oex), loc))
|
||||
else
|
||||
out:write(format("[TRACE --- %s%s -- %s]\n",
|
||||
startex, startloc, fmterr(otr, oex)))
|
||||
end
|
||||
elseif what == "stop" then
|
||||
local info = traceinfo(tr)
|
||||
local link, ltype = info.link, info.linktype
|
||||
if ltype == "interpreter" then
|
||||
out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
|
||||
tr, startex, startloc))
|
||||
elseif ltype == "stitch" then
|
||||
out:write(format("[TRACE %3s %s%s %s %s]\n",
|
||||
tr, startex, startloc, ltype, fmtfunc(func, pc)))
|
||||
elseif link == tr or link == 0 then
|
||||
out:write(format("[TRACE %3s %s%s %s]\n",
|
||||
tr, startex, startloc, ltype))
|
||||
elseif ltype == "root" then
|
||||
out:write(format("[TRACE %3s %s%s -> %d]\n",
|
||||
tr, startex, startloc, link))
|
||||
else
|
||||
out:write(format("[TRACE %3s %s%s -> %d %s]\n",
|
||||
tr, startex, startloc, link, ltype))
|
||||
end
|
||||
else
|
||||
out:write(format("[TRACE %s]\n", what))
|
||||
end
|
||||
out:flush()
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Detach dump handlers.
|
||||
local function dumpoff()
|
||||
if active then
|
||||
active = false
|
||||
jit.attach(dump_trace)
|
||||
if out and out ~= stdout and out ~= stderr then out:close() end
|
||||
out = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Open the output file and attach dump handlers.
|
||||
local function dumpon(outfile)
|
||||
if active then dumpoff() end
|
||||
if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end
|
||||
if outfile then
|
||||
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
|
||||
else
|
||||
out = stderr
|
||||
end
|
||||
jit.attach(dump_trace, "trace")
|
||||
active = true
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
return {
|
||||
on = dumpon,
|
||||
off = dumpoff,
|
||||
start = dumpon -- For -j command line option.
|
||||
}
|
||||
|
||||
45
thirdPart/luajit/src/jit/zone.lua
Normal file
45
thirdPart/luajit/src/jit/zone.lua
Normal file
@@ -0,0 +1,45 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT profiler zones.
|
||||
--
|
||||
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- This module implements a simple hierarchical zone model.
|
||||
--
|
||||
-- Example usage:
|
||||
--
|
||||
-- local zone = require("jit.zone")
|
||||
-- zone("AI")
|
||||
-- ...
|
||||
-- zone("A*")
|
||||
-- ...
|
||||
-- print(zone:get()) --> "A*"
|
||||
-- ...
|
||||
-- zone()
|
||||
-- ...
|
||||
-- print(zone:get()) --> "AI"
|
||||
-- ...
|
||||
-- zone()
|
||||
--
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
local remove = table.remove
|
||||
|
||||
return setmetatable({
|
||||
flush = function(t)
|
||||
for i=#t,1,-1 do t[i] = nil end
|
||||
end,
|
||||
get = function(t)
|
||||
return t[#t]
|
||||
end
|
||||
}, {
|
||||
__call = function(t, zone)
|
||||
if zone then
|
||||
t[#t+1] = zone
|
||||
else
|
||||
return (assert(remove(t), "empty zone stack"))
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
161
thirdPart/luajit/src/lauxlib.h
Normal file
161
thirdPart/luajit/src/lauxlib.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
|
||||
** Auxiliary functions for building Lua libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef lauxlib_h
|
||||
#define lauxlib_h
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
/* extra error code for `luaL_load' */
|
||||
#define LUA_ERRFILE (LUA_ERRERR+1)
|
||||
|
||||
typedef struct luaL_Reg {
|
||||
const char *name;
|
||||
lua_CFunction func;
|
||||
} luaL_Reg;
|
||||
|
||||
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
|
||||
const luaL_Reg *l, int nup);
|
||||
LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
|
||||
const luaL_Reg *l);
|
||||
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
|
||||
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
|
||||
LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
|
||||
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
|
||||
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
|
||||
size_t *l);
|
||||
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
|
||||
const char *def, size_t *l);
|
||||
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
|
||||
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
|
||||
|
||||
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
|
||||
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
|
||||
lua_Integer def);
|
||||
|
||||
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
|
||||
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
|
||||
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
|
||||
|
||||
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
|
||||
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
|
||||
|
||||
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
|
||||
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
|
||||
|
||||
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
|
||||
const char *const lst[]);
|
||||
|
||||
/* pre-defined references */
|
||||
#define LUA_NOREF (-2)
|
||||
#define LUA_REFNIL (-1)
|
||||
|
||||
LUALIB_API int (luaL_ref) (lua_State *L, int t);
|
||||
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
|
||||
|
||||
LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
|
||||
LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
|
||||
const char *name);
|
||||
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
|
||||
|
||||
LUALIB_API lua_State *(luaL_newstate) (void);
|
||||
|
||||
|
||||
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
|
||||
const char *r);
|
||||
|
||||
LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
|
||||
const char *fname, int szhint);
|
||||
|
||||
/* From Lua 5.2. */
|
||||
LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname);
|
||||
LUALIB_API int luaL_execresult(lua_State *L, int stat);
|
||||
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
|
||||
const char *mode);
|
||||
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
|
||||
const char *name, const char *mode);
|
||||
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
|
||||
int level);
|
||||
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
|
||||
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
|
||||
int sizehint);
|
||||
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
|
||||
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
|
||||
|
||||
|
||||
/*
|
||||
** ===============================================================
|
||||
** some useful macros
|
||||
** ===============================================================
|
||||
*/
|
||||
|
||||
#define luaL_argcheck(L, cond,numarg,extramsg) \
|
||||
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
|
||||
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
|
||||
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
|
||||
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
|
||||
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
|
||||
|
||||
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
|
||||
|
||||
#define luaL_dofile(L, fn) \
|
||||
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
||||
|
||||
#define luaL_dostring(L, s) \
|
||||
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
||||
|
||||
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
|
||||
|
||||
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
|
||||
|
||||
/* From Lua 5.2. */
|
||||
#define luaL_newlibtable(L, l) \
|
||||
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
|
||||
#define luaL_newlib(L, l) (luaL_newlibtable(L, l), luaL_setfuncs(L, l, 0))
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Generic Buffer manipulation
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
|
||||
typedef struct luaL_Buffer {
|
||||
char *p; /* current position in buffer */
|
||||
int lvl; /* number of strings in the stack (level) */
|
||||
lua_State *L;
|
||||
char buffer[LUAL_BUFFERSIZE];
|
||||
} luaL_Buffer;
|
||||
|
||||
#define luaL_addchar(B,c) \
|
||||
((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
|
||||
(*(B)->p++ = (char)(c)))
|
||||
|
||||
/* compatibility only */
|
||||
#define luaL_putchar(B,c) luaL_addchar(B,c)
|
||||
|
||||
#define luaL_addsize(B,n) ((B)->p += (n))
|
||||
|
||||
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
|
||||
LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
|
||||
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
|
||||
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
|
||||
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
|
||||
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
|
||||
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
#endif
|
||||
401
thirdPart/luajit/src/lib_aux.c
Normal file
401
thirdPart/luajit/src/lib_aux.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
** Auxiliary library for the Lua/C API.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** Major parts taken verbatim or adapted from the Lua interpreter.
|
||||
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define lib_aux_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_state.h"
|
||||
#include "lj_trace.h"
|
||||
#include "lj_lib.h"
|
||||
#include "lj_vmevent.h"
|
||||
|
||||
#if LJ_TARGET_POSIX
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
/* -- I/O error handling -------------------------------------------------- */
|
||||
|
||||
LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname)
|
||||
{
|
||||
if (stat) {
|
||||
setboolV(L->top++, 1);
|
||||
return 1;
|
||||
} else {
|
||||
int en = errno; /* Lua API calls may change this value. */
|
||||
setnilV(L->top++);
|
||||
if (fname)
|
||||
lua_pushfstring(L, "%s: %s", fname, strerror(en));
|
||||
else
|
||||
lua_pushfstring(L, "%s", strerror(en));
|
||||
setintV(L->top++, en);
|
||||
lj_trace_abort(G(L));
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
LUALIB_API int luaL_execresult(lua_State *L, int stat)
|
||||
{
|
||||
if (stat != -1) {
|
||||
#if LJ_TARGET_POSIX
|
||||
if (WIFSIGNALED(stat)) {
|
||||
stat = WTERMSIG(stat);
|
||||
setnilV(L->top++);
|
||||
lua_pushliteral(L, "signal");
|
||||
} else {
|
||||
if (WIFEXITED(stat))
|
||||
stat = WEXITSTATUS(stat);
|
||||
if (stat == 0)
|
||||
setboolV(L->top++, 1);
|
||||
else
|
||||
setnilV(L->top++);
|
||||
lua_pushliteral(L, "exit");
|
||||
}
|
||||
#else
|
||||
if (stat == 0)
|
||||
setboolV(L->top++, 1);
|
||||
else
|
||||
setnilV(L->top++);
|
||||
lua_pushliteral(L, "exit");
|
||||
#endif
|
||||
setintV(L->top++, stat);
|
||||
return 3;
|
||||
}
|
||||
return luaL_fileresult(L, 0, NULL);
|
||||
}
|
||||
|
||||
/* -- Module registration ------------------------------------------------- */
|
||||
|
||||
LUALIB_API const char *luaL_findtable(lua_State *L, int idx,
|
||||
const char *fname, int szhint)
|
||||
{
|
||||
const char *e;
|
||||
lua_pushvalue(L, idx);
|
||||
do {
|
||||
e = strchr(fname, '.');
|
||||
if (e == NULL) e = fname + strlen(fname);
|
||||
lua_pushlstring(L, fname, (size_t)(e - fname));
|
||||
lua_rawget(L, -2);
|
||||
if (lua_isnil(L, -1)) { /* no such field? */
|
||||
lua_pop(L, 1); /* remove this nil */
|
||||
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
|
||||
lua_pushlstring(L, fname, (size_t)(e - fname));
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, -4); /* set new table into field */
|
||||
} else if (!lua_istable(L, -1)) { /* field has a non-table value? */
|
||||
lua_pop(L, 2); /* remove table and value */
|
||||
return fname; /* return problematic part of the name */
|
||||
}
|
||||
lua_remove(L, -2); /* remove previous table */
|
||||
fname = e + 1;
|
||||
} while (*e == '.');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int libsize(const luaL_Reg *l)
|
||||
{
|
||||
int size = 0;
|
||||
for (; l && l->name; l++) size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
LUALIB_API void luaL_pushmodule(lua_State *L, const char *modname, int sizehint)
|
||||
{
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
|
||||
lua_getfield(L, -1, modname);
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, sizehint) != NULL)
|
||||
lj_err_callerv(L, LJ_ERR_BADMODN, modname);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -3, modname); /* _LOADED[modname] = new table. */
|
||||
}
|
||||
lua_remove(L, -2); /* Remove _LOADED table. */
|
||||
}
|
||||
|
||||
LUALIB_API void luaL_openlib(lua_State *L, const char *libname,
|
||||
const luaL_Reg *l, int nup)
|
||||
{
|
||||
lj_lib_checkfpu(L);
|
||||
if (libname) {
|
||||
luaL_pushmodule(L, libname, libsize(l));
|
||||
lua_insert(L, -(nup + 1)); /* Move module table below upvalues. */
|
||||
}
|
||||
if (l)
|
||||
luaL_setfuncs(L, l, nup);
|
||||
else
|
||||
lua_pop(L, nup); /* Remove upvalues. */
|
||||
}
|
||||
|
||||
LUALIB_API void luaL_register(lua_State *L, const char *libname,
|
||||
const luaL_Reg *l)
|
||||
{
|
||||
luaL_openlib(L, libname, l, 0);
|
||||
}
|
||||
|
||||
LUALIB_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup)
|
||||
{
|
||||
luaL_checkstack(L, nup, "too many upvalues");
|
||||
for (; l->name; l++) {
|
||||
int i;
|
||||
for (i = 0; i < nup; i++) /* Copy upvalues to the top. */
|
||||
lua_pushvalue(L, -nup);
|
||||
lua_pushcclosure(L, l->func, nup);
|
||||
lua_setfield(L, -(nup + 2), l->name);
|
||||
}
|
||||
lua_pop(L, nup); /* Remove upvalues. */
|
||||
}
|
||||
|
||||
LUALIB_API const char *luaL_gsub(lua_State *L, const char *s,
|
||||
const char *p, const char *r)
|
||||
{
|
||||
const char *wild;
|
||||
size_t l = strlen(p);
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
while ((wild = strstr(s, p)) != NULL) {
|
||||
luaL_addlstring(&b, s, (size_t)(wild - s)); /* push prefix */
|
||||
luaL_addstring(&b, r); /* push replacement in place of pattern */
|
||||
s = wild + l; /* continue after `p' */
|
||||
}
|
||||
luaL_addstring(&b, s); /* push last suffix */
|
||||
luaL_pushresult(&b);
|
||||
return lua_tostring(L, -1);
|
||||
}
|
||||
|
||||
/* -- Buffer handling ----------------------------------------------------- */
|
||||
|
||||
#define bufflen(B) ((size_t)((B)->p - (B)->buffer))
|
||||
#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
|
||||
|
||||
static int emptybuffer(luaL_Buffer *B)
|
||||
{
|
||||
size_t l = bufflen(B);
|
||||
if (l == 0)
|
||||
return 0; /* put nothing on stack */
|
||||
lua_pushlstring(B->L, B->buffer, l);
|
||||
B->p = B->buffer;
|
||||
B->lvl++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void adjuststack(luaL_Buffer *B)
|
||||
{
|
||||
if (B->lvl > 1) {
|
||||
lua_State *L = B->L;
|
||||
int toget = 1; /* number of levels to concat */
|
||||
size_t toplen = lua_strlen(L, -1);
|
||||
do {
|
||||
size_t l = lua_strlen(L, -(toget+1));
|
||||
if (!(B->lvl - toget + 1 >= LUA_MINSTACK/2 || toplen > l))
|
||||
break;
|
||||
toplen += l;
|
||||
toget++;
|
||||
} while (toget < B->lvl);
|
||||
lua_concat(L, toget);
|
||||
B->lvl = B->lvl - toget + 1;
|
||||
}
|
||||
}
|
||||
|
||||
LUALIB_API char *luaL_prepbuffer(luaL_Buffer *B)
|
||||
{
|
||||
if (emptybuffer(B))
|
||||
adjuststack(B);
|
||||
return B->buffer;
|
||||
}
|
||||
|
||||
LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l)
|
||||
{
|
||||
if (l <= bufffree(B)) {
|
||||
memcpy(B->p, s, l);
|
||||
B->p += l;
|
||||
} else {
|
||||
emptybuffer(B);
|
||||
lua_pushlstring(B->L, s, l);
|
||||
B->lvl++;
|
||||
adjuststack(B);
|
||||
}
|
||||
}
|
||||
|
||||
LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s)
|
||||
{
|
||||
luaL_addlstring(B, s, strlen(s));
|
||||
}
|
||||
|
||||
LUALIB_API void luaL_pushresult(luaL_Buffer *B)
|
||||
{
|
||||
emptybuffer(B);
|
||||
lua_concat(B->L, B->lvl);
|
||||
B->lvl = 1;
|
||||
}
|
||||
|
||||
LUALIB_API void luaL_addvalue(luaL_Buffer *B)
|
||||
{
|
||||
lua_State *L = B->L;
|
||||
size_t vl;
|
||||
const char *s = lua_tolstring(L, -1, &vl);
|
||||
if (vl <= bufffree(B)) { /* fit into buffer? */
|
||||
memcpy(B->p, s, vl); /* put it there */
|
||||
B->p += vl;
|
||||
lua_pop(L, 1); /* remove from stack */
|
||||
} else {
|
||||
if (emptybuffer(B))
|
||||
lua_insert(L, -2); /* put buffer before new value */
|
||||
B->lvl++; /* add new value into B stack */
|
||||
adjuststack(B);
|
||||
}
|
||||
}
|
||||
|
||||
LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
|
||||
{
|
||||
B->L = L;
|
||||
B->p = B->buffer;
|
||||
B->lvl = 0;
|
||||
}
|
||||
|
||||
/* -- Reference management ------------------------------------------------ */
|
||||
|
||||
#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;
|
||||
t = abs_index(L, t);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1); /* remove from stack */
|
||||
return LUA_REFNIL; /* `nil' has a unique fixed reference */
|
||||
}
|
||||
lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
|
||||
ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */
|
||||
lua_pop(L, 1); /* remove it from stack */
|
||||
if (ref != 0) { /* any free element? */
|
||||
lua_rawgeti(L, t, ref); /* remove it from list */
|
||||
lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
|
||||
} else { /* no free elements */
|
||||
ref = (int)lua_objlen(L, t);
|
||||
ref++; /* create new reference */
|
||||
}
|
||||
lua_rawseti(L, t, ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
LUALIB_API void luaL_unref(lua_State *L, int t, int ref)
|
||||
{
|
||||
if (ref >= 0) {
|
||||
t = abs_index(L, t);
|
||||
lua_rawgeti(L, t, FREELIST_REF);
|
||||
lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
|
||||
lua_pushinteger(L, ref);
|
||||
lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
|
||||
}
|
||||
}
|
||||
|
||||
/* -- Default allocator and panic function -------------------------------- */
|
||||
|
||||
static int panic(lua_State *L)
|
||||
{
|
||||
const char *s = lua_tostring(L, -1);
|
||||
fputs("PANIC: unprotected error in call to Lua API (", stderr);
|
||||
fputs(s ? s : "?", stderr);
|
||||
fputc(')', stderr); fputc('\n', stderr);
|
||||
fflush(stderr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef LUAJIT_DISABLE_VMEVENT
|
||||
static int error_finalizer(lua_State *L)
|
||||
{
|
||||
const char *s = lua_tostring(L, -1);
|
||||
fputs("ERROR in finalizer: ", stderr);
|
||||
fputs(s ? s : "?", stderr);
|
||||
fputc('\n', stderr);
|
||||
fflush(stderr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LUAJIT_USE_SYSMALLOC
|
||||
|
||||
#if LJ_64 && !LJ_GC64 && !defined(LUAJIT_USE_VALGRIND)
|
||||
#error "Must use builtin allocator for 64 bit target"
|
||||
#endif
|
||||
|
||||
static void *mem_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
|
||||
{
|
||||
(void)ud;
|
||||
(void)osize;
|
||||
if (nsize == 0) {
|
||||
free(ptr);
|
||||
return NULL;
|
||||
} else {
|
||||
return realloc(ptr, nsize);
|
||||
}
|
||||
}
|
||||
|
||||
LUALIB_API lua_State *luaL_newstate(void)
|
||||
{
|
||||
lua_State *L = lua_newstate(mem_alloc, NULL);
|
||||
if (L) {
|
||||
G(L)->panic = panic;
|
||||
#ifndef LUAJIT_DISABLE_VMEVENT
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
|
||||
lua_pushcfunction(L, error_finalizer);
|
||||
lua_rawseti(L, -2, VMEVENT_HASH(LJ_VMEVENT_ERRFIN));
|
||||
G(L)->vmevmask = VMEVENT_MASK(LJ_VMEVENT_ERRFIN);
|
||||
L->top--;
|
||||
#endif
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
LUALIB_API lua_State *luaL_newstate(void)
|
||||
{
|
||||
lua_State *L;
|
||||
#if LJ_64 && !LJ_GC64
|
||||
L = lj_state_newstate(LJ_ALLOCF_INTERNAL, NULL);
|
||||
#else
|
||||
L = lua_newstate(LJ_ALLOCF_INTERNAL, NULL);
|
||||
#endif
|
||||
if (L) {
|
||||
G(L)->panic = panic;
|
||||
#ifndef LUAJIT_DISABLE_VMEVENT
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
|
||||
lua_pushcfunction(L, error_finalizer);
|
||||
lua_rawseti(L, -2, VMEVENT_HASH(LJ_VMEVENT_ERRFIN));
|
||||
G(L)->vmevmask = VMEVENT_MASK(LJ_VMEVENT_ERRFIN);
|
||||
L->top--;
|
||||
#endif
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
#if LJ_64 && !LJ_GC64
|
||||
LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
|
||||
{
|
||||
UNUSED(f); UNUSED(ud);
|
||||
fputs("Must use luaL_newstate() for 64 bit target\n", stderr);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
703
thirdPart/luajit/src/lib_base.c
Normal file
703
thirdPart/luajit/src/lib_base.c
Normal file
@@ -0,0 +1,703 @@
|
||||
/*
|
||||
** Base and coroutine library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** Major portions taken verbatim or adapted from the Lua interpreter.
|
||||
** Copyright (C) 1994-2011 Lua.org, PUC-Rio. See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define lib_base_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_gc.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_debug.h"
|
||||
#include "lj_buf.h"
|
||||
#include "lj_str.h"
|
||||
#include "lj_tab.h"
|
||||
#include "lj_meta.h"
|
||||
#include "lj_state.h"
|
||||
#include "lj_frame.h"
|
||||
#if LJ_HASFFI
|
||||
#include "lj_ctype.h"
|
||||
#include "lj_cconv.h"
|
||||
#endif
|
||||
#include "lj_bc.h"
|
||||
#include "lj_ff.h"
|
||||
#include "lj_dispatch.h"
|
||||
#include "lj_char.h"
|
||||
#include "lj_strscan.h"
|
||||
#include "lj_strfmt.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
/* -- Base library: checks ------------------------------------------------ */
|
||||
|
||||
#define LJLIB_MODULE_base
|
||||
|
||||
LJLIB_ASM(assert) LJLIB_REC(.)
|
||||
{
|
||||
lj_lib_checkany(L, 1);
|
||||
if (L->top == L->base+1)
|
||||
lj_err_caller(L, LJ_ERR_ASSERT);
|
||||
else if (tvisstr(L->base+1) || tvisnumber(L->base+1))
|
||||
lj_err_callermsg(L, strdata(lj_lib_checkstr(L, 2)));
|
||||
else
|
||||
lj_err_run(L);
|
||||
return FFH_UNREACHABLE;
|
||||
}
|
||||
|
||||
/* ORDER LJ_T */
|
||||
LJLIB_PUSH("nil")
|
||||
LJLIB_PUSH("boolean")
|
||||
LJLIB_PUSH(top-1) /* boolean */
|
||||
LJLIB_PUSH("userdata")
|
||||
LJLIB_PUSH("string")
|
||||
LJLIB_PUSH("upval")
|
||||
LJLIB_PUSH("thread")
|
||||
LJLIB_PUSH("proto")
|
||||
LJLIB_PUSH("function")
|
||||
LJLIB_PUSH("trace")
|
||||
LJLIB_PUSH("cdata")
|
||||
LJLIB_PUSH("table")
|
||||
LJLIB_PUSH(top-9) /* userdata */
|
||||
LJLIB_PUSH("number")
|
||||
LJLIB_ASM_(type) LJLIB_REC(.)
|
||||
/* Recycle the lj_lib_checkany(L, 1) from assert. */
|
||||
|
||||
/* -- Base library: iterators --------------------------------------------- */
|
||||
|
||||
/* This solves a circular dependency problem -- change FF_next_N as needed. */
|
||||
LJ_STATIC_ASSERT((int)FF_next == FF_next_N);
|
||||
|
||||
LJLIB_ASM(next) LJLIB_REC(.)
|
||||
{
|
||||
lj_lib_checktab(L, 1);
|
||||
lj_err_msg(L, LJ_ERR_NEXTIDX);
|
||||
return FFH_UNREACHABLE;
|
||||
}
|
||||
|
||||
#if LJ_52 || LJ_HASFFI
|
||||
static int ffh_pairs(lua_State *L, MMS mm)
|
||||
{
|
||||
TValue *o = lj_lib_checkany(L, 1);
|
||||
cTValue *mo = lj_meta_lookup(L, o, mm);
|
||||
if ((LJ_52 || tviscdata(o)) && !tvisnil(mo)) {
|
||||
L->top = o+1; /* Only keep one argument. */
|
||||
copyTV(L, L->base-1-LJ_FR2, mo); /* Replace callable. */
|
||||
return FFH_TAILCALL;
|
||||
} else {
|
||||
if (!tvistab(o)) lj_err_argt(L, 1, LUA_TTABLE);
|
||||
if (LJ_FR2) { copyTV(L, o-1, o); o--; }
|
||||
setfuncV(L, o-1, funcV(lj_lib_upvalue(L, 1)));
|
||||
if (mm == MM_pairs) setnilV(o+1); else setintV(o+1, 0);
|
||||
return FFH_RES(3);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define ffh_pairs(L, mm) (lj_lib_checktab(L, 1), FFH_UNREACHABLE)
|
||||
#endif
|
||||
|
||||
LJLIB_PUSH(lastcl)
|
||||
LJLIB_ASM(pairs) LJLIB_REC(xpairs 0)
|
||||
{
|
||||
return ffh_pairs(L, MM_pairs);
|
||||
}
|
||||
|
||||
LJLIB_NOREGUV LJLIB_ASM(ipairs_aux) LJLIB_REC(.)
|
||||
{
|
||||
lj_lib_checktab(L, 1);
|
||||
lj_lib_checkint(L, 2);
|
||||
return FFH_UNREACHABLE;
|
||||
}
|
||||
|
||||
LJLIB_PUSH(lastcl)
|
||||
LJLIB_ASM(ipairs) LJLIB_REC(xpairs 1)
|
||||
{
|
||||
return ffh_pairs(L, MM_ipairs);
|
||||
}
|
||||
|
||||
/* -- Base library: getters and setters ----------------------------------- */
|
||||
|
||||
LJLIB_ASM_(getmetatable) LJLIB_REC(.)
|
||||
/* Recycle the lj_lib_checkany(L, 1) from assert. */
|
||||
|
||||
LJLIB_ASM(setmetatable) LJLIB_REC(.)
|
||||
{
|
||||
GCtab *t = lj_lib_checktab(L, 1);
|
||||
GCtab *mt = lj_lib_checktabornil(L, 2);
|
||||
if (!tvisnil(lj_meta_lookup(L, L->base, MM_metatable)))
|
||||
lj_err_caller(L, LJ_ERR_PROTMT);
|
||||
setgcref(t->metatable, obj2gco(mt));
|
||||
if (mt) { lj_gc_objbarriert(L, t, mt); }
|
||||
settabV(L, L->base-1-LJ_FR2, t);
|
||||
return FFH_RES(1);
|
||||
}
|
||||
|
||||
LJLIB_CF(getfenv) LJLIB_REC(.)
|
||||
{
|
||||
GCfunc *fn;
|
||||
cTValue *o = L->base;
|
||||
if (!(o < L->top && tvisfunc(o))) {
|
||||
int level = lj_lib_optint(L, 1, 1);
|
||||
o = lj_debug_frame(L, level, &level);
|
||||
if (o == NULL)
|
||||
lj_err_arg(L, 1, LJ_ERR_INVLVL);
|
||||
if (LJ_FR2) o--;
|
||||
}
|
||||
fn = &gcval(o)->fn;
|
||||
settabV(L, L->top++, isluafunc(fn) ? tabref(fn->l.env) : tabref(L->env));
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(setfenv)
|
||||
{
|
||||
GCfunc *fn;
|
||||
GCtab *t = lj_lib_checktab(L, 2);
|
||||
cTValue *o = L->base;
|
||||
if (!(o < L->top && tvisfunc(o))) {
|
||||
int level = lj_lib_checkint(L, 1);
|
||||
if (level == 0) {
|
||||
/* NOBARRIER: A thread (i.e. L) is never black. */
|
||||
setgcref(L->env, obj2gco(t));
|
||||
return 0;
|
||||
}
|
||||
o = lj_debug_frame(L, level, &level);
|
||||
if (o == NULL)
|
||||
lj_err_arg(L, 1, LJ_ERR_INVLVL);
|
||||
if (LJ_FR2) o--;
|
||||
}
|
||||
fn = &gcval(o)->fn;
|
||||
if (!isluafunc(fn))
|
||||
lj_err_caller(L, LJ_ERR_SETFENV);
|
||||
setgcref(fn->l.env, obj2gco(t));
|
||||
lj_gc_objbarrier(L, obj2gco(fn), t);
|
||||
setfuncV(L, L->top++, fn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_ASM(rawget) LJLIB_REC(.)
|
||||
{
|
||||
lj_lib_checktab(L, 1);
|
||||
lj_lib_checkany(L, 2);
|
||||
return FFH_UNREACHABLE;
|
||||
}
|
||||
|
||||
LJLIB_CF(rawset) LJLIB_REC(.)
|
||||
{
|
||||
lj_lib_checktab(L, 1);
|
||||
lj_lib_checkany(L, 2);
|
||||
L->top = 1+lj_lib_checkany(L, 3);
|
||||
lua_rawset(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(rawequal) LJLIB_REC(.)
|
||||
{
|
||||
cTValue *o1 = lj_lib_checkany(L, 1);
|
||||
cTValue *o2 = lj_lib_checkany(L, 2);
|
||||
setboolV(L->top-1, lj_obj_equal(o1, o2));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if LJ_52
|
||||
LJLIB_CF(rawlen) LJLIB_REC(.)
|
||||
{
|
||||
cTValue *o = L->base;
|
||||
int32_t len;
|
||||
if (L->top > o && tvisstr(o))
|
||||
len = (int32_t)strV(o)->len;
|
||||
else
|
||||
len = (int32_t)lj_tab_len(lj_lib_checktab(L, 1));
|
||||
setintV(L->top-1, len);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
LJLIB_CF(unpack)
|
||||
{
|
||||
GCtab *t = lj_lib_checktab(L, 1);
|
||||
int32_t n, i = lj_lib_optint(L, 2, 1);
|
||||
int32_t e = (L->base+3-1 < L->top && !tvisnil(L->base+3-1)) ?
|
||||
lj_lib_checkint(L, 3) : (int32_t)lj_tab_len(t);
|
||||
uint32_t nu;
|
||||
if (i > e) return 0;
|
||||
nu = (uint32_t)e - (uint32_t)i;
|
||||
n = (int32_t)(nu+1);
|
||||
if (nu >= LUAI_MAXCSTACK || !lua_checkstack(L, n))
|
||||
lj_err_caller(L, LJ_ERR_UNPACK);
|
||||
do {
|
||||
cTValue *tv = lj_tab_getint(t, i);
|
||||
if (tv) {
|
||||
copyTV(L, L->top++, tv);
|
||||
} else {
|
||||
setnilV(L->top++);
|
||||
}
|
||||
} while (i++ < e);
|
||||
return n;
|
||||
}
|
||||
|
||||
LJLIB_CF(select) LJLIB_REC(.)
|
||||
{
|
||||
int32_t n = (int32_t)(L->top - L->base);
|
||||
if (n >= 1 && tvisstr(L->base) && *strVdata(L->base) == '#') {
|
||||
setintV(L->top-1, n-1);
|
||||
return 1;
|
||||
} else {
|
||||
int32_t i = lj_lib_checkint(L, 1);
|
||||
if (i < 0) i = n + i; else if (i > n) i = n;
|
||||
if (i < 1)
|
||||
lj_err_arg(L, 1, LJ_ERR_IDXRNG);
|
||||
return n - i;
|
||||
}
|
||||
}
|
||||
|
||||
/* -- Base library: conversions ------------------------------------------- */
|
||||
|
||||
LJLIB_ASM(tonumber) LJLIB_REC(.)
|
||||
{
|
||||
int32_t base = lj_lib_optint(L, 2, 10);
|
||||
if (base == 10) {
|
||||
TValue *o = lj_lib_checkany(L, 1);
|
||||
if (lj_strscan_numberobj(o)) {
|
||||
copyTV(L, L->base-1-LJ_FR2, o);
|
||||
return FFH_RES(1);
|
||||
}
|
||||
#if LJ_HASFFI
|
||||
if (tviscdata(o)) {
|
||||
CTState *cts = ctype_cts(L);
|
||||
CType *ct = lj_ctype_rawref(cts, cdataV(o)->ctypeid);
|
||||
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
|
||||
if (ctype_isnum(ct->info) || ctype_iscomplex(ct->info)) {
|
||||
if (LJ_DUALNUM && ctype_isinteger_or_bool(ct->info) &&
|
||||
ct->size <= 4 && !(ct->size == 4 && (ct->info & CTF_UNSIGNED))) {
|
||||
int32_t i;
|
||||
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o, 0);
|
||||
setintV(L->base-1-LJ_FR2, i);
|
||||
return FFH_RES(1);
|
||||
}
|
||||
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_DOUBLE),
|
||||
(uint8_t *)&(L->base-1-LJ_FR2)->n, o, 0);
|
||||
return FFH_RES(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
const char *p = strdata(lj_lib_checkstr(L, 1));
|
||||
char *ep;
|
||||
unsigned int neg = 0;
|
||||
unsigned long ul;
|
||||
if (base < 2 || base > 36)
|
||||
lj_err_arg(L, 2, LJ_ERR_BASERNG);
|
||||
while (lj_char_isspace((unsigned char)(*p))) p++;
|
||||
if (*p == '-') { p++; neg = 1; } else if (*p == '+') { p++; }
|
||||
if (lj_char_isalnum((unsigned char)(*p))) {
|
||||
ul = strtoul(p, &ep, base);
|
||||
if (p != ep) {
|
||||
while (lj_char_isspace((unsigned char)(*ep))) ep++;
|
||||
if (*ep == '\0') {
|
||||
if (LJ_DUALNUM && LJ_LIKELY(ul < 0x80000000u+neg)) {
|
||||
if (neg) ul = ~ul+1u;
|
||||
setintV(L->base-1-LJ_FR2, (int32_t)ul);
|
||||
} else {
|
||||
lua_Number n = (lua_Number)ul;
|
||||
if (neg) n = -n;
|
||||
setnumV(L->base-1-LJ_FR2, n);
|
||||
}
|
||||
return FFH_RES(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setnilV(L->base-1-LJ_FR2);
|
||||
return FFH_RES(1);
|
||||
}
|
||||
|
||||
LJLIB_ASM(tostring) LJLIB_REC(.)
|
||||
{
|
||||
TValue *o = lj_lib_checkany(L, 1);
|
||||
cTValue *mo;
|
||||
L->top = o+1; /* Only keep one argument. */
|
||||
if (!tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
|
||||
copyTV(L, L->base-1-LJ_FR2, mo); /* Replace callable. */
|
||||
return FFH_TAILCALL;
|
||||
}
|
||||
lj_gc_check(L);
|
||||
setstrV(L, L->base-1-LJ_FR2, lj_strfmt_obj(L, L->base));
|
||||
return FFH_RES(1);
|
||||
}
|
||||
|
||||
/* -- Base library: throw and catch errors -------------------------------- */
|
||||
|
||||
LJLIB_CF(error)
|
||||
{
|
||||
int32_t level = lj_lib_optint(L, 2, 1);
|
||||
lua_settop(L, 1);
|
||||
if (lua_isstring(L, 1) && level > 0) {
|
||||
luaL_where(L, level);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_concat(L, 2);
|
||||
}
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
LJLIB_ASM(pcall) LJLIB_REC(.)
|
||||
{
|
||||
lj_lib_checkany(L, 1);
|
||||
lj_lib_checkfunc(L, 2); /* For xpcall only. */
|
||||
return FFH_UNREACHABLE;
|
||||
}
|
||||
LJLIB_ASM_(xpcall) LJLIB_REC(.)
|
||||
|
||||
/* -- Base library: load Lua code ----------------------------------------- */
|
||||
|
||||
static int load_aux(lua_State *L, int status, int envarg)
|
||||
{
|
||||
if (status == LUA_OK) {
|
||||
/*
|
||||
** Set environment table for top-level function.
|
||||
** Don't do this for non-native bytecode, which returns a prototype.
|
||||
*/
|
||||
if (tvistab(L->base+envarg-1) && tvisfunc(L->top-1)) {
|
||||
GCfunc *fn = funcV(L->top-1);
|
||||
GCtab *t = tabV(L->base+envarg-1);
|
||||
setgcref(fn->c.env, obj2gco(t));
|
||||
lj_gc_objbarrier(L, fn, t);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
setnilV(L->top-2);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
LJLIB_CF(loadfile)
|
||||
{
|
||||
GCstr *fname = lj_lib_optstr(L, 1);
|
||||
GCstr *mode = lj_lib_optstr(L, 2);
|
||||
int status;
|
||||
lua_settop(L, 3); /* Ensure env arg exists. */
|
||||
status = luaL_loadfilex(L, fname ? strdata(fname) : NULL,
|
||||
mode ? strdata(mode) : NULL);
|
||||
return load_aux(L, status, 3);
|
||||
}
|
||||
|
||||
static const char *reader_func(lua_State *L, void *ud, size_t *size)
|
||||
{
|
||||
UNUSED(ud);
|
||||
luaL_checkstack(L, 2, "too many nested functions");
|
||||
copyTV(L, L->top++, L->base);
|
||||
lua_call(L, 0, 1); /* Call user-supplied function. */
|
||||
L->top--;
|
||||
if (tvisnil(L->top)) {
|
||||
*size = 0;
|
||||
return NULL;
|
||||
} else if (tvisstr(L->top) || tvisnumber(L->top)) {
|
||||
copyTV(L, L->base+4, L->top); /* Anchor string in reserved stack slot. */
|
||||
return lua_tolstring(L, 5, size);
|
||||
} else {
|
||||
lj_err_caller(L, LJ_ERR_RDRSTR);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
LJLIB_CF(load)
|
||||
{
|
||||
GCstr *name = lj_lib_optstr(L, 2);
|
||||
GCstr *mode = lj_lib_optstr(L, 3);
|
||||
int status;
|
||||
if (L->base < L->top &&
|
||||
(tvisstr(L->base) || tvisnumber(L->base) || tvisbuf(L->base))) {
|
||||
const char *s;
|
||||
MSize len;
|
||||
if (tvisbuf(L->base)) {
|
||||
SBufExt *sbx = bufV(L->base);
|
||||
s = sbx->r;
|
||||
len = sbufxlen(sbx);
|
||||
if (!name) name = &G(L)->strempty; /* Buffers are not NUL-terminated. */
|
||||
} else {
|
||||
GCstr *str = lj_lib_checkstr(L, 1);
|
||||
s = strdata(str);
|
||||
len = str->len;
|
||||
}
|
||||
lua_settop(L, 4); /* Ensure env arg exists. */
|
||||
status = luaL_loadbufferx(L, s, len, name ? strdata(name) : s,
|
||||
mode ? strdata(mode) : NULL);
|
||||
} else {
|
||||
lj_lib_checkfunc(L, 1);
|
||||
lua_settop(L, 5); /* Reserve a slot for the string from the reader. */
|
||||
status = lua_loadx(L, reader_func, NULL, name ? strdata(name) : "=(load)",
|
||||
mode ? strdata(mode) : NULL);
|
||||
}
|
||||
return load_aux(L, status, 4);
|
||||
}
|
||||
|
||||
LJLIB_CF(loadstring)
|
||||
{
|
||||
return lj_cf_load(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(dofile)
|
||||
{
|
||||
GCstr *fname = lj_lib_optstr(L, 1);
|
||||
setnilV(L->top);
|
||||
L->top = L->base+1;
|
||||
if (luaL_loadfile(L, fname ? strdata(fname) : NULL) != LUA_OK)
|
||||
lua_error(L);
|
||||
lua_call(L, 0, LUA_MULTRET);
|
||||
return (int)(L->top - L->base) - 1;
|
||||
}
|
||||
|
||||
/* -- Base library: GC control -------------------------------------------- */
|
||||
|
||||
LJLIB_CF(gcinfo)
|
||||
{
|
||||
setintV(L->top++, (int32_t)(G(L)->gc.total >> 10));
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(collectgarbage)
|
||||
{
|
||||
int opt = lj_lib_checkopt(L, 1, LUA_GCCOLLECT, /* ORDER LUA_GC* */
|
||||
"\4stop\7restart\7collect\5count\1\377\4step\10setpause\12setstepmul\1\377\11isrunning");
|
||||
int32_t data = lj_lib_optint(L, 2, 0);
|
||||
if (opt == LUA_GCCOUNT) {
|
||||
setnumV(L->top, (lua_Number)G(L)->gc.total/1024.0);
|
||||
} else {
|
||||
int res = lua_gc(L, opt, data);
|
||||
if (opt == LUA_GCSTEP || opt == LUA_GCISRUNNING)
|
||||
setboolV(L->top, res);
|
||||
else
|
||||
setintV(L->top, res);
|
||||
}
|
||||
L->top++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* -- Base library: miscellaneous functions ------------------------------- */
|
||||
|
||||
LJLIB_PUSH(top-2) /* Upvalue holds weak table. */
|
||||
LJLIB_CF(newproxy)
|
||||
{
|
||||
lua_settop(L, 1);
|
||||
lua_newuserdata(L, 0);
|
||||
if (lua_toboolean(L, 1) == 0) { /* newproxy(): without metatable. */
|
||||
return 1;
|
||||
} else if (lua_isboolean(L, 1)) { /* newproxy(true): with metatable. */
|
||||
lua_newtable(L);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_pushboolean(L, 1);
|
||||
lua_rawset(L, lua_upvalueindex(1)); /* Remember mt in weak table. */
|
||||
} else { /* newproxy(proxy): inherit metatable. */
|
||||
int validproxy = 0;
|
||||
if (lua_getmetatable(L, 1)) {
|
||||
lua_rawget(L, lua_upvalueindex(1));
|
||||
validproxy = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
if (!validproxy)
|
||||
lj_err_arg(L, 1, LJ_ERR_NOPROXY);
|
||||
lua_getmetatable(L, 1);
|
||||
}
|
||||
lua_setmetatable(L, 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_PUSH("tostring")
|
||||
LJLIB_CF(print)
|
||||
{
|
||||
ptrdiff_t i, nargs = L->top - L->base;
|
||||
cTValue *tv = lj_tab_getstr(tabref(L->env), strV(lj_lib_upvalue(L, 1)));
|
||||
int shortcut;
|
||||
if (tv && !tvisnil(tv)) {
|
||||
copyTV(L, L->top++, tv);
|
||||
} else {
|
||||
setstrV(L, L->top++, strV(lj_lib_upvalue(L, 1)));
|
||||
lua_gettable(L, LUA_GLOBALSINDEX);
|
||||
tv = L->top-1;
|
||||
}
|
||||
shortcut = (tvisfunc(tv) && funcV(tv)->c.ffid == FF_tostring) &&
|
||||
!gcrefu(basemt_it(G(L), LJ_TNUMX));
|
||||
for (i = 0; i < nargs; i++) {
|
||||
cTValue *o = &L->base[i];
|
||||
const char *str;
|
||||
size_t size;
|
||||
MSize len;
|
||||
if (shortcut && (str = lj_strfmt_wstrnum(L, o, &len)) != NULL) {
|
||||
size = len;
|
||||
} else {
|
||||
copyTV(L, L->top+1, o);
|
||||
copyTV(L, L->top, L->top-1);
|
||||
L->top += 2;
|
||||
lua_call(L, 1, 1);
|
||||
str = lua_tolstring(L, -1, &size);
|
||||
if (!str)
|
||||
lj_err_caller(L, LJ_ERR_PRTOSTR);
|
||||
L->top--;
|
||||
}
|
||||
if (i)
|
||||
putchar('\t');
|
||||
fwrite(str, 1, size, stdout);
|
||||
}
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_PUSH(top-3)
|
||||
LJLIB_SET(_VERSION)
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
/* -- Coroutine library --------------------------------------------------- */
|
||||
|
||||
#define LJLIB_MODULE_coroutine
|
||||
|
||||
LJLIB_CF(coroutine_status)
|
||||
{
|
||||
const char *s;
|
||||
lua_State *co;
|
||||
if (!(L->top > L->base && tvisthread(L->base)))
|
||||
lj_err_arg(L, 1, LJ_ERR_NOCORO);
|
||||
co = threadV(L->base);
|
||||
if (co == L) s = "running";
|
||||
else if (co->status == LUA_YIELD) s = "suspended";
|
||||
else if (co->status != LUA_OK) s = "dead";
|
||||
else if (co->base > tvref(co->stack)+1+LJ_FR2) s = "normal";
|
||||
else if (co->top == co->base) s = "dead";
|
||||
else s = "suspended";
|
||||
lua_pushstring(L, s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(coroutine_running)
|
||||
{
|
||||
#if LJ_52
|
||||
int ismain = lua_pushthread(L);
|
||||
setboolV(L->top++, ismain);
|
||||
return 2;
|
||||
#else
|
||||
if (lua_pushthread(L))
|
||||
setnilV(L->top++);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
LJLIB_CF(coroutine_isyieldable)
|
||||
{
|
||||
setboolV(L->top++, cframe_canyield(L->cframe));
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(coroutine_create)
|
||||
{
|
||||
lua_State *L1;
|
||||
if (!(L->base < L->top && tvisfunc(L->base)))
|
||||
lj_err_argt(L, 1, LUA_TFUNCTION);
|
||||
L1 = lua_newthread(L);
|
||||
setfuncV(L, L1->top++, funcV(L->base));
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_ASM(coroutine_yield)
|
||||
{
|
||||
lj_err_caller(L, LJ_ERR_CYIELD);
|
||||
return FFH_UNREACHABLE;
|
||||
}
|
||||
|
||||
static int ffh_resume(lua_State *L, lua_State *co, int wrap)
|
||||
{
|
||||
if (co->cframe != NULL || co->status > LUA_YIELD ||
|
||||
(co->status == LUA_OK && co->top == co->base)) {
|
||||
ErrMsg em = co->cframe ? LJ_ERR_CORUN : LJ_ERR_CODEAD;
|
||||
if (wrap) lj_err_caller(L, em);
|
||||
setboolV(L->base-1-LJ_FR2, 0);
|
||||
setstrV(L, L->base-LJ_FR2, lj_err_str(L, em));
|
||||
return FFH_RES(2);
|
||||
}
|
||||
if (lj_state_cpgrowstack(co, (MSize)(L->top - L->base)) != LUA_OK) {
|
||||
cTValue *msg = --co->top;
|
||||
lj_err_callermsg(L, strVdata(msg));
|
||||
}
|
||||
return FFH_RETRY;
|
||||
}
|
||||
|
||||
LJLIB_ASM(coroutine_resume)
|
||||
{
|
||||
if (!(L->top > L->base && tvisthread(L->base)))
|
||||
lj_err_arg(L, 1, LJ_ERR_NOCORO);
|
||||
return ffh_resume(L, threadV(L->base), 0);
|
||||
}
|
||||
|
||||
LJLIB_NOREG LJLIB_ASM(coroutine_wrap_aux)
|
||||
{
|
||||
return ffh_resume(L, threadV(lj_lib_upvalue(L, 1)), 1);
|
||||
}
|
||||
|
||||
/* Inline declarations. */
|
||||
LJ_ASMF void lj_ff_coroutine_wrap_aux(void);
|
||||
#if !(LJ_TARGET_MIPS && defined(ljamalg_c))
|
||||
LJ_FUNCA_NORET void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L,
|
||||
lua_State *co);
|
||||
#endif
|
||||
|
||||
/* Error handler, called from assembler VM. */
|
||||
void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L, lua_State *co)
|
||||
{
|
||||
co->top--; copyTV(L, L->top, co->top); L->top++;
|
||||
if (tvisstr(L->top-1))
|
||||
lj_err_callermsg(L, strVdata(L->top-1));
|
||||
else
|
||||
lj_err_run(L);
|
||||
}
|
||||
|
||||
/* Forward declaration. */
|
||||
static void setpc_wrap_aux(lua_State *L, GCfunc *fn);
|
||||
|
||||
LJLIB_CF(coroutine_wrap)
|
||||
{
|
||||
GCfunc *fn;
|
||||
lj_cf_coroutine_create(L);
|
||||
fn = lj_lib_pushcc(L, lj_ffh_coroutine_wrap_aux, FF_coroutine_wrap_aux, 1);
|
||||
setpc_wrap_aux(L, fn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
/* Fix the PC of wrap_aux. Really ugly workaround. */
|
||||
static void setpc_wrap_aux(lua_State *L, GCfunc *fn)
|
||||
{
|
||||
setmref(fn->c.pc, &L2GG(L)->bcff[lj_lib_init_coroutine[1]+2]);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static void newproxy_weaktable(lua_State *L)
|
||||
{
|
||||
/* NOBARRIER: The table is new (marked white). */
|
||||
GCtab *t = lj_tab_new(L, 0, 1);
|
||||
settabV(L, L->top++, t);
|
||||
setgcref(t->metatable, obj2gco(t));
|
||||
setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
|
||||
lj_str_newlit(L, "kv"));
|
||||
t->nomm = (uint8_t)(~(1u<<MM_mode));
|
||||
}
|
||||
|
||||
LUALIB_API int luaopen_base(lua_State *L)
|
||||
{
|
||||
/* NOBARRIER: Table and value are the same. */
|
||||
GCtab *env = tabref(L->env);
|
||||
settabV(L, lj_tab_setstr(L, env, lj_str_newlit(L, "_G")), env);
|
||||
lua_pushliteral(L, LUA_VERSION); /* top-3. */
|
||||
newproxy_weaktable(L); /* top-2. */
|
||||
LJ_LIB_REG(L, "_G", base);
|
||||
LJ_LIB_REG(L, LUA_COLIBNAME, coroutine);
|
||||
return 2;
|
||||
}
|
||||
|
||||
181
thirdPart/luajit/src/lib_bit.c
Normal file
181
thirdPart/luajit/src/lib_bit.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
** Bit manipulation library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#define lib_bit_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_buf.h"
|
||||
#include "lj_strscan.h"
|
||||
#include "lj_strfmt.h"
|
||||
#if LJ_HASFFI
|
||||
#include "lj_ctype.h"
|
||||
#include "lj_cdata.h"
|
||||
#include "lj_cconv.h"
|
||||
#include "lj_carith.h"
|
||||
#endif
|
||||
#include "lj_ff.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define LJLIB_MODULE_bit
|
||||
|
||||
#if LJ_HASFFI
|
||||
static int bit_result64(lua_State *L, CTypeID id, uint64_t x)
|
||||
{
|
||||
GCcdata *cd = lj_cdata_new_(L, id, 8);
|
||||
*(uint64_t *)cdataptr(cd) = x;
|
||||
setcdataV(L, L->base-1-LJ_FR2, cd);
|
||||
return FFH_RES(1);
|
||||
}
|
||||
#else
|
||||
static int32_t bit_checkbit(lua_State *L, int narg)
|
||||
{
|
||||
TValue *o = L->base + narg-1;
|
||||
if (!(o < L->top && lj_strscan_numberobj(o)))
|
||||
lj_err_argt(L, narg, LUA_TNUMBER);
|
||||
if (LJ_LIKELY(tvisint(o))) {
|
||||
return intV(o);
|
||||
} else {
|
||||
int32_t i = lj_num2bit(numV(o));
|
||||
if (LJ_DUALNUM) setintV(o, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
LJLIB_ASM(bit_tobit) LJLIB_REC(bit_tobit)
|
||||
{
|
||||
#if LJ_HASFFI
|
||||
CTypeID id = 0;
|
||||
setintV(L->base-1-LJ_FR2, (int32_t)lj_carith_check64(L, 1, &id));
|
||||
return FFH_RES(1);
|
||||
#else
|
||||
lj_lib_checknumber(L, 1);
|
||||
return FFH_RETRY;
|
||||
#endif
|
||||
}
|
||||
|
||||
LJLIB_ASM(bit_bnot) LJLIB_REC(bit_unary IR_BNOT)
|
||||
{
|
||||
#if LJ_HASFFI
|
||||
CTypeID id = 0;
|
||||
uint64_t x = lj_carith_check64(L, 1, &id);
|
||||
return id ? bit_result64(L, id, ~x) : FFH_RETRY;
|
||||
#else
|
||||
lj_lib_checknumber(L, 1);
|
||||
return FFH_RETRY;
|
||||
#endif
|
||||
}
|
||||
|
||||
LJLIB_ASM(bit_bswap) LJLIB_REC(bit_unary IR_BSWAP)
|
||||
{
|
||||
#if LJ_HASFFI
|
||||
CTypeID id = 0;
|
||||
uint64_t x = lj_carith_check64(L, 1, &id);
|
||||
return id ? bit_result64(L, id, lj_bswap64(x)) : FFH_RETRY;
|
||||
#else
|
||||
lj_lib_checknumber(L, 1);
|
||||
return FFH_RETRY;
|
||||
#endif
|
||||
}
|
||||
|
||||
LJLIB_ASM(bit_lshift) LJLIB_REC(bit_shift IR_BSHL)
|
||||
{
|
||||
#if LJ_HASFFI
|
||||
CTypeID id = 0, id2 = 0;
|
||||
uint64_t x = lj_carith_check64(L, 1, &id);
|
||||
int32_t sh = (int32_t)lj_carith_check64(L, 2, &id2);
|
||||
if (id) {
|
||||
x = lj_carith_shift64(x, sh, curr_func(L)->c.ffid - (int)FF_bit_lshift);
|
||||
return bit_result64(L, id, x);
|
||||
}
|
||||
if (id2) setintV(L->base+1, sh);
|
||||
return FFH_RETRY;
|
||||
#else
|
||||
lj_lib_checknumber(L, 1);
|
||||
bit_checkbit(L, 2);
|
||||
return FFH_RETRY;
|
||||
#endif
|
||||
}
|
||||
LJLIB_ASM_(bit_rshift) LJLIB_REC(bit_shift IR_BSHR)
|
||||
LJLIB_ASM_(bit_arshift) LJLIB_REC(bit_shift IR_BSAR)
|
||||
LJLIB_ASM_(bit_rol) LJLIB_REC(bit_shift IR_BROL)
|
||||
LJLIB_ASM_(bit_ror) LJLIB_REC(bit_shift IR_BROR)
|
||||
|
||||
LJLIB_ASM(bit_band) LJLIB_REC(bit_nary IR_BAND)
|
||||
{
|
||||
#if LJ_HASFFI
|
||||
CTypeID id = 0;
|
||||
TValue *o = L->base, *top = L->top;
|
||||
int i = 0;
|
||||
do { lj_carith_check64(L, ++i, &id); } while (++o < top);
|
||||
if (id) {
|
||||
CTState *cts = ctype_cts(L);
|
||||
CType *ct = ctype_get(cts, id);
|
||||
int op = curr_func(L)->c.ffid - (int)FF_bit_bor;
|
||||
uint64_t x, y = op >= 0 ? 0 : ~(uint64_t)0;
|
||||
o = L->base;
|
||||
do {
|
||||
lj_cconv_ct_tv(cts, ct, (uint8_t *)&x, o, 0);
|
||||
if (op < 0) y &= x; else if (op == 0) y |= x; else y ^= x;
|
||||
} while (++o < top);
|
||||
return bit_result64(L, id, y);
|
||||
}
|
||||
return FFH_RETRY;
|
||||
#else
|
||||
int i = 0;
|
||||
do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top);
|
||||
return FFH_RETRY;
|
||||
#endif
|
||||
}
|
||||
LJLIB_ASM_(bit_bor) LJLIB_REC(bit_nary IR_BOR)
|
||||
LJLIB_ASM_(bit_bxor) LJLIB_REC(bit_nary IR_BXOR)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
LJLIB_CF(bit_tohex) LJLIB_REC(.)
|
||||
{
|
||||
#if LJ_HASFFI
|
||||
CTypeID id = 0, id2 = 0;
|
||||
uint64_t b = lj_carith_check64(L, 1, &id);
|
||||
int32_t n = L->base+1>=L->top ? (id ? 16 : 8) :
|
||||
(int32_t)lj_carith_check64(L, 2, &id2);
|
||||
#else
|
||||
uint32_t b = (uint32_t)bit_checkbit(L, 1);
|
||||
int32_t n = L->base+1>=L->top ? 8 : bit_checkbit(L, 2);
|
||||
#endif
|
||||
SBuf *sb = lj_buf_tmp_(L);
|
||||
SFormat sf = (STRFMT_UINT|STRFMT_T_HEX);
|
||||
if (n < 0) { n = (int32_t)(~(uint32_t)n+1u); sf |= STRFMT_F_UPPER; }
|
||||
if ((uint32_t)n > 254) n = 254;
|
||||
sf |= ((SFormat)((n+1)&255) << STRFMT_SH_PREC);
|
||||
#if LJ_HASFFI
|
||||
if (n < 16) b &= ((uint64_t)1 << 4*n)-1;
|
||||
#else
|
||||
if (n < 8) b &= (1u << 4*n)-1;
|
||||
#endif
|
||||
sb = lj_strfmt_putfxint(sb, sf, b);
|
||||
setstrV(L, L->top-1, lj_buf_str(L, sb));
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
LUALIB_API int luaopen_bit(lua_State *L)
|
||||
{
|
||||
LJ_LIB_REG(L, LUA_BITLIBNAME, bit);
|
||||
return 1;
|
||||
}
|
||||
|
||||
360
thirdPart/luajit/src/lib_buffer.c
Normal file
360
thirdPart/luajit/src/lib_buffer.c
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
** Buffer library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#define lib_buffer_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
|
||||
#if LJ_HASBUFFER
|
||||
#include "lj_gc.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_buf.h"
|
||||
#include "lj_str.h"
|
||||
#include "lj_tab.h"
|
||||
#include "lj_udata.h"
|
||||
#include "lj_meta.h"
|
||||
#if LJ_HASFFI
|
||||
#include "lj_ctype.h"
|
||||
#include "lj_cdata.h"
|
||||
#include "lj_cconv.h"
|
||||
#endif
|
||||
#include "lj_strfmt.h"
|
||||
#include "lj_serialize.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
/* -- Helper functions ---------------------------------------------------- */
|
||||
|
||||
/* Check that the first argument is a string buffer. */
|
||||
static SBufExt *buffer_tobuf(lua_State *L)
|
||||
{
|
||||
if (!(L->base < L->top && tvisbuf(L->base)))
|
||||
lj_err_argtype(L, 1, "buffer");
|
||||
return bufV(L->base);
|
||||
}
|
||||
|
||||
/* Ditto, but for writers. */
|
||||
static LJ_AINLINE SBufExt *buffer_tobufw(lua_State *L)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
setsbufXL_(sbx, L);
|
||||
return sbx;
|
||||
}
|
||||
|
||||
#define buffer_toudata(sbx) ((GCudata *)(sbx)-1)
|
||||
|
||||
/* -- Buffer methods ------------------------------------------------------ */
|
||||
|
||||
#define LJLIB_MODULE_buffer_method
|
||||
|
||||
LJLIB_CF(buffer_method_free)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
lj_bufx_free(L, sbx);
|
||||
L->top = L->base+1; /* Chain buffer object. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method_reset) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
lj_bufx_reset(sbx);
|
||||
L->top = L->base+1; /* Chain buffer object. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method_skip) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
|
||||
MSize len = sbufxlen(sbx);
|
||||
if (n < len) {
|
||||
sbx->r += n;
|
||||
} else if (sbufiscow(sbx)) {
|
||||
sbx->r = sbx->w;
|
||||
} else {
|
||||
sbx->r = sbx->w = sbx->b;
|
||||
}
|
||||
L->top = L->base+1; /* Chain buffer object. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method_set) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
GCobj *ref;
|
||||
const char *p;
|
||||
MSize len;
|
||||
#if LJ_HASFFI
|
||||
if (tviscdata(L->base+1)) {
|
||||
CTState *cts = ctype_cts(L);
|
||||
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
|
||||
L->base+1, CCF_ARG(2));
|
||||
len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
GCstr *str = lj_lib_checkstrx(L, 2);
|
||||
p = strdata(str);
|
||||
len = str->len;
|
||||
}
|
||||
lj_bufx_free(L, sbx);
|
||||
lj_bufx_set_cow(L, sbx, p, len);
|
||||
ref = gcV(L->base+1);
|
||||
setgcref(sbx->cowref, ref);
|
||||
lj_gc_objbarrier(L, buffer_toudata(sbx), ref);
|
||||
L->top = L->base+1; /* Chain buffer object. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method_put) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobufw(L);
|
||||
ptrdiff_t arg, narg = L->top - L->base;
|
||||
for (arg = 1; arg < narg; arg++) {
|
||||
cTValue *o = &L->base[arg], *mo = NULL;
|
||||
retry:
|
||||
if (tvisstr(o)) {
|
||||
lj_buf_putstr((SBuf *)sbx, strV(o));
|
||||
} else if (tvisint(o)) {
|
||||
lj_strfmt_putint((SBuf *)sbx, intV(o));
|
||||
} else if (tvisnum(o)) {
|
||||
lj_strfmt_putfnum((SBuf *)sbx, STRFMT_G14, numV(o));
|
||||
} else if (tvisbuf(o)) {
|
||||
SBufExt *sbx2 = bufV(o);
|
||||
if (sbx2 == sbx) lj_err_arg(L, (int)(arg+1), LJ_ERR_BUFFER_SELF);
|
||||
lj_buf_putmem((SBuf *)sbx, sbx2->r, sbufxlen(sbx2));
|
||||
} else if (!mo && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
|
||||
/* Call __tostring metamethod inline. */
|
||||
copyTV(L, L->top++, mo);
|
||||
copyTV(L, L->top++, o);
|
||||
lua_call(L, 1, 1);
|
||||
o = &L->base[arg]; /* The stack may have been reallocated. */
|
||||
copyTV(L, &L->base[arg], L->top-1);
|
||||
L->top = L->base + narg;
|
||||
goto retry; /* Retry with the result. */
|
||||
} else {
|
||||
lj_err_argtype(L, (int)(arg+1), "string/number/__tostring");
|
||||
}
|
||||
/* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */
|
||||
}
|
||||
L->top = L->base+1; /* Chain buffer object. */
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method_putf) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobufw(L);
|
||||
lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2);
|
||||
L->top = L->base+1; /* Chain buffer object. */
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method_get) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
ptrdiff_t arg, narg = L->top - L->base;
|
||||
if (narg == 1) {
|
||||
narg++;
|
||||
setnilV(L->top++); /* get() is the same as get(nil). */
|
||||
}
|
||||
for (arg = 1; arg < narg; arg++) {
|
||||
TValue *o = &L->base[arg];
|
||||
MSize n = tvisnil(o) ? LJ_MAX_BUF :
|
||||
(MSize) lj_lib_checkintrange(L, (int)(arg+1), 0, LJ_MAX_BUF);
|
||||
MSize len = sbufxlen(sbx);
|
||||
if (n > len) n = len;
|
||||
setstrV(L, o, lj_str_new(L, sbx->r, n));
|
||||
sbx->r += n;
|
||||
}
|
||||
if (sbx->r == sbx->w && !sbufiscow(sbx)) sbx->r = sbx->w = sbx->b;
|
||||
lj_gc_check(L);
|
||||
return (int)(narg-1);
|
||||
}
|
||||
|
||||
#if LJ_HASFFI
|
||||
LJLIB_CF(buffer_method_putcdata) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobufw(L);
|
||||
const char *p;
|
||||
MSize len;
|
||||
if (tviscdata(L->base+1)) {
|
||||
CTState *cts = ctype_cts(L);
|
||||
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
|
||||
L->base+1, CCF_ARG(2));
|
||||
} else {
|
||||
lj_err_argtype(L, 2, "cdata");
|
||||
}
|
||||
len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
|
||||
lj_buf_putmem((SBuf *)sbx, p, len);
|
||||
L->top = L->base+1; /* Chain buffer object. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method_reserve) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobufw(L);
|
||||
MSize sz = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
|
||||
GCcdata *cd;
|
||||
lj_buf_more((SBuf *)sbx, sz);
|
||||
ctype_loadffi(L);
|
||||
cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
|
||||
*(void **)cdataptr(cd) = sbx->w;
|
||||
setcdataV(L, L->top++, cd);
|
||||
setintV(L->top++, sbufleft(sbx));
|
||||
return 2;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method_commit) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
|
||||
if (len > sbufleft(sbx)) lj_err_arg(L, 2, LJ_ERR_NUMRNG);
|
||||
sbx->w += len;
|
||||
L->top = L->base+1; /* Chain buffer object. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method_ref) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
GCcdata *cd;
|
||||
ctype_loadffi(L);
|
||||
cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
|
||||
*(void **)cdataptr(cd) = sbx->r;
|
||||
setcdataV(L, L->top++, cd);
|
||||
setintV(L->top++, sbufxlen(sbx));
|
||||
return 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
LJLIB_CF(buffer_method_encode) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobufw(L);
|
||||
cTValue *o = lj_lib_checkany(L, 2);
|
||||
lj_serialize_put(sbx, o);
|
||||
lj_gc_check(L);
|
||||
L->top = L->base+1; /* Chain buffer object. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method_decode) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobufw(L);
|
||||
setnilV(L->top++);
|
||||
sbx->r = lj_serialize_get(sbx, L->top-1);
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method___gc)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
lj_bufx_free(L, sbx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method___tostring) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx)));
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_method___len) LJLIB_REC(.)
|
||||
{
|
||||
SBufExt *sbx = buffer_tobuf(L);
|
||||
setintV(L->top-1, (int32_t)sbufxlen(sbx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_PUSH("buffer") LJLIB_SET(__metatable)
|
||||
LJLIB_PUSH(top-1) LJLIB_SET(__index)
|
||||
|
||||
/* -- Buffer library functions -------------------------------------------- */
|
||||
|
||||
#define LJLIB_MODULE_buffer
|
||||
|
||||
LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
|
||||
|
||||
LJLIB_CF(buffer_new)
|
||||
{
|
||||
MSize sz = 0;
|
||||
int targ = 1;
|
||||
GCtab *env, *dict_str = NULL, *dict_mt = NULL;
|
||||
GCudata *ud;
|
||||
SBufExt *sbx;
|
||||
if (L->base < L->top && !tvistab(L->base)) {
|
||||
targ = 2;
|
||||
if (!tvisnil(L->base))
|
||||
sz = (MSize)lj_lib_checkintrange(L, 1, 0, LJ_MAX_BUF);
|
||||
}
|
||||
if (L->base+targ-1 < L->top) {
|
||||
GCtab *options = lj_lib_checktab(L, targ);
|
||||
cTValue *opt_dict, *opt_mt;
|
||||
opt_dict = lj_tab_getstr(options, lj_str_newlit(L, "dict"));
|
||||
if (opt_dict && tvistab(opt_dict)) {
|
||||
dict_str = tabV(opt_dict);
|
||||
lj_serialize_dict_prep_str(L, dict_str);
|
||||
}
|
||||
opt_mt = lj_tab_getstr(options, lj_str_newlit(L, "metatable"));
|
||||
if (opt_mt && tvistab(opt_mt)) {
|
||||
dict_mt = tabV(opt_mt);
|
||||
lj_serialize_dict_prep_mt(L, dict_mt);
|
||||
}
|
||||
}
|
||||
env = tabref(curr_func(L)->c.env);
|
||||
ud = lj_udata_new(L, sizeof(SBufExt), env);
|
||||
ud->udtype = UDTYPE_BUFFER;
|
||||
/* NOBARRIER: The GCudata is new (marked white). */
|
||||
setgcref(ud->metatable, obj2gco(env));
|
||||
setudataV(L, L->top++, ud);
|
||||
sbx = (SBufExt *)uddata(ud);
|
||||
lj_bufx_init(L, sbx);
|
||||
setgcref(sbx->dict_str, obj2gco(dict_str));
|
||||
setgcref(sbx->dict_mt, obj2gco(dict_mt));
|
||||
if (sz > 0) lj_buf_need2((SBuf *)sbx, sz);
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_encode) LJLIB_REC(.)
|
||||
{
|
||||
cTValue *o = lj_lib_checkany(L, 1);
|
||||
setstrV(L, L->top++, lj_serialize_encode(L, o));
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(buffer_decode) LJLIB_REC(.)
|
||||
{
|
||||
GCstr *str = lj_lib_checkstrx(L, 1);
|
||||
setnilV(L->top++);
|
||||
lj_serialize_decode(L, L->top-1, str);
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
int luaopen_string_buffer(lua_State *L)
|
||||
{
|
||||
LJ_LIB_REG(L, NULL, buffer_method);
|
||||
lua_getfield(L, -1, "__tostring");
|
||||
lua_setfield(L, -2, "tostring");
|
||||
LJ_LIB_REG(L, NULL, buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
406
thirdPart/luajit/src/lib_debug.c
Normal file
406
thirdPart/luajit/src/lib_debug.c
Normal file
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
** Debug library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** Major portions taken verbatim or adapted from the Lua interpreter.
|
||||
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lib_debug_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_gc.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_debug.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define LJLIB_MODULE_debug
|
||||
|
||||
LJLIB_CF(debug_getregistry)
|
||||
{
|
||||
copyTV(L, L->top++, registry(L));
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_getmetatable) LJLIB_REC(.)
|
||||
{
|
||||
lj_lib_checkany(L, 1);
|
||||
if (!lua_getmetatable(L, 1)) {
|
||||
setnilV(L->top-1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_setmetatable)
|
||||
{
|
||||
lj_lib_checktabornil(L, 2);
|
||||
L->top = L->base+2;
|
||||
lua_setmetatable(L, 1);
|
||||
#if !LJ_52
|
||||
setboolV(L->top-1, 1);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_getfenv)
|
||||
{
|
||||
lj_lib_checkany(L, 1);
|
||||
lua_getfenv(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_setfenv)
|
||||
{
|
||||
lj_lib_checktab(L, 2);
|
||||
L->top = L->base+2;
|
||||
if (!lua_setfenv(L, 1))
|
||||
lj_err_caller(L, LJ_ERR_SETFENV);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static void settabss(lua_State *L, const char *i, const char *v)
|
||||
{
|
||||
lua_pushstring(L, v);
|
||||
lua_setfield(L, -2, i);
|
||||
}
|
||||
|
||||
static void settabsi(lua_State *L, const char *i, int v)
|
||||
{
|
||||
lua_pushinteger(L, v);
|
||||
lua_setfield(L, -2, i);
|
||||
}
|
||||
|
||||
static void settabsb(lua_State *L, const char *i, int v)
|
||||
{
|
||||
lua_pushboolean(L, v);
|
||||
lua_setfield(L, -2, i);
|
||||
}
|
||||
|
||||
static lua_State *getthread(lua_State *L, int *arg)
|
||||
{
|
||||
if (L->base < L->top && tvisthread(L->base)) {
|
||||
*arg = 1;
|
||||
return threadV(L->base);
|
||||
} else {
|
||||
*arg = 0;
|
||||
return L;
|
||||
}
|
||||
}
|
||||
|
||||
static void treatstackoption(lua_State *L, lua_State *L1, const char *fname)
|
||||
{
|
||||
if (L == L1) {
|
||||
lua_pushvalue(L, -2);
|
||||
lua_remove(L, -3);
|
||||
}
|
||||
else
|
||||
lua_xmove(L1, L, 1);
|
||||
lua_setfield(L, -2, fname);
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_getinfo)
|
||||
{
|
||||
lj_Debug ar;
|
||||
int arg, opt_f = 0, opt_L = 0;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
const char *options = luaL_optstring(L, arg+2, "flnSu");
|
||||
if (lua_isnumber(L, arg+1)) {
|
||||
if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), (lua_Debug *)&ar)) {
|
||||
setnilV(L->top-1);
|
||||
return 1;
|
||||
}
|
||||
} else if (L->base+arg < L->top && tvisfunc(L->base+arg)) {
|
||||
options = lua_pushfstring(L, ">%s", options);
|
||||
setfuncV(L1, L1->top++, funcV(L->base+arg));
|
||||
} else {
|
||||
lj_err_arg(L, arg+1, LJ_ERR_NOFUNCL);
|
||||
}
|
||||
if (!lj_debug_getinfo(L1, options, &ar, 1))
|
||||
lj_err_arg(L, arg+2, LJ_ERR_INVOPT);
|
||||
lua_createtable(L, 0, 16); /* Create result table. */
|
||||
for (; *options; options++) {
|
||||
switch (*options) {
|
||||
case 'S':
|
||||
settabss(L, "source", ar.source);
|
||||
settabss(L, "short_src", ar.short_src);
|
||||
settabsi(L, "linedefined", ar.linedefined);
|
||||
settabsi(L, "lastlinedefined", ar.lastlinedefined);
|
||||
settabss(L, "what", ar.what);
|
||||
break;
|
||||
case 'l':
|
||||
settabsi(L, "currentline", ar.currentline);
|
||||
break;
|
||||
case 'u':
|
||||
settabsi(L, "nups", ar.nups);
|
||||
settabsi(L, "nparams", ar.nparams);
|
||||
settabsb(L, "isvararg", ar.isvararg);
|
||||
break;
|
||||
case 'n':
|
||||
settabss(L, "name", ar.name);
|
||||
settabss(L, "namewhat", ar.namewhat);
|
||||
break;
|
||||
case 'f': opt_f = 1; break;
|
||||
case 'L': opt_L = 1; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (opt_L) treatstackoption(L, L1, "activelines");
|
||||
if (opt_f) treatstackoption(L, L1, "func");
|
||||
return 1; /* Return result table. */
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_getlocal)
|
||||
{
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
lua_Debug ar;
|
||||
const char *name;
|
||||
int slot = lj_lib_checkint(L, arg+2);
|
||||
if (tvisfunc(L->base+arg)) {
|
||||
L->top = L->base+arg+1;
|
||||
lua_pushstring(L, lua_getlocal(L, NULL, slot));
|
||||
return 1;
|
||||
}
|
||||
if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar))
|
||||
lj_err_arg(L, arg+1, LJ_ERR_LVLRNG);
|
||||
name = lua_getlocal(L1, &ar, slot);
|
||||
if (name) {
|
||||
lua_xmove(L1, L, 1);
|
||||
lua_pushstring(L, name);
|
||||
lua_pushvalue(L, -2);
|
||||
return 2;
|
||||
} else {
|
||||
setnilV(L->top-1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_setlocal)
|
||||
{
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
lua_Debug ar;
|
||||
TValue *tv;
|
||||
if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar))
|
||||
lj_err_arg(L, arg+1, LJ_ERR_LVLRNG);
|
||||
tv = lj_lib_checkany(L, arg+3);
|
||||
copyTV(L1, L1->top++, tv);
|
||||
lua_pushstring(L, lua_setlocal(L1, &ar, lj_lib_checkint(L, arg+2)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int debug_getupvalue(lua_State *L, int get)
|
||||
{
|
||||
int32_t n = lj_lib_checkint(L, 2);
|
||||
const char *name;
|
||||
lj_lib_checkfunc(L, 1);
|
||||
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
|
||||
if (name) {
|
||||
lua_pushstring(L, name);
|
||||
if (!get) return 1;
|
||||
copyTV(L, L->top, L->top-2);
|
||||
L->top++;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_getupvalue)
|
||||
{
|
||||
return debug_getupvalue(L, 1);
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_setupvalue)
|
||||
{
|
||||
lj_lib_checkany(L, 3);
|
||||
return debug_getupvalue(L, 0);
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_upvalueid)
|
||||
{
|
||||
GCfunc *fn = lj_lib_checkfunc(L, 1);
|
||||
int32_t n = lj_lib_checkint(L, 2) - 1;
|
||||
if ((uint32_t)n >= fn->l.nupvalues)
|
||||
lj_err_arg(L, 2, LJ_ERR_IDXRNG);
|
||||
lua_pushlightuserdata(L, isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) :
|
||||
(void *)&fn->c.upvalue[n]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_upvaluejoin)
|
||||
{
|
||||
GCfunc *fn[2];
|
||||
GCRef *p[2];
|
||||
int i;
|
||||
for (i = 0; i < 2; i++) {
|
||||
int32_t n;
|
||||
fn[i] = lj_lib_checkfunc(L, 2*i+1);
|
||||
if (!isluafunc(fn[i]))
|
||||
lj_err_arg(L, 2*i+1, LJ_ERR_NOLFUNC);
|
||||
n = lj_lib_checkint(L, 2*i+2) - 1;
|
||||
if ((uint32_t)n >= fn[i]->l.nupvalues)
|
||||
lj_err_arg(L, 2*i+2, LJ_ERR_IDXRNG);
|
||||
p[i] = &fn[i]->l.uvptr[n];
|
||||
}
|
||||
setgcrefr(*p[0], *p[1]);
|
||||
lj_gc_objbarrier(L, fn[0], gcref(*p[1]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LJ_52
|
||||
LJLIB_CF(debug_getuservalue)
|
||||
{
|
||||
TValue *o = L->base;
|
||||
if (o < L->top && tvisudata(o))
|
||||
settabV(L, o, tabref(udataV(o)->env));
|
||||
else
|
||||
setnilV(o);
|
||||
L->top = o+1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_setuservalue)
|
||||
{
|
||||
TValue *o = L->base;
|
||||
if (!(o < L->top && tvisudata(o)))
|
||||
lj_err_argt(L, 1, LUA_TUSERDATA);
|
||||
if (!(o+1 < L->top && tvistab(o+1)))
|
||||
lj_err_argt(L, 2, LUA_TTABLE);
|
||||
L->top = o+2;
|
||||
lua_setfenv(L, 1);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define KEY_HOOK (U64x(80000000,00000000)|'h')
|
||||
|
||||
static void hookf(lua_State *L, lua_Debug *ar)
|
||||
{
|
||||
static const char *const hooknames[] =
|
||||
{"call", "return", "line", "count", "tail return"};
|
||||
(L->top++)->u64 = KEY_HOOK;
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
if (lua_isfunction(L, -1)) {
|
||||
lua_pushstring(L, hooknames[(int)ar->event]);
|
||||
if (ar->currentline >= 0)
|
||||
lua_pushinteger(L, ar->currentline);
|
||||
else lua_pushnil(L);
|
||||
lua_call(L, 2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int makemask(const char *smask, int count)
|
||||
{
|
||||
int mask = 0;
|
||||
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
|
||||
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
|
||||
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
|
||||
if (count > 0) mask |= LUA_MASKCOUNT;
|
||||
return mask;
|
||||
}
|
||||
|
||||
static char *unmakemask(int mask, char *smask)
|
||||
{
|
||||
int i = 0;
|
||||
if (mask & LUA_MASKCALL) smask[i++] = 'c';
|
||||
if (mask & LUA_MASKRET) smask[i++] = 'r';
|
||||
if (mask & LUA_MASKLINE) smask[i++] = 'l';
|
||||
smask[i] = '\0';
|
||||
return smask;
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_sethook)
|
||||
{
|
||||
int arg, mask, count;
|
||||
lua_Hook func;
|
||||
(void)getthread(L, &arg);
|
||||
if (lua_isnoneornil(L, arg+1)) {
|
||||
lua_settop(L, arg+1);
|
||||
func = NULL; mask = 0; count = 0; /* turn off hooks */
|
||||
} else {
|
||||
const char *smask = luaL_checkstring(L, arg+2);
|
||||
luaL_checktype(L, arg+1, LUA_TFUNCTION);
|
||||
count = luaL_optint(L, arg+3, 0);
|
||||
func = hookf; mask = makemask(smask, count);
|
||||
}
|
||||
(L->top++)->u64 = KEY_HOOK;
|
||||
lua_pushvalue(L, arg+1);
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
lua_sethook(L, func, mask, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(debug_gethook)
|
||||
{
|
||||
char buff[5];
|
||||
int mask = lua_gethookmask(L);
|
||||
lua_Hook hook = lua_gethook(L);
|
||||
if (hook != NULL && hook != hookf) { /* external hook? */
|
||||
lua_pushliteral(L, "external hook");
|
||||
} else {
|
||||
(L->top++)->u64 = KEY_HOOK;
|
||||
lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
|
||||
}
|
||||
lua_pushstring(L, unmakemask(mask, buff));
|
||||
lua_pushinteger(L, lua_gethookcount(L));
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
LJLIB_CF(debug_debug)
|
||||
{
|
||||
for (;;) {
|
||||
char buffer[250];
|
||||
fputs("lua_debug> ", stderr);
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
|
||||
strcmp(buffer, "cont\n") == 0)
|
||||
return 0;
|
||||
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
|
||||
lua_pcall(L, 0, 0, 0)) {
|
||||
const char *s = lua_tostring(L, -1);
|
||||
fputs(s ? s : "(error object is not a string)", stderr);
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
lua_settop(L, 0); /* remove eventual returns */
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define LEVELS1 12 /* size of the first part of the stack */
|
||||
#define LEVELS2 10 /* size of the second part of the stack */
|
||||
|
||||
LJLIB_CF(debug_traceback)
|
||||
{
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
const char *msg = lua_tostring(L, arg+1);
|
||||
if (msg == NULL && L->top > L->base+arg)
|
||||
L->top = L->base+arg+1;
|
||||
else
|
||||
luaL_traceback(L, L1, msg, lj_lib_optint(L, arg+2, (L == L1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
LUALIB_API int luaopen_debug(lua_State *L)
|
||||
{
|
||||
LJ_LIB_REG(L, LUA_DBLIBNAME, debug);
|
||||
return 1;
|
||||
}
|
||||
|
||||
857
thirdPart/luajit/src/lib_ffi.c
Normal file
857
thirdPart/luajit/src/lib_ffi.c
Normal file
@@ -0,0 +1,857 @@
|
||||
/*
|
||||
** FFI library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#define lib_ffi_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
|
||||
#if LJ_HASFFI
|
||||
|
||||
#include "lj_gc.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_str.h"
|
||||
#include "lj_tab.h"
|
||||
#include "lj_meta.h"
|
||||
#include "lj_ctype.h"
|
||||
#include "lj_cparse.h"
|
||||
#include "lj_cdata.h"
|
||||
#include "lj_cconv.h"
|
||||
#include "lj_carith.h"
|
||||
#include "lj_ccall.h"
|
||||
#include "lj_ccallback.h"
|
||||
#include "lj_clib.h"
|
||||
#include "lj_strfmt.h"
|
||||
#include "lj_ff.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
/* -- C type checks ------------------------------------------------------- */
|
||||
|
||||
/* Check first argument for a C type and returns its ID. */
|
||||
static CTypeID ffi_checkctype(lua_State *L, CTState *cts, TValue *param)
|
||||
{
|
||||
TValue *o = L->base;
|
||||
if (!(o < L->top)) {
|
||||
err_argtype:
|
||||
lj_err_argtype(L, 1, "C type");
|
||||
}
|
||||
if (tvisstr(o)) { /* Parse an abstract C type declaration. */
|
||||
GCstr *s = strV(o);
|
||||
CPState cp;
|
||||
int errcode;
|
||||
cp.L = L;
|
||||
cp.cts = cts;
|
||||
cp.srcname = strdata(s);
|
||||
cp.p = strdata(s);
|
||||
cp.param = param;
|
||||
cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT;
|
||||
errcode = lj_cparse(&cp);
|
||||
if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */
|
||||
return cp.val.id;
|
||||
} else {
|
||||
GCcdata *cd;
|
||||
if (!tviscdata(o)) goto err_argtype;
|
||||
if (param && param < L->top) lj_err_arg(L, 1, LJ_ERR_FFI_NUMPARAM);
|
||||
cd = cdataV(o);
|
||||
return cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->ctypeid;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check argument for C data and return it. */
|
||||
static GCcdata *ffi_checkcdata(lua_State *L, int narg)
|
||||
{
|
||||
TValue *o = L->base + narg-1;
|
||||
if (!(o < L->top && tviscdata(o)))
|
||||
lj_err_argt(L, narg, LUA_TCDATA);
|
||||
return cdataV(o);
|
||||
}
|
||||
|
||||
/* Convert argument to C pointer. */
|
||||
static void *ffi_checkptr(lua_State *L, int narg, CTypeID id)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
TValue *o = L->base + narg-1;
|
||||
void *p;
|
||||
if (o >= L->top)
|
||||
lj_err_arg(L, narg, LJ_ERR_NOVAL);
|
||||
lj_cconv_ct_tv(cts, ctype_get(cts, id), (uint8_t *)&p, o, CCF_ARG(narg));
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Convert argument to int32_t. */
|
||||
static int32_t ffi_checkint(lua_State *L, int narg)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
TValue *o = L->base + narg-1;
|
||||
int32_t i;
|
||||
if (o >= L->top)
|
||||
lj_err_arg(L, narg, LJ_ERR_NOVAL);
|
||||
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o,
|
||||
CCF_ARG(narg));
|
||||
return i;
|
||||
}
|
||||
|
||||
/* -- C type metamethods -------------------------------------------------- */
|
||||
|
||||
#define LJLIB_MODULE_ffi_meta
|
||||
|
||||
/* Handle ctype __index/__newindex metamethods. */
|
||||
static int ffi_index_meta(lua_State *L, CTState *cts, CType *ct, MMS mm)
|
||||
{
|
||||
CTypeID id = ctype_typeid(cts, ct);
|
||||
cTValue *tv = lj_ctype_meta(cts, id, mm);
|
||||
TValue *base = L->base;
|
||||
if (!tv) {
|
||||
const char *s;
|
||||
err_index:
|
||||
s = strdata(lj_ctype_repr(L, id, NULL));
|
||||
if (tvisstr(L->base+1)) {
|
||||
lj_err_callerv(L, LJ_ERR_FFI_BADMEMBER, s, strVdata(L->base+1));
|
||||
} else {
|
||||
const char *key = tviscdata(L->base+1) ?
|
||||
strdata(lj_ctype_repr(L, cdataV(L->base+1)->ctypeid, NULL)) :
|
||||
lj_typename(L->base+1);
|
||||
lj_err_callerv(L, LJ_ERR_FFI_BADIDXW, s, key);
|
||||
}
|
||||
}
|
||||
if (!tvisfunc(tv)) {
|
||||
if (mm == MM_index) {
|
||||
cTValue *o = lj_meta_tget(L, tv, base+1);
|
||||
if (o) {
|
||||
if (tvisnil(o)) goto err_index;
|
||||
copyTV(L, L->top-1, o);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
TValue *o = lj_meta_tset(L, tv, base+1);
|
||||
if (o) {
|
||||
copyTV(L, o, base+2);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
copyTV(L, base, L->top);
|
||||
tv = L->top-1-LJ_FR2;
|
||||
}
|
||||
return lj_meta_tailcall(L, tv);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTInfo qual = 0;
|
||||
CType *ct;
|
||||
uint8_t *p;
|
||||
TValue *o = L->base;
|
||||
if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */
|
||||
lj_err_argt(L, 1, LUA_TCDATA);
|
||||
ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
|
||||
if ((qual & 1))
|
||||
return ffi_index_meta(L, cts, ct, MM_index);
|
||||
if (lj_cdata_get(cts, ct, L->top-1, p))
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___newindex) LJLIB_REC(cdata_index 1)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTInfo qual = 0;
|
||||
CType *ct;
|
||||
uint8_t *p;
|
||||
TValue *o = L->base;
|
||||
if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */
|
||||
lj_err_argt(L, 1, LUA_TCDATA);
|
||||
ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
|
||||
if ((qual & 1)) {
|
||||
if ((qual & CTF_CONST))
|
||||
lj_err_caller(L, LJ_ERR_FFI_WRCONST);
|
||||
return ffi_index_meta(L, cts, ct, MM_newindex);
|
||||
}
|
||||
lj_cdata_set(cts, ct, p, o+2, qual);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Common handler for cdata arithmetic. */
|
||||
static int ffi_arith(lua_State *L)
|
||||
{
|
||||
MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___eq + (int)MM_eq);
|
||||
return lj_carith_op(L, mm);
|
||||
}
|
||||
|
||||
/* The following functions must be in contiguous ORDER MM. */
|
||||
LJLIB_CF(ffi_meta___eq) LJLIB_REC(cdata_arith MM_eq)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___len) LJLIB_REC(cdata_arith MM_len)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___lt) LJLIB_REC(cdata_arith MM_lt)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___le) LJLIB_REC(cdata_arith MM_le)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___concat) LJLIB_REC(cdata_arith MM_concat)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
/* Forward declaration. */
|
||||
static int lj_cf_ffi_new(lua_State *L);
|
||||
|
||||
LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
GCcdata *cd = ffi_checkcdata(L, 1);
|
||||
CTypeID id = cd->ctypeid;
|
||||
CType *ct;
|
||||
cTValue *tv;
|
||||
MMS mm = MM_call;
|
||||
if (cd->ctypeid == CTID_CTYPEID) {
|
||||
id = *(CTypeID *)cdataptr(cd);
|
||||
mm = MM_new;
|
||||
} else {
|
||||
int ret = lj_ccall_func(L, cd);
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
}
|
||||
/* Handle ctype __call/__new metamethod. */
|
||||
ct = ctype_raw(cts, id);
|
||||
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
|
||||
tv = lj_ctype_meta(cts, id, mm);
|
||||
if (tv)
|
||||
return lj_meta_tailcall(L, tv);
|
||||
else if (mm == MM_call)
|
||||
lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL)));
|
||||
return lj_cf_ffi_new(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___add) LJLIB_REC(cdata_arith MM_add)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___sub) LJLIB_REC(cdata_arith MM_sub)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___mul) LJLIB_REC(cdata_arith MM_mul)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___div) LJLIB_REC(cdata_arith MM_div)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___mod) LJLIB_REC(cdata_arith MM_mod)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___pow) LJLIB_REC(cdata_arith MM_pow)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___unm) LJLIB_REC(cdata_arith MM_unm)
|
||||
{
|
||||
return ffi_arith(L);
|
||||
}
|
||||
/* End of contiguous ORDER MM. */
|
||||
|
||||
LJLIB_CF(ffi_meta___tostring)
|
||||
{
|
||||
GCcdata *cd = ffi_checkcdata(L, 1);
|
||||
const char *msg = "cdata<%s>: %p";
|
||||
CTypeID id = cd->ctypeid;
|
||||
void *p = cdataptr(cd);
|
||||
if (id == CTID_CTYPEID) {
|
||||
msg = "ctype<%s>";
|
||||
id = *(CTypeID *)p;
|
||||
} else {
|
||||
CTState *cts = ctype_cts(L);
|
||||
CType *ct = ctype_raw(cts, id);
|
||||
if (ctype_isref(ct->info)) {
|
||||
p = *(void **)p;
|
||||
ct = ctype_rawchild(cts, ct);
|
||||
}
|
||||
if (ctype_iscomplex(ct->info)) {
|
||||
setstrV(L, L->top-1, lj_ctype_repr_complex(L, cdataptr(cd), ct->size));
|
||||
goto checkgc;
|
||||
} else if (ct->size == 8 && ctype_isinteger(ct->info)) {
|
||||
setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd),
|
||||
(ct->info & CTF_UNSIGNED)));
|
||||
goto checkgc;
|
||||
} else if (ctype_isfunc(ct->info)) {
|
||||
p = *(void **)p;
|
||||
} else if (ctype_isenum(ct->info)) {
|
||||
msg = "cdata<%s>: %d";
|
||||
p = (void *)(uintptr_t)*(uint32_t **)p;
|
||||
} else {
|
||||
if (ctype_isptr(ct->info)) {
|
||||
p = cdata_getptr(p, ct->size);
|
||||
ct = ctype_rawchild(cts, ct);
|
||||
}
|
||||
if (ctype_isstruct(ct->info) || ctype_isvector(ct->info)) {
|
||||
/* Handle ctype __tostring metamethod. */
|
||||
cTValue *tv = lj_ctype_meta(cts, ctype_typeid(cts, ct), MM_tostring);
|
||||
if (tv)
|
||||
return lj_meta_tailcall(L, tv);
|
||||
}
|
||||
}
|
||||
}
|
||||
lj_strfmt_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), p);
|
||||
checkgc:
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ffi_pairs(lua_State *L, MMS mm)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTypeID id = ffi_checkcdata(L, 1)->ctypeid;
|
||||
CType *ct = ctype_raw(cts, id);
|
||||
cTValue *tv;
|
||||
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
|
||||
tv = lj_ctype_meta(cts, id, mm);
|
||||
if (!tv)
|
||||
lj_err_callerv(L, LJ_ERR_FFI_BADMM, strdata(lj_ctype_repr(L, id, NULL)),
|
||||
strdata(mmname_str(G(L), mm)));
|
||||
return lj_meta_tailcall(L, tv);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___pairs)
|
||||
{
|
||||
return ffi_pairs(L, MM_pairs);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_meta___ipairs)
|
||||
{
|
||||
return ffi_pairs(L, MM_ipairs);
|
||||
}
|
||||
|
||||
LJLIB_PUSH("ffi") LJLIB_SET(__metatable)
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
/* -- C library metamethods ----------------------------------------------- */
|
||||
|
||||
#define LJLIB_MODULE_ffi_clib
|
||||
|
||||
/* Index C library by a name. */
|
||||
static TValue *ffi_clib_index(lua_State *L)
|
||||
{
|
||||
TValue *o = L->base;
|
||||
CLibrary *cl;
|
||||
if (!(o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB))
|
||||
lj_err_argt(L, 1, LUA_TUSERDATA);
|
||||
cl = (CLibrary *)uddata(udataV(o));
|
||||
if (!(o+1 < L->top && tvisstr(o+1)))
|
||||
lj_err_argt(L, 2, LUA_TSTRING);
|
||||
return lj_clib_index(L, cl, strV(o+1));
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_clib___index) LJLIB_REC(clib_index 1)
|
||||
{
|
||||
TValue *tv = ffi_clib_index(L);
|
||||
if (tviscdata(tv)) {
|
||||
CTState *cts = ctype_cts(L);
|
||||
GCcdata *cd = cdataV(tv);
|
||||
CType *s = ctype_get(cts, cd->ctypeid);
|
||||
if (ctype_isextern(s->info)) {
|
||||
CTypeID sid = ctype_cid(s->info);
|
||||
void *sp = *(void **)cdataptr(cd);
|
||||
CType *ct = ctype_raw(cts, sid);
|
||||
if (lj_cconv_tv_ct(cts, ct, sid, L->top-1, sp))
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
copyTV(L, L->top-1, tv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_clib___newindex) LJLIB_REC(clib_index 0)
|
||||
{
|
||||
TValue *tv = ffi_clib_index(L);
|
||||
TValue *o = L->base+2;
|
||||
if (o < L->top && tviscdata(tv)) {
|
||||
CTState *cts = ctype_cts(L);
|
||||
GCcdata *cd = cdataV(tv);
|
||||
CType *d = ctype_get(cts, cd->ctypeid);
|
||||
if (ctype_isextern(d->info)) {
|
||||
CTInfo qual = 0;
|
||||
for (;;) { /* Skip attributes and collect qualifiers. */
|
||||
d = ctype_child(cts, d);
|
||||
if (!ctype_isattrib(d->info)) break;
|
||||
if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
|
||||
}
|
||||
if (!((d->info|qual) & CTF_CONST)) {
|
||||
lj_cconv_ct_tv(cts, d, *(void **)cdataptr(cd), o, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
lj_err_caller(L, LJ_ERR_FFI_WRCONST);
|
||||
return 0; /* unreachable */
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_clib___gc)
|
||||
{
|
||||
TValue *o = L->base;
|
||||
if (o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB)
|
||||
lj_clib_unload((CLibrary *)uddata(udataV(o)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
/* -- Callback function metamethods --------------------------------------- */
|
||||
|
||||
#define LJLIB_MODULE_ffi_callback
|
||||
|
||||
static int ffi_callback_set(lua_State *L, GCfunc *fn)
|
||||
{
|
||||
GCcdata *cd = ffi_checkcdata(L, 1);
|
||||
CTState *cts = ctype_cts(L);
|
||||
CType *ct = ctype_raw(cts, cd->ctypeid);
|
||||
if (ctype_isptr(ct->info) && (LJ_32 || ct->size == 8)) {
|
||||
MSize slot = lj_ccallback_ptr2slot(cts, *(void **)cdataptr(cd));
|
||||
if (slot < cts->cb.sizeid && cts->cb.cbid[slot] != 0) {
|
||||
GCtab *t = cts->miscmap;
|
||||
TValue *tv = lj_tab_setint(L, t, (int32_t)slot);
|
||||
if (fn) {
|
||||
setfuncV(L, tv, fn);
|
||||
lj_gc_anybarriert(L, t);
|
||||
} else {
|
||||
setnilV(tv);
|
||||
cts->cb.cbid[slot] = 0;
|
||||
cts->cb.topid = slot < cts->cb.topid ? slot : cts->cb.topid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
lj_err_caller(L, LJ_ERR_FFI_BADCBACK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_callback_free)
|
||||
{
|
||||
return ffi_callback_set(L, NULL);
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_callback_set)
|
||||
{
|
||||
GCfunc *fn = lj_lib_checkfunc(L, 2);
|
||||
return ffi_callback_set(L, fn);
|
||||
}
|
||||
|
||||
LJLIB_PUSH(top-1) LJLIB_SET(__index)
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
/* -- FFI library functions ----------------------------------------------- */
|
||||
|
||||
#define LJLIB_MODULE_ffi
|
||||
|
||||
LJLIB_CF(ffi_cdef)
|
||||
{
|
||||
GCstr *s = lj_lib_checkstr(L, 1);
|
||||
CPState cp;
|
||||
int errcode;
|
||||
cp.L = L;
|
||||
cp.cts = ctype_cts(L);
|
||||
cp.srcname = strdata(s);
|
||||
cp.p = strdata(s);
|
||||
cp.param = L->base+1;
|
||||
cp.mode = CPARSE_MODE_MULTI|CPARSE_MODE_DIRECT;
|
||||
errcode = lj_cparse(&cp);
|
||||
if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */
|
||||
lj_gc_check(L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_new) LJLIB_REC(.)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTypeID id = ffi_checkctype(L, cts, NULL);
|
||||
CType *ct = ctype_raw(cts, id);
|
||||
CTSize sz;
|
||||
CTInfo info = lj_ctype_info(cts, id, &sz);
|
||||
TValue *o = L->base+1;
|
||||
GCcdata *cd;
|
||||
if ((info & CTF_VLA)) {
|
||||
o++;
|
||||
sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
|
||||
}
|
||||
if (sz == CTSIZE_INVALID)
|
||||
lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE);
|
||||
cd = lj_cdata_newx(cts, id, sz, info);
|
||||
setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */
|
||||
lj_cconv_ct_init(cts, ct, sz, cdataptr(cd),
|
||||
o, (MSize)(L->top - o)); /* Initialize cdata. */
|
||||
if (ctype_isstruct(ct->info)) {
|
||||
/* Handle ctype __gc metamethod. Use the fast lookup here. */
|
||||
cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)id);
|
||||
if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) {
|
||||
GCtab *t = tabref(G(L)->gcroot[GCROOT_FFI_FIN]);
|
||||
if (gcref(t->metatable)) {
|
||||
/* Add to finalizer table, if still enabled. */
|
||||
copyTV(L, lj_tab_set(L, t, o-1), tv);
|
||||
lj_gc_anybarriert(L, t);
|
||||
cd->marked |= LJ_GC_CDATA_FIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
L->top = o; /* Only return the cdata itself. */
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_cast) LJLIB_REC(ffi_new)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTypeID id = ffi_checkctype(L, cts, NULL);
|
||||
CType *d = ctype_raw(cts, id);
|
||||
TValue *o = lj_lib_checkany(L, 2);
|
||||
L->top = o+1; /* Make sure this is the last item on the stack. */
|
||||
if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || ctype_isenum(d->info)))
|
||||
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
|
||||
if (!(tviscdata(o) && cdataV(o)->ctypeid == id)) {
|
||||
GCcdata *cd = lj_cdata_new(cts, id, d->size);
|
||||
lj_cconv_ct_tv(cts, d, cdataptr(cd), o, CCF_CAST);
|
||||
setcdataV(L, o, cd);
|
||||
lj_gc_check(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_typeof) LJLIB_REC(.)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTypeID id = ffi_checkctype(L, cts, L->base+1);
|
||||
GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
|
||||
*(CTypeID *)cdataptr(cd) = id;
|
||||
setcdataV(L, L->top-1, cd);
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Internal and unsupported API. */
|
||||
LJLIB_CF(ffi_typeinfo)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTypeID id = (CTypeID)ffi_checkint(L, 1);
|
||||
if (id > 0 && id < cts->top) {
|
||||
CType *ct = ctype_get(cts, id);
|
||||
GCtab *t;
|
||||
lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */
|
||||
t = tabV(L->top-1);
|
||||
setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "info")), (int32_t)ct->info);
|
||||
if (ct->size != CTSIZE_INVALID)
|
||||
setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "size")), (int32_t)ct->size);
|
||||
if (ct->sib)
|
||||
setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "sib")), (int32_t)ct->sib);
|
||||
if (gcref(ct->name)) {
|
||||
GCstr *s = gco2str(gcref(ct->name));
|
||||
if (isdead(G(L), obj2gco(s))) flipwhite(obj2gco(s));
|
||||
setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "name")), s);
|
||||
}
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_istype) LJLIB_REC(.)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTypeID id1 = ffi_checkctype(L, cts, NULL);
|
||||
TValue *o = lj_lib_checkany(L, 2);
|
||||
int b = 0;
|
||||
if (tviscdata(o)) {
|
||||
GCcdata *cd = cdataV(o);
|
||||
CTypeID id2 = cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) :
|
||||
cd->ctypeid;
|
||||
CType *ct1 = lj_ctype_rawref(cts, id1);
|
||||
CType *ct2 = lj_ctype_rawref(cts, id2);
|
||||
if (ct1 == ct2) {
|
||||
b = 1;
|
||||
} else if (ctype_type(ct1->info) == ctype_type(ct2->info) &&
|
||||
ct1->size == ct2->size) {
|
||||
if (ctype_ispointer(ct1->info))
|
||||
b = lj_cconv_compatptr(cts, ct1, ct2, CCF_IGNQUAL);
|
||||
else if (ctype_isnum(ct1->info) || ctype_isvoid(ct1->info))
|
||||
b = (((ct1->info ^ ct2->info) & ~(CTF_QUAL|CTF_LONG)) == 0);
|
||||
} else if (ctype_isstruct(ct1->info) && ctype_isptr(ct2->info) &&
|
||||
ct1 == ctype_rawchild(cts, ct2)) {
|
||||
b = 1;
|
||||
}
|
||||
}
|
||||
setboolV(L->top-1, b);
|
||||
setboolV(&G(L)->tmptv2, b); /* Remember for trace recorder. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_sizeof) LJLIB_REC(ffi_xof FF_ffi_sizeof)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTypeID id = ffi_checkctype(L, cts, NULL);
|
||||
CTSize sz;
|
||||
if (LJ_UNLIKELY(tviscdata(L->base) && cdataisv(cdataV(L->base)))) {
|
||||
sz = cdatavlen(cdataV(L->base));
|
||||
} else {
|
||||
CType *ct = lj_ctype_rawref(cts, id);
|
||||
if (ctype_isvltype(ct->info))
|
||||
sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
|
||||
else
|
||||
sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_INVALID;
|
||||
if (LJ_UNLIKELY(sz == CTSIZE_INVALID)) {
|
||||
setnilV(L->top-1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
setintV(L->top-1, (int32_t)sz);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_alignof) LJLIB_REC(ffi_xof FF_ffi_alignof)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTypeID id = ffi_checkctype(L, cts, NULL);
|
||||
CTSize sz = 0;
|
||||
CTInfo info = lj_ctype_info_raw(cts, id, &sz);
|
||||
setintV(L->top-1, 1 << ctype_align(info));
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_offsetof) LJLIB_REC(ffi_xof FF_ffi_offsetof)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTypeID id = ffi_checkctype(L, cts, NULL);
|
||||
GCstr *name = lj_lib_checkstr(L, 2);
|
||||
CType *ct = lj_ctype_rawref(cts, id);
|
||||
CTSize ofs;
|
||||
if (ctype_isstruct(ct->info) && ct->size != CTSIZE_INVALID) {
|
||||
CType *fct = lj_ctype_getfield(cts, ct, name, &ofs);
|
||||
if (fct) {
|
||||
setintV(L->top-1, ofs);
|
||||
if (ctype_isfield(fct->info)) {
|
||||
return 1;
|
||||
} else if (ctype_isbitfield(fct->info)) {
|
||||
setintV(L->top++, ctype_bitpos(fct->info));
|
||||
setintV(L->top++, ctype_bitbsz(fct->info));
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_errno) LJLIB_REC(.)
|
||||
{
|
||||
int err = errno;
|
||||
if (L->top > L->base)
|
||||
errno = ffi_checkint(L, 1);
|
||||
setintV(L->top++, err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_string) LJLIB_REC(.)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
TValue *o = lj_lib_checkany(L, 1);
|
||||
const char *p;
|
||||
size_t len;
|
||||
if (o+1 < L->top && !tvisnil(o+1)) {
|
||||
len = (size_t)ffi_checkint(L, 2);
|
||||
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p, o,
|
||||
CCF_ARG(1));
|
||||
} else {
|
||||
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CCHAR), (uint8_t *)&p, o,
|
||||
CCF_ARG(1));
|
||||
len = strlen(p);
|
||||
}
|
||||
L->top = o+1; /* Make sure this is the last item on the stack. */
|
||||
setstrV(L, o, lj_str_new(L, p, len));
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_copy) LJLIB_REC(.)
|
||||
{
|
||||
void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
|
||||
void *sp = ffi_checkptr(L, 2, CTID_P_CVOID);
|
||||
TValue *o = L->base+1;
|
||||
CTSize len;
|
||||
if (tvisstr(o) && o+1 >= L->top)
|
||||
len = strV(o)->len+1; /* Copy Lua string including trailing '\0'. */
|
||||
else
|
||||
len = (CTSize)ffi_checkint(L, 3);
|
||||
memcpy(dp, sp, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_fill) LJLIB_REC(.)
|
||||
{
|
||||
void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
|
||||
CTSize len = (CTSize)ffi_checkint(L, 2);
|
||||
int32_t fill = 0;
|
||||
if (L->base+2 < L->top && !tvisnil(L->base+2)) fill = ffi_checkint(L, 3);
|
||||
memset(dp, fill, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test ABI string. */
|
||||
LJLIB_CF(ffi_abi) LJLIB_REC(.)
|
||||
{
|
||||
GCstr *s = lj_lib_checkstr(L, 1);
|
||||
int b = lj_cparse_case(s,
|
||||
#if LJ_64
|
||||
"\00564bit"
|
||||
#else
|
||||
"\00532bit"
|
||||
#endif
|
||||
#if LJ_ARCH_HASFPU
|
||||
"\003fpu"
|
||||
#endif
|
||||
#if LJ_ABI_SOFTFP
|
||||
"\006softfp"
|
||||
#else
|
||||
"\006hardfp"
|
||||
#endif
|
||||
#if LJ_ABI_EABI
|
||||
"\004eabi"
|
||||
#endif
|
||||
#if LJ_ABI_WIN
|
||||
"\003win"
|
||||
#endif
|
||||
#if LJ_ABI_PAUTH
|
||||
"\005pauth"
|
||||
#endif
|
||||
#if LJ_TARGET_UWP
|
||||
"\003uwp"
|
||||
#endif
|
||||
#if LJ_LE
|
||||
"\002le"
|
||||
#else
|
||||
"\002be"
|
||||
#endif
|
||||
#if LJ_GC64
|
||||
"\004gc64"
|
||||
#endif
|
||||
) >= 0;
|
||||
setboolV(L->top-1, b);
|
||||
setboolV(&G(L)->tmptv2, b); /* Remember for trace recorder. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to miscmap table. */
|
||||
|
||||
LJLIB_CF(ffi_metatype)
|
||||
{
|
||||
CTState *cts = ctype_cts(L);
|
||||
CTypeID id = ffi_checkctype(L, cts, NULL);
|
||||
GCtab *mt = lj_lib_checktab(L, 2);
|
||||
GCtab *t = cts->miscmap;
|
||||
CType *ct = ctype_raw(cts, id);
|
||||
TValue *tv;
|
||||
GCcdata *cd;
|
||||
if (!(ctype_isstruct(ct->info) || ctype_iscomplex(ct->info) ||
|
||||
ctype_isvector(ct->info)))
|
||||
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
|
||||
tv = lj_tab_setinth(L, t, -(int32_t)ctype_typeid(cts, ct));
|
||||
if (!tvisnil(tv))
|
||||
lj_err_caller(L, LJ_ERR_PROTMT);
|
||||
settabV(L, tv, mt);
|
||||
lj_gc_anybarriert(L, t);
|
||||
cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
|
||||
*(CTypeID *)cdataptr(cd) = id;
|
||||
setcdataV(L, L->top-1, cd);
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(ffi_gc) LJLIB_REC(.)
|
||||
{
|
||||
GCcdata *cd = ffi_checkcdata(L, 1);
|
||||
TValue *fin = lj_lib_checkany(L, 2);
|
||||
CTState *cts = ctype_cts(L);
|
||||
CType *ct = ctype_raw(cts, cd->ctypeid);
|
||||
if (!(ctype_isptr(ct->info) || ctype_isstruct(ct->info) ||
|
||||
ctype_isrefarray(ct->info)))
|
||||
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
|
||||
lj_cdata_setfin(L, cd, gcval(fin), itype(fin));
|
||||
L->top = L->base+1; /* Pass through the cdata object. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_PUSH(top-5) LJLIB_SET(!) /* Store clib metatable in func environment. */
|
||||
|
||||
LJLIB_CF(ffi_load)
|
||||
{
|
||||
GCstr *name = lj_lib_checkstr(L, 1);
|
||||
int global = (L->base+1 < L->top && tvistruecond(L->base+1));
|
||||
lj_clib_load(L, tabref(curr_func(L)->c.env), name, global);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_PUSH(top-4) LJLIB_SET(C)
|
||||
LJLIB_PUSH(top-3) LJLIB_SET(os)
|
||||
LJLIB_PUSH(top-2) LJLIB_SET(arch)
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Register FFI module as loaded. */
|
||||
static void ffi_register_module(lua_State *L)
|
||||
{
|
||||
cTValue *tmp = lj_tab_getstr(tabV(registry(L)), lj_str_newlit(L, "_LOADED"));
|
||||
if (tmp && tvistab(tmp)) {
|
||||
GCtab *t = tabV(tmp);
|
||||
copyTV(L, lj_tab_setstr(L, t, lj_str_newlit(L, LUA_FFILIBNAME)), L->top-1);
|
||||
lj_gc_anybarriert(L, t);
|
||||
}
|
||||
}
|
||||
|
||||
LUALIB_API int luaopen_ffi(lua_State *L)
|
||||
{
|
||||
CTState *cts = lj_ctype_init(L);
|
||||
settabV(L, L->top++, (cts->miscmap = lj_tab_new(L, 0, 1)));
|
||||
LJ_LIB_REG(L, NULL, ffi_meta);
|
||||
/* NOBARRIER: basemt is a GC root. */
|
||||
setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
|
||||
LJ_LIB_REG(L, NULL, ffi_clib);
|
||||
LJ_LIB_REG(L, NULL, ffi_callback);
|
||||
/* NOBARRIER: the key is new and lj_tab_newkey() handles the barrier. */
|
||||
settabV(L, lj_tab_setstr(L, cts->miscmap, &cts->g->strempty), tabV(L->top-1));
|
||||
L->top--;
|
||||
lj_clib_default(L, tabV(L->top-1)); /* Create ffi.C default namespace. */
|
||||
lua_pushliteral(L, LJ_OS_NAME);
|
||||
lua_pushliteral(L, LJ_ARCH_NAME);
|
||||
LJ_LIB_REG(L, NULL, ffi); /* Note: no global "ffi" created! */
|
||||
ffi_register_module(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
55
thirdPart/luajit/src/lib_init.c
Normal file
55
thirdPart/luajit/src/lib_init.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
** Library initialization.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** Major parts taken verbatim from the Lua interpreter.
|
||||
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lib_init_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_arch.h"
|
||||
|
||||
static const luaL_Reg lj_lib_load[] = {
|
||||
{ "", luaopen_base },
|
||||
{ LUA_LOADLIBNAME, luaopen_package },
|
||||
{ LUA_TABLIBNAME, luaopen_table },
|
||||
{ LUA_IOLIBNAME, luaopen_io },
|
||||
{ LUA_OSLIBNAME, luaopen_os },
|
||||
{ LUA_STRLIBNAME, luaopen_string },
|
||||
{ LUA_MATHLIBNAME, luaopen_math },
|
||||
{ LUA_DBLIBNAME, luaopen_debug },
|
||||
{ LUA_BITLIBNAME, luaopen_bit },
|
||||
{ LUA_JITLIBNAME, luaopen_jit },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_Reg lj_lib_preload[] = {
|
||||
#if LJ_HASFFI
|
||||
{ LUA_FFILIBNAME, luaopen_ffi },
|
||||
#endif
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
LUALIB_API void luaL_openlibs(lua_State *L)
|
||||
{
|
||||
const luaL_Reg *lib;
|
||||
for (lib = lj_lib_load; lib->func; lib++) {
|
||||
lua_pushcfunction(L, lib->func);
|
||||
lua_pushstring(L, lib->name);
|
||||
lua_call(L, 1, 0);
|
||||
}
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD",
|
||||
sizeof(lj_lib_preload)/sizeof(lj_lib_preload[0])-1);
|
||||
for (lib = lj_lib_preload; lib->func; lib++) {
|
||||
lua_pushcfunction(L, lib->func);
|
||||
lua_setfield(L, -2, lib->name);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
551
thirdPart/luajit/src/lib_io.c
Normal file
551
thirdPart/luajit/src/lib_io.c
Normal file
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
** I/O library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** Major portions taken verbatim or adapted from the Lua interpreter.
|
||||
** Copyright (C) 1994-2011 Lua.org, PUC-Rio. See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define lib_io_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_gc.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_buf.h"
|
||||
#include "lj_str.h"
|
||||
#include "lj_state.h"
|
||||
#include "lj_strfmt.h"
|
||||
#include "lj_ff.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
/* Userdata payload for I/O file. */
|
||||
typedef struct IOFileUD {
|
||||
FILE *fp; /* File handle. */
|
||||
uint32_t type; /* File type. */
|
||||
} IOFileUD;
|
||||
|
||||
#define IOFILE_TYPE_FILE 0 /* Regular file. */
|
||||
#define IOFILE_TYPE_PIPE 1 /* Pipe. */
|
||||
#define IOFILE_TYPE_STDF 2 /* Standard file handle. */
|
||||
#define IOFILE_TYPE_MASK 3
|
||||
|
||||
#define IOFILE_FLAG_CLOSE 4 /* Close after io.lines() iterator. */
|
||||
|
||||
#define IOSTDF_UD(L, id) (&gcref(G(L)->gcroot[(id)])->ud)
|
||||
#define IOSTDF_IOF(L, id) ((IOFileUD *)uddata(IOSTDF_UD(L, (id))))
|
||||
|
||||
/* -- Open/close helpers -------------------------------------------------- */
|
||||
|
||||
static IOFileUD *io_tofilep(lua_State *L)
|
||||
{
|
||||
if (!(L->base < L->top && tvisudata(L->base) &&
|
||||
udataV(L->base)->udtype == UDTYPE_IO_FILE))
|
||||
lj_err_argtype(L, 1, "FILE*");
|
||||
return (IOFileUD *)uddata(udataV(L->base));
|
||||
}
|
||||
|
||||
static IOFileUD *io_tofile(lua_State *L)
|
||||
{
|
||||
IOFileUD *iof = io_tofilep(L);
|
||||
if (iof->fp == NULL)
|
||||
lj_err_caller(L, LJ_ERR_IOCLFL);
|
||||
return iof;
|
||||
}
|
||||
|
||||
static IOFileUD *io_stdfile(lua_State *L, ptrdiff_t id)
|
||||
{
|
||||
IOFileUD *iof = IOSTDF_IOF(L, id);
|
||||
if (iof->fp == NULL)
|
||||
lj_err_caller(L, LJ_ERR_IOSTDCL);
|
||||
return iof;
|
||||
}
|
||||
|
||||
static IOFileUD *io_file_new(lua_State *L)
|
||||
{
|
||||
IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD));
|
||||
GCudata *ud = udataV(L->top-1);
|
||||
ud->udtype = UDTYPE_IO_FILE;
|
||||
/* NOBARRIER: The GCudata is new (marked white). */
|
||||
setgcrefr(ud->metatable, curr_func(L)->c.env);
|
||||
iof->fp = NULL;
|
||||
iof->type = IOFILE_TYPE_FILE;
|
||||
return iof;
|
||||
}
|
||||
|
||||
static IOFileUD *io_file_open(lua_State *L, const char *mode)
|
||||
{
|
||||
const char *fname = strdata(lj_lib_checkstr(L, 1));
|
||||
IOFileUD *iof = io_file_new(L);
|
||||
iof->fp = fopen(fname, mode);
|
||||
if (iof->fp == NULL)
|
||||
luaL_argerror(L, 1, lj_strfmt_pushf(L, "%s: %s", fname, strerror(errno)));
|
||||
return iof;
|
||||
}
|
||||
|
||||
static int io_file_close(lua_State *L, IOFileUD *iof)
|
||||
{
|
||||
int ok;
|
||||
if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_FILE) {
|
||||
ok = (fclose(iof->fp) == 0);
|
||||
} else if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_PIPE) {
|
||||
int stat = -1;
|
||||
#if LJ_TARGET_POSIX
|
||||
stat = pclose(iof->fp);
|
||||
#elif LJ_TARGET_WINDOWS && !LJ_TARGET_XBOXONE && !LJ_TARGET_UWP
|
||||
stat = _pclose(iof->fp);
|
||||
#endif
|
||||
#if LJ_52
|
||||
iof->fp = NULL;
|
||||
return luaL_execresult(L, stat);
|
||||
#else
|
||||
ok = (stat != -1);
|
||||
#endif
|
||||
} else {
|
||||
lj_assertL((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_STDF,
|
||||
"close of unknown FILE* type");
|
||||
setnilV(L->top++);
|
||||
lua_pushliteral(L, "cannot close standard file");
|
||||
return 2;
|
||||
}
|
||||
iof->fp = NULL;
|
||||
return luaL_fileresult(L, ok, NULL);
|
||||
}
|
||||
|
||||
/* -- Read/write helpers -------------------------------------------------- */
|
||||
|
||||
static int io_file_readnum(lua_State *L, FILE *fp)
|
||||
{
|
||||
lua_Number d;
|
||||
if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) {
|
||||
if (LJ_DUALNUM) {
|
||||
int32_t i = lj_num2int(d);
|
||||
if (d == (lua_Number)i && !tvismzero((cTValue *)&d)) {
|
||||
setintV(L->top++, i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
setnumV(L->top++, d);
|
||||
return 1;
|
||||
} else {
|
||||
setnilV(L->top++);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int io_file_readline(lua_State *L, FILE *fp, MSize chop)
|
||||
{
|
||||
MSize m = LUAL_BUFFERSIZE, n = 0, ok = 0;
|
||||
char *buf;
|
||||
for (;;) {
|
||||
buf = lj_buf_tmp(L, m);
|
||||
if (fgets(buf+n, m-n, fp) == NULL) break;
|
||||
n += (MSize)strlen(buf+n);
|
||||
ok |= n;
|
||||
if (n && buf[n-1] == '\n') { n -= chop; break; }
|
||||
if (n >= m - 64) m += m;
|
||||
}
|
||||
setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n));
|
||||
lj_gc_check(L);
|
||||
return (int)ok;
|
||||
}
|
||||
|
||||
static void io_file_readall(lua_State *L, FILE *fp)
|
||||
{
|
||||
MSize m, n;
|
||||
for (m = LUAL_BUFFERSIZE, n = 0; ; m += m) {
|
||||
char *buf = lj_buf_tmp(L, m);
|
||||
n += (MSize)fread(buf+n, 1, m-n, fp);
|
||||
if (n != m) {
|
||||
setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n));
|
||||
lj_gc_check(L);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int io_file_readlen(lua_State *L, FILE *fp, MSize m)
|
||||
{
|
||||
if (m) {
|
||||
char *buf = lj_buf_tmp(L, m);
|
||||
MSize n = (MSize)fread(buf, 1, m, fp);
|
||||
setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n));
|
||||
lj_gc_check(L);
|
||||
return n > 0;
|
||||
} else {
|
||||
int c = getc(fp);
|
||||
ungetc(c, fp);
|
||||
setstrV(L, L->top++, &G(L)->strempty);
|
||||
return (c != EOF);
|
||||
}
|
||||
}
|
||||
|
||||
static int io_file_read(lua_State *L, IOFileUD *iof, int start)
|
||||
{
|
||||
FILE *fp = iof->fp;
|
||||
int ok, n, nargs = (int)(L->top - L->base) - start;
|
||||
clearerr(fp);
|
||||
if (nargs == 0) {
|
||||
ok = io_file_readline(L, fp, 1);
|
||||
n = start+1; /* Return 1 result. */
|
||||
} else {
|
||||
/* The results plus the buffers go on top of the args. */
|
||||
luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
|
||||
ok = 1;
|
||||
for (n = start; nargs-- && ok; n++) {
|
||||
if (tvisstr(L->base+n)) {
|
||||
const char *p = strVdata(L->base+n);
|
||||
if (p[0] == '*') p++;
|
||||
if (p[0] == 'n')
|
||||
ok = io_file_readnum(L, fp);
|
||||
else if ((p[0] & ~0x20) == 'L')
|
||||
ok = io_file_readline(L, fp, (p[0] == 'l'));
|
||||
else if (p[0] == 'a')
|
||||
io_file_readall(L, fp);
|
||||
else
|
||||
lj_err_arg(L, n+1, LJ_ERR_INVFMT);
|
||||
} else if (tvisnumber(L->base+n)) {
|
||||
ok = io_file_readlen(L, fp, (MSize)lj_lib_checkint(L, n+1));
|
||||
} else {
|
||||
lj_err_arg(L, n+1, LJ_ERR_INVOPT);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ferror(fp))
|
||||
return luaL_fileresult(L, 0, NULL);
|
||||
if (!ok)
|
||||
setnilV(L->top-1); /* Replace last result with nil. */
|
||||
return n - start;
|
||||
}
|
||||
|
||||
static int io_file_write(lua_State *L, IOFileUD *iof, int start)
|
||||
{
|
||||
FILE *fp = iof->fp;
|
||||
cTValue *tv;
|
||||
int status = 1;
|
||||
for (tv = L->base+start; tv < L->top; tv++) {
|
||||
MSize len;
|
||||
const char *p = lj_strfmt_wstrnum(L, tv, &len);
|
||||
if (!p)
|
||||
lj_err_argt(L, (int)(tv - L->base) + 1, LUA_TSTRING);
|
||||
status = status && (fwrite(p, 1, len, fp) == len);
|
||||
}
|
||||
if (LJ_52 && status) {
|
||||
L->top = L->base+1;
|
||||
if (start == 0)
|
||||
setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_OUTPUT));
|
||||
return 1;
|
||||
}
|
||||
return luaL_fileresult(L, status, NULL);
|
||||
}
|
||||
|
||||
static int io_file_iter(lua_State *L)
|
||||
{
|
||||
GCfunc *fn = curr_func(L);
|
||||
IOFileUD *iof = uddata(udataV(&fn->c.upvalue[0]));
|
||||
int n = fn->c.nupvalues - 1;
|
||||
if (iof->fp == NULL)
|
||||
lj_err_caller(L, LJ_ERR_IOCLFL);
|
||||
L->top = L->base;
|
||||
if (n) { /* Copy upvalues with options to stack. */
|
||||
lj_state_checkstack(L, (MSize)n);
|
||||
memcpy(L->top, &fn->c.upvalue[1], n*sizeof(TValue));
|
||||
L->top += n;
|
||||
}
|
||||
n = io_file_read(L, iof, 0);
|
||||
if (ferror(iof->fp))
|
||||
lj_err_callermsg(L, strVdata(L->top-2));
|
||||
if (tvisnil(L->base) && (iof->type & IOFILE_FLAG_CLOSE)) {
|
||||
io_file_close(L, iof); /* Return values are ignored. */
|
||||
return 0;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static int io_file_lines(lua_State *L)
|
||||
{
|
||||
int n = (int)(L->top - L->base);
|
||||
if (n > LJ_MAX_UPVAL)
|
||||
lj_err_caller(L, LJ_ERR_UNPACK);
|
||||
lua_pushcclosure(L, io_file_iter, n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* -- I/O file methods ---------------------------------------------------- */
|
||||
|
||||
#define LJLIB_MODULE_io_method
|
||||
|
||||
LJLIB_CF(io_method_close)
|
||||
{
|
||||
IOFileUD *iof;
|
||||
if (L->base < L->top) {
|
||||
iof = io_tofile(L);
|
||||
} else {
|
||||
iof = IOSTDF_IOF(L, GCROOT_IO_OUTPUT);
|
||||
if (iof->fp == NULL)
|
||||
lj_err_caller(L, LJ_ERR_IOCLFL);
|
||||
}
|
||||
return io_file_close(L, iof);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_method_read)
|
||||
{
|
||||
return io_file_read(L, io_tofile(L), 1);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_method_write) LJLIB_REC(io_write 0)
|
||||
{
|
||||
return io_file_write(L, io_tofile(L), 1);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_method_flush) LJLIB_REC(io_flush 0)
|
||||
{
|
||||
return luaL_fileresult(L, fflush(io_tofile(L)->fp) == 0, NULL);
|
||||
}
|
||||
|
||||
#if LJ_32 && defined(__ANDROID__) && __ANDROID_API__ < 24
|
||||
/* The Android NDK is such an unmatched marvel of engineering. */
|
||||
extern int fseeko32(FILE *, long int, int) __asm__("fseeko");
|
||||
extern long int ftello32(FILE *) __asm__("ftello");
|
||||
#define fseeko(fp, pos, whence) (fseeko32((fp), (pos), (whence)))
|
||||
#define ftello(fp) (ftello32((fp)))
|
||||
#endif
|
||||
|
||||
LJLIB_CF(io_method_seek)
|
||||
{
|
||||
FILE *fp = io_tofile(L)->fp;
|
||||
int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end");
|
||||
int64_t ofs = 0;
|
||||
cTValue *o;
|
||||
int res;
|
||||
if (opt == 0) opt = SEEK_SET;
|
||||
else if (opt == 1) opt = SEEK_CUR;
|
||||
else if (opt == 2) opt = SEEK_END;
|
||||
o = L->base+2;
|
||||
if (o < L->top) {
|
||||
if (tvisint(o))
|
||||
ofs = (int64_t)intV(o);
|
||||
else if (tvisnum(o))
|
||||
ofs = (int64_t)numV(o);
|
||||
else if (!tvisnil(o))
|
||||
lj_err_argt(L, 3, LUA_TNUMBER);
|
||||
}
|
||||
#if LJ_TARGET_POSIX
|
||||
res = fseeko(fp, ofs, opt);
|
||||
#elif _MSC_VER >= 1400
|
||||
res = _fseeki64(fp, ofs, opt);
|
||||
#elif defined(__MINGW32__)
|
||||
res = fseeko64(fp, ofs, opt);
|
||||
#else
|
||||
res = fseek(fp, (long)ofs, opt);
|
||||
#endif
|
||||
if (res)
|
||||
return luaL_fileresult(L, 0, NULL);
|
||||
#if LJ_TARGET_POSIX
|
||||
ofs = ftello(fp);
|
||||
#elif _MSC_VER >= 1400
|
||||
ofs = _ftelli64(fp);
|
||||
#elif defined(__MINGW32__)
|
||||
ofs = ftello64(fp);
|
||||
#else
|
||||
ofs = (int64_t)ftell(fp);
|
||||
#endif
|
||||
setint64V(L->top-1, ofs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(io_method_setvbuf)
|
||||
{
|
||||
FILE *fp = io_tofile(L)->fp;
|
||||
int opt = lj_lib_checkopt(L, 2, -1, "\4full\4line\2no");
|
||||
size_t sz = (size_t)lj_lib_optint(L, 3, LUAL_BUFFERSIZE);
|
||||
if (opt == 0) opt = _IOFBF;
|
||||
else if (opt == 1) opt = _IOLBF;
|
||||
else if (opt == 2) opt = _IONBF;
|
||||
return luaL_fileresult(L, setvbuf(fp, NULL, opt, sz) == 0, NULL);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_method_lines)
|
||||
{
|
||||
io_tofile(L);
|
||||
return io_file_lines(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_method___gc)
|
||||
{
|
||||
IOFileUD *iof = io_tofilep(L);
|
||||
if (iof->fp != NULL && (iof->type & IOFILE_TYPE_MASK) != IOFILE_TYPE_STDF)
|
||||
io_file_close(L, iof);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(io_method___tostring)
|
||||
{
|
||||
IOFileUD *iof = io_tofilep(L);
|
||||
if (iof->fp != NULL)
|
||||
lua_pushfstring(L, "file (%p)", iof->fp);
|
||||
else
|
||||
lua_pushliteral(L, "file (closed)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_PUSH(top-1) LJLIB_SET(__index)
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
/* -- I/O library functions ----------------------------------------------- */
|
||||
|
||||
#define LJLIB_MODULE_io
|
||||
|
||||
LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
|
||||
|
||||
LJLIB_CF(io_open)
|
||||
{
|
||||
const char *fname = strdata(lj_lib_checkstr(L, 1));
|
||||
GCstr *s = lj_lib_optstr(L, 2);
|
||||
const char *mode = s ? strdata(s) : "r";
|
||||
IOFileUD *iof = io_file_new(L);
|
||||
iof->fp = fopen(fname, mode);
|
||||
return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_popen)
|
||||
{
|
||||
#if LJ_TARGET_POSIX || (LJ_TARGET_WINDOWS && !LJ_TARGET_XBOXONE && !LJ_TARGET_UWP)
|
||||
const char *fname = strdata(lj_lib_checkstr(L, 1));
|
||||
GCstr *s = lj_lib_optstr(L, 2);
|
||||
const char *mode = s ? strdata(s) : "r";
|
||||
IOFileUD *iof = io_file_new(L);
|
||||
iof->type = IOFILE_TYPE_PIPE;
|
||||
#if LJ_TARGET_POSIX
|
||||
fflush(NULL);
|
||||
iof->fp = popen(fname, mode);
|
||||
#else
|
||||
iof->fp = _popen(fname, mode);
|
||||
#endif
|
||||
return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname);
|
||||
#else
|
||||
return luaL_error(L, LUA_QL("popen") " not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
LJLIB_CF(io_tmpfile)
|
||||
{
|
||||
IOFileUD *iof = io_file_new(L);
|
||||
#if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PS5 || LJ_TARGET_PSVITA || LJ_TARGET_NX
|
||||
iof->fp = NULL; errno = ENOSYS;
|
||||
#else
|
||||
iof->fp = tmpfile();
|
||||
#endif
|
||||
return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, NULL);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_close)
|
||||
{
|
||||
return lj_cf_io_method_close(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_read)
|
||||
{
|
||||
return io_file_read(L, io_stdfile(L, GCROOT_IO_INPUT), 0);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_write) LJLIB_REC(io_write GCROOT_IO_OUTPUT)
|
||||
{
|
||||
return io_file_write(L, io_stdfile(L, GCROOT_IO_OUTPUT), 0);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_flush) LJLIB_REC(io_flush GCROOT_IO_OUTPUT)
|
||||
{
|
||||
return luaL_fileresult(L, fflush(io_stdfile(L, GCROOT_IO_OUTPUT)->fp) == 0, NULL);
|
||||
}
|
||||
|
||||
static int io_std_getset(lua_State *L, ptrdiff_t id, const char *mode)
|
||||
{
|
||||
if (L->base < L->top && !tvisnil(L->base)) {
|
||||
if (tvisudata(L->base)) {
|
||||
io_tofile(L);
|
||||
L->top = L->base+1;
|
||||
} else {
|
||||
io_file_open(L, mode);
|
||||
}
|
||||
/* NOBARRIER: The standard I/O handles are GC roots. */
|
||||
setgcref(G(L)->gcroot[id], gcV(L->top-1));
|
||||
} else {
|
||||
setudataV(L, L->top++, IOSTDF_UD(L, id));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(io_input)
|
||||
{
|
||||
return io_std_getset(L, GCROOT_IO_INPUT, "r");
|
||||
}
|
||||
|
||||
LJLIB_CF(io_output)
|
||||
{
|
||||
return io_std_getset(L, GCROOT_IO_OUTPUT, "w");
|
||||
}
|
||||
|
||||
LJLIB_CF(io_lines)
|
||||
{
|
||||
if (L->base == L->top) setnilV(L->top++);
|
||||
if (!tvisnil(L->base)) { /* io.lines(fname) */
|
||||
IOFileUD *iof = io_file_open(L, "r");
|
||||
iof->type = IOFILE_TYPE_FILE|IOFILE_FLAG_CLOSE;
|
||||
L->top--;
|
||||
setudataV(L, L->base, udataV(L->top));
|
||||
} else { /* io.lines() iterates over stdin. */
|
||||
setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_INPUT));
|
||||
}
|
||||
return io_file_lines(L);
|
||||
}
|
||||
|
||||
LJLIB_CF(io_type)
|
||||
{
|
||||
cTValue *o = lj_lib_checkany(L, 1);
|
||||
if (!(tvisudata(o) && udataV(o)->udtype == UDTYPE_IO_FILE))
|
||||
setnilV(L->top++);
|
||||
else if (((IOFileUD *)uddata(udataV(o)))->fp != NULL)
|
||||
lua_pushliteral(L, "file");
|
||||
else
|
||||
lua_pushliteral(L, "closed file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static GCobj *io_std_new(lua_State *L, FILE *fp, const char *name)
|
||||
{
|
||||
IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD));
|
||||
GCudata *ud = udataV(L->top-1);
|
||||
ud->udtype = UDTYPE_IO_FILE;
|
||||
/* NOBARRIER: The GCudata is new (marked white). */
|
||||
setgcref(ud->metatable, gcV(L->top-3));
|
||||
iof->fp = fp;
|
||||
iof->type = IOFILE_TYPE_STDF;
|
||||
lua_setfield(L, -2, name);
|
||||
return obj2gco(ud);
|
||||
}
|
||||
|
||||
LUALIB_API int luaopen_io(lua_State *L)
|
||||
{
|
||||
LJ_LIB_REG(L, NULL, io_method);
|
||||
copyTV(L, L->top, L->top-1); L->top++;
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
|
||||
LJ_LIB_REG(L, LUA_IOLIBNAME, io);
|
||||
setgcref(G(L)->gcroot[GCROOT_IO_INPUT], io_std_new(L, stdin, "stdin"));
|
||||
setgcref(G(L)->gcroot[GCROOT_IO_OUTPUT], io_std_new(L, stdout, "stdout"));
|
||||
io_std_new(L, stderr, "stderr");
|
||||
return 1;
|
||||
}
|
||||
|
||||
744
thirdPart/luajit/src/lib_jit.c
Normal file
744
thirdPart/luajit/src/lib_jit.c
Normal file
@@ -0,0 +1,744 @@
|
||||
/*
|
||||
** JIT library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#define lib_jit_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_gc.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_debug.h"
|
||||
#include "lj_str.h"
|
||||
#include "lj_tab.h"
|
||||
#include "lj_state.h"
|
||||
#include "lj_bc.h"
|
||||
#if LJ_HASFFI
|
||||
#include "lj_ctype.h"
|
||||
#endif
|
||||
#if LJ_HASJIT
|
||||
#include "lj_ir.h"
|
||||
#include "lj_jit.h"
|
||||
#include "lj_ircall.h"
|
||||
#include "lj_iropt.h"
|
||||
#include "lj_target.h"
|
||||
#endif
|
||||
#include "lj_trace.h"
|
||||
#include "lj_dispatch.h"
|
||||
#include "lj_vm.h"
|
||||
#include "lj_vmevent.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
#include "luajit.h"
|
||||
|
||||
/* -- jit.* functions ----------------------------------------------------- */
|
||||
|
||||
#define LJLIB_MODULE_jit
|
||||
|
||||
static int setjitmode(lua_State *L, int mode)
|
||||
{
|
||||
int idx = 0;
|
||||
if (L->base == L->top || tvisnil(L->base)) { /* jit.on/off/flush([nil]) */
|
||||
mode |= LUAJIT_MODE_ENGINE;
|
||||
} else {
|
||||
/* jit.on/off/flush(func|proto, nil|true|false) */
|
||||
if (tvisfunc(L->base) || tvisproto(L->base))
|
||||
idx = 1;
|
||||
else if (!tvistrue(L->base)) /* jit.on/off/flush(true, nil|true|false) */
|
||||
goto err;
|
||||
if (L->base+1 < L->top && tvisbool(L->base+1))
|
||||
mode |= boolV(L->base+1) ? LUAJIT_MODE_ALLFUNC : LUAJIT_MODE_ALLSUBFUNC;
|
||||
else
|
||||
mode |= LUAJIT_MODE_FUNC;
|
||||
}
|
||||
if (luaJIT_setmode(L, idx, mode) != 1) {
|
||||
if ((mode & LUAJIT_MODE_MASK) == LUAJIT_MODE_ENGINE)
|
||||
lj_err_caller(L, LJ_ERR_NOJIT);
|
||||
err:
|
||||
lj_err_argt(L, 1, LUA_TFUNCTION);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(jit_on)
|
||||
{
|
||||
return setjitmode(L, LUAJIT_MODE_ON);
|
||||
}
|
||||
|
||||
LJLIB_CF(jit_off)
|
||||
{
|
||||
return setjitmode(L, LUAJIT_MODE_OFF);
|
||||
}
|
||||
|
||||
LJLIB_CF(jit_flush)
|
||||
{
|
||||
#if LJ_HASJIT
|
||||
if (L->base < L->top && tvisnumber(L->base)) {
|
||||
int traceno = lj_lib_checkint(L, 1);
|
||||
luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return setjitmode(L, LUAJIT_MODE_FLUSH);
|
||||
}
|
||||
|
||||
#if LJ_HASJIT
|
||||
/* Push a string for every flag bit that is set. */
|
||||
static void flagbits_to_strings(lua_State *L, uint32_t flags, uint32_t base,
|
||||
const char *str)
|
||||
{
|
||||
for (; *str; base <<= 1, str += 1+*str)
|
||||
if (flags & base)
|
||||
setstrV(L, L->top++, lj_str_new(L, str+1, *(uint8_t *)str));
|
||||
}
|
||||
#endif
|
||||
|
||||
LJLIB_CF(jit_status)
|
||||
{
|
||||
#if LJ_HASJIT
|
||||
jit_State *J = L2J(L);
|
||||
L->top = L->base;
|
||||
setboolV(L->top++, (J->flags & JIT_F_ON) ? 1 : 0);
|
||||
flagbits_to_strings(L, J->flags, JIT_F_CPU, JIT_F_CPUSTRING);
|
||||
flagbits_to_strings(L, J->flags, JIT_F_OPT, JIT_F_OPTSTRING);
|
||||
return (int)(L->top - L->base);
|
||||
#else
|
||||
setboolV(L->top++, 0);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
LJLIB_CF(jit_security)
|
||||
{
|
||||
int idx = lj_lib_checkopt(L, 1, -1, LJ_SECURITY_MODESTRING);
|
||||
setintV(L->top++, ((LJ_SECURITY_MODE >> (2*idx)) & 3));
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(jit_attach)
|
||||
{
|
||||
#ifdef LUAJIT_DISABLE_VMEVENT
|
||||
luaL_error(L, "vmevent API disabled");
|
||||
#else
|
||||
GCfunc *fn = lj_lib_checkfunc(L, 1);
|
||||
GCstr *s = lj_lib_optstr(L, 2);
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
|
||||
if (s) { /* Attach to given event. */
|
||||
const uint8_t *p = (const uint8_t *)strdata(s);
|
||||
uint32_t h = s->len;
|
||||
while (*p) h = h ^ (lj_rol(h, 6) + *p++);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_rawseti(L, -2, VMEVENT_HASHIDX(h));
|
||||
G(L)->vmevmask = VMEVENT_NOCACHE; /* Invalidate cache. */
|
||||
} else { /* Detach if no event given. */
|
||||
setnilV(L->top++);
|
||||
while (lua_next(L, -2)) {
|
||||
L->top--;
|
||||
if (tvisfunc(L->top) && funcV(L->top) == fn) {
|
||||
setnilV(lj_tab_set(L, tabV(L->top-2), L->top-1));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_PUSH(top-5) LJLIB_SET(os)
|
||||
LJLIB_PUSH(top-4) LJLIB_SET(arch)
|
||||
LJLIB_PUSH(top-3) LJLIB_SET(version_num)
|
||||
LJLIB_PUSH(top-2) LJLIB_SET(version)
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
/* -- jit.util.* functions ------------------------------------------------ */
|
||||
|
||||
#define LJLIB_MODULE_jit_util
|
||||
|
||||
/* -- Reflection API for Lua functions ------------------------------------ */
|
||||
|
||||
static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val)
|
||||
{
|
||||
setintV(lj_tab_setstr(L, t, lj_str_newz(L, name)), val);
|
||||
}
|
||||
|
||||
/* local info = jit.util.funcinfo(func [,pc]) */
|
||||
LJLIB_CF(jit_util_funcinfo)
|
||||
{
|
||||
GCproto *pt = lj_lib_checkLproto(L, 1, 1);
|
||||
if (pt) {
|
||||
BCPos pc = (BCPos)lj_lib_optint(L, 2, 0);
|
||||
GCtab *t;
|
||||
lua_createtable(L, 0, 16); /* Increment hash size if fields are added. */
|
||||
t = tabV(L->top-1);
|
||||
setintfield(L, t, "linedefined", pt->firstline);
|
||||
setintfield(L, t, "lastlinedefined", pt->firstline + pt->numline);
|
||||
setintfield(L, t, "stackslots", pt->framesize);
|
||||
setintfield(L, t, "params", pt->numparams);
|
||||
setintfield(L, t, "bytecodes", (int32_t)pt->sizebc);
|
||||
setintfield(L, t, "gcconsts", (int32_t)pt->sizekgc);
|
||||
setintfield(L, t, "nconsts", (int32_t)pt->sizekn);
|
||||
setintfield(L, t, "upvalues", (int32_t)pt->sizeuv);
|
||||
if (pc < pt->sizebc)
|
||||
setintfield(L, t, "currentline", lj_debug_line(pt, pc));
|
||||
lua_pushboolean(L, (pt->flags & PROTO_VARARG));
|
||||
lua_setfield(L, -2, "isvararg");
|
||||
lua_pushboolean(L, (pt->flags & PROTO_CHILD));
|
||||
lua_setfield(L, -2, "children");
|
||||
setstrV(L, L->top++, proto_chunkname(pt));
|
||||
lua_setfield(L, -2, "source");
|
||||
lj_debug_pushloc(L, pt, pc);
|
||||
lua_setfield(L, -2, "loc");
|
||||
setprotoV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "proto")), pt);
|
||||
} else {
|
||||
GCfunc *fn = funcV(L->base);
|
||||
GCtab *t;
|
||||
lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */
|
||||
t = tabV(L->top-1);
|
||||
if (!iscfunc(fn))
|
||||
setintfield(L, t, "ffid", fn->c.ffid);
|
||||
setintptrV(lj_tab_setstr(L, t, lj_str_newlit(L, "addr")),
|
||||
(intptr_t)(void *)fn->c.f);
|
||||
setintfield(L, t, "upvalues", fn->c.nupvalues);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* local ins, m = jit.util.funcbc(func, pc) */
|
||||
LJLIB_CF(jit_util_funcbc)
|
||||
{
|
||||
GCproto *pt = lj_lib_checkLproto(L, 1, 0);
|
||||
BCPos pc = (BCPos)lj_lib_checkint(L, 2);
|
||||
if (pc < pt->sizebc) {
|
||||
BCIns ins = proto_bc(pt)[pc];
|
||||
BCOp op = bc_op(ins);
|
||||
lj_assertL(op < BC__MAX, "bad bytecode op %d", op);
|
||||
setintV(L->top, ins);
|
||||
setintV(L->top+1, lj_bc_mode[op]);
|
||||
L->top += 2;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* local k = jit.util.funck(func, idx) */
|
||||
LJLIB_CF(jit_util_funck)
|
||||
{
|
||||
GCproto *pt = lj_lib_checkLproto(L, 1, 0);
|
||||
ptrdiff_t idx = (ptrdiff_t)lj_lib_checkint(L, 2);
|
||||
if (idx >= 0) {
|
||||
if (idx < (ptrdiff_t)pt->sizekn) {
|
||||
copyTV(L, L->top-1, proto_knumtv(pt, idx));
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (~idx < (ptrdiff_t)pt->sizekgc) {
|
||||
GCobj *gc = proto_kgc(pt, idx);
|
||||
setgcV(L, L->top-1, gc, ~gc->gch.gct);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* local name = jit.util.funcuvname(func, idx) */
|
||||
LJLIB_CF(jit_util_funcuvname)
|
||||
{
|
||||
GCproto *pt = lj_lib_checkLproto(L, 1, 0);
|
||||
uint32_t idx = (uint32_t)lj_lib_checkint(L, 2);
|
||||
if (idx < pt->sizeuv) {
|
||||
setstrV(L, L->top-1, lj_str_newz(L, lj_debug_uvname(pt, idx)));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -- Reflection API for traces ------------------------------------------- */
|
||||
|
||||
#if LJ_HASJIT
|
||||
|
||||
/* Check trace argument. Must not throw for non-existent trace numbers. */
|
||||
static GCtrace *jit_checktrace(lua_State *L)
|
||||
{
|
||||
TraceNo tr = (TraceNo)lj_lib_checkint(L, 1);
|
||||
jit_State *J = L2J(L);
|
||||
if (tr > 0 && tr < J->sizetrace)
|
||||
return traceref(J, tr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Names of link types. ORDER LJ_TRLINK */
|
||||
static const char *const jit_trlinkname[] = {
|
||||
"none", "root", "loop", "tail-recursion", "up-recursion", "down-recursion",
|
||||
"interpreter", "return", "stitch"
|
||||
};
|
||||
|
||||
/* local info = jit.util.traceinfo(tr) */
|
||||
LJLIB_CF(jit_util_traceinfo)
|
||||
{
|
||||
GCtrace *T = jit_checktrace(L);
|
||||
if (T) {
|
||||
GCtab *t;
|
||||
lua_createtable(L, 0, 8); /* Increment hash size if fields are added. */
|
||||
t = tabV(L->top-1);
|
||||
setintfield(L, t, "nins", (int32_t)T->nins - REF_BIAS - 1);
|
||||
setintfield(L, t, "nk", REF_BIAS - (int32_t)T->nk);
|
||||
setintfield(L, t, "link", T->link);
|
||||
setintfield(L, t, "nexit", T->nsnap);
|
||||
setstrV(L, L->top++, lj_str_newz(L, jit_trlinkname[T->linktype]));
|
||||
lua_setfield(L, -2, "linktype");
|
||||
/* There are many more fields. Add them only when needed. */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* local m, ot, op1, op2, prev = jit.util.traceir(tr, idx) */
|
||||
LJLIB_CF(jit_util_traceir)
|
||||
{
|
||||
GCtrace *T = jit_checktrace(L);
|
||||
IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
|
||||
if (T && ref >= REF_BIAS && ref < T->nins) {
|
||||
IRIns *ir = &T->ir[ref];
|
||||
int32_t m = lj_ir_mode[ir->o];
|
||||
setintV(L->top-2, m);
|
||||
setintV(L->top-1, ir->ot);
|
||||
setintV(L->top++, (int32_t)ir->op1 - (irm_op1(m)==IRMref ? REF_BIAS : 0));
|
||||
setintV(L->top++, (int32_t)ir->op2 - (irm_op2(m)==IRMref ? REF_BIAS : 0));
|
||||
setintV(L->top++, ir->prev);
|
||||
return 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* local k, t [, slot] = jit.util.tracek(tr, idx) */
|
||||
LJLIB_CF(jit_util_tracek)
|
||||
{
|
||||
GCtrace *T = jit_checktrace(L);
|
||||
IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
|
||||
if (T && ref >= T->nk && ref < REF_BIAS) {
|
||||
IRIns *ir = &T->ir[ref];
|
||||
int32_t slot = -1;
|
||||
if (ir->o == IR_KSLOT) {
|
||||
slot = ir->op2;
|
||||
ir = &T->ir[ir->op1];
|
||||
}
|
||||
#if LJ_HASFFI
|
||||
if (ir->o == IR_KINT64) ctype_loadffi(L);
|
||||
#endif
|
||||
lj_ir_kvalue(L, L->top-2, ir);
|
||||
setintV(L->top-1, (int32_t)irt_type(ir->t));
|
||||
if (slot == -1)
|
||||
return 2;
|
||||
setintV(L->top++, slot);
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* local snap = jit.util.tracesnap(tr, sn) */
|
||||
LJLIB_CF(jit_util_tracesnap)
|
||||
{
|
||||
GCtrace *T = jit_checktrace(L);
|
||||
SnapNo sn = (SnapNo)lj_lib_checkint(L, 2);
|
||||
if (T && sn < T->nsnap) {
|
||||
SnapShot *snap = &T->snap[sn];
|
||||
SnapEntry *map = &T->snapmap[snap->mapofs];
|
||||
MSize n, nent = snap->nent;
|
||||
GCtab *t;
|
||||
lua_createtable(L, nent+2, 0);
|
||||
t = tabV(L->top-1);
|
||||
setintV(lj_tab_setint(L, t, 0), (int32_t)snap->ref - REF_BIAS);
|
||||
setintV(lj_tab_setint(L, t, 1), (int32_t)snap->nslots);
|
||||
for (n = 0; n < nent; n++)
|
||||
setintV(lj_tab_setint(L, t, (int32_t)(n+2)), (int32_t)map[n]);
|
||||
setintV(lj_tab_setint(L, t, (int32_t)(nent+2)), (int32_t)SNAP(255, 0, 0));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* local mcode, addr, loop = jit.util.tracemc(tr) */
|
||||
LJLIB_CF(jit_util_tracemc)
|
||||
{
|
||||
GCtrace *T = jit_checktrace(L);
|
||||
if (T && T->mcode != NULL) {
|
||||
setstrV(L, L->top-1, lj_str_new(L, (const char *)T->mcode, T->szmcode));
|
||||
setintptrV(L->top++, (intptr_t)(void *)T->mcode);
|
||||
setintV(L->top++, T->mcloop);
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* local addr = jit.util.traceexitstub([tr,] exitno) */
|
||||
LJLIB_CF(jit_util_traceexitstub)
|
||||
{
|
||||
#ifdef EXITSTUBS_PER_GROUP
|
||||
ExitNo exitno = (ExitNo)lj_lib_checkint(L, 1);
|
||||
jit_State *J = L2J(L);
|
||||
if (exitno < EXITSTUBS_PER_GROUP*LJ_MAX_EXITSTUBGR) {
|
||||
setintptrV(L->top-1, (intptr_t)(void *)exitstub_addr(J, exitno));
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
if (L->top > L->base+1) { /* Don't throw for one-argument variant. */
|
||||
GCtrace *T = jit_checktrace(L);
|
||||
ExitNo exitno = (ExitNo)lj_lib_checkint(L, 2);
|
||||
ExitNo maxexit = T->root ? T->nsnap+1 : T->nsnap;
|
||||
if (T && T->mcode != NULL && exitno < maxexit) {
|
||||
setintptrV(L->top-1, (intptr_t)(void *)exitstub_trace_addr(T, exitno));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* local addr = jit.util.ircalladdr(idx) */
|
||||
LJLIB_CF(jit_util_ircalladdr)
|
||||
{
|
||||
uint32_t idx = (uint32_t)lj_lib_checkint(L, 1);
|
||||
if (idx < IRCALL__MAX) {
|
||||
ASMFunction func = lj_ir_callinfo[idx].func;
|
||||
setintptrV(L->top-1, (intptr_t)(void *)lj_ptr_strip(func));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
static int luaopen_jit_util(lua_State *L)
|
||||
{
|
||||
LJ_LIB_REG(L, NULL, jit_util);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* -- jit.opt module ------------------------------------------------------ */
|
||||
|
||||
#if LJ_HASJIT
|
||||
|
||||
#define LJLIB_MODULE_jit_opt
|
||||
|
||||
/* Parse optimization level. */
|
||||
static int jitopt_level(jit_State *J, const char *str)
|
||||
{
|
||||
if (str[0] >= '0' && str[0] <= '9' && str[1] == '\0') {
|
||||
uint32_t flags;
|
||||
if (str[0] == '0') flags = JIT_F_OPT_0;
|
||||
else if (str[0] == '1') flags = JIT_F_OPT_1;
|
||||
else if (str[0] == '2') flags = JIT_F_OPT_2;
|
||||
else flags = JIT_F_OPT_3;
|
||||
J->flags = (J->flags & ~JIT_F_OPT_MASK) | flags;
|
||||
return 1; /* Ok. */
|
||||
}
|
||||
return 0; /* No match. */
|
||||
}
|
||||
|
||||
/* Parse optimization flag. */
|
||||
static int jitopt_flag(jit_State *J, const char *str)
|
||||
{
|
||||
const char *lst = JIT_F_OPTSTRING;
|
||||
uint32_t opt;
|
||||
int set = 1;
|
||||
if (str[0] == '+') {
|
||||
str++;
|
||||
} else if (str[0] == '-') {
|
||||
str++;
|
||||
set = 0;
|
||||
} else if (str[0] == 'n' && str[1] == 'o') {
|
||||
str += str[2] == '-' ? 3 : 2;
|
||||
set = 0;
|
||||
}
|
||||
for (opt = JIT_F_OPT; ; opt <<= 1) {
|
||||
size_t len = *(const uint8_t *)lst;
|
||||
if (len == 0)
|
||||
break;
|
||||
if (strncmp(str, lst+1, len) == 0 && str[len] == '\0') {
|
||||
if (set) J->flags |= opt; else J->flags &= ~opt;
|
||||
return 1; /* Ok. */
|
||||
}
|
||||
lst += 1+len;
|
||||
}
|
||||
return 0; /* No match. */
|
||||
}
|
||||
|
||||
/* Parse optimization parameter. */
|
||||
static int jitopt_param(jit_State *J, const char *str)
|
||||
{
|
||||
const char *lst = JIT_P_STRING;
|
||||
int i;
|
||||
for (i = 0; i < JIT_P__MAX; i++) {
|
||||
size_t len = *(const uint8_t *)lst;
|
||||
lj_assertJ(len != 0, "bad JIT_P_STRING");
|
||||
if (strncmp(str, lst+1, len) == 0 && str[len] == '=') {
|
||||
int32_t n = 0;
|
||||
const char *p = &str[len+1];
|
||||
while (*p >= '0' && *p <= '9')
|
||||
n = n*10 + (*p++ - '0');
|
||||
if (*p) return 0; /* Malformed number. */
|
||||
J->param[i] = n;
|
||||
if (i == JIT_P_hotloop)
|
||||
lj_dispatch_init_hotcount(J2G(J));
|
||||
return 1; /* Ok. */
|
||||
}
|
||||
lst += 1+len;
|
||||
}
|
||||
return 0; /* No match. */
|
||||
}
|
||||
|
||||
/* jit.opt.start(flags...) */
|
||||
LJLIB_CF(jit_opt_start)
|
||||
{
|
||||
jit_State *J = L2J(L);
|
||||
int nargs = (int)(L->top - L->base);
|
||||
if (nargs == 0) {
|
||||
J->flags = (J->flags & ~JIT_F_OPT_MASK) | JIT_F_OPT_DEFAULT;
|
||||
} else {
|
||||
int i;
|
||||
for (i = 1; i <= nargs; i++) {
|
||||
const char *str = strdata(lj_lib_checkstr(L, i));
|
||||
if (!jitopt_level(J, str) &&
|
||||
!jitopt_flag(J, str) &&
|
||||
!jitopt_param(J, str))
|
||||
lj_err_callerv(L, LJ_ERR_JITOPT, str);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
#endif
|
||||
|
||||
/* -- jit.profile module -------------------------------------------------- */
|
||||
|
||||
#if LJ_HASPROFILE
|
||||
|
||||
#define LJLIB_MODULE_jit_profile
|
||||
|
||||
/* Not loaded by default, use: local profile = require("jit.profile") */
|
||||
|
||||
#define KEY_PROFILE_THREAD (U64x(80000000,00000000)|'t')
|
||||
#define KEY_PROFILE_FUNC (U64x(80000000,00000000)|'f')
|
||||
|
||||
static void jit_profile_callback(lua_State *L2, lua_State *L, int samples,
|
||||
int vmstate)
|
||||
{
|
||||
TValue key;
|
||||
cTValue *tv;
|
||||
key.u64 = KEY_PROFILE_FUNC;
|
||||
tv = lj_tab_get(L, tabV(registry(L)), &key);
|
||||
if (tvisfunc(tv)) {
|
||||
char vmst = (char)vmstate;
|
||||
int status;
|
||||
setfuncV(L2, L2->top++, funcV(tv));
|
||||
setthreadV(L2, L2->top++, L);
|
||||
setintV(L2->top++, samples);
|
||||
setstrV(L2, L2->top++, lj_str_new(L2, &vmst, 1));
|
||||
status = lua_pcall(L2, 3, 0, 0); /* callback(thread, samples, vmstate) */
|
||||
if (status) {
|
||||
if (G(L2)->panic) G(L2)->panic(L2);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
lj_trace_abort(G(L2));
|
||||
}
|
||||
}
|
||||
|
||||
/* profile.start(mode, cb) */
|
||||
LJLIB_CF(jit_profile_start)
|
||||
{
|
||||
GCtab *registry = tabV(registry(L));
|
||||
GCstr *mode = lj_lib_optstr(L, 1);
|
||||
GCfunc *func = lj_lib_checkfunc(L, 2);
|
||||
lua_State *L2 = lua_newthread(L); /* Thread that runs profiler callback. */
|
||||
TValue key;
|
||||
/* Anchor thread and function in registry. */
|
||||
key.u64 = KEY_PROFILE_THREAD;
|
||||
setthreadV(L, lj_tab_set(L, registry, &key), L2);
|
||||
key.u64 = KEY_PROFILE_FUNC;
|
||||
setfuncV(L, lj_tab_set(L, registry, &key), func);
|
||||
lj_gc_anybarriert(L, registry);
|
||||
luaJIT_profile_start(L, mode ? strdata(mode) : "",
|
||||
(luaJIT_profile_callback)jit_profile_callback, L2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* profile.stop() */
|
||||
LJLIB_CF(jit_profile_stop)
|
||||
{
|
||||
GCtab *registry;
|
||||
TValue key;
|
||||
luaJIT_profile_stop(L);
|
||||
registry = tabV(registry(L));
|
||||
key.u64 = KEY_PROFILE_THREAD;
|
||||
setnilV(lj_tab_set(L, registry, &key));
|
||||
key.u64 = KEY_PROFILE_FUNC;
|
||||
setnilV(lj_tab_set(L, registry, &key));
|
||||
lj_gc_anybarriert(L, registry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* dump = profile.dumpstack([thread,] fmt, depth) */
|
||||
LJLIB_CF(jit_profile_dumpstack)
|
||||
{
|
||||
lua_State *L2 = L;
|
||||
int arg = 0;
|
||||
size_t len;
|
||||
int depth;
|
||||
GCstr *fmt;
|
||||
const char *p;
|
||||
if (L->top > L->base && tvisthread(L->base)) {
|
||||
L2 = threadV(L->base);
|
||||
arg = 1;
|
||||
}
|
||||
fmt = lj_lib_checkstr(L, arg+1);
|
||||
depth = lj_lib_checkint(L, arg+2);
|
||||
p = luaJIT_profile_dumpstack(L2, strdata(fmt), depth, &len);
|
||||
lua_pushlstring(L, p, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
static int luaopen_jit_profile(lua_State *L)
|
||||
{
|
||||
LJ_LIB_REG(L, NULL, jit_profile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* -- JIT compiler initialization ----------------------------------------- */
|
||||
|
||||
#if LJ_HASJIT
|
||||
/* Default values for JIT parameters. */
|
||||
static const int32_t jit_param_default[JIT_P__MAX+1] = {
|
||||
#define JIT_PARAMINIT(len, name, value) (value),
|
||||
JIT_PARAMDEF(JIT_PARAMINIT)
|
||||
#undef JIT_PARAMINIT
|
||||
0
|
||||
};
|
||||
|
||||
#if LJ_TARGET_ARM && LJ_TARGET_LINUX
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
/* Arch-dependent CPU feature detection. */
|
||||
static uint32_t jit_cpudetect(void)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
#if LJ_TARGET_X86ORX64
|
||||
|
||||
uint32_t vendor[4];
|
||||
uint32_t features[4];
|
||||
if (lj_vm_cpuid(0, vendor) && lj_vm_cpuid(1, features)) {
|
||||
flags |= ((features[2] >> 0)&1) * JIT_F_SSE3;
|
||||
flags |= ((features[2] >> 19)&1) * JIT_F_SSE4_1;
|
||||
if (vendor[0] >= 7) {
|
||||
uint32_t xfeatures[4];
|
||||
lj_vm_cpuid(7, xfeatures);
|
||||
flags |= ((xfeatures[1] >> 8)&1) * JIT_F_BMI2;
|
||||
}
|
||||
}
|
||||
/* Don't bother checking for SSE2 -- the VM will crash before getting here. */
|
||||
|
||||
#elif LJ_TARGET_ARM
|
||||
|
||||
int ver = LJ_ARCH_VERSION; /* Compile-time ARM CPU detection. */
|
||||
#if LJ_TARGET_LINUX
|
||||
if (ver < 70) { /* Runtime ARM CPU detection. */
|
||||
struct utsname ut;
|
||||
uname(&ut);
|
||||
if (strncmp(ut.machine, "armv", 4) == 0) {
|
||||
if (ut.machine[4] >= '8') ver = 80;
|
||||
else if (ut.machine[4] == '7') ver = 70;
|
||||
else if (ut.machine[4] == '6') ver = 60;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
flags |= ver >= 70 ? JIT_F_ARMV7 :
|
||||
ver >= 61 ? JIT_F_ARMV6T2_ :
|
||||
ver >= 60 ? JIT_F_ARMV6_ : 0;
|
||||
flags |= LJ_ARCH_HASFPU == 0 ? 0 : ver >= 70 ? JIT_F_VFPV3 : JIT_F_VFPV2;
|
||||
|
||||
#elif LJ_TARGET_ARM64
|
||||
|
||||
/* No optional CPU features to detect (for now). */
|
||||
|
||||
#elif LJ_TARGET_PPC
|
||||
|
||||
#if LJ_ARCH_SQRT
|
||||
flags |= JIT_F_SQRT;
|
||||
#endif
|
||||
#if LJ_ARCH_ROUND
|
||||
flags |= JIT_F_ROUND;
|
||||
#endif
|
||||
|
||||
#elif LJ_TARGET_MIPS
|
||||
|
||||
/* Compile-time MIPS CPU detection. */
|
||||
#if LJ_ARCH_VERSION >= 20
|
||||
flags |= JIT_F_MIPSXXR2;
|
||||
#endif
|
||||
/* Runtime MIPS CPU detection. */
|
||||
#if defined(__GNUC__)
|
||||
if (!(flags & JIT_F_MIPSXXR2)) {
|
||||
int x;
|
||||
#ifdef __mips16
|
||||
x = 0; /* Runtime detection is difficult. Ensure optimal -march flags. */
|
||||
#else
|
||||
/* On MIPS32R1 rotr is treated as srl. rotr r2,r2,1 -> srl r2,r2,1. */
|
||||
__asm__("li $2, 1\n\t.long 0x00221042\n\tmove %0, $2" : "=r"(x) : : "$2");
|
||||
#endif
|
||||
if (x) flags |= JIT_F_MIPSXXR2; /* Either 0x80000000 (R2) or 0 (R1). */
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "Missing CPU detection for this architecture"
|
||||
#endif
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* Initialize JIT compiler. */
|
||||
static void jit_init(lua_State *L)
|
||||
{
|
||||
jit_State *J = L2J(L);
|
||||
J->flags = jit_cpudetect() | JIT_F_ON | JIT_F_OPT_DEFAULT;
|
||||
memcpy(J->param, jit_param_default, sizeof(J->param));
|
||||
lj_dispatch_update(G(L));
|
||||
}
|
||||
#endif
|
||||
|
||||
LUALIB_API int luaopen_jit(lua_State *L)
|
||||
{
|
||||
#if LJ_HASJIT
|
||||
jit_init(L);
|
||||
#endif
|
||||
lua_pushliteral(L, LJ_OS_NAME);
|
||||
lua_pushliteral(L, LJ_ARCH_NAME);
|
||||
lua_pushinteger(L, LUAJIT_VERSION_NUM); /* Deprecated. */
|
||||
lua_pushliteral(L, LUAJIT_VERSION);
|
||||
LJ_LIB_REG(L, LUA_JITLIBNAME, jit);
|
||||
#if LJ_HASPROFILE
|
||||
lj_lib_prereg(L, LUA_JITLIBNAME ".profile", luaopen_jit_profile,
|
||||
tabref(L->env));
|
||||
#endif
|
||||
#ifndef LUAJIT_DISABLE_JITUTIL
|
||||
lj_lib_prereg(L, LUA_JITLIBNAME ".util", luaopen_jit_util, tabref(L->env));
|
||||
#endif
|
||||
#if LJ_HASJIT
|
||||
LJ_LIB_REG(L, "jit.opt", jit_opt);
|
||||
#endif
|
||||
L->top -= 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
201
thirdPart/luajit/src/lib_math.c
Normal file
201
thirdPart/luajit/src/lib_math.c
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
** Math library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define lib_math_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_lib.h"
|
||||
#include "lj_vm.h"
|
||||
#include "lj_prng.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define LJLIB_MODULE_math
|
||||
|
||||
LJLIB_ASM(math_abs) LJLIB_REC(.)
|
||||
{
|
||||
lj_lib_checknumber(L, 1);
|
||||
return FFH_RETRY;
|
||||
}
|
||||
LJLIB_ASM_(math_floor) LJLIB_REC(math_round IRFPM_FLOOR)
|
||||
LJLIB_ASM_(math_ceil) LJLIB_REC(math_round IRFPM_CEIL)
|
||||
|
||||
LJLIB_ASM(math_sqrt) LJLIB_REC(math_unary IRFPM_SQRT)
|
||||
{
|
||||
lj_lib_checknum(L, 1);
|
||||
return FFH_RETRY;
|
||||
}
|
||||
LJLIB_ASM_(math_log10) LJLIB_REC(math_call IRCALL_log10)
|
||||
LJLIB_ASM_(math_exp) LJLIB_REC(math_call IRCALL_exp)
|
||||
LJLIB_ASM_(math_sin) LJLIB_REC(math_call IRCALL_sin)
|
||||
LJLIB_ASM_(math_cos) LJLIB_REC(math_call IRCALL_cos)
|
||||
LJLIB_ASM_(math_tan) LJLIB_REC(math_call IRCALL_tan)
|
||||
LJLIB_ASM_(math_asin) LJLIB_REC(math_call IRCALL_asin)
|
||||
LJLIB_ASM_(math_acos) LJLIB_REC(math_call IRCALL_acos)
|
||||
LJLIB_ASM_(math_atan) LJLIB_REC(math_call IRCALL_atan)
|
||||
LJLIB_ASM_(math_sinh) LJLIB_REC(math_call IRCALL_sinh)
|
||||
LJLIB_ASM_(math_cosh) LJLIB_REC(math_call IRCALL_cosh)
|
||||
LJLIB_ASM_(math_tanh) LJLIB_REC(math_call IRCALL_tanh)
|
||||
LJLIB_ASM_(math_frexp)
|
||||
LJLIB_ASM_(math_modf)
|
||||
|
||||
LJLIB_ASM(math_log) LJLIB_REC(math_log)
|
||||
{
|
||||
double x = lj_lib_checknum(L, 1);
|
||||
if (L->base+1 < L->top) {
|
||||
double y = lj_lib_checknum(L, 2);
|
||||
#ifdef LUAJIT_NO_LOG2
|
||||
x = log(x); y = 1.0 / log(y);
|
||||
#else
|
||||
x = lj_vm_log2(x); y = 1.0 / lj_vm_log2(y);
|
||||
#endif
|
||||
setnumV(L->base-1-LJ_FR2, x*y); /* Do NOT join the expression to x / y. */
|
||||
return FFH_RES(1);
|
||||
}
|
||||
return FFH_RETRY;
|
||||
}
|
||||
|
||||
LJLIB_LUA(math_deg) /* function(x) return x * 57.29577951308232 end */
|
||||
LJLIB_LUA(math_rad) /* function(x) return x * 0.017453292519943295 end */
|
||||
|
||||
LJLIB_ASM(math_atan2) LJLIB_REC(.)
|
||||
{
|
||||
lj_lib_checknum(L, 1);
|
||||
lj_lib_checknum(L, 2);
|
||||
return FFH_RETRY;
|
||||
}
|
||||
LJLIB_ASM_(math_pow) LJLIB_REC(.)
|
||||
LJLIB_ASM_(math_fmod)
|
||||
|
||||
LJLIB_ASM(math_ldexp) LJLIB_REC(.)
|
||||
{
|
||||
lj_lib_checknum(L, 1);
|
||||
#if LJ_DUALNUM && !LJ_TARGET_X86ORX64
|
||||
lj_lib_checkint(L, 2);
|
||||
#else
|
||||
lj_lib_checknum(L, 2);
|
||||
#endif
|
||||
return FFH_RETRY;
|
||||
}
|
||||
|
||||
LJLIB_ASM(math_min) LJLIB_REC(math_minmax IR_MIN)
|
||||
{
|
||||
int i = 0;
|
||||
do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top);
|
||||
return FFH_RETRY;
|
||||
}
|
||||
LJLIB_ASM_(math_max) LJLIB_REC(math_minmax IR_MAX)
|
||||
|
||||
LJLIB_PUSH(3.14159265358979323846) LJLIB_SET(pi)
|
||||
LJLIB_PUSH(1e310) LJLIB_SET(huge)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* This implements a Tausworthe PRNG with period 2^223. Based on:
|
||||
** Tables of maximally-equidistributed combined LFSR generators,
|
||||
** Pierre L'Ecuyer, 1991, table 3, 1st entry.
|
||||
** Full-period ME-CF generator with L=64, J=4, k=223, N1=49.
|
||||
*/
|
||||
|
||||
/* Union needed for bit-pattern conversion between uint64_t and double. */
|
||||
typedef union { uint64_t u64; double d; } U64double;
|
||||
|
||||
/* PRNG seeding function. */
|
||||
static void random_seed(PRNGState *rs, double d)
|
||||
{
|
||||
uint32_t r = 0x11090601; /* 64-k[i] as four 8 bit constants. */
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
U64double u;
|
||||
uint32_t m = 1u << (r&255);
|
||||
r >>= 8;
|
||||
u.d = d = d * 3.14159265358979323846 + 2.7182818284590452354;
|
||||
if (u.u64 < m) u.u64 += m; /* Ensure k[i] MSB of u[i] are non-zero. */
|
||||
rs->u[i] = u.u64;
|
||||
}
|
||||
for (i = 0; i < 10; i++)
|
||||
(void)lj_prng_u64(rs);
|
||||
}
|
||||
|
||||
/* PRNG extract function. */
|
||||
LJLIB_PUSH(top-2) /* Upvalue holds userdata with PRNGState. */
|
||||
LJLIB_CF(math_random) LJLIB_REC(.)
|
||||
{
|
||||
int n = (int)(L->top - L->base);
|
||||
PRNGState *rs = (PRNGState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
|
||||
U64double u;
|
||||
double d;
|
||||
u.u64 = lj_prng_u64d(rs);
|
||||
d = u.d - 1.0;
|
||||
if (n > 0) {
|
||||
#if LJ_DUALNUM
|
||||
int isint = 1;
|
||||
double r1;
|
||||
lj_lib_checknumber(L, 1);
|
||||
if (tvisint(L->base)) {
|
||||
r1 = (lua_Number)intV(L->base);
|
||||
} else {
|
||||
isint = 0;
|
||||
r1 = numV(L->base);
|
||||
}
|
||||
#else
|
||||
double r1 = lj_lib_checknum(L, 1);
|
||||
#endif
|
||||
if (n == 1) {
|
||||
d = lj_vm_floor(d*r1) + 1.0; /* d is an int in range [1, r1] */
|
||||
} else {
|
||||
#if LJ_DUALNUM
|
||||
double r2;
|
||||
lj_lib_checknumber(L, 2);
|
||||
if (tvisint(L->base+1)) {
|
||||
r2 = (lua_Number)intV(L->base+1);
|
||||
} else {
|
||||
isint = 0;
|
||||
r2 = numV(L->base+1);
|
||||
}
|
||||
#else
|
||||
double r2 = lj_lib_checknum(L, 2);
|
||||
#endif
|
||||
d = lj_vm_floor(d*(r2-r1+1.0)) + r1; /* d is an int in range [r1, r2] */
|
||||
}
|
||||
#if LJ_DUALNUM
|
||||
if (isint) {
|
||||
setintV(L->top-1, lj_num2int(d));
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
} /* else: d is a double in range [0, 1] */
|
||||
setnumV(L->top++, d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* PRNG seed function. */
|
||||
LJLIB_PUSH(top-2) /* Upvalue holds userdata with PRNGState. */
|
||||
LJLIB_CF(math_randomseed)
|
||||
{
|
||||
PRNGState *rs = (PRNGState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
|
||||
random_seed(rs, lj_lib_checknum(L, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
LUALIB_API int luaopen_math(lua_State *L)
|
||||
{
|
||||
PRNGState *rs = (PRNGState *)lua_newuserdata(L, sizeof(PRNGState));
|
||||
lj_prng_seed_fixed(rs);
|
||||
LJ_LIB_REG(L, LUA_MATHLIBNAME, math);
|
||||
return 1;
|
||||
}
|
||||
|
||||
292
thirdPart/luajit/src/lib_os.c
Normal file
292
thirdPart/luajit/src/lib_os.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
** OS library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** Major portions taken verbatim or adapted from the Lua interpreter.
|
||||
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#define lib_os_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_gc.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_buf.h"
|
||||
#include "lj_str.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
#if LJ_TARGET_POSIX
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if !LJ_TARGET_PSVITA
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define LJLIB_MODULE_os
|
||||
|
||||
LJLIB_CF(os_execute)
|
||||
{
|
||||
#if LJ_NO_SYSTEM
|
||||
#if LJ_52
|
||||
errno = ENOSYS;
|
||||
return luaL_fileresult(L, 0, NULL);
|
||||
#else
|
||||
lua_pushinteger(L, -1);
|
||||
return 1;
|
||||
#endif
|
||||
#else
|
||||
const char *cmd = luaL_optstring(L, 1, NULL);
|
||||
int stat = system(cmd);
|
||||
#if LJ_52
|
||||
if (cmd)
|
||||
return luaL_execresult(L, stat);
|
||||
setboolV(L->top++, 1);
|
||||
#else
|
||||
setintV(L->top++, stat);
|
||||
#endif
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
LJLIB_CF(os_remove)
|
||||
{
|
||||
const char *filename = luaL_checkstring(L, 1);
|
||||
return luaL_fileresult(L, remove(filename) == 0, filename);
|
||||
}
|
||||
|
||||
LJLIB_CF(os_rename)
|
||||
{
|
||||
const char *fromname = luaL_checkstring(L, 1);
|
||||
const char *toname = luaL_checkstring(L, 2);
|
||||
return luaL_fileresult(L, rename(fromname, toname) == 0, fromname);
|
||||
}
|
||||
|
||||
LJLIB_CF(os_tmpname)
|
||||
{
|
||||
#if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PS5 || LJ_TARGET_PSVITA || LJ_TARGET_NX
|
||||
lj_err_caller(L, LJ_ERR_OSUNIQF);
|
||||
return 0;
|
||||
#else
|
||||
#if LJ_TARGET_POSIX
|
||||
char buf[15+1];
|
||||
int fp;
|
||||
strcpy(buf, "/tmp/lua_XXXXXX");
|
||||
fp = mkstemp(buf);
|
||||
if (fp != -1)
|
||||
close(fp);
|
||||
else
|
||||
lj_err_caller(L, LJ_ERR_OSUNIQF);
|
||||
#else
|
||||
char buf[L_tmpnam];
|
||||
if (tmpnam(buf) == NULL)
|
||||
lj_err_caller(L, LJ_ERR_OSUNIQF);
|
||||
#endif
|
||||
lua_pushstring(L, buf);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
LJLIB_CF(os_getenv)
|
||||
{
|
||||
#if LJ_TARGET_CONSOLE
|
||||
lua_pushnil(L);
|
||||
#else
|
||||
lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(os_exit)
|
||||
{
|
||||
int status;
|
||||
if (L->base < L->top && tvisbool(L->base))
|
||||
status = boolV(L->base) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
else
|
||||
status = lj_lib_optint(L, 1, EXIT_SUCCESS);
|
||||
if (L->base+1 < L->top && tvistruecond(L->base+1))
|
||||
lua_close(L);
|
||||
exit(status);
|
||||
return 0; /* Unreachable. */
|
||||
}
|
||||
|
||||
LJLIB_CF(os_clock)
|
||||
{
|
||||
setnumV(L->top++, ((lua_Number)clock())*(1.0/(lua_Number)CLOCKS_PER_SEC));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static void setfield(lua_State *L, const char *key, int value)
|
||||
{
|
||||
lua_pushinteger(L, value);
|
||||
lua_setfield(L, -2, key);
|
||||
}
|
||||
|
||||
static void setboolfield(lua_State *L, const char *key, int value)
|
||||
{
|
||||
if (value < 0) /* undefined? */
|
||||
return; /* does not set field */
|
||||
lua_pushboolean(L, value);
|
||||
lua_setfield(L, -2, key);
|
||||
}
|
||||
|
||||
static int getboolfield(lua_State *L, const char *key)
|
||||
{
|
||||
int res;
|
||||
lua_getfield(L, -1, key);
|
||||
res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int getfield(lua_State *L, const char *key, int d)
|
||||
{
|
||||
int res;
|
||||
lua_getfield(L, -1, key);
|
||||
if (lua_isnumber(L, -1)) {
|
||||
res = (int)lua_tointeger(L, -1);
|
||||
} else {
|
||||
if (d < 0)
|
||||
lj_err_callerv(L, LJ_ERR_OSDATEF, key);
|
||||
res = d;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
LJLIB_CF(os_date)
|
||||
{
|
||||
const char *s = luaL_optstring(L, 1, "%c");
|
||||
time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL));
|
||||
struct tm *stm;
|
||||
#if LJ_TARGET_POSIX
|
||||
struct tm rtm;
|
||||
#endif
|
||||
if (*s == '!') { /* UTC? */
|
||||
s++; /* Skip '!' */
|
||||
#if LJ_TARGET_POSIX
|
||||
stm = gmtime_r(&t, &rtm);
|
||||
#else
|
||||
stm = gmtime(&t);
|
||||
#endif
|
||||
} else {
|
||||
#if LJ_TARGET_POSIX
|
||||
stm = localtime_r(&t, &rtm);
|
||||
#else
|
||||
stm = localtime(&t);
|
||||
#endif
|
||||
}
|
||||
if (stm == NULL) { /* Invalid date? */
|
||||
setnilV(L->top++);
|
||||
} else if (strcmp(s, "*t") == 0) {
|
||||
lua_createtable(L, 0, 9); /* 9 = number of fields */
|
||||
setfield(L, "sec", stm->tm_sec);
|
||||
setfield(L, "min", stm->tm_min);
|
||||
setfield(L, "hour", stm->tm_hour);
|
||||
setfield(L, "day", stm->tm_mday);
|
||||
setfield(L, "month", stm->tm_mon+1);
|
||||
setfield(L, "year", stm->tm_year+1900);
|
||||
setfield(L, "wday", stm->tm_wday+1);
|
||||
setfield(L, "yday", stm->tm_yday+1);
|
||||
setboolfield(L, "isdst", stm->tm_isdst);
|
||||
} else if (*s) {
|
||||
SBuf *sb = &G(L)->tmpbuf;
|
||||
MSize sz = 0, retry = 4;
|
||||
const char *q;
|
||||
for (q = s; *q; q++)
|
||||
sz += (*q == '%') ? 30 : 1; /* Overflow doesn't matter. */
|
||||
setsbufL(sb, L);
|
||||
while (retry--) { /* Limit growth for invalid format or empty result. */
|
||||
char *buf = lj_buf_need(sb, sz);
|
||||
size_t len = strftime(buf, sbufsz(sb), s, stm);
|
||||
if (len) {
|
||||
setstrV(L, L->top++, lj_str_new(L, buf, len));
|
||||
lj_gc_check(L);
|
||||
break;
|
||||
}
|
||||
sz += (sz|1);
|
||||
}
|
||||
} else {
|
||||
setstrV(L, L->top++, &G(L)->strempty);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(os_time)
|
||||
{
|
||||
time_t t;
|
||||
if (lua_isnoneornil(L, 1)) { /* called without args? */
|
||||
t = time(NULL); /* get current time */
|
||||
} else {
|
||||
struct tm ts;
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_settop(L, 1); /* make sure table is at the top */
|
||||
ts.tm_sec = getfield(L, "sec", 0);
|
||||
ts.tm_min = getfield(L, "min", 0);
|
||||
ts.tm_hour = getfield(L, "hour", 12);
|
||||
ts.tm_mday = getfield(L, "day", -1);
|
||||
ts.tm_mon = getfield(L, "month", -1) - 1;
|
||||
ts.tm_year = getfield(L, "year", -1) - 1900;
|
||||
ts.tm_isdst = getboolfield(L, "isdst");
|
||||
t = mktime(&ts);
|
||||
}
|
||||
if (t == (time_t)(-1))
|
||||
lua_pushnil(L);
|
||||
else
|
||||
lua_pushnumber(L, (lua_Number)t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(os_difftime)
|
||||
{
|
||||
lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
|
||||
(time_t)(luaL_optnumber(L, 2, (lua_Number)0))));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
LJLIB_CF(os_setlocale)
|
||||
{
|
||||
#if LJ_TARGET_PSVITA
|
||||
lua_pushliteral(L, "C");
|
||||
#else
|
||||
GCstr *s = lj_lib_optstr(L, 1);
|
||||
const char *str = s ? strdata(s) : NULL;
|
||||
int opt = lj_lib_checkopt(L, 2, 6,
|
||||
"\5ctype\7numeric\4time\7collate\10monetary\1\377\3all");
|
||||
if (opt == 0) opt = LC_CTYPE;
|
||||
else if (opt == 1) opt = LC_NUMERIC;
|
||||
else if (opt == 2) opt = LC_TIME;
|
||||
else if (opt == 3) opt = LC_COLLATE;
|
||||
else if (opt == 4) opt = LC_MONETARY;
|
||||
else if (opt == 6) opt = LC_ALL;
|
||||
lua_pushstring(L, setlocale(opt, str));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
LUALIB_API int luaopen_os(lua_State *L)
|
||||
{
|
||||
LJ_LIB_REG(L, LUA_OSLIBNAME, os);
|
||||
return 1;
|
||||
}
|
||||
|
||||
628
thirdPart/luajit/src/lib_package.c
Normal file
628
thirdPart/luajit/src/lib_package.c
Normal file
@@ -0,0 +1,628 @@
|
||||
/*
|
||||
** Package library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** Major portions taken verbatim or adapted from the Lua interpreter.
|
||||
** Copyright (C) 1994-2012 Lua.org, PUC-Rio. See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lib_package_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Error codes for ll_loadfunc. */
|
||||
#define PACKAGE_ERR_LIB 1
|
||||
#define PACKAGE_ERR_FUNC 2
|
||||
#define PACKAGE_ERR_LOAD 3
|
||||
|
||||
/* Redefined in platform specific part. */
|
||||
#define PACKAGE_LIB_FAIL "open"
|
||||
#define setprogdir(L) ((void)0)
|
||||
|
||||
/* Symbol name prefixes. */
|
||||
#define SYMPREFIX_CF "luaopen_%s"
|
||||
#define SYMPREFIX_BC "luaJIT_BC_%s"
|
||||
|
||||
#if LJ_TARGET_DLOPEN
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void ll_unloadlib(void *lib)
|
||||
{
|
||||
dlclose(lib);
|
||||
}
|
||||
|
||||
static void *ll_load(lua_State *L, const char *path, int gl)
|
||||
{
|
||||
void *lib = dlopen(path, RTLD_NOW | (gl ? RTLD_GLOBAL : RTLD_LOCAL));
|
||||
if (lib == NULL) lua_pushstring(L, dlerror());
|
||||
return lib;
|
||||
}
|
||||
|
||||
static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym)
|
||||
{
|
||||
lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
|
||||
if (f == NULL) lua_pushstring(L, dlerror());
|
||||
return f;
|
||||
}
|
||||
|
||||
static const char *ll_bcsym(void *lib, const char *sym)
|
||||
{
|
||||
#if defined(RTLD_DEFAULT) && !defined(NO_RTLD_DEFAULT)
|
||||
if (lib == NULL) lib = RTLD_DEFAULT;
|
||||
#elif LJ_TARGET_OSX || LJ_TARGET_BSD
|
||||
if (lib == NULL) lib = (void *)(intptr_t)-2;
|
||||
#endif
|
||||
return (const char *)dlsym(lib, sym);
|
||||
}
|
||||
|
||||
#elif LJ_TARGET_WINDOWS
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
||||
#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
|
||||
#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
|
||||
BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
|
||||
#endif
|
||||
|
||||
#if LJ_TARGET_UWP
|
||||
void *LJ_WIN_LOADLIBA(const char *path)
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
wchar_t wpath[256];
|
||||
HANDLE lib = NULL;
|
||||
if (MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, 256) > 0) {
|
||||
lib = LoadPackagedLibrary(wpath, 0);
|
||||
}
|
||||
SetLastError(err);
|
||||
return lib;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef setprogdir
|
||||
|
||||
static void setprogdir(lua_State *L)
|
||||
{
|
||||
char buff[MAX_PATH + 1];
|
||||
char *lb;
|
||||
DWORD nsize = sizeof(buff);
|
||||
DWORD n = GetModuleFileNameA(NULL, buff, nsize);
|
||||
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) {
|
||||
luaL_error(L, "unable to get ModuleFileName");
|
||||
} else {
|
||||
*lb = '\0';
|
||||
luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff);
|
||||
lua_remove(L, -2); /* remove original string */
|
||||
}
|
||||
}
|
||||
|
||||
static void pusherror(lua_State *L)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
#if LJ_TARGET_XBOXONE
|
||||
wchar_t wbuffer[128];
|
||||
char buffer[128*2];
|
||||
if (FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, error, 0, wbuffer, sizeof(wbuffer)/sizeof(wchar_t), NULL) &&
|
||||
WideCharToMultiByte(CP_ACP, 0, wbuffer, 128, buffer, 128*2, NULL, NULL))
|
||||
#else
|
||||
char buffer[128];
|
||||
if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, error, 0, buffer, sizeof(buffer), NULL))
|
||||
#endif
|
||||
lua_pushstring(L, buffer);
|
||||
else
|
||||
lua_pushfstring(L, "system error %d\n", error);
|
||||
}
|
||||
|
||||
static void ll_unloadlib(void *lib)
|
||||
{
|
||||
FreeLibrary((HINSTANCE)lib);
|
||||
}
|
||||
|
||||
static void *ll_load(lua_State *L, const char *path, int gl)
|
||||
{
|
||||
HINSTANCE lib = LJ_WIN_LOADLIBA(path);
|
||||
if (lib == NULL) pusherror(L);
|
||||
UNUSED(gl);
|
||||
return lib;
|
||||
}
|
||||
|
||||
static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym)
|
||||
{
|
||||
lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym);
|
||||
if (f == NULL) pusherror(L);
|
||||
return f;
|
||||
}
|
||||
|
||||
#if LJ_TARGET_UWP
|
||||
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
||||
#endif
|
||||
|
||||
static const char *ll_bcsym(void *lib, const char *sym)
|
||||
{
|
||||
if (lib) {
|
||||
return (const char *)GetProcAddress((HINSTANCE)lib, sym);
|
||||
} else {
|
||||
#if LJ_TARGET_UWP
|
||||
return (const char *)GetProcAddress((HINSTANCE)&__ImageBase, sym);
|
||||
#else
|
||||
HINSTANCE h = GetModuleHandleA(NULL);
|
||||
const char *p = (const char *)GetProcAddress(h, sym);
|
||||
if (p == NULL && GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
(const char *)ll_bcsym, &h))
|
||||
p = (const char *)GetProcAddress(h, sym);
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#undef PACKAGE_LIB_FAIL
|
||||
#define PACKAGE_LIB_FAIL "absent"
|
||||
|
||||
#define DLMSG "dynamic libraries not enabled; no support for target OS"
|
||||
|
||||
static void ll_unloadlib(void *lib)
|
||||
{
|
||||
UNUSED(lib);
|
||||
}
|
||||
|
||||
static void *ll_load(lua_State *L, const char *path, int gl)
|
||||
{
|
||||
UNUSED(path); UNUSED(gl);
|
||||
lua_pushliteral(L, DLMSG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym)
|
||||
{
|
||||
UNUSED(lib); UNUSED(sym);
|
||||
lua_pushliteral(L, DLMSG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *ll_bcsym(void *lib, const char *sym)
|
||||
{
|
||||
UNUSED(lib); UNUSED(sym);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static void **ll_register(lua_State *L, const char *path)
|
||||
{
|
||||
void **plib;
|
||||
lua_pushfstring(L, "LOADLIB: %s", path);
|
||||
lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */
|
||||
if (!lua_isnil(L, -1)) { /* is there an entry? */
|
||||
plib = (void **)lua_touserdata(L, -1);
|
||||
} else { /* no entry yet; create one */
|
||||
lua_pop(L, 1);
|
||||
plib = (void **)lua_newuserdata(L, sizeof(void *));
|
||||
*plib = NULL;
|
||||
luaL_setmetatable(L, "_LOADLIB");
|
||||
lua_pushfstring(L, "LOADLIB: %s", path);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
return plib;
|
||||
}
|
||||
|
||||
static const char *mksymname(lua_State *L, const char *modname,
|
||||
const char *prefix)
|
||||
{
|
||||
const char *funcname;
|
||||
const char *mark = strchr(modname, *LUA_IGMARK);
|
||||
if (mark) modname = mark + 1;
|
||||
funcname = luaL_gsub(L, modname, ".", "_");
|
||||
funcname = lua_pushfstring(L, prefix, funcname);
|
||||
lua_remove(L, -2); /* remove 'gsub' result */
|
||||
return funcname;
|
||||
}
|
||||
|
||||
static int ll_loadfunc(lua_State *L, const char *path, const char *name, int r)
|
||||
{
|
||||
void **reg;
|
||||
if (strlen(path) >= 4096) {
|
||||
lua_pushliteral(L, "path too long");
|
||||
return PACKAGE_ERR_LIB;
|
||||
}
|
||||
reg = ll_register(L, path);
|
||||
if (*reg == NULL) *reg = ll_load(L, path, (*name == '*'));
|
||||
if (*reg == NULL) {
|
||||
return PACKAGE_ERR_LIB; /* Unable to load library. */
|
||||
} else if (*name == '*') { /* Only load library into global namespace. */
|
||||
lua_pushboolean(L, 1);
|
||||
return 0;
|
||||
} else {
|
||||
const char *sym = r ? name : mksymname(L, name, SYMPREFIX_CF);
|
||||
lua_CFunction f = ll_sym(L, *reg, sym);
|
||||
if (f) {
|
||||
lua_pushcfunction(L, f);
|
||||
return 0;
|
||||
}
|
||||
if (!r) {
|
||||
const char *bcdata = ll_bcsym(*reg, mksymname(L, name, SYMPREFIX_BC));
|
||||
lua_pop(L, 1);
|
||||
if (bcdata) {
|
||||
if (luaL_loadbuffer(L, bcdata, ~(size_t)0, name) != 0)
|
||||
return PACKAGE_ERR_LOAD;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return PACKAGE_ERR_FUNC; /* Unable to find function. */
|
||||
}
|
||||
}
|
||||
|
||||
static int lj_cf_package_loadlib(lua_State *L)
|
||||
{
|
||||
const char *path = luaL_checkstring(L, 1);
|
||||
const char *init = luaL_checkstring(L, 2);
|
||||
int st = ll_loadfunc(L, path, init, 1);
|
||||
if (st == 0) { /* no errors? */
|
||||
return 1; /* return the loaded function */
|
||||
} else { /* error; error message is on stack top */
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2);
|
||||
lua_pushstring(L, (st == PACKAGE_ERR_LIB) ? PACKAGE_LIB_FAIL : "init");
|
||||
return 3; /* return nil, error message, and where */
|
||||
}
|
||||
}
|
||||
|
||||
static int lj_cf_package_unloadlib(lua_State *L)
|
||||
{
|
||||
void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
|
||||
if (*lib) ll_unloadlib(*lib);
|
||||
*lib = NULL; /* mark library as closed */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int readable(const char *filename)
|
||||
{
|
||||
FILE *f = fopen(filename, "r"); /* try to open file */
|
||||
if (f == NULL) return 0; /* open failed */
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *pushnexttemplate(lua_State *L, const char *path)
|
||||
{
|
||||
const char *l;
|
||||
while (*path == *LUA_PATHSEP) path++; /* skip separators */
|
||||
if (*path == '\0') return NULL; /* no more templates */
|
||||
l = strchr(path, *LUA_PATHSEP); /* find next separator */
|
||||
if (l == NULL) l = path + strlen(path);
|
||||
lua_pushlstring(L, path, (size_t)(l - path)); /* template */
|
||||
return l;
|
||||
}
|
||||
|
||||
static const char *searchpath (lua_State *L, const char *name,
|
||||
const char *path, const char *sep,
|
||||
const char *dirsep)
|
||||
{
|
||||
luaL_Buffer msg; /* to build error message */
|
||||
luaL_buffinit(L, &msg);
|
||||
if (*sep != '\0') /* non-empty separator? */
|
||||
name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */
|
||||
while ((path = pushnexttemplate(L, path)) != NULL) {
|
||||
const char *filename = luaL_gsub(L, lua_tostring(L, -1),
|
||||
LUA_PATH_MARK, name);
|
||||
lua_remove(L, -2); /* remove path template */
|
||||
if (readable(filename)) /* does file exist and is readable? */
|
||||
return filename; /* return that file name */
|
||||
lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
|
||||
lua_remove(L, -2); /* remove file name */
|
||||
luaL_addvalue(&msg); /* concatenate error msg. entry */
|
||||
}
|
||||
luaL_pushresult(&msg); /* create error message */
|
||||
return NULL; /* not found */
|
||||
}
|
||||
|
||||
static int lj_cf_package_searchpath(lua_State *L)
|
||||
{
|
||||
const char *f = searchpath(L, luaL_checkstring(L, 1),
|
||||
luaL_checkstring(L, 2),
|
||||
luaL_optstring(L, 3, "."),
|
||||
luaL_optstring(L, 4, LUA_DIRSEP));
|
||||
if (f != NULL) {
|
||||
return 1;
|
||||
} else { /* error message is on top of the stack */
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2);
|
||||
return 2; /* return nil + error message */
|
||||
}
|
||||
}
|
||||
|
||||
static const char *findfile(lua_State *L, const char *name,
|
||||
const char *pname)
|
||||
{
|
||||
const char *path;
|
||||
lua_getfield(L, LUA_ENVIRONINDEX, pname);
|
||||
path = lua_tostring(L, -1);
|
||||
if (path == NULL)
|
||||
luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
|
||||
return searchpath(L, name, path, ".", LUA_DIRSEP);
|
||||
}
|
||||
|
||||
static void loaderror(lua_State *L, const char *filename)
|
||||
{
|
||||
luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s",
|
||||
lua_tostring(L, 1), filename, lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
static int lj_cf_package_loader_lua(lua_State *L)
|
||||
{
|
||||
const char *filename;
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
filename = findfile(L, name, "path");
|
||||
if (filename == NULL) return 1; /* library not found in this path */
|
||||
if (luaL_loadfile(L, filename) != 0)
|
||||
loaderror(L, filename);
|
||||
return 1; /* library loaded successfully */
|
||||
}
|
||||
|
||||
static int lj_cf_package_loader_c(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
const char *filename = findfile(L, name, "cpath");
|
||||
if (filename == NULL) return 1; /* library not found in this path */
|
||||
if (ll_loadfunc(L, filename, name, 0) != 0)
|
||||
loaderror(L, filename);
|
||||
return 1; /* library loaded successfully */
|
||||
}
|
||||
|
||||
static int lj_cf_package_loader_croot(lua_State *L)
|
||||
{
|
||||
const char *filename;
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
const char *p = strchr(name, '.');
|
||||
int st;
|
||||
if (p == NULL) return 0; /* is root */
|
||||
lua_pushlstring(L, name, (size_t)(p - name));
|
||||
filename = findfile(L, lua_tostring(L, -1), "cpath");
|
||||
if (filename == NULL) return 1; /* root not found */
|
||||
if ((st = ll_loadfunc(L, filename, name, 0)) != 0) {
|
||||
if (st != PACKAGE_ERR_FUNC) loaderror(L, filename); /* real error */
|
||||
lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
|
||||
name, filename);
|
||||
return 1; /* function not found */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lj_cf_package_loader_preload(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
lua_getfield(L, LUA_ENVIRONINDEX, "preload");
|
||||
if (!lua_istable(L, -1))
|
||||
luaL_error(L, LUA_QL("package.preload") " must be a table");
|
||||
lua_getfield(L, -1, name);
|
||||
if (lua_isnil(L, -1)) { /* Not found? */
|
||||
const char *bcname = mksymname(L, name, SYMPREFIX_BC);
|
||||
const char *bcdata = ll_bcsym(NULL, bcname);
|
||||
if (bcdata == NULL || luaL_loadbuffer(L, bcdata, ~(size_t)0, name) != 0)
|
||||
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define KEY_SENTINEL (U64x(80000000,00000000)|'s')
|
||||
|
||||
static int lj_cf_package_require(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
int i;
|
||||
lua_settop(L, 1); /* _LOADED table will be at index 2 */
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
|
||||
lua_getfield(L, 2, name);
|
||||
if (lua_toboolean(L, -1)) { /* is it there? */
|
||||
if ((L->top-1)->u64 == KEY_SENTINEL) /* check loops */
|
||||
luaL_error(L, "loop or previous error loading module " LUA_QS, name);
|
||||
return 1; /* package is already loaded */
|
||||
}
|
||||
/* else must load it; iterate over available loaders */
|
||||
lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
|
||||
if (!lua_istable(L, -1))
|
||||
luaL_error(L, LUA_QL("package.loaders") " must be a table");
|
||||
lua_pushliteral(L, ""); /* error message accumulator */
|
||||
for (i = 1; ; i++) {
|
||||
lua_rawgeti(L, -2, i); /* get a loader */
|
||||
if (lua_isnil(L, -1))
|
||||
luaL_error(L, "module " LUA_QS " not found:%s",
|
||||
name, lua_tostring(L, -2));
|
||||
lua_pushstring(L, name);
|
||||
lua_call(L, 1, 1); /* call it */
|
||||
if (lua_isfunction(L, -1)) /* did it find module? */
|
||||
break; /* module loaded successfully */
|
||||
else if (lua_isstring(L, -1)) /* loader returned error message? */
|
||||
lua_concat(L, 2); /* accumulate it */
|
||||
else
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
(L->top++)->u64 = KEY_SENTINEL;
|
||||
lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */
|
||||
lua_pushstring(L, name); /* pass name as argument to module */
|
||||
lua_call(L, 1, 1); /* run loaded module */
|
||||
if (!lua_isnil(L, -1)) /* non-nil return? */
|
||||
lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
|
||||
lua_getfield(L, 2, name);
|
||||
if ((L->top-1)->u64 == KEY_SENTINEL) { /* module did not set a value? */
|
||||
lua_pushboolean(L, 1); /* use true as result */
|
||||
lua_pushvalue(L, -1); /* extra copy to be returned */
|
||||
lua_setfield(L, 2, name); /* _LOADED[name] = true */
|
||||
}
|
||||
lj_lib_checkfpu(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static void setfenv(lua_State *L)
|
||||
{
|
||||
lua_Debug ar;
|
||||
if (lua_getstack(L, 1, &ar) == 0 ||
|
||||
lua_getinfo(L, "f", &ar) == 0 || /* get calling function */
|
||||
lua_iscfunction(L, -1))
|
||||
luaL_error(L, LUA_QL("module") " not called from a Lua function");
|
||||
lua_pushvalue(L, -2);
|
||||
lua_setfenv(L, -2);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
static void dooptions(lua_State *L, int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 2; i <= n; i++) {
|
||||
lua_pushvalue(L, i); /* get option (a function) */
|
||||
lua_pushvalue(L, -2); /* module */
|
||||
lua_call(L, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void modinit(lua_State *L, const char *modname)
|
||||
{
|
||||
const char *dot;
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "_M"); /* module._M = module */
|
||||
lua_pushstring(L, modname);
|
||||
lua_setfield(L, -2, "_NAME");
|
||||
dot = strrchr(modname, '.'); /* look for last dot in module name */
|
||||
if (dot == NULL) dot = modname; else dot++;
|
||||
/* set _PACKAGE as package name (full module name minus last part) */
|
||||
lua_pushlstring(L, modname, (size_t)(dot - modname));
|
||||
lua_setfield(L, -2, "_PACKAGE");
|
||||
}
|
||||
|
||||
static int lj_cf_package_module(lua_State *L)
|
||||
{
|
||||
const char *modname = luaL_checkstring(L, 1);
|
||||
int lastarg = (int)(L->top - L->base);
|
||||
luaL_pushmodule(L, modname, 1);
|
||||
lua_getfield(L, -1, "_NAME");
|
||||
if (!lua_isnil(L, -1)) { /* Module already initialized? */
|
||||
lua_pop(L, 1);
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
modinit(L, modname);
|
||||
}
|
||||
lua_pushvalue(L, -1);
|
||||
setfenv(L);
|
||||
dooptions(L, lastarg);
|
||||
return LJ_52;
|
||||
}
|
||||
|
||||
static int lj_cf_package_seeall(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
if (!lua_getmetatable(L, 1)) {
|
||||
lua_createtable(L, 0, 1); /* create new metatable */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setmetatable(L, 1);
|
||||
}
|
||||
lua_pushvalue(L, LUA_GLOBALSINDEX);
|
||||
lua_setfield(L, -2, "__index"); /* mt.__index = _G */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define AUXMARK "\1"
|
||||
|
||||
static void setpath(lua_State *L, const char *fieldname, const char *envname,
|
||||
const char *def, int noenv)
|
||||
{
|
||||
#if LJ_TARGET_CONSOLE
|
||||
const char *path = NULL;
|
||||
UNUSED(envname);
|
||||
#else
|
||||
const char *path = getenv(envname);
|
||||
#endif
|
||||
if (path == NULL || noenv) {
|
||||
lua_pushstring(L, def);
|
||||
} else {
|
||||
path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP,
|
||||
LUA_PATHSEP AUXMARK LUA_PATHSEP);
|
||||
luaL_gsub(L, path, AUXMARK, def);
|
||||
lua_remove(L, -2);
|
||||
}
|
||||
setprogdir(L);
|
||||
lua_setfield(L, -2, fieldname);
|
||||
}
|
||||
|
||||
static const luaL_Reg package_lib[] = {
|
||||
{ "loadlib", lj_cf_package_loadlib },
|
||||
{ "searchpath", lj_cf_package_searchpath },
|
||||
{ "seeall", lj_cf_package_seeall },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_Reg package_global[] = {
|
||||
{ "module", lj_cf_package_module },
|
||||
{ "require", lj_cf_package_require },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const lua_CFunction package_loaders[] =
|
||||
{
|
||||
lj_cf_package_loader_preload,
|
||||
lj_cf_package_loader_lua,
|
||||
lj_cf_package_loader_c,
|
||||
lj_cf_package_loader_croot,
|
||||
NULL
|
||||
};
|
||||
|
||||
LUALIB_API int luaopen_package(lua_State *L)
|
||||
{
|
||||
int i;
|
||||
int noenv;
|
||||
luaL_newmetatable(L, "_LOADLIB");
|
||||
lj_lib_pushcf(L, lj_cf_package_unloadlib, 1);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
luaL_register(L, LUA_LOADLIBNAME, package_lib);
|
||||
lua_copy(L, -1, LUA_ENVIRONINDEX);
|
||||
lua_createtable(L, sizeof(package_loaders)/sizeof(package_loaders[0])-1, 0);
|
||||
for (i = 0; package_loaders[i] != NULL; i++) {
|
||||
lj_lib_pushcf(L, package_loaders[i], 1);
|
||||
lua_rawseti(L, -2, i+1);
|
||||
}
|
||||
#if LJ_52
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -3, "searchers");
|
||||
#endif
|
||||
lua_setfield(L, -2, "loaders");
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
|
||||
noenv = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT, noenv);
|
||||
setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT, noenv);
|
||||
lua_pushliteral(L, LUA_PATH_CONFIG);
|
||||
lua_setfield(L, -2, "config");
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
|
||||
lua_setfield(L, -2, "loaded");
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD", 4);
|
||||
lua_setfield(L, -2, "preload");
|
||||
lua_pushvalue(L, LUA_GLOBALSINDEX);
|
||||
luaL_register(L, NULL, package_global);
|
||||
lua_pop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
690
thirdPart/luajit/src/lib_string.c
Normal file
690
thirdPart/luajit/src/lib_string.c
Normal file
@@ -0,0 +1,690 @@
|
||||
/*
|
||||
** String library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** Major portions taken verbatim or adapted from the Lua interpreter.
|
||||
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lib_string_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_gc.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_buf.h"
|
||||
#include "lj_str.h"
|
||||
#include "lj_tab.h"
|
||||
#include "lj_meta.h"
|
||||
#include "lj_state.h"
|
||||
#include "lj_ff.h"
|
||||
#include "lj_bcdump.h"
|
||||
#include "lj_char.h"
|
||||
#include "lj_strfmt.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define LJLIB_MODULE_string
|
||||
|
||||
LJLIB_LUA(string_len) /*
|
||||
function(s)
|
||||
CHECK_str(s)
|
||||
return #s
|
||||
end
|
||||
*/
|
||||
|
||||
LJLIB_ASM(string_byte) LJLIB_REC(string_range 0)
|
||||
{
|
||||
GCstr *s = lj_lib_checkstr(L, 1);
|
||||
int32_t len = (int32_t)s->len;
|
||||
int32_t start = lj_lib_optint(L, 2, 1);
|
||||
int32_t stop = lj_lib_optint(L, 3, start);
|
||||
int32_t n, i;
|
||||
const unsigned char *p;
|
||||
if (stop < 0) stop += len+1;
|
||||
if (start < 0) start += len+1;
|
||||
if (start <= 0) start = 1;
|
||||
if (stop > len) stop = len;
|
||||
if (start > stop) return FFH_RES(0); /* Empty interval: return no results. */
|
||||
start--;
|
||||
n = stop - start;
|
||||
if ((uint32_t)n > LUAI_MAXCSTACK)
|
||||
lj_err_caller(L, LJ_ERR_STRSLC);
|
||||
lj_state_checkstack(L, (MSize)n);
|
||||
p = (const unsigned char *)strdata(s) + start;
|
||||
for (i = 0; i < n; i++)
|
||||
setintV(L->base + i-1-LJ_FR2, p[i]);
|
||||
return FFH_RES(n);
|
||||
}
|
||||
|
||||
LJLIB_ASM(string_char) LJLIB_REC(.)
|
||||
{
|
||||
int i, nargs = (int)(L->top - L->base);
|
||||
char *buf = lj_buf_tmp(L, (MSize)nargs);
|
||||
for (i = 1; i <= nargs; i++) {
|
||||
int32_t k = lj_lib_checkint(L, i);
|
||||
if (!checku8(k))
|
||||
lj_err_arg(L, i, LJ_ERR_BADVAL);
|
||||
buf[i-1] = (char)k;
|
||||
}
|
||||
setstrV(L, L->base-1-LJ_FR2, lj_str_new(L, buf, (size_t)nargs));
|
||||
return FFH_RES(1);
|
||||
}
|
||||
|
||||
LJLIB_ASM(string_sub) LJLIB_REC(string_range 1)
|
||||
{
|
||||
lj_lib_checkstr(L, 1);
|
||||
lj_lib_checkint(L, 2);
|
||||
setintV(L->base+2, lj_lib_optint(L, 3, -1));
|
||||
return FFH_RETRY;
|
||||
}
|
||||
|
||||
LJLIB_CF(string_rep) LJLIB_REC(.)
|
||||
{
|
||||
GCstr *s = lj_lib_checkstr(L, 1);
|
||||
int32_t rep = lj_lib_checkint(L, 2);
|
||||
GCstr *sep = lj_lib_optstr(L, 3);
|
||||
SBuf *sb = lj_buf_tmp_(L);
|
||||
if (sep && rep > 1) {
|
||||
GCstr *s2 = lj_buf_cat2str(L, sep, s);
|
||||
lj_buf_reset(sb);
|
||||
lj_buf_putstr(sb, s);
|
||||
s = s2;
|
||||
rep--;
|
||||
}
|
||||
sb = lj_buf_putstr_rep(sb, s, rep);
|
||||
setstrV(L, L->top-1, lj_buf_str(L, sb));
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_ASM(string_reverse) LJLIB_REC(string_op IRCALL_lj_buf_putstr_reverse)
|
||||
{
|
||||
lj_lib_checkstr(L, 1);
|
||||
return FFH_RETRY;
|
||||
}
|
||||
LJLIB_ASM_(string_lower) LJLIB_REC(string_op IRCALL_lj_buf_putstr_lower)
|
||||
LJLIB_ASM_(string_upper) LJLIB_REC(string_op IRCALL_lj_buf_putstr_upper)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int writer_buf(lua_State *L, const void *p, size_t size, void *sb)
|
||||
{
|
||||
lj_buf_putmem((SBuf *)sb, p, (MSize)size);
|
||||
UNUSED(L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_CF(string_dump)
|
||||
{
|
||||
GCproto *pt = lj_lib_checkLproto(L, 1, 1);
|
||||
uint32_t flags = 0;
|
||||
SBuf *sb;
|
||||
TValue *o = L->base+1;
|
||||
if (o < L->top) {
|
||||
if (tvisstr(o)) {
|
||||
const char *mode = strVdata(o);
|
||||
char c;
|
||||
while ((c = *mode++)) {
|
||||
if (c == 's') flags |= BCDUMP_F_STRIP;
|
||||
if (c == 'd') flags |= BCDUMP_F_DETERMINISTIC;
|
||||
}
|
||||
} else if (tvistruecond(o)) {
|
||||
flags |= BCDUMP_F_STRIP;
|
||||
}
|
||||
}
|
||||
sb = lj_buf_tmp_(L); /* Assumes lj_bcwrite() doesn't use tmpbuf. */
|
||||
L->top = L->base+1;
|
||||
if (!pt || lj_bcwrite(L, pt, writer_buf, sb, flags))
|
||||
lj_err_caller(L, LJ_ERR_STRDUMP);
|
||||
setstrV(L, L->top-1, lj_buf_str(L, sb));
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* macro to `unsign' a character */
|
||||
#define uchar(c) ((unsigned char)(c))
|
||||
|
||||
#define CAP_UNFINISHED (-1)
|
||||
#define CAP_POSITION (-2)
|
||||
|
||||
typedef struct MatchState {
|
||||
const char *src_init; /* init of source string */
|
||||
const char *src_end; /* end (`\0') of source string */
|
||||
lua_State *L;
|
||||
int level; /* total number of captures (finished or unfinished) */
|
||||
int depth;
|
||||
struct {
|
||||
const char *init;
|
||||
ptrdiff_t len;
|
||||
} capture[LUA_MAXCAPTURES];
|
||||
} MatchState;
|
||||
|
||||
#define L_ESC '%'
|
||||
|
||||
static int check_capture(MatchState *ms, int l)
|
||||
{
|
||||
l -= '1';
|
||||
if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
|
||||
lj_err_caller(ms->L, LJ_ERR_STRCAPI);
|
||||
return l;
|
||||
}
|
||||
|
||||
static int capture_to_close(MatchState *ms)
|
||||
{
|
||||
int level = ms->level;
|
||||
for (level--; level>=0; level--)
|
||||
if (ms->capture[level].len == CAP_UNFINISHED) return level;
|
||||
lj_err_caller(ms->L, LJ_ERR_STRPATC);
|
||||
return 0; /* unreachable */
|
||||
}
|
||||
|
||||
static const char *classend(MatchState *ms, const char *p)
|
||||
{
|
||||
switch (*p++) {
|
||||
case L_ESC:
|
||||
if (*p == '\0')
|
||||
lj_err_caller(ms->L, LJ_ERR_STRPATE);
|
||||
return p+1;
|
||||
case '[':
|
||||
if (*p == '^') p++;
|
||||
do { /* look for a `]' */
|
||||
if (*p == '\0')
|
||||
lj_err_caller(ms->L, LJ_ERR_STRPATM);
|
||||
if (*(p++) == L_ESC && *p != '\0')
|
||||
p++; /* skip escapes (e.g. `%]') */
|
||||
} while (*p != ']');
|
||||
return p+1;
|
||||
default:
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned char match_class_map[32] = {
|
||||
0,LJ_CHAR_ALPHA,0,LJ_CHAR_CNTRL,LJ_CHAR_DIGIT,0,0,LJ_CHAR_GRAPH,0,0,0,0,
|
||||
LJ_CHAR_LOWER,0,0,0,LJ_CHAR_PUNCT,0,0,LJ_CHAR_SPACE,0,
|
||||
LJ_CHAR_UPPER,0,LJ_CHAR_ALNUM,LJ_CHAR_XDIGIT,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static int match_class(int c, int cl)
|
||||
{
|
||||
if ((cl & 0xc0) == 0x40) {
|
||||
int t = match_class_map[(cl&0x1f)];
|
||||
if (t) {
|
||||
t = lj_char_isa(c, t);
|
||||
return (cl & 0x20) ? t : !t;
|
||||
}
|
||||
if (cl == 'z') return c == 0;
|
||||
if (cl == 'Z') return c != 0;
|
||||
}
|
||||
return (cl == c);
|
||||
}
|
||||
|
||||
static int matchbracketclass(int c, const char *p, const char *ec)
|
||||
{
|
||||
int sig = 1;
|
||||
if (*(p+1) == '^') {
|
||||
sig = 0;
|
||||
p++; /* skip the `^' */
|
||||
}
|
||||
while (++p < ec) {
|
||||
if (*p == L_ESC) {
|
||||
p++;
|
||||
if (match_class(c, uchar(*p)))
|
||||
return sig;
|
||||
}
|
||||
else if ((*(p+1) == '-') && (p+2 < ec)) {
|
||||
p+=2;
|
||||
if (uchar(*(p-2)) <= c && c <= uchar(*p))
|
||||
return sig;
|
||||
}
|
||||
else if (uchar(*p) == c) return sig;
|
||||
}
|
||||
return !sig;
|
||||
}
|
||||
|
||||
static int singlematch(int c, const char *p, const char *ep)
|
||||
{
|
||||
switch (*p) {
|
||||
case '.': return 1; /* matches any char */
|
||||
case L_ESC: return match_class(c, uchar(*(p+1)));
|
||||
case '[': return matchbracketclass(c, p, ep-1);
|
||||
default: return (uchar(*p) == c);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *match(MatchState *ms, const char *s, const char *p);
|
||||
|
||||
static const char *matchbalance(MatchState *ms, const char *s, const char *p)
|
||||
{
|
||||
if (*p == 0 || *(p+1) == 0)
|
||||
lj_err_caller(ms->L, LJ_ERR_STRPATU);
|
||||
if (*s != *p) {
|
||||
return NULL;
|
||||
} else {
|
||||
int b = *p;
|
||||
int e = *(p+1);
|
||||
int cont = 1;
|
||||
while (++s < ms->src_end) {
|
||||
if (*s == e) {
|
||||
if (--cont == 0) return s+1;
|
||||
} else if (*s == b) {
|
||||
cont++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL; /* string ends out of balance */
|
||||
}
|
||||
|
||||
static const char *max_expand(MatchState *ms, const char *s,
|
||||
const char *p, const char *ep)
|
||||
{
|
||||
ptrdiff_t i = 0; /* counts maximum expand for item */
|
||||
while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
|
||||
i++;
|
||||
/* keeps trying to match with the maximum repetitions */
|
||||
while (i>=0) {
|
||||
const char *res = match(ms, (s+i), ep+1);
|
||||
if (res) return res;
|
||||
i--; /* else didn't match; reduce 1 repetition to try again */
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *min_expand(MatchState *ms, const char *s,
|
||||
const char *p, const char *ep)
|
||||
{
|
||||
for (;;) {
|
||||
const char *res = match(ms, s, ep+1);
|
||||
if (res != NULL)
|
||||
return res;
|
||||
else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
|
||||
s++; /* try with one more repetition */
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *start_capture(MatchState *ms, const char *s,
|
||||
const char *p, int what)
|
||||
{
|
||||
const char *res;
|
||||
int level = ms->level;
|
||||
if (level >= LUA_MAXCAPTURES) lj_err_caller(ms->L, LJ_ERR_STRCAPN);
|
||||
ms->capture[level].init = s;
|
||||
ms->capture[level].len = what;
|
||||
ms->level = level+1;
|
||||
if ((res=match(ms, s, p)) == NULL) /* match failed? */
|
||||
ms->level--; /* undo capture */
|
||||
return res;
|
||||
}
|
||||
|
||||
static const char *end_capture(MatchState *ms, const char *s,
|
||||
const char *p)
|
||||
{
|
||||
int l = capture_to_close(ms);
|
||||
const char *res;
|
||||
ms->capture[l].len = s - ms->capture[l].init; /* close capture */
|
||||
if ((res = match(ms, s, p)) == NULL) /* match failed? */
|
||||
ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
|
||||
return res;
|
||||
}
|
||||
|
||||
static const char *match_capture(MatchState *ms, const char *s, int l)
|
||||
{
|
||||
size_t len;
|
||||
l = check_capture(ms, l);
|
||||
len = (size_t)ms->capture[l].len;
|
||||
if ((size_t)(ms->src_end-s) >= len &&
|
||||
memcmp(ms->capture[l].init, s, len) == 0)
|
||||
return s+len;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *match(MatchState *ms, const char *s, const char *p)
|
||||
{
|
||||
if (++ms->depth > LJ_MAX_XLEVEL)
|
||||
lj_err_caller(ms->L, LJ_ERR_STRPATX);
|
||||
init: /* using goto's to optimize tail recursion */
|
||||
switch (*p) {
|
||||
case '(': /* start capture */
|
||||
if (*(p+1) == ')') /* position capture? */
|
||||
s = start_capture(ms, s, p+2, CAP_POSITION);
|
||||
else
|
||||
s = start_capture(ms, s, p+1, CAP_UNFINISHED);
|
||||
break;
|
||||
case ')': /* end capture */
|
||||
s = end_capture(ms, s, p+1);
|
||||
break;
|
||||
case L_ESC:
|
||||
switch (*(p+1)) {
|
||||
case 'b': /* balanced string? */
|
||||
s = matchbalance(ms, s, p+2);
|
||||
if (s == NULL) break;
|
||||
p+=4;
|
||||
goto init; /* else s = match(ms, s, p+4); */
|
||||
case 'f': { /* frontier? */
|
||||
const char *ep; char previous;
|
||||
p += 2;
|
||||
if (*p != '[')
|
||||
lj_err_caller(ms->L, LJ_ERR_STRPATB);
|
||||
ep = classend(ms, p); /* points to what is next */
|
||||
previous = (s == ms->src_init) ? '\0' : *(s-1);
|
||||
if (matchbracketclass(uchar(previous), p, ep-1) ||
|
||||
!matchbracketclass(uchar(*s), p, ep-1)) { s = NULL; break; }
|
||||
p=ep;
|
||||
goto init; /* else s = match(ms, s, ep); */
|
||||
}
|
||||
default:
|
||||
if (lj_char_isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */
|
||||
s = match_capture(ms, s, uchar(*(p+1)));
|
||||
if (s == NULL) break;
|
||||
p+=2;
|
||||
goto init; /* else s = match(ms, s, p+2) */
|
||||
}
|
||||
goto dflt; /* case default */
|
||||
}
|
||||
break;
|
||||
case '\0': /* end of pattern */
|
||||
break; /* match succeeded */
|
||||
case '$':
|
||||
/* is the `$' the last char in pattern? */
|
||||
if (*(p+1) != '\0') goto dflt;
|
||||
if (s != ms->src_end) s = NULL; /* check end of string */
|
||||
break;
|
||||
default: dflt: { /* it is a pattern item */
|
||||
const char *ep = classend(ms, p); /* points to what is next */
|
||||
int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
|
||||
switch (*ep) {
|
||||
case '?': { /* optional */
|
||||
const char *res;
|
||||
if (m && ((res=match(ms, s+1, ep+1)) != NULL)) {
|
||||
s = res;
|
||||
break;
|
||||
}
|
||||
p=ep+1;
|
||||
goto init; /* else s = match(ms, s, ep+1); */
|
||||
}
|
||||
case '*': /* 0 or more repetitions */
|
||||
s = max_expand(ms, s, p, ep);
|
||||
break;
|
||||
case '+': /* 1 or more repetitions */
|
||||
s = (m ? max_expand(ms, s+1, p, ep) : NULL);
|
||||
break;
|
||||
case '-': /* 0 or more repetitions (minimum) */
|
||||
s = min_expand(ms, s, p, ep);
|
||||
break;
|
||||
default:
|
||||
if (m) { s++; p=ep; goto init; } /* else s = match(ms, s+1, ep); */
|
||||
s = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ms->depth--;
|
||||
return s;
|
||||
}
|
||||
|
||||
static void push_onecapture(MatchState *ms, int i, const char *s, const char *e)
|
||||
{
|
||||
if (i >= ms->level) {
|
||||
if (i == 0) /* ms->level == 0, too */
|
||||
lua_pushlstring(ms->L, s, (size_t)(e - s)); /* add whole match */
|
||||
else
|
||||
lj_err_caller(ms->L, LJ_ERR_STRCAPI);
|
||||
} else {
|
||||
ptrdiff_t l = ms->capture[i].len;
|
||||
if (l == CAP_UNFINISHED) lj_err_caller(ms->L, LJ_ERR_STRCAPU);
|
||||
if (l == CAP_POSITION)
|
||||
lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
|
||||
else
|
||||
lua_pushlstring(ms->L, ms->capture[i].init, (size_t)l);
|
||||
}
|
||||
}
|
||||
|
||||
static int push_captures(MatchState *ms, const char *s, const char *e)
|
||||
{
|
||||
int i;
|
||||
int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
|
||||
luaL_checkstack(ms->L, nlevels, "too many captures");
|
||||
for (i = 0; i < nlevels; i++)
|
||||
push_onecapture(ms, i, s, e);
|
||||
return nlevels; /* number of strings pushed */
|
||||
}
|
||||
|
||||
static int str_find_aux(lua_State *L, int find)
|
||||
{
|
||||
GCstr *s = lj_lib_checkstr(L, 1);
|
||||
GCstr *p = lj_lib_checkstr(L, 2);
|
||||
int32_t start = lj_lib_optint(L, 3, 1);
|
||||
MSize st;
|
||||
if (start < 0) start += (int32_t)s->len; else start--;
|
||||
if (start < 0) start = 0;
|
||||
st = (MSize)start;
|
||||
if (st > s->len) {
|
||||
#if LJ_52
|
||||
setnilV(L->top-1);
|
||||
return 1;
|
||||
#else
|
||||
st = s->len;
|
||||
#endif
|
||||
}
|
||||
if (find && ((L->base+3 < L->top && tvistruecond(L->base+3)) ||
|
||||
!lj_str_haspattern(p))) { /* Search for fixed string. */
|
||||
const char *q = lj_str_find(strdata(s)+st, strdata(p), s->len-st, p->len);
|
||||
if (q) {
|
||||
setintV(L->top-2, (int32_t)(q-strdata(s)) + 1);
|
||||
setintV(L->top-1, (int32_t)(q-strdata(s)) + (int32_t)p->len);
|
||||
return 2;
|
||||
}
|
||||
} else { /* Search for pattern. */
|
||||
MatchState ms;
|
||||
const char *pstr = strdata(p);
|
||||
const char *sstr = strdata(s) + st;
|
||||
int anchor = 0;
|
||||
if (*pstr == '^') { pstr++; anchor = 1; }
|
||||
ms.L = L;
|
||||
ms.src_init = strdata(s);
|
||||
ms.src_end = strdata(s) + s->len;
|
||||
do { /* Loop through string and try to match the pattern. */
|
||||
const char *q;
|
||||
ms.level = ms.depth = 0;
|
||||
q = match(&ms, sstr, pstr);
|
||||
if (q) {
|
||||
if (find) {
|
||||
setintV(L->top++, (int32_t)(sstr-(strdata(s)-1)));
|
||||
setintV(L->top++, (int32_t)(q-strdata(s)));
|
||||
return push_captures(&ms, NULL, NULL) + 2;
|
||||
} else {
|
||||
return push_captures(&ms, sstr, q);
|
||||
}
|
||||
}
|
||||
} while (sstr++ < ms.src_end && !anchor);
|
||||
}
|
||||
setnilV(L->top-1); /* Not found. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(string_find) LJLIB_REC(.)
|
||||
{
|
||||
return str_find_aux(L, 1);
|
||||
}
|
||||
|
||||
LJLIB_CF(string_match)
|
||||
{
|
||||
return str_find_aux(L, 0);
|
||||
}
|
||||
|
||||
LJLIB_NOREG LJLIB_CF(string_gmatch_aux)
|
||||
{
|
||||
const char *p = strVdata(lj_lib_upvalue(L, 2));
|
||||
GCstr *str = strV(lj_lib_upvalue(L, 1));
|
||||
const char *s = strdata(str);
|
||||
TValue *tvpos = lj_lib_upvalue(L, 3);
|
||||
const char *src = s + tvpos->u32.lo;
|
||||
MatchState ms;
|
||||
ms.L = L;
|
||||
ms.src_init = s;
|
||||
ms.src_end = s + str->len;
|
||||
for (; src <= ms.src_end; src++) {
|
||||
const char *e;
|
||||
ms.level = ms.depth = 0;
|
||||
if ((e = match(&ms, src, p)) != NULL) {
|
||||
int32_t pos = (int32_t)(e - s);
|
||||
if (e == src) pos++; /* Ensure progress for empty match. */
|
||||
tvpos->u32.lo = (uint32_t)pos;
|
||||
return push_captures(&ms, src, e);
|
||||
}
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
LJLIB_CF(string_gmatch)
|
||||
{
|
||||
lj_lib_checkstr(L, 1);
|
||||
lj_lib_checkstr(L, 2);
|
||||
L->top = L->base+3;
|
||||
(L->top-1)->u64 = 0;
|
||||
lj_lib_pushcc(L, lj_cf_string_gmatch_aux, FF_string_gmatch_aux, 3);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void add_s(MatchState *ms, luaL_Buffer *b, const char *s, const char *e)
|
||||
{
|
||||
size_t l, i;
|
||||
const char *news = lua_tolstring(ms->L, 3, &l);
|
||||
for (i = 0; i < l; i++) {
|
||||
if (news[i] != L_ESC) {
|
||||
luaL_addchar(b, news[i]);
|
||||
} else {
|
||||
i++; /* skip ESC */
|
||||
if (!lj_char_isdigit(uchar(news[i]))) {
|
||||
luaL_addchar(b, news[i]);
|
||||
} else if (news[i] == '0') {
|
||||
luaL_addlstring(b, s, (size_t)(e - s));
|
||||
} else {
|
||||
push_onecapture(ms, news[i] - '1', s, e);
|
||||
luaL_addvalue(b); /* add capture to accumulated result */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void add_value(MatchState *ms, luaL_Buffer *b,
|
||||
const char *s, const char *e)
|
||||
{
|
||||
lua_State *L = ms->L;
|
||||
switch (lua_type(L, 3)) {
|
||||
case LUA_TNUMBER:
|
||||
case LUA_TSTRING: {
|
||||
add_s(ms, b, s, e);
|
||||
return;
|
||||
}
|
||||
case LUA_TFUNCTION: {
|
||||
int n;
|
||||
lua_pushvalue(L, 3);
|
||||
n = push_captures(ms, s, e);
|
||||
lua_call(L, n, 1);
|
||||
break;
|
||||
}
|
||||
case LUA_TTABLE: {
|
||||
push_onecapture(ms, 0, s, e);
|
||||
lua_gettable(L, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!lua_toboolean(L, -1)) { /* nil or false? */
|
||||
lua_pop(L, 1);
|
||||
lua_pushlstring(L, s, (size_t)(e - s)); /* keep original text */
|
||||
} else if (!lua_isstring(L, -1)) {
|
||||
lj_err_callerv(L, LJ_ERR_STRGSRV, luaL_typename(L, -1));
|
||||
}
|
||||
luaL_addvalue(b); /* add result to accumulator */
|
||||
}
|
||||
|
||||
LJLIB_CF(string_gsub)
|
||||
{
|
||||
size_t srcl;
|
||||
const char *src = luaL_checklstring(L, 1, &srcl);
|
||||
const char *p = luaL_checkstring(L, 2);
|
||||
int tr = lua_type(L, 3);
|
||||
int max_s = luaL_optint(L, 4, (int)(srcl+1));
|
||||
int anchor = (*p == '^') ? (p++, 1) : 0;
|
||||
int n = 0;
|
||||
MatchState ms;
|
||||
luaL_Buffer b;
|
||||
if (!(tr == LUA_TNUMBER || tr == LUA_TSTRING ||
|
||||
tr == LUA_TFUNCTION || tr == LUA_TTABLE))
|
||||
lj_err_arg(L, 3, LJ_ERR_NOSFT);
|
||||
luaL_buffinit(L, &b);
|
||||
ms.L = L;
|
||||
ms.src_init = src;
|
||||
ms.src_end = src+srcl;
|
||||
while (n < max_s) {
|
||||
const char *e;
|
||||
ms.level = ms.depth = 0;
|
||||
e = match(&ms, src, p);
|
||||
if (e) {
|
||||
n++;
|
||||
add_value(&ms, &b, src, e);
|
||||
}
|
||||
if (e && e>src) /* non empty match? */
|
||||
src = e; /* skip it */
|
||||
else if (src < ms.src_end)
|
||||
luaL_addchar(&b, *src++);
|
||||
else
|
||||
break;
|
||||
if (anchor)
|
||||
break;
|
||||
}
|
||||
luaL_addlstring(&b, src, (size_t)(ms.src_end-src));
|
||||
luaL_pushresult(&b);
|
||||
lua_pushinteger(L, n); /* number of substitutions */
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
LJLIB_CF(string_format) LJLIB_REC(.)
|
||||
{
|
||||
int retry = 0;
|
||||
SBuf *sb;
|
||||
do {
|
||||
sb = lj_buf_tmp_(L);
|
||||
retry = lj_strfmt_putarg(L, sb, 1, -retry);
|
||||
} while (retry > 0);
|
||||
setstrV(L, L->top-1, lj_buf_str(L, sb));
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
LUALIB_API int luaopen_string(lua_State *L)
|
||||
{
|
||||
GCtab *mt;
|
||||
global_State *g;
|
||||
LJ_LIB_REG(L, LUA_STRLIBNAME, string);
|
||||
mt = lj_tab_new(L, 0, 1);
|
||||
/* NOBARRIER: basemt is a GC root. */
|
||||
g = G(L);
|
||||
setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt));
|
||||
settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1));
|
||||
mt->nomm = (uint8_t)(~(1u<<MM_index));
|
||||
#if LJ_HASBUFFER
|
||||
lj_lib_prereg(L, LUA_STRLIBNAME ".buffer", luaopen_string_buffer, tabV(L->top-1));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
327
thirdPart/luajit/src/lib_table.c
Normal file
327
thirdPart/luajit/src/lib_table.c
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
** Table library.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
**
|
||||
** Major portions taken verbatim or adapted from the Lua interpreter.
|
||||
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lib_table_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_gc.h"
|
||||
#include "lj_err.h"
|
||||
#include "lj_buf.h"
|
||||
#include "lj_tab.h"
|
||||
#include "lj_ff.h"
|
||||
#include "lj_lib.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define LJLIB_MODULE_table
|
||||
|
||||
LJLIB_LUA(table_foreachi) /*
|
||||
function(t, f)
|
||||
CHECK_tab(t)
|
||||
CHECK_func(f)
|
||||
for i=1,#t do
|
||||
local r = f(i, t[i])
|
||||
if r ~= nil then return r end
|
||||
end
|
||||
end
|
||||
*/
|
||||
|
||||
LJLIB_LUA(table_foreach) /*
|
||||
function(t, f)
|
||||
CHECK_tab(t)
|
||||
CHECK_func(f)
|
||||
for k, v in PAIRS(t) do
|
||||
local r = f(k, v)
|
||||
if r ~= nil then return r end
|
||||
end
|
||||
end
|
||||
*/
|
||||
|
||||
LJLIB_LUA(table_getn) /*
|
||||
function(t)
|
||||
CHECK_tab(t)
|
||||
return #t
|
||||
end
|
||||
*/
|
||||
|
||||
LJLIB_CF(table_maxn)
|
||||
{
|
||||
GCtab *t = lj_lib_checktab(L, 1);
|
||||
TValue *array = tvref(t->array);
|
||||
Node *node;
|
||||
lua_Number m = 0;
|
||||
ptrdiff_t i;
|
||||
for (i = (ptrdiff_t)t->asize - 1; i >= 0; i--)
|
||||
if (!tvisnil(&array[i])) {
|
||||
m = (lua_Number)(int32_t)i;
|
||||
break;
|
||||
}
|
||||
node = noderef(t->node);
|
||||
for (i = (ptrdiff_t)t->hmask; i >= 0; i--)
|
||||
if (!tvisnil(&node[i].val) && tvisnumber(&node[i].key)) {
|
||||
lua_Number n = numberVnum(&node[i].key);
|
||||
if (n > m) m = n;
|
||||
}
|
||||
setnumV(L->top-1, m);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_CF(table_insert) LJLIB_REC(.)
|
||||
{
|
||||
GCtab *t = lj_lib_checktab(L, 1);
|
||||
int32_t n, i = (int32_t)lj_tab_len(t) + 1;
|
||||
int nargs = (int)((char *)L->top - (char *)L->base);
|
||||
if (nargs != 2*sizeof(TValue)) {
|
||||
if (nargs != 3*sizeof(TValue))
|
||||
lj_err_caller(L, LJ_ERR_TABINS);
|
||||
/* NOBARRIER: This just moves existing elements around. */
|
||||
for (n = lj_lib_checkint(L, 2); i > n; i--) {
|
||||
/* The set may invalidate the get pointer, so need to do it first! */
|
||||
TValue *dst = lj_tab_setint(L, t, i);
|
||||
cTValue *src = lj_tab_getint(t, i-1);
|
||||
if (src) {
|
||||
copyTV(L, dst, src);
|
||||
} else {
|
||||
setnilV(dst);
|
||||
}
|
||||
}
|
||||
i = n;
|
||||
}
|
||||
{
|
||||
TValue *dst = lj_tab_setint(L, t, i);
|
||||
copyTV(L, dst, L->top-1); /* Set new value. */
|
||||
lj_gc_barriert(L, t, dst);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LJLIB_LUA(table_remove) /*
|
||||
function(t, pos)
|
||||
CHECK_tab(t)
|
||||
local len = #t
|
||||
if pos == nil then
|
||||
if len ~= 0 then
|
||||
local old = t[len]
|
||||
t[len] = nil
|
||||
return old
|
||||
end
|
||||
else
|
||||
CHECK_int(pos)
|
||||
if pos >= 1 and pos <= len then
|
||||
local old = t[pos]
|
||||
for i=pos+1,len do
|
||||
t[i-1] = t[i]
|
||||
end
|
||||
t[len] = nil
|
||||
return old
|
||||
end
|
||||
end
|
||||
end
|
||||
*/
|
||||
|
||||
LJLIB_LUA(table_move) /*
|
||||
function(a1, f, e, t, a2)
|
||||
CHECK_tab(a1)
|
||||
CHECK_int(f)
|
||||
CHECK_int(e)
|
||||
CHECK_int(t)
|
||||
if a2 == nil then a2 = a1 end
|
||||
CHECK_tab(a2)
|
||||
if e >= f then
|
||||
local d = t - f
|
||||
if t > e or t <= f or a2 ~= a1 then
|
||||
for i=f,e do a2[i+d] = a1[i] end
|
||||
else
|
||||
for i=e,f,-1 do a2[i+d] = a1[i] end
|
||||
end
|
||||
end
|
||||
return a2
|
||||
end
|
||||
*/
|
||||
|
||||
LJLIB_CF(table_concat) LJLIB_REC(.)
|
||||
{
|
||||
GCtab *t = lj_lib_checktab(L, 1);
|
||||
GCstr *sep = lj_lib_optstr(L, 2);
|
||||
int32_t i = lj_lib_optint(L, 3, 1);
|
||||
int32_t e = (L->base+3 < L->top && !tvisnil(L->base+3)) ?
|
||||
lj_lib_checkint(L, 4) : (int32_t)lj_tab_len(t);
|
||||
SBuf *sb = lj_buf_tmp_(L);
|
||||
SBuf *sbx = lj_buf_puttab(sb, t, sep, i, e);
|
||||
if (LJ_UNLIKELY(!sbx)) { /* Error: bad element type. */
|
||||
int32_t idx = (int32_t)(intptr_t)sb->w;
|
||||
cTValue *o = lj_tab_getint(t, idx);
|
||||
lj_err_callerv(L, LJ_ERR_TABCAT,
|
||||
lj_obj_itypename[o ? itypemap(o) : ~LJ_TNIL], idx);
|
||||
}
|
||||
setstrV(L, L->top-1, lj_buf_str(L, sbx));
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static void set2(lua_State *L, int i, int j)
|
||||
{
|
||||
lua_rawseti(L, 1, i);
|
||||
lua_rawseti(L, 1, j);
|
||||
}
|
||||
|
||||
static int sort_comp(lua_State *L, int a, int b)
|
||||
{
|
||||
if (!lua_isnil(L, 2)) { /* function? */
|
||||
int res;
|
||||
lua_pushvalue(L, 2);
|
||||
lua_pushvalue(L, a-1); /* -1 to compensate function */
|
||||
lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */
|
||||
lua_call(L, 2, 1);
|
||||
res = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return res;
|
||||
} else { /* a < b? */
|
||||
return lua_lessthan(L, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
static void auxsort(lua_State *L, int l, int u)
|
||||
{
|
||||
while (l < u) { /* for tail recursion */
|
||||
int i, j;
|
||||
/* sort elements a[l], a[(l+u)/2] and a[u] */
|
||||
lua_rawgeti(L, 1, l);
|
||||
lua_rawgeti(L, 1, u);
|
||||
if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
|
||||
set2(L, l, u); /* swap a[l] - a[u] */
|
||||
else
|
||||
lua_pop(L, 2);
|
||||
if (u-l == 1) break; /* only 2 elements */
|
||||
i = (l+u)/2;
|
||||
lua_rawgeti(L, 1, i);
|
||||
lua_rawgeti(L, 1, l);
|
||||
if (sort_comp(L, -2, -1)) { /* a[i]<a[l]? */
|
||||
set2(L, i, l);
|
||||
} else {
|
||||
lua_pop(L, 1); /* remove a[l] */
|
||||
lua_rawgeti(L, 1, u);
|
||||
if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
|
||||
set2(L, i, u);
|
||||
else
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
if (u-l == 2) break; /* only 3 elements */
|
||||
lua_rawgeti(L, 1, i); /* Pivot */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_rawgeti(L, 1, u-1);
|
||||
set2(L, i, u-1);
|
||||
/* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
|
||||
i = l; j = u-1;
|
||||
for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
|
||||
/* repeat ++i until a[i] >= P */
|
||||
while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
|
||||
if (i>=u) lj_err_caller(L, LJ_ERR_TABSORT);
|
||||
lua_pop(L, 1); /* remove a[i] */
|
||||
}
|
||||
/* repeat --j until a[j] <= P */
|
||||
while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
|
||||
if (j<=l) lj_err_caller(L, LJ_ERR_TABSORT);
|
||||
lua_pop(L, 1); /* remove a[j] */
|
||||
}
|
||||
if (j<i) {
|
||||
lua_pop(L, 3); /* pop pivot, a[i], a[j] */
|
||||
break;
|
||||
}
|
||||
set2(L, i, j);
|
||||
}
|
||||
lua_rawgeti(L, 1, u-1);
|
||||
lua_rawgeti(L, 1, i);
|
||||
set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */
|
||||
/* a[l..i-1] <= a[i] == P <= a[i+1..u] */
|
||||
/* adjust so that smaller half is in [j..i] and larger one in [l..u] */
|
||||
if (i-l < u-i) {
|
||||
j=l; i=i-1; l=i+2;
|
||||
} else {
|
||||
j=i+1; i=u; u=j-2;
|
||||
}
|
||||
auxsort(L, j, i); /* call recursively the smaller one */
|
||||
} /* repeat the routine for the larger one */
|
||||
}
|
||||
|
||||
LJLIB_CF(table_sort)
|
||||
{
|
||||
GCtab *t = lj_lib_checktab(L, 1);
|
||||
int32_t n = (int32_t)lj_tab_len(t);
|
||||
lua_settop(L, 2);
|
||||
if (!tvisnil(L->base+1))
|
||||
lj_lib_checkfunc(L, 2);
|
||||
auxsort(L, 1, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LJ_52
|
||||
LJLIB_PUSH("n")
|
||||
LJLIB_CF(table_pack)
|
||||
{
|
||||
TValue *array, *base = L->base;
|
||||
MSize i, n = (uint32_t)(L->top - base);
|
||||
GCtab *t = lj_tab_new(L, n ? n+1 : 0, 1);
|
||||
/* NOBARRIER: The table is new (marked white). */
|
||||
setintV(lj_tab_setstr(L, t, strV(lj_lib_upvalue(L, 1))), (int32_t)n);
|
||||
for (array = tvref(t->array) + 1, i = 0; i < n; i++)
|
||||
copyTV(L, &array[i], &base[i]);
|
||||
settabV(L, base, t);
|
||||
L->top = base+1;
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
LJLIB_NOREG LJLIB_CF(table_new) LJLIB_REC(.)
|
||||
{
|
||||
int32_t a = lj_lib_checkint(L, 1);
|
||||
int32_t h = lj_lib_checkint(L, 2);
|
||||
lua_createtable(L, a, h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_NOREG LJLIB_CF(table_clear) LJLIB_REC(.)
|
||||
{
|
||||
lj_tab_clear(lj_lib_checktab(L, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaopen_table_new(lua_State *L)
|
||||
{
|
||||
return lj_lib_postreg(L, lj_cf_table_new, FF_table_new, "new");
|
||||
}
|
||||
|
||||
static int luaopen_table_clear(lua_State *L)
|
||||
{
|
||||
return lj_lib_postreg(L, lj_cf_table_clear, FF_table_clear, "clear");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#include "lj_libdef.h"
|
||||
|
||||
LUALIB_API int luaopen_table(lua_State *L)
|
||||
{
|
||||
LJ_LIB_REG(L, LUA_TABLIBNAME, table);
|
||||
#if LJ_52
|
||||
lua_getglobal(L, "unpack");
|
||||
lua_setfield(L, -2, "unpack");
|
||||
#endif
|
||||
lj_lib_prereg(L, LUA_TABLIBNAME ".new", luaopen_table_new, tabV(L->top-1));
|
||||
lj_lib_prereg(L, LUA_TABLIBNAME ".clear", luaopen_table_clear, tabV(L->top-1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
1485
thirdPart/luajit/src/lj_alloc.c
Normal file
1485
thirdPart/luajit/src/lj_alloc.c
Normal file
File diff suppressed because it is too large
Load Diff
18
thirdPart/luajit/src/lj_alloc.h
Normal file
18
thirdPart/luajit/src/lj_alloc.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
** Bundled memory allocator.
|
||||
** Donated to the public domain.
|
||||
*/
|
||||
|
||||
#ifndef _LJ_ALLOC_H
|
||||
#define _LJ_ALLOC_H
|
||||
|
||||
#include "lj_def.h"
|
||||
|
||||
#ifndef LUAJIT_USE_SYSMALLOC
|
||||
LJ_FUNC void *lj_alloc_create(PRNGState *rs);
|
||||
LJ_FUNC void lj_alloc_setprng(void *msp, PRNGState *rs);
|
||||
LJ_FUNC void lj_alloc_destroy(void *msp);
|
||||
LJ_FUNC void *lj_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1319
thirdPart/luajit/src/lj_api.c
Normal file
1319
thirdPart/luajit/src/lj_api.c
Normal file
File diff suppressed because it is too large
Load Diff
742
thirdPart/luajit/src/lj_arch.h
Normal file
742
thirdPart/luajit/src/lj_arch.h
Normal file
@@ -0,0 +1,742 @@
|
||||
/*
|
||||
** Target architecture selection.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#ifndef _LJ_ARCH_H
|
||||
#define _LJ_ARCH_H
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
/* -- Target definitions -------------------------------------------------- */
|
||||
|
||||
/* Target endianess. */
|
||||
#define LUAJIT_LE 0
|
||||
#define LUAJIT_BE 1
|
||||
|
||||
/* Target architectures. */
|
||||
#define LUAJIT_ARCH_X86 1
|
||||
#define LUAJIT_ARCH_x86 1
|
||||
#define LUAJIT_ARCH_X64 2
|
||||
#define LUAJIT_ARCH_x64 2
|
||||
#define LUAJIT_ARCH_ARM 3
|
||||
#define LUAJIT_ARCH_arm 3
|
||||
#define LUAJIT_ARCH_ARM64 4
|
||||
#define LUAJIT_ARCH_arm64 4
|
||||
#define LUAJIT_ARCH_PPC 5
|
||||
#define LUAJIT_ARCH_ppc 5
|
||||
#define LUAJIT_ARCH_MIPS 6
|
||||
#define LUAJIT_ARCH_mips 6
|
||||
#define LUAJIT_ARCH_MIPS32 6
|
||||
#define LUAJIT_ARCH_mips32 6
|
||||
#define LUAJIT_ARCH_MIPS64 7
|
||||
#define LUAJIT_ARCH_mips64 7
|
||||
|
||||
/* Target OS. */
|
||||
#define LUAJIT_OS_OTHER 0
|
||||
#define LUAJIT_OS_WINDOWS 1
|
||||
#define LUAJIT_OS_LINUX 2
|
||||
#define LUAJIT_OS_OSX 3
|
||||
#define LUAJIT_OS_BSD 4
|
||||
#define LUAJIT_OS_POSIX 5
|
||||
|
||||
/* Number mode. */
|
||||
#define LJ_NUMMODE_SINGLE 0 /* Single-number mode only. */
|
||||
#define LJ_NUMMODE_SINGLE_DUAL 1 /* Default to single-number mode. */
|
||||
#define LJ_NUMMODE_DUAL 2 /* Dual-number mode only. */
|
||||
#define LJ_NUMMODE_DUAL_SINGLE 3 /* Default to dual-number mode. */
|
||||
|
||||
/* -- Target detection ---------------------------------------------------- */
|
||||
|
||||
/* Select native target if no target defined. */
|
||||
#ifndef LUAJIT_TARGET
|
||||
|
||||
#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
||||
#define LUAJIT_TARGET LUAJIT_ARCH_X86
|
||||
#elif defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
|
||||
#define LUAJIT_TARGET LUAJIT_ARCH_X64
|
||||
#elif defined(__arm__) || defined(__arm) || defined(__ARM__) || defined(__ARM)
|
||||
#define LUAJIT_TARGET LUAJIT_ARCH_ARM
|
||||
#elif defined(__aarch64__) || defined(_M_ARM64)
|
||||
#define LUAJIT_TARGET LUAJIT_ARCH_ARM64
|
||||
#elif defined(__ppc__) || defined(__ppc) || defined(__PPC__) || defined(__PPC) || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) || defined(__POWERPC) || defined(_M_PPC)
|
||||
#define LUAJIT_TARGET LUAJIT_ARCH_PPC
|
||||
#elif defined(__mips64__) || defined(__mips64) || defined(__MIPS64__) || defined(__MIPS64)
|
||||
#define LUAJIT_TARGET LUAJIT_ARCH_MIPS64
|
||||
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(__MIPS)
|
||||
#define LUAJIT_TARGET LUAJIT_ARCH_MIPS32
|
||||
#else
|
||||
#error "Architecture not supported (in this version), see: https://luajit.org/status.html#architectures"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Select native OS if no target OS defined. */
|
||||
#ifndef LUAJIT_OS
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX_VER)
|
||||
#define LUAJIT_OS LUAJIT_OS_WINDOWS
|
||||
#elif defined(__linux__)
|
||||
#define LUAJIT_OS LUAJIT_OS_LINUX
|
||||
#elif defined(__MACH__) && defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#define LUAJIT_OS LUAJIT_OS_OSX
|
||||
#elif (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__) || defined(__OpenBSD__) || \
|
||||
defined(__DragonFly__)) && !defined(__ORBIS__) && !defined(__PROSPERO__)
|
||||
#define LUAJIT_OS LUAJIT_OS_BSD
|
||||
#elif (defined(__sun__) && defined(__svr4__))
|
||||
#define LJ_TARGET_SOLARIS 1
|
||||
#define LUAJIT_OS LUAJIT_OS_POSIX
|
||||
#elif defined(__HAIKU__)
|
||||
#define LUAJIT_OS LUAJIT_OS_POSIX
|
||||
#elif defined(__CYGWIN__)
|
||||
#define LJ_TARGET_CYGWIN 1
|
||||
#define LUAJIT_OS LUAJIT_OS_POSIX
|
||||
#elif defined(__QNX__)
|
||||
#define LJ_TARGET_QNX 1
|
||||
#define LUAJIT_OS LUAJIT_OS_POSIX
|
||||
#else
|
||||
#define LUAJIT_OS LUAJIT_OS_OTHER
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Set target OS properties. */
|
||||
#if LUAJIT_OS == LUAJIT_OS_WINDOWS
|
||||
#define LJ_OS_NAME "Windows"
|
||||
#elif LUAJIT_OS == LUAJIT_OS_LINUX
|
||||
#define LJ_OS_NAME "Linux"
|
||||
#elif LUAJIT_OS == LUAJIT_OS_OSX
|
||||
#define LJ_OS_NAME "OSX"
|
||||
#elif LUAJIT_OS == LUAJIT_OS_BSD
|
||||
#define LJ_OS_NAME "BSD"
|
||||
#elif LUAJIT_OS == LUAJIT_OS_POSIX
|
||||
#define LJ_OS_NAME "POSIX"
|
||||
#else
|
||||
#define LJ_OS_NAME "Other"
|
||||
#endif
|
||||
|
||||
#define LJ_TARGET_WINDOWS (LUAJIT_OS == LUAJIT_OS_WINDOWS)
|
||||
#define LJ_TARGET_LINUX (LUAJIT_OS == LUAJIT_OS_LINUX)
|
||||
#define LJ_TARGET_OSX (LUAJIT_OS == LUAJIT_OS_OSX)
|
||||
#define LJ_TARGET_BSD (LUAJIT_OS == LUAJIT_OS_BSD)
|
||||
#define LJ_TARGET_POSIX (LUAJIT_OS > LUAJIT_OS_WINDOWS)
|
||||
#define LJ_TARGET_DLOPEN LJ_TARGET_POSIX
|
||||
|
||||
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
|
||||
#define LJ_TARGET_IOS 1
|
||||
#else
|
||||
#define LJ_TARGET_IOS 0
|
||||
#endif
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
#define LJ_TARGET_PS3 1
|
||||
#define LJ_TARGET_CONSOLE 1
|
||||
#endif
|
||||
|
||||
#ifdef __ORBIS__
|
||||
#define LJ_TARGET_PS4 1
|
||||
#define LJ_TARGET_CONSOLE 1
|
||||
#undef NULL
|
||||
#define NULL ((void*)0)
|
||||
#endif
|
||||
|
||||
#ifdef __PROSPERO__
|
||||
#define LJ_TARGET_PS5 1
|
||||
#define LJ_TARGET_CONSOLE 1
|
||||
#undef NULL
|
||||
#define NULL ((void*)0)
|
||||
#endif
|
||||
|
||||
#ifdef __psp2__
|
||||
#define LJ_TARGET_PSVITA 1
|
||||
#define LJ_TARGET_CONSOLE 1
|
||||
#endif
|
||||
|
||||
#if _XBOX_VER >= 200
|
||||
#define LJ_TARGET_XBOX360 1
|
||||
#define LJ_TARGET_CONSOLE 1
|
||||
#endif
|
||||
|
||||
#ifdef _DURANGO
|
||||
#define LJ_TARGET_XBOXONE 1
|
||||
#define LJ_TARGET_CONSOLE 1
|
||||
#define LJ_TARGET_GC64 1
|
||||
#endif
|
||||
|
||||
#ifdef __NX__
|
||||
#define LJ_TARGET_NX 1
|
||||
#define LJ_TARGET_CONSOLE 1
|
||||
#undef NULL
|
||||
#define NULL ((void*)0)
|
||||
#endif
|
||||
|
||||
#ifdef _UWP
|
||||
#define LJ_TARGET_UWP 1
|
||||
#if LUAJIT_TARGET == LUAJIT_ARCH_X64
|
||||
#define LJ_TARGET_GC64 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* -- Arch-specific settings ---------------------------------------------- */
|
||||
|
||||
/* Set target architecture properties. */
|
||||
#if LUAJIT_TARGET == LUAJIT_ARCH_X86
|
||||
|
||||
#define LJ_ARCH_NAME "x86"
|
||||
#define LJ_ARCH_BITS 32
|
||||
#define LJ_ARCH_ENDIAN LUAJIT_LE
|
||||
#define LJ_TARGET_X86 1
|
||||
#define LJ_TARGET_X86ORX64 1
|
||||
#define LJ_TARGET_EHRETREG 0
|
||||
#define LJ_TARGET_EHRAREG 8
|
||||
#define LJ_TARGET_MASKSHIFT 1
|
||||
#define LJ_TARGET_MASKROT 1
|
||||
#define LJ_TARGET_UNALIGNED 1
|
||||
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL
|
||||
|
||||
#elif LUAJIT_TARGET == LUAJIT_ARCH_X64
|
||||
|
||||
#define LJ_ARCH_NAME "x64"
|
||||
#define LJ_ARCH_BITS 64
|
||||
#define LJ_ARCH_ENDIAN LUAJIT_LE
|
||||
#define LJ_TARGET_X64 1
|
||||
#define LJ_TARGET_X86ORX64 1
|
||||
#define LJ_TARGET_EHRETREG 0
|
||||
#define LJ_TARGET_EHRAREG 16
|
||||
#define LJ_TARGET_JUMPRANGE 31 /* +-2^31 = +-2GB */
|
||||
#define LJ_TARGET_MASKSHIFT 1
|
||||
#define LJ_TARGET_MASKROT 1
|
||||
#define LJ_TARGET_UNALIGNED 1
|
||||
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL
|
||||
#ifndef LUAJIT_DISABLE_GC64
|
||||
#define LJ_TARGET_GC64 1
|
||||
#elif LJ_TARGET_OSX
|
||||
#error "macOS requires GC64 -- don't disable it"
|
||||
#endif
|
||||
|
||||
#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM
|
||||
|
||||
#define LJ_ARCH_NAME "arm"
|
||||
#define LJ_ARCH_BITS 32
|
||||
#define LJ_ARCH_ENDIAN LUAJIT_LE
|
||||
#if !defined(LJ_ARCH_HASFPU) && __SOFTFP__
|
||||
#define LJ_ARCH_HASFPU 0
|
||||
#endif
|
||||
#if !defined(LJ_ABI_SOFTFP) && !__ARM_PCS_VFP
|
||||
#define LJ_ABI_SOFTFP 1
|
||||
#endif
|
||||
#define LJ_ABI_EABI 1
|
||||
#define LJ_TARGET_ARM 1
|
||||
#define LJ_TARGET_EHRETREG 0
|
||||
#define LJ_TARGET_EHRAREG 14
|
||||
#define LJ_TARGET_JUMPRANGE 25 /* +-2^25 = +-32MB */
|
||||
#define LJ_TARGET_MASKSHIFT 0
|
||||
#define LJ_TARGET_MASKROT 1
|
||||
#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */
|
||||
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
|
||||
|
||||
#if __ARM_ARCH >= 8 || __ARM_ARCH_8__ || __ARM_ARCH_8A__
|
||||
#define LJ_ARCH_VERSION 80
|
||||
#elif __ARM_ARCH == 7 || __ARM_ARCH_7__ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH_7S__ || __ARM_ARCH_7VE__
|
||||
#define LJ_ARCH_VERSION 70
|
||||
#elif __ARM_ARCH_6T2__
|
||||
#define LJ_ARCH_VERSION 61
|
||||
#elif __ARM_ARCH == 6 || __ARM_ARCH_6__ || __ARM_ARCH_6J__ || __ARM_ARCH_6K__ || __ARM_ARCH_6Z__ || __ARM_ARCH_6ZK__
|
||||
#define LJ_ARCH_VERSION 60
|
||||
#else
|
||||
#define LJ_ARCH_VERSION 50
|
||||
#endif
|
||||
|
||||
#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM64
|
||||
|
||||
#define LJ_ARCH_BITS 64
|
||||
#if defined(__AARCH64EB__)
|
||||
#define LJ_ARCH_NAME "arm64be"
|
||||
#define LJ_ARCH_ENDIAN LUAJIT_BE
|
||||
#else
|
||||
#define LJ_ARCH_NAME "arm64"
|
||||
#define LJ_ARCH_ENDIAN LUAJIT_LE
|
||||
#endif
|
||||
#if !defined(LJ_ABI_PAUTH) && defined(__arm64e__)
|
||||
#define LJ_ABI_PAUTH 1
|
||||
#endif
|
||||
#define LJ_TARGET_ARM64 1
|
||||
#define LJ_TARGET_EHRETREG 0
|
||||
#define LJ_TARGET_EHRAREG 30
|
||||
#define LJ_TARGET_JUMPRANGE 27 /* +-2^27 = +-128MB */
|
||||
#define LJ_TARGET_MASKSHIFT 1
|
||||
#define LJ_TARGET_MASKROT 1
|
||||
#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */
|
||||
#define LJ_TARGET_GC64 1
|
||||
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
|
||||
|
||||
#define LJ_ARCH_VERSION 80
|
||||
|
||||
#elif LUAJIT_TARGET == LUAJIT_ARCH_PPC
|
||||
|
||||
#ifndef LJ_ARCH_ENDIAN
|
||||
#if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
|
||||
#define LJ_ARCH_ENDIAN LUAJIT_LE
|
||||
#else
|
||||
#define LJ_ARCH_ENDIAN LUAJIT_BE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if _LP64
|
||||
#define LJ_ARCH_BITS 64
|
||||
#if LJ_ARCH_ENDIAN == LUAJIT_LE
|
||||
#define LJ_ARCH_NAME "ppc64le"
|
||||
#else
|
||||
#define LJ_ARCH_NAME "ppc64"
|
||||
#endif
|
||||
#else
|
||||
#define LJ_ARCH_BITS 32
|
||||
#define LJ_ARCH_NAME "ppc"
|
||||
|
||||
#if !defined(LJ_ARCH_HASFPU)
|
||||
#if defined(_SOFT_FLOAT) || defined(_SOFT_DOUBLE)
|
||||
#define LJ_ARCH_HASFPU 0
|
||||
#else
|
||||
#define LJ_ARCH_HASFPU 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(LJ_ABI_SOFTFP)
|
||||
#if defined(_SOFT_FLOAT) || defined(_SOFT_DOUBLE)
|
||||
#define LJ_ABI_SOFTFP 1
|
||||
#else
|
||||
#define LJ_ABI_SOFTFP 0
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LJ_ABI_SOFTFP
|
||||
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
|
||||
#else
|
||||
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL_SINGLE
|
||||
#endif
|
||||
|
||||
#define LJ_TARGET_PPC 1
|
||||
#define LJ_TARGET_EHRETREG 3
|
||||
#define LJ_TARGET_EHRAREG 65
|
||||
#define LJ_TARGET_JUMPRANGE 25 /* +-2^25 = +-32MB */
|
||||
#define LJ_TARGET_MASKSHIFT 0
|
||||
#define LJ_TARGET_MASKROT 1
|
||||
#define LJ_TARGET_UNIFYROT 1 /* Want only IR_BROL. */
|
||||
|
||||
#if LJ_TARGET_CONSOLE
|
||||
#define LJ_ARCH_PPC32ON64 1
|
||||
#define LJ_ARCH_NOFFI 1
|
||||
#elif LJ_ARCH_BITS == 64
|
||||
#error "No support for PPC64"
|
||||
#undef LJ_TARGET_PPC
|
||||
#endif
|
||||
|
||||
#if _ARCH_PWR7
|
||||
#define LJ_ARCH_VERSION 70
|
||||
#elif _ARCH_PWR6
|
||||
#define LJ_ARCH_VERSION 60
|
||||
#elif _ARCH_PWR5X
|
||||
#define LJ_ARCH_VERSION 51
|
||||
#elif _ARCH_PWR5
|
||||
#define LJ_ARCH_VERSION 50
|
||||
#elif _ARCH_PWR4
|
||||
#define LJ_ARCH_VERSION 40
|
||||
#else
|
||||
#define LJ_ARCH_VERSION 0
|
||||
#endif
|
||||
#if _ARCH_PPCSQ
|
||||
#define LJ_ARCH_SQRT 1
|
||||
#endif
|
||||
#if _ARCH_PWR5X
|
||||
#define LJ_ARCH_ROUND 1
|
||||
#endif
|
||||
#if __PPU__
|
||||
#define LJ_ARCH_CELL 1
|
||||
#endif
|
||||
#if LJ_TARGET_XBOX360
|
||||
#define LJ_ARCH_XENON 1
|
||||
#endif
|
||||
|
||||
#elif LUAJIT_TARGET == LUAJIT_ARCH_MIPS32 || LUAJIT_TARGET == LUAJIT_ARCH_MIPS64
|
||||
|
||||
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
|
||||
#if __mips_isa_rev >= 6
|
||||
#define LJ_TARGET_MIPSR6 1
|
||||
#define LJ_TARGET_UNALIGNED 1
|
||||
#endif
|
||||
#if LUAJIT_TARGET == LUAJIT_ARCH_MIPS32
|
||||
#if LJ_TARGET_MIPSR6
|
||||
#define LJ_ARCH_NAME "mips32r6el"
|
||||
#else
|
||||
#define LJ_ARCH_NAME "mipsel"
|
||||
#endif
|
||||
#else
|
||||
#if LJ_TARGET_MIPSR6
|
||||
#define LJ_ARCH_NAME "mips64r6el"
|
||||
#else
|
||||
#define LJ_ARCH_NAME "mips64el"
|
||||
#endif
|
||||
#endif
|
||||
#define LJ_ARCH_ENDIAN LUAJIT_LE
|
||||
#else
|
||||
#if LUAJIT_TARGET == LUAJIT_ARCH_MIPS32
|
||||
#if LJ_TARGET_MIPSR6
|
||||
#define LJ_ARCH_NAME "mips32r6"
|
||||
#else
|
||||
#define LJ_ARCH_NAME "mips"
|
||||
#endif
|
||||
#else
|
||||
#if LJ_TARGET_MIPSR6
|
||||
#define LJ_ARCH_NAME "mips64r6"
|
||||
#else
|
||||
#define LJ_ARCH_NAME "mips64"
|
||||
#endif
|
||||
#endif
|
||||
#define LJ_ARCH_ENDIAN LUAJIT_BE
|
||||
#endif
|
||||
|
||||
#if !defined(LJ_ARCH_HASFPU)
|
||||
#ifdef __mips_soft_float
|
||||
#define LJ_ARCH_HASFPU 0
|
||||
#else
|
||||
#define LJ_ARCH_HASFPU 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(LJ_ABI_SOFTFP)
|
||||
#ifdef __mips_soft_float
|
||||
#define LJ_ABI_SOFTFP 1
|
||||
#else
|
||||
#define LJ_ABI_SOFTFP 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LUAJIT_TARGET == LUAJIT_ARCH_MIPS32
|
||||
#define LJ_ARCH_BITS 32
|
||||
#define LJ_TARGET_MIPS32 1
|
||||
#else
|
||||
#define LJ_ARCH_BITS 64
|
||||
#define LJ_TARGET_MIPS64 1
|
||||
#define LJ_TARGET_GC64 1
|
||||
#endif
|
||||
#define LJ_TARGET_MIPS 1
|
||||
#define LJ_TARGET_EHRETREG 4
|
||||
#define LJ_TARGET_EHRAREG 31
|
||||
#define LJ_TARGET_JUMPRANGE 27 /* 2*2^27 = 256MB-aligned region */
|
||||
#define LJ_TARGET_MASKSHIFT 1
|
||||
#define LJ_TARGET_MASKROT 1
|
||||
#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */
|
||||
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
|
||||
|
||||
#if LJ_TARGET_MIPSR6
|
||||
#define LJ_ARCH_VERSION 60
|
||||
#elif _MIPS_ARCH_MIPS32R2 || _MIPS_ARCH_MIPS64R2
|
||||
#define LJ_ARCH_VERSION 20
|
||||
#else
|
||||
#define LJ_ARCH_VERSION 10
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "No target architecture defined"
|
||||
#endif
|
||||
|
||||
/* -- Checks for requirements --------------------------------------------- */
|
||||
|
||||
/* Check for minimum required compiler versions. */
|
||||
#if defined(__GNUC__)
|
||||
#if LJ_TARGET_X86
|
||||
#if (__GNUC__ < 3) || ((__GNUC__ == 3) && __GNUC_MINOR__ < 4)
|
||||
#error "Need at least GCC 3.4 or newer"
|
||||
#endif
|
||||
#elif LJ_TARGET_X64
|
||||
#if __GNUC__ < 4
|
||||
#error "Need at least GCC 4.0 or newer"
|
||||
#endif
|
||||
#elif LJ_TARGET_ARM
|
||||
#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 2)
|
||||
#error "Need at least GCC 4.2 or newer"
|
||||
#endif
|
||||
#elif LJ_TARGET_ARM64
|
||||
#if __clang__
|
||||
#if ((__clang_major__ < 3) || ((__clang_major__ == 3) && __clang_minor__ < 5)) && !defined(__NX_TOOLCHAIN_MAJOR__)
|
||||
#error "Need at least Clang 3.5 or newer"
|
||||
#endif
|
||||
#else
|
||||
#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 8)
|
||||
#error "Need at least GCC 4.8 or newer"
|
||||
#endif
|
||||
#endif
|
||||
#elif !LJ_TARGET_PS3
|
||||
#if __clang__
|
||||
#if ((__clang_major__ < 3) || ((__clang_major__ == 3) && __clang_minor__ < 5))
|
||||
#error "Need at least Clang 3.5 or newer"
|
||||
#endif
|
||||
#else
|
||||
#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 3)
|
||||
#error "Need at least GCC 4.3 or newer"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Check target-specific constraints. */
|
||||
#ifndef _BUILDVM_H
|
||||
#if LJ_TARGET_X64
|
||||
#if __USING_SJLJ_EXCEPTIONS__
|
||||
#error "Need a C compiler with native exception handling on x64"
|
||||
#endif
|
||||
#elif LJ_TARGET_ARM
|
||||
#if defined(__ARMEB__)
|
||||
#error "No support for big-endian ARM"
|
||||
#undef LJ_TARGET_ARM
|
||||
#endif
|
||||
#if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__
|
||||
#error "No support for Cortex-M CPUs"
|
||||
#undef LJ_TARGET_ARM
|
||||
#endif
|
||||
#if !(__ARM_EABI__ || LJ_TARGET_IOS)
|
||||
#error "Only ARM EABI or iOS 3.0+ ABI is supported"
|
||||
#undef LJ_TARGET_ARM
|
||||
#endif
|
||||
#elif LJ_TARGET_ARM64
|
||||
#if defined(_ILP32)
|
||||
#error "No support for ILP32 model on ARM64"
|
||||
#undef LJ_TARGET_ARM64
|
||||
#endif
|
||||
#elif LJ_TARGET_PPC
|
||||
#if defined(_LITTLE_ENDIAN) && (!defined(_BYTE_ORDER) || (_BYTE_ORDER == _LITTLE_ENDIAN))
|
||||
#error "No support for little-endian PPC32"
|
||||
#undef LJ_TARGET_PPC
|
||||
#endif
|
||||
#if defined(__NO_FPRS__) && !defined(_SOFT_FLOAT)
|
||||
#error "No support for PPC/e500, use LuaJIT 2.0"
|
||||
#undef LJ_TARGET_PPC
|
||||
#endif
|
||||
#elif LJ_TARGET_MIPS32
|
||||
#if !((defined(_MIPS_SIM_ABI32) && _MIPS_SIM == _MIPS_SIM_ABI32) || (defined(_ABIO32) && _MIPS_SIM == _ABIO32))
|
||||
#error "Only o32 ABI supported for MIPS32"
|
||||
#undef LJ_TARGET_MIPS
|
||||
#endif
|
||||
#if LJ_TARGET_MIPSR6
|
||||
/* Not that useful, since most available r6 CPUs are 64 bit. */
|
||||
#error "No support for MIPS32R6"
|
||||
#undef LJ_TARGET_MIPS
|
||||
#endif
|
||||
#elif LJ_TARGET_MIPS64
|
||||
#if !((defined(_MIPS_SIM_ABI64) && _MIPS_SIM == _MIPS_SIM_ABI64) || (defined(_ABI64) && _MIPS_SIM == _ABI64))
|
||||
/* MIPS32ON64 aka n32 ABI support might be desirable, but difficult. */
|
||||
#error "Only n64 ABI supported for MIPS64"
|
||||
#undef LJ_TARGET_MIPS
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* -- Derived defines ----------------------------------------------------- */
|
||||
|
||||
/* Enable or disable the dual-number mode for the VM. */
|
||||
#if (LJ_ARCH_NUMMODE == LJ_NUMMODE_SINGLE && LUAJIT_NUMMODE == 2) || \
|
||||
(LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL && LUAJIT_NUMMODE == 1)
|
||||
#error "No support for this number mode on this architecture"
|
||||
#endif
|
||||
#if LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL || \
|
||||
(LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL_SINGLE && LUAJIT_NUMMODE != 1) || \
|
||||
(LJ_ARCH_NUMMODE == LJ_NUMMODE_SINGLE_DUAL && LUAJIT_NUMMODE == 2)
|
||||
#define LJ_DUALNUM 1
|
||||
#else
|
||||
#define LJ_DUALNUM 0
|
||||
#endif
|
||||
|
||||
#if LJ_TARGET_IOS || LJ_TARGET_CONSOLE
|
||||
/* Runtime code generation is restricted on iOS. Complain to Apple, not me. */
|
||||
/* Ditto for the consoles. Complain to Sony or MS, not me. */
|
||||
#ifndef LUAJIT_ENABLE_JIT
|
||||
#define LJ_OS_NOJIT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 64 bit GC references. */
|
||||
#if LJ_TARGET_GC64
|
||||
#define LJ_GC64 1
|
||||
#else
|
||||
#define LJ_GC64 0
|
||||
#endif
|
||||
|
||||
/* 2-slot frame info. */
|
||||
#if LJ_GC64
|
||||
#define LJ_FR2 1
|
||||
#else
|
||||
#define LJ_FR2 0
|
||||
#endif
|
||||
|
||||
/* Disable or enable the JIT compiler. */
|
||||
#if defined(LUAJIT_DISABLE_JIT) || defined(LJ_ARCH_NOJIT) || defined(LJ_OS_NOJIT)
|
||||
#define LJ_HASJIT 0
|
||||
#else
|
||||
#define LJ_HASJIT 1
|
||||
#endif
|
||||
|
||||
/* Disable or enable the FFI extension. */
|
||||
#if defined(LUAJIT_DISABLE_FFI) || defined(LJ_ARCH_NOFFI)
|
||||
#define LJ_HASFFI 0
|
||||
#else
|
||||
#define LJ_HASFFI 1
|
||||
#endif
|
||||
|
||||
/* Disable or enable the string buffer extension. */
|
||||
#if defined(LUAJIT_DISABLE_BUFFER)
|
||||
#define LJ_HASBUFFER 0
|
||||
#else
|
||||
#define LJ_HASBUFFER 1
|
||||
#endif
|
||||
|
||||
#if defined(LUAJIT_DISABLE_PROFILE)
|
||||
#define LJ_HASPROFILE 0
|
||||
#elif LJ_TARGET_POSIX
|
||||
#define LJ_HASPROFILE 1
|
||||
#define LJ_PROFILE_SIGPROF 1
|
||||
#elif LJ_TARGET_PS3
|
||||
#define LJ_HASPROFILE 1
|
||||
#define LJ_PROFILE_PTHREAD 1
|
||||
#elif LJ_TARGET_WINDOWS || LJ_TARGET_XBOX360
|
||||
#define LJ_HASPROFILE 1
|
||||
#define LJ_PROFILE_WTHREAD 1
|
||||
#else
|
||||
#define LJ_HASPROFILE 0
|
||||
#endif
|
||||
|
||||
#ifndef LJ_ARCH_HASFPU
|
||||
#define LJ_ARCH_HASFPU 1
|
||||
#endif
|
||||
#ifndef LJ_ABI_SOFTFP
|
||||
#define LJ_ABI_SOFTFP 0
|
||||
#endif
|
||||
#define LJ_SOFTFP (!LJ_ARCH_HASFPU)
|
||||
#define LJ_SOFTFP32 (LJ_SOFTFP && LJ_32)
|
||||
|
||||
#ifndef LJ_ABI_PAUTH
|
||||
#define LJ_ABI_PAUTH 0
|
||||
#endif
|
||||
|
||||
#if LJ_ARCH_ENDIAN == LUAJIT_BE
|
||||
#define LJ_LE 0
|
||||
#define LJ_BE 1
|
||||
#define LJ_ENDIAN_SELECT(le, be) be
|
||||
#define LJ_ENDIAN_LOHI(lo, hi) hi lo
|
||||
#else
|
||||
#define LJ_LE 1
|
||||
#define LJ_BE 0
|
||||
#define LJ_ENDIAN_SELECT(le, be) le
|
||||
#define LJ_ENDIAN_LOHI(lo, hi) lo hi
|
||||
#endif
|
||||
|
||||
#if LJ_ARCH_BITS == 32
|
||||
#define LJ_32 1
|
||||
#define LJ_64 0
|
||||
#else
|
||||
#define LJ_32 0
|
||||
#define LJ_64 1
|
||||
#endif
|
||||
|
||||
#ifndef LJ_TARGET_UNALIGNED
|
||||
#define LJ_TARGET_UNALIGNED 0
|
||||
#endif
|
||||
|
||||
#ifndef LJ_PAGESIZE
|
||||
#define LJ_PAGESIZE 4096
|
||||
#endif
|
||||
|
||||
/* Various workarounds for embedded operating systems or weak C runtimes. */
|
||||
#if defined(__ANDROID__) || defined(__symbian__) || LJ_TARGET_XBOX360 || LJ_TARGET_WINDOWS
|
||||
#define LUAJIT_NO_LOG2
|
||||
#endif
|
||||
#if LJ_TARGET_CONSOLE || (LJ_TARGET_IOS && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0)
|
||||
#define LJ_NO_SYSTEM 1
|
||||
#endif
|
||||
|
||||
#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
|
||||
#define LJ_ABI_WIN 1
|
||||
#else
|
||||
#define LJ_ABI_WIN 0
|
||||
#endif
|
||||
|
||||
#if LJ_TARGET_WINDOWS
|
||||
#if LJ_TARGET_UWP
|
||||
#define LJ_WIN_VALLOC VirtualAllocFromApp
|
||||
#define LJ_WIN_VPROTECT VirtualProtectFromApp
|
||||
extern void *LJ_WIN_LOADLIBA(const char *path);
|
||||
#else
|
||||
#define LJ_WIN_VALLOC VirtualAlloc
|
||||
#define LJ_WIN_VPROTECT VirtualProtect
|
||||
#define LJ_WIN_LOADLIBA(path) LoadLibraryExA((path), NULL, 0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LUAJIT_NO_UNWIND) || __GNU_COMPACT_EH__ || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PS5
|
||||
#define LJ_NO_UNWIND 1
|
||||
#endif
|
||||
|
||||
#if !LJ_NO_UNWIND && !defined(LUAJIT_UNWIND_INTERNAL) && (LJ_ABI_WIN || (defined(LUAJIT_UNWIND_EXTERNAL) && (defined(__GNUC__) || defined(__clang__))))
|
||||
#define LJ_UNWIND_EXT 1
|
||||
#else
|
||||
#define LJ_UNWIND_EXT 0
|
||||
#endif
|
||||
|
||||
#if LJ_UNWIND_EXT && LJ_HASJIT && !LJ_TARGET_ARM && !(LJ_ABI_WIN && LJ_TARGET_X86)
|
||||
#define LJ_UNWIND_JIT 1
|
||||
#else
|
||||
#define LJ_UNWIND_JIT 0
|
||||
#endif
|
||||
|
||||
/* Compatibility with Lua 5.1 vs. 5.2. */
|
||||
#ifdef LUAJIT_ENABLE_LUA52COMPAT
|
||||
#define LJ_52 1
|
||||
#else
|
||||
#define LJ_52 0
|
||||
#endif
|
||||
|
||||
/* -- VM security --------------------------------------------------------- */
|
||||
|
||||
/* Don't make any changes here. Instead build with:
|
||||
** make "XCFLAGS=-DLUAJIT_SECURITY_flag=value"
|
||||
**
|
||||
** Important note to distro maintainers: DO NOT change the defaults for a
|
||||
** regular distro build -- neither upwards, nor downwards!
|
||||
** These build-time configurable security flags are intended for embedders
|
||||
** who may have specific needs wrt. security vs. performance.
|
||||
*/
|
||||
|
||||
/* Security defaults. */
|
||||
#ifndef LUAJIT_SECURITY_PRNG
|
||||
/* PRNG init: 0 = fixed/insecure, 1 = secure from OS. */
|
||||
#define LUAJIT_SECURITY_PRNG 1
|
||||
#endif
|
||||
|
||||
#ifndef LUAJIT_SECURITY_STRHASH
|
||||
/* String hash: 0 = sparse only, 1 = sparse + dense. */
|
||||
#define LUAJIT_SECURITY_STRHASH 1
|
||||
#endif
|
||||
|
||||
#ifndef LUAJIT_SECURITY_STRID
|
||||
/* String IDs: 0 = linear, 1 = reseed < 255, 2 = reseed < 15, 3 = random. */
|
||||
#define LUAJIT_SECURITY_STRID 1
|
||||
#endif
|
||||
|
||||
#ifndef LUAJIT_SECURITY_MCODE
|
||||
/* Machine code page protection: 0 = insecure RWX, 1 = secure RW^X. */
|
||||
#define LUAJIT_SECURITY_MCODE 1
|
||||
#endif
|
||||
|
||||
#define LJ_SECURITY_MODE \
|
||||
( 0u \
|
||||
| ((LUAJIT_SECURITY_PRNG & 3) << 0) \
|
||||
| ((LUAJIT_SECURITY_STRHASH & 3) << 2) \
|
||||
| ((LUAJIT_SECURITY_STRID & 3) << 4) \
|
||||
| ((LUAJIT_SECURITY_MCODE & 3) << 6) \
|
||||
)
|
||||
#define LJ_SECURITY_MODESTRING \
|
||||
"\004prng\007strhash\005strid\005mcode"
|
||||
|
||||
#endif
|
||||
2631
thirdPart/luajit/src/lj_asm.c
Normal file
2631
thirdPart/luajit/src/lj_asm.c
Normal file
File diff suppressed because it is too large
Load Diff
17
thirdPart/luajit/src/lj_asm.h
Normal file
17
thirdPart/luajit/src/lj_asm.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
** IR assembler (SSA IR -> machine code).
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#ifndef _LJ_ASM_H
|
||||
#define _LJ_ASM_H
|
||||
|
||||
#include "lj_jit.h"
|
||||
|
||||
#if LJ_HASJIT
|
||||
LJ_FUNC void lj_asm_trace(jit_State *J, GCtrace *T);
|
||||
LJ_FUNC void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno,
|
||||
MCode *target);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
2308
thirdPart/luajit/src/lj_asm_arm.h
Normal file
2308
thirdPart/luajit/src/lj_asm_arm.h
Normal file
File diff suppressed because it is too large
Load Diff
2075
thirdPart/luajit/src/lj_asm_arm64.h
Normal file
2075
thirdPart/luajit/src/lj_asm_arm64.h
Normal file
File diff suppressed because it is too large
Load Diff
2815
thirdPart/luajit/src/lj_asm_mips.h
Normal file
2815
thirdPart/luajit/src/lj_asm_mips.h
Normal file
File diff suppressed because it is too large
Load Diff
2333
thirdPart/luajit/src/lj_asm_ppc.h
Normal file
2333
thirdPart/luajit/src/lj_asm_ppc.h
Normal file
File diff suppressed because it is too large
Load Diff
3139
thirdPart/luajit/src/lj_asm_x86.h
Normal file
3139
thirdPart/luajit/src/lj_asm_x86.h
Normal file
File diff suppressed because it is too large
Load Diff
28
thirdPart/luajit/src/lj_assert.c
Normal file
28
thirdPart/luajit/src/lj_assert.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
** Internal assertions.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#define lj_assert_c
|
||||
#define LUA_CORE
|
||||
|
||||
#if defined(LUA_USE_ASSERT) || defined(LUA_USE_APICHECK)
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lj_obj.h"
|
||||
|
||||
void lj_assert_fail(global_State *g, const char *file, int line,
|
||||
const char *func, const char *fmt, ...)
|
||||
{
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
fprintf(stderr, "LuaJIT ASSERT %s:%d: %s: ", file, line, func);
|
||||
vfprintf(stderr, fmt, argp);
|
||||
fputc('\n', stderr);
|
||||
va_end(argp);
|
||||
UNUSED(g); /* May be NULL. TODO: optionally dump state. */
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif
|
||||
14
thirdPart/luajit/src/lj_bc.c
Normal file
14
thirdPart/luajit/src/lj_bc.c
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
** Bytecode instruction modes.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#define lj_bc_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_bc.h"
|
||||
|
||||
/* Bytecode offsets and bytecode instruction modes. */
|
||||
#include "lj_bcdef.h"
|
||||
|
||||
265
thirdPart/luajit/src/lj_bc.h
Normal file
265
thirdPart/luajit/src/lj_bc.h
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
** Bytecode instruction format.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#ifndef _LJ_BC_H
|
||||
#define _LJ_BC_H
|
||||
|
||||
#include "lj_def.h"
|
||||
#include "lj_arch.h"
|
||||
|
||||
/* Bytecode instruction format, 32 bit wide, fields of 8 or 16 bit:
|
||||
**
|
||||
** +----+----+----+----+
|
||||
** | B | C | A | OP | Format ABC
|
||||
** +----+----+----+----+
|
||||
** | D | A | OP | Format AD
|
||||
** +--------------------
|
||||
** MSB LSB
|
||||
**
|
||||
** In-memory instructions are always stored in host byte order.
|
||||
*/
|
||||
|
||||
/* Operand ranges and related constants. */
|
||||
#define BCMAX_A 0xff
|
||||
#define BCMAX_B 0xff
|
||||
#define BCMAX_C 0xff
|
||||
#define BCMAX_D 0xffff
|
||||
#define BCBIAS_J 0x8000
|
||||
#define NO_REG BCMAX_A
|
||||
#define NO_JMP (~(BCPos)0)
|
||||
|
||||
/* Macros to get instruction fields. */
|
||||
#define bc_op(i) ((BCOp)((i)&0xff))
|
||||
#define bc_a(i) ((BCReg)(((i)>>8)&0xff))
|
||||
#define bc_b(i) ((BCReg)((i)>>24))
|
||||
#define bc_c(i) ((BCReg)(((i)>>16)&0xff))
|
||||
#define bc_d(i) ((BCReg)((i)>>16))
|
||||
#define bc_j(i) ((ptrdiff_t)bc_d(i)-BCBIAS_J)
|
||||
|
||||
/* Macros to set instruction fields. */
|
||||
#define setbc_byte(p, x, ofs) \
|
||||
((uint8_t *)(p))[LJ_ENDIAN_SELECT(ofs, 3-ofs)] = (uint8_t)(x)
|
||||
#define setbc_op(p, x) setbc_byte(p, (x), 0)
|
||||
#define setbc_a(p, x) setbc_byte(p, (x), 1)
|
||||
#define setbc_b(p, x) setbc_byte(p, (x), 3)
|
||||
#define setbc_c(p, x) setbc_byte(p, (x), 2)
|
||||
#define setbc_d(p, x) \
|
||||
((uint16_t *)(p))[LJ_ENDIAN_SELECT(1, 0)] = (uint16_t)(x)
|
||||
#define setbc_j(p, x) setbc_d(p, (BCPos)((int32_t)(x)+BCBIAS_J))
|
||||
|
||||
/* Macros to compose instructions. */
|
||||
#define BCINS_ABC(o, a, b, c) \
|
||||
(((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(b)<<24)|((BCIns)(c)<<16))
|
||||
#define BCINS_AD(o, a, d) \
|
||||
(((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(d)<<16))
|
||||
#define BCINS_AJ(o, a, j) BCINS_AD(o, a, (BCPos)((int32_t)(j)+BCBIAS_J))
|
||||
|
||||
/* Bytecode instruction definition. Order matters, see below.
|
||||
**
|
||||
** (name, filler, Amode, Bmode, Cmode or Dmode, metamethod)
|
||||
**
|
||||
** The opcode name suffixes specify the type for RB/RC or RD:
|
||||
** V = variable slot
|
||||
** S = string const
|
||||
** N = number const
|
||||
** P = primitive type (~itype)
|
||||
** B = unsigned byte literal
|
||||
** M = multiple args/results
|
||||
*/
|
||||
#define BCDEF(_) \
|
||||
/* Comparison ops. ORDER OPR. */ \
|
||||
_(ISLT, var, ___, var, lt) \
|
||||
_(ISGE, var, ___, var, lt) \
|
||||
_(ISLE, var, ___, var, le) \
|
||||
_(ISGT, var, ___, var, le) \
|
||||
\
|
||||
_(ISEQV, var, ___, var, eq) \
|
||||
_(ISNEV, var, ___, var, eq) \
|
||||
_(ISEQS, var, ___, str, eq) \
|
||||
_(ISNES, var, ___, str, eq) \
|
||||
_(ISEQN, var, ___, num, eq) \
|
||||
_(ISNEN, var, ___, num, eq) \
|
||||
_(ISEQP, var, ___, pri, eq) \
|
||||
_(ISNEP, var, ___, pri, eq) \
|
||||
\
|
||||
/* Unary test and copy ops. */ \
|
||||
_(ISTC, dst, ___, var, ___) \
|
||||
_(ISFC, dst, ___, var, ___) \
|
||||
_(IST, ___, ___, var, ___) \
|
||||
_(ISF, ___, ___, var, ___) \
|
||||
_(ISTYPE, var, ___, lit, ___) \
|
||||
_(ISNUM, var, ___, lit, ___) \
|
||||
\
|
||||
/* Unary ops. */ \
|
||||
_(MOV, dst, ___, var, ___) \
|
||||
_(NOT, dst, ___, var, ___) \
|
||||
_(UNM, dst, ___, var, unm) \
|
||||
_(LEN, dst, ___, var, len) \
|
||||
\
|
||||
/* Binary ops. ORDER OPR. VV last, POW must be next. */ \
|
||||
_(ADDVN, dst, var, num, add) \
|
||||
_(SUBVN, dst, var, num, sub) \
|
||||
_(MULVN, dst, var, num, mul) \
|
||||
_(DIVVN, dst, var, num, div) \
|
||||
_(MODVN, dst, var, num, mod) \
|
||||
\
|
||||
_(ADDNV, dst, var, num, add) \
|
||||
_(SUBNV, dst, var, num, sub) \
|
||||
_(MULNV, dst, var, num, mul) \
|
||||
_(DIVNV, dst, var, num, div) \
|
||||
_(MODNV, dst, var, num, mod) \
|
||||
\
|
||||
_(ADDVV, dst, var, var, add) \
|
||||
_(SUBVV, dst, var, var, sub) \
|
||||
_(MULVV, dst, var, var, mul) \
|
||||
_(DIVVV, dst, var, var, div) \
|
||||
_(MODVV, dst, var, var, mod) \
|
||||
\
|
||||
_(POW, dst, var, var, pow) \
|
||||
_(CAT, dst, rbase, rbase, concat) \
|
||||
\
|
||||
/* Constant ops. */ \
|
||||
_(KSTR, dst, ___, str, ___) \
|
||||
_(KCDATA, dst, ___, cdata, ___) \
|
||||
_(KSHORT, dst, ___, lits, ___) \
|
||||
_(KNUM, dst, ___, num, ___) \
|
||||
_(KPRI, dst, ___, pri, ___) \
|
||||
_(KNIL, base, ___, base, ___) \
|
||||
\
|
||||
/* Upvalue and function ops. */ \
|
||||
_(UGET, dst, ___, uv, ___) \
|
||||
_(USETV, uv, ___, var, ___) \
|
||||
_(USETS, uv, ___, str, ___) \
|
||||
_(USETN, uv, ___, num, ___) \
|
||||
_(USETP, uv, ___, pri, ___) \
|
||||
_(UCLO, rbase, ___, jump, ___) \
|
||||
_(FNEW, dst, ___, func, gc) \
|
||||
\
|
||||
/* Table ops. */ \
|
||||
_(TNEW, dst, ___, lit, gc) \
|
||||
_(TDUP, dst, ___, tab, gc) \
|
||||
_(GGET, dst, ___, str, index) \
|
||||
_(GSET, var, ___, str, newindex) \
|
||||
_(TGETV, dst, var, var, index) \
|
||||
_(TGETS, dst, var, str, index) \
|
||||
_(TGETB, dst, var, lit, index) \
|
||||
_(TGETR, dst, var, var, index) \
|
||||
_(TSETV, var, var, var, newindex) \
|
||||
_(TSETS, var, var, str, newindex) \
|
||||
_(TSETB, var, var, lit, newindex) \
|
||||
_(TSETM, base, ___, num, newindex) \
|
||||
_(TSETR, var, var, var, newindex) \
|
||||
\
|
||||
/* Calls and vararg handling. T = tail call. */ \
|
||||
_(CALLM, base, lit, lit, call) \
|
||||
_(CALL, base, lit, lit, call) \
|
||||
_(CALLMT, base, ___, lit, call) \
|
||||
_(CALLT, base, ___, lit, call) \
|
||||
_(ITERC, base, lit, lit, call) \
|
||||
_(ITERN, base, lit, lit, call) \
|
||||
_(VARG, base, lit, lit, ___) \
|
||||
_(ISNEXT, base, ___, jump, ___) \
|
||||
\
|
||||
/* Returns. */ \
|
||||
_(RETM, base, ___, lit, ___) \
|
||||
_(RET, rbase, ___, lit, ___) \
|
||||
_(RET0, rbase, ___, lit, ___) \
|
||||
_(RET1, rbase, ___, lit, ___) \
|
||||
\
|
||||
/* Loops and branches. I/J = interp/JIT, I/C/L = init/call/loop. */ \
|
||||
_(FORI, base, ___, jump, ___) \
|
||||
_(JFORI, base, ___, jump, ___) \
|
||||
\
|
||||
_(FORL, base, ___, jump, ___) \
|
||||
_(IFORL, base, ___, jump, ___) \
|
||||
_(JFORL, base, ___, lit, ___) \
|
||||
\
|
||||
_(ITERL, base, ___, jump, ___) \
|
||||
_(IITERL, base, ___, jump, ___) \
|
||||
_(JITERL, base, ___, lit, ___) \
|
||||
\
|
||||
_(LOOP, rbase, ___, jump, ___) \
|
||||
_(ILOOP, rbase, ___, jump, ___) \
|
||||
_(JLOOP, rbase, ___, lit, ___) \
|
||||
\
|
||||
_(JMP, rbase, ___, jump, ___) \
|
||||
\
|
||||
/* Function headers. I/J = interp/JIT, F/V/C = fixarg/vararg/C func. */ \
|
||||
_(FUNCF, rbase, ___, ___, ___) \
|
||||
_(IFUNCF, rbase, ___, ___, ___) \
|
||||
_(JFUNCF, rbase, ___, lit, ___) \
|
||||
_(FUNCV, rbase, ___, ___, ___) \
|
||||
_(IFUNCV, rbase, ___, ___, ___) \
|
||||
_(JFUNCV, rbase, ___, lit, ___) \
|
||||
_(FUNCC, rbase, ___, ___, ___) \
|
||||
_(FUNCCW, rbase, ___, ___, ___)
|
||||
|
||||
/* Bytecode opcode numbers. */
|
||||
typedef enum {
|
||||
#define BCENUM(name, ma, mb, mc, mt) BC_##name,
|
||||
BCDEF(BCENUM)
|
||||
#undef BCENUM
|
||||
BC__MAX
|
||||
} BCOp;
|
||||
|
||||
LJ_STATIC_ASSERT((int)BC_ISEQV+1 == (int)BC_ISNEV);
|
||||
LJ_STATIC_ASSERT(((int)BC_ISEQV^1) == (int)BC_ISNEV);
|
||||
LJ_STATIC_ASSERT(((int)BC_ISEQS^1) == (int)BC_ISNES);
|
||||
LJ_STATIC_ASSERT(((int)BC_ISEQN^1) == (int)BC_ISNEN);
|
||||
LJ_STATIC_ASSERT(((int)BC_ISEQP^1) == (int)BC_ISNEP);
|
||||
LJ_STATIC_ASSERT(((int)BC_ISLT^1) == (int)BC_ISGE);
|
||||
LJ_STATIC_ASSERT(((int)BC_ISLE^1) == (int)BC_ISGT);
|
||||
LJ_STATIC_ASSERT(((int)BC_ISLT^3) == (int)BC_ISGT);
|
||||
LJ_STATIC_ASSERT((int)BC_IST-(int)BC_ISTC == (int)BC_ISF-(int)BC_ISFC);
|
||||
LJ_STATIC_ASSERT((int)BC_CALLT-(int)BC_CALL == (int)BC_CALLMT-(int)BC_CALLM);
|
||||
LJ_STATIC_ASSERT((int)BC_CALLMT + 1 == (int)BC_CALLT);
|
||||
LJ_STATIC_ASSERT((int)BC_RETM + 1 == (int)BC_RET);
|
||||
LJ_STATIC_ASSERT((int)BC_FORL + 1 == (int)BC_IFORL);
|
||||
LJ_STATIC_ASSERT((int)BC_FORL + 2 == (int)BC_JFORL);
|
||||
LJ_STATIC_ASSERT((int)BC_ITERL + 1 == (int)BC_IITERL);
|
||||
LJ_STATIC_ASSERT((int)BC_ITERL + 2 == (int)BC_JITERL);
|
||||
LJ_STATIC_ASSERT((int)BC_LOOP + 1 == (int)BC_ILOOP);
|
||||
LJ_STATIC_ASSERT((int)BC_LOOP + 2 == (int)BC_JLOOP);
|
||||
LJ_STATIC_ASSERT((int)BC_FUNCF + 1 == (int)BC_IFUNCF);
|
||||
LJ_STATIC_ASSERT((int)BC_FUNCF + 2 == (int)BC_JFUNCF);
|
||||
LJ_STATIC_ASSERT((int)BC_FUNCV + 1 == (int)BC_IFUNCV);
|
||||
LJ_STATIC_ASSERT((int)BC_FUNCV + 2 == (int)BC_JFUNCV);
|
||||
|
||||
/* This solves a circular dependency problem, change as needed. */
|
||||
#define FF_next_N 4
|
||||
|
||||
/* Stack slots used by FORI/FORL, relative to operand A. */
|
||||
enum {
|
||||
FORL_IDX, FORL_STOP, FORL_STEP, FORL_EXT
|
||||
};
|
||||
|
||||
/* Bytecode operand modes. ORDER BCMode */
|
||||
typedef enum {
|
||||
BCMnone, BCMdst, BCMbase, BCMvar, BCMrbase, BCMuv, /* Mode A must be <= 7 */
|
||||
BCMlit, BCMlits, BCMpri, BCMnum, BCMstr, BCMtab, BCMfunc, BCMjump, BCMcdata,
|
||||
BCM_max
|
||||
} BCMode;
|
||||
#define BCM___ BCMnone
|
||||
|
||||
#define bcmode_a(op) ((BCMode)(lj_bc_mode[op] & 7))
|
||||
#define bcmode_b(op) ((BCMode)((lj_bc_mode[op]>>3) & 15))
|
||||
#define bcmode_c(op) ((BCMode)((lj_bc_mode[op]>>7) & 15))
|
||||
#define bcmode_d(op) bcmode_c(op)
|
||||
#define bcmode_hasd(op) ((lj_bc_mode[op] & (15<<3)) == (BCMnone<<3))
|
||||
#define bcmode_mm(op) ((MMS)(lj_bc_mode[op]>>11))
|
||||
|
||||
#define BCMODE(name, ma, mb, mc, mm) \
|
||||
(BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)),
|
||||
#define BCMODE_FF 0
|
||||
|
||||
static LJ_AINLINE int bc_isret(BCOp op)
|
||||
{
|
||||
return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1);
|
||||
}
|
||||
|
||||
LJ_DATA const uint16_t lj_bc_mode[];
|
||||
LJ_DATA const uint16_t lj_bc_ofs[];
|
||||
|
||||
#endif
|
||||
70
thirdPart/luajit/src/lj_bcdump.h
Normal file
70
thirdPart/luajit/src/lj_bcdump.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
** Bytecode dump definitions.
|
||||
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#ifndef _LJ_BCDUMP_H
|
||||
#define _LJ_BCDUMP_H
|
||||
|
||||
#include "lj_obj.h"
|
||||
#include "lj_lex.h"
|
||||
|
||||
/* -- Bytecode dump format ------------------------------------------------ */
|
||||
|
||||
/*
|
||||
** dump = header proto+ 0U
|
||||
** header = ESC 'L' 'J' versionB flagsU [namelenU nameB*]
|
||||
** proto = lengthU pdata
|
||||
** pdata = phead bcinsW* uvdataH* kgc* knum* [debugB*]
|
||||
** phead = flagsB numparamsB framesizeB numuvB numkgcU numknU numbcU
|
||||
** [debuglenU [firstlineU numlineU]]
|
||||
** kgc = kgctypeU { ktab | (loU hiU) | (rloU rhiU iloU ihiU) | strB* }
|
||||
** knum = intU0 | (loU1 hiU)
|
||||
** ktab = narrayU nhashU karray* khash*
|
||||
** karray = ktabk
|
||||
** khash = ktabk ktabk
|
||||
** ktabk = ktabtypeU { intU | (loU hiU) | strB* }
|
||||
**
|
||||
** B = 8 bit, H = 16 bit, W = 32 bit, U = ULEB128 of W, U0/U1 = ULEB128 of W+1
|
||||
*/
|
||||
|
||||
/* Bytecode dump header. */
|
||||
#define BCDUMP_HEAD1 0x1b
|
||||
#define BCDUMP_HEAD2 0x4c
|
||||
#define BCDUMP_HEAD3 0x4a
|
||||
|
||||
/* If you perform *any* kind of private modifications to the bytecode itself
|
||||
** or to the dump format, you *must* set BCDUMP_VERSION to 0x80 or higher.
|
||||
*/
|
||||
#define BCDUMP_VERSION 2
|
||||
|
||||
/* Compatibility flags. */
|
||||
#define BCDUMP_F_BE 0x01
|
||||
#define BCDUMP_F_STRIP 0x02
|
||||
#define BCDUMP_F_FFI 0x04
|
||||
#define BCDUMP_F_FR2 0x08
|
||||
|
||||
#define BCDUMP_F_KNOWN (BCDUMP_F_FR2*2-1)
|
||||
|
||||
#define BCDUMP_F_DETERMINISTIC 0x80000000
|
||||
|
||||
/* Type codes for the GC constants of a prototype. Plus length for strings. */
|
||||
enum {
|
||||
BCDUMP_KGC_CHILD, BCDUMP_KGC_TAB, BCDUMP_KGC_I64, BCDUMP_KGC_U64,
|
||||
BCDUMP_KGC_COMPLEX, BCDUMP_KGC_STR
|
||||
};
|
||||
|
||||
/* Type codes for the keys/values of a constant table. */
|
||||
enum {
|
||||
BCDUMP_KTAB_NIL, BCDUMP_KTAB_FALSE, BCDUMP_KTAB_TRUE,
|
||||
BCDUMP_KTAB_INT, BCDUMP_KTAB_NUM, BCDUMP_KTAB_STR
|
||||
};
|
||||
|
||||
/* -- Bytecode reader/writer ---------------------------------------------- */
|
||||
|
||||
LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer,
|
||||
void *data, uint32_t flags);
|
||||
LJ_FUNC GCproto *lj_bcread_proto(LexState *ls);
|
||||
LJ_FUNC GCproto *lj_bcread(LexState *ls);
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user