Skip to content
Snippets Groups Projects
Commit 72096fad authored by dg's avatar dg
Browse files

Included LuaJIT 1.1, it only works for x86 (NOT i64)

it is off by default it can be turned on when premaking:
premake4 --lua=jitx86 gmake


git-svn-id: http://svn.net-core.org/repos/t-engine4@438 51575b47-30f0-44d4-a5cc-537603b46e54
parent 43ae62bf
No related branches found
No related tags found
No related merge requests found
Showing
with 8827 additions and 9 deletions
-- Turn on LuaJIT if available
pcall(require, "jit")
if jit then
jit.on()
require("jit.opt").start(2)
print("LuaVM:", jit.version, jit.arch)
else
print("LuaVM:", _VERSION)
end
-- Requiring "socketed" instead of "socket" makes sockets work
-- Thsi is due to the way luasocket is embeded statically in TE4
require "socketed"
This diff is collapsed.
----------------------------------------------------------------------------
-- LuaJIT machine code dumper module.
--
-- Copyright (C) 2005-2008 Mike Pall. All rights reserved.
-- Released under the MIT/X license. See luajit.h for full copyright notice.
----------------------------------------------------------------------------
-- Activate this module to dump the machine code for all functions
-- immediately after they have been compiled. The disassembler
-- output is mixed with the bytecode listing.
--
-- Try: luajit -j dump -e 'print "foo"'
-- luajit -j dump=foo.dump foo.lua
-- luajit -j off -j dump -e 'jit.compile(assert(loadfile"foo.lua")))'
--
-- Default output is to stderr. To redirect output to a file,
-- pass a filename as an argument or set the environment variable
-- "LUAJIT_DUMPFILE".
-- Note: The file is overwritten each time you run luajit.
--
-- TODO: Find a way to be more selective on what to dump.
------------------------------------------------------------------------------
-- Priority for compiler pipeline. Must run after backend (negative)
-- and should be even because we only catch successful compiles.
local PRIORITY = -98
-- Cache some library functions and objects.
local jit = require("jit")
assert(jit.version_num == 10105, "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local type, format, gsub = type, string.format, string.gsub
local bytecode, const = jutil.bytecode, jutil.const
local getinfo = debug.getinfo
local stdout, stderr = io.stdout, io.stderr
-- Load the right disassembler.
local dis = require("jit.dis_"..jit.arch)
local discreate, disass_ = dis.create, dis.disass
-- Turn compilation off for the whole module. LuaJIT would do that anyway.
jit.off(true, true)
-- Separator line.
local sepline = "-------------------------------"
-- Map JSUB indices to names.
-- CHECK: must match the order in ljit_x86.h. Regenerate with:
-- grep '^ *JSUB_[^_].*,' ljit_x86.h | sed -e 's/^ *JSUB_/ "/' -e 's/,.*/",/'
local jsubnames = {
"STACKPTR",
"GATE_LJ",
"GATE_JL",
"GATE_JC",
"GROW_STACK",
"GROW_CI",
"GATE_JC_PATCH",
"GATE_JC_DEBUG",
"DEOPTIMIZE_CALLER",
"DEOPTIMIZE",
"DEOPTIMIZE_OPEN",
"HOOKINS",
"GCSTEP",
"STRING_SUB3",
"STRING_SUB2",
"HOOKCALL",
"HOOKRET",
"METACALL",
"METATAILCALL",
"BARRIERF",
"GETGLOBAL",
"GETTABLE_KSTR",
"GETTABLE_STR",
"BARRIERBACK",
"SETGLOBAL",
"SETTABLE_KSTR",
"SETTABLE_STR",
"GETTABLE_KNUM",
"GETTABLE_NUM",
"SETTABLE_KNUM",
"SETTABLE_NUM",
"LOG2_TWORD",
"CONCAT_STR2",
}
-- Generate map from JSUB addresses to JSUB names.
local jsubmap = {}
do
local jsubmcode = jutil.jsubmcode
for pc=0,100000 do
local addr = jsubmcode(pc)
if not addr then break end
jsubmap[addr] = jsubnames[pc+1] or "JSUB#"..pc
end
end
-- Pretty-print a constant.
local function conststr(func, idx)
local k = const(func, idx)
if k == nil then return "nil"
elseif k == true then return "true"
elseif k == false then return "false"
elseif type(k) == "string" then
if #k > 10 then return format('"%.10s"~', k)
else return '"'..k..'"' end
else return k.."" end
end
-- Pretty-print a bytecode instruction (one or two lines).
local function bytecodeout(out, func, pc)
local op, a, b, c = bytecode(func, pc)
if not op then
return true
elseif op == "JMP" then
out:write(format("\n--%04d-- JMP => %04d", pc, pc+1+b))
elseif op == "FORLOOP" or op == "FORPREP" then
out:write(format("\n--%04d-- %-9s %3d => %04d", pc, op, a, pc+1+b))
else
out:write(format("\n--%04d-- %-9s %3d %4s %4s",
pc, op, a, b or "", c or ""))
if b and b < 0 then out:write(" ; ", conststr(func, b)) end
if c and c < 0 then out:write(" ; ", conststr(func, c)) end
end
end
-- Dump machine code and mix it with the bytecode listing.
local function dumpfunc(func, out, deopt)
if not out then out = stderr end
local info = getinfo(func, "S")
-- Don't bother checking for the right blocks to dump.
-- Dump the main block (if not deopt) and always all deopt blocks.
for block=deopt and 2 or 1,1000000 do
local addr, code, mfmiter = jutil.mcode(func, block)
if not addr then
if code then return code end -- Not compiled: return status.
break -- No more blocks to dump.
end
-- Print header.
out:write(sepline, " ", info.source, ":", info.linedefined)
if block ~= 1 then out:write(" DEOPT block ", block) end
-- Create disassembler context.
local ctx = discreate(code, addr, function(s) out:write(s) end)
ctx.symtab = jsubmap
-- Dump an mcode block.
local pc, ofs = 1, 0
local len, isdeopt = mfmiter()
if isdeopt then pc = len; len = 0
elseif block ~= 1 then break end -- Stop before next main block.
for t, m in mfmiter do
if t == "COMBINE" then
bytecodeout(out, func, pc)
else
if len ~= 0 then
out:write("\n")
if len > 0 then
ctx:disass(ofs, len)
ofs = ofs + len
else
out:write(format("%08x ** deoptimized\n", addr+ofs))
ofs = ofs - len
end
len = 0
end
if type(t) == "number" then
if m then
if isdeopt then
pc = t - 1
else
bytecodeout(out, func, pc)
len = -t
end
else
len = t
if bytecodeout(out, func, pc) then break end
end
end
end
pc = pc + 1
end
if len and len ~= 0 then
out:write(sepline, " tail code\n")
ctx:disass(ofs, len)
end
end
-- Print footer.
out:write(sepline, "\n")
out:flush()
end
-- Dump the internal JIT subroutines.
local function dumpjsub_(out)
if not out then out = stderr end
local addr, code = jutil.jsubmcode()
-- Create disassembler context.
local ctx = discreate(code, addr, function(s) out:write(s) end)
ctx.symtab = jsubmap
-- Collect addresses and sort them.
local t = {}
for addr in pairs(jsubmap) do t[#t+1] = addr end
t[#t+1] = addr + #code
table.sort(t)
-- Go through the addresses in ascending order.
local ofs = addr
for i=2,#t do
local next = t[i]
out:write("\n->", jsubmap[ofs], ":\n") -- Output label for JSUB.
ctx:disass(ofs-addr, next-ofs) -- Disassemble corresponding code block.
ofs = next
end
out:flush()
end
-- Active flag and output file handle.
local active, out
-- Dump handler for compiler pipeline.
local function h_dump(st)
local ok, err = pcall(dumpfunc, st.func, out, st.deopt)
if not ok then
stderr:write("\nERROR: jit.dump disabled: ", err, "\n")
jit.attach(h_dump) -- Better turn ourselves off after a failure.
if out and out ~= stdout then out:close() end
out = nil
active = nil
end
end
-- Detach dump handler from compiler pipeline.
local function dumpoff()
if active then
active = false
jit.attach(h_dump)
if out and out ~= stdout then out:close() end
out = nil
end
end
-- Open the output file and attach dump handler to compiler pipeline.
local function dumpon(filename)
if active then dumpoff() end
local outfile = filename or os.getenv("LUAJIT_DUMPFILE")
out = outfile and (outfile == "-" and stdout or assert(io.open(outfile, "w")))
jit.attach(h_dump, PRIORITY)
active = true
end
-- Public module functions.
module(...)
disass = disass_
dump = dumpfunc
dumpjsub = dumpjsub_
on = dumpon
off = dumpoff
start = dumpon -- For -j command line option.
----------------------------------------------------------------------------
-- LuaJIT hints dumper module.
--
-- Copyright (C) 2005-2008 Mike Pall. All rights reserved.
-- Released under the MIT/X license. See luajit.h for full copyright notice.
----------------------------------------------------------------------------
-- Activate this module to dump the bytecode and the hints from
-- the optimizer for all functions to be compiled.
--
-- Try: luajit -O -j dumphints -e 'return 1'
--
-- Default output is to stderr. To redirect output to a file,
-- pass a filename as an argument or set the environment variable
-- "LUAJIT_DUMPHINTSFILE".
-- Note: The file is overwritten each time you run luajit.
--
-- TODO: Find a way to be more selective on what to dump.
------------------------------------------------------------------------------
-- Priority for compiler pipeline. Should run before backend (positive)
-- and should be even because we only catch successful compiles.
local PRIORITY = 10
-- Cache some library functions and objects.
local jit = require("jit")
assert(jit.version_num == 10105, "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local type, pairs, format = type, pairs, string.format
local bytecode, const = jutil.bytecode, jutil.const
local hints, fhints = jutil.hints, jutil.fhints
local stdout, stderr = io.stdout, io.stderr
-- Turn compilation off for the whole module. LuaJIT would do that anyway.
jit.off(true, true)
-- Separator line.
local sepline = "-------------------------------"
-- Pretty-print a constant.
local function conststr(func, idx)
local k = const(func, idx)
if k == nil then return "nil"
elseif k == true then return "true"
elseif k == false then return "false"
elseif type(k) == "string" then
if #k > 10 then return format('"%.10s"~', k)
else return '"'..k..'"' end
else return k.."" end
end
-- Pretty-print a bytecode instruction.
local function bytecodeline(func, pc, flag)
local op, a, b, c = bytecode(func, pc)
if not op then return end
if op == "JMP" then
return format("\n%04d %s JMP => %04d", pc, flag, pc+1+b)
end
if op == "FORLOOP" or op == "FORPREP" then
return format("\n%04d %s %-9s %3d => %04d", pc, flag, op, a, pc+1+b)
end
local s = format("\n%04d %s %-9s %3d %4s %4s",
pc, flag, op, a, b or "", c or "")
if b and b < 0 then s = s.." ; "..conststr(func, b) end
if c and c < 0 then s = s.." ; "..conststr(func, c) end
return s
end
-- Precompute inverse hints table.
local invhints = {}
for k,v in pairs(hints) do invhints[v] = k end
-- The inverse resolver for inline functions is loaded on demand.
local getname
-- Helper functions to pretty-print hints.
local function typehint(h, v, st, pc)
if st[pc+hints.INLINE] then return "" end
local tp = type(v)
if tp == "function" then
tp = debug.getinfo(v, "S").what
elseif tp == "number" and v % 1 == 0 then
tp = "integer"
elseif v == false then
tp = "mixed"
end
return " #"..h.."("..tp..")"
end
local hintprint = {
COMBINE = function(h, v, st, pc)
if v == false then return "" end -- Dead instructions are already marked.
end,
TYPE = typehint,
TYPEKEY = typehint,
INLINE = function(h, v, st, pc)
if not getname then getname = require("jit.opt_inline").getname end
return " #INLINE("..getname(st[pc+hints.TYPE], v)..")"
end,
}
-- Generate range string from table: pc[-pc] [,...]
local function rangestring(t)
local s = ""
for i,range in ipairs(t) do
if i ~= 1 then s = s.."," end
local pc = range % 65536
range = (range - pc) / 65536
s = s..pc
if range ~= 0 then s = s..(-(pc+range)) end
end
return s
end
-- Dump instructions and hints for a (to be compiled) function.
local function dumphints(st, out)
if not out then out = stderr end
local func = st.func
local COMBINE = hints.COMBINE
-- Need to recompute branch targets (not part of hints).
local target = {}
for pc=1,1e6 do
local op, a, b, c = bytecode(func, pc)
if not op then break end
if op == "JMP" or op == "FORLOOP" then
local t = pc+1+b
if st[pc+COMBINE] ~= false then target[t] = true end
elseif op == "LOADBOOL" and c ~= 0 then
target[pc+2] = true
end
end
-- Map hints to bytecode instructions.
local hintstr = {}
for k,v in pairs(st) do
-- CHECK: must match hint shift in ljit_hints.h:JIT_H2NUM().
if type(k) == "number" and k >= 65536 then
local pc = k % 65536
if pc > 0 then
k = k - pc
local h = invhints[k] or (k/65536)
local hp = hintprint[h]
local s = hp and hp(h, v, st, pc) or (" #"..h)
local hs = hintstr[pc]
hintstr[pc] = hs and (hs..s) or s
end
end
end
-- Write header.
local info = debug.getinfo(func, "S")
out:write(sepline, " ", info.source, ":", info.linedefined)
-- Write function hints.
for k,v in pairs(fhints) do
if st[v] then out:write("\n#", k) end
end
-- Write instruction hints and bytecode.
local function dumprange(firstpc, lastpc)
for pc=firstpc,lastpc do
local prefix = " "
if st[pc+COMBINE] == false then prefix = "**"
elseif target[pc] then prefix = "=>" end
local line = bytecodeline(func, pc, prefix)
if not line then break end
local h = hintstr[pc]
if h then
out:write(format("%-40s %s", line, h))
else
out:write(line)
end
end
end
-- Handle deoptimization range table.
local t = st.deopt
if t then
out:write(" DEOPT=", rangestring(t))
for i,range in ipairs(t) do
if i ~= 1 then out:write("\n----") end
local pc = range % 65536
range = (range - pc) / 65536
dumprange(pc, pc+range)
end
else
dumprange(1, 1000000)
end
-- Write footer.
out:write("\n", sepline, "\n")
out:flush()
end
-- Active flag and output file handle.
local active, out
-- Dump hints handler for compiler pipeline.
local function h_dumphints(st)
local ok, err = pcall(dumphints, st, out)
if not ok then
stderr:write("\nERROR: jit.dumphints disabled: ", err, "\n")
jit.attach(h_dumphints) -- Better turn ourselves off after a failure.
if out and out ~= stdout then out:close() end
out = nil
active = nil
end
end
-- Detach dump handler from compiler pipeline.
local function dumphintsoff()
if active then
active = false
jit.attach(h_dumphints)
if out and out ~= stdout then out:close() end
out = nil
end
end
-- Open the output file and attach dump handler to compiler pipeline.
local function dumphintson(filename)
if active then dumphintsoff() end
local outfile = filename or os.getenv("LUAJIT_DUMPHINTSFILE")
out = outfile and (outfile == "-" and stdout or assert(io.open(outfile, "w")))
jit.attach(h_dumphints, PRIORITY)
active = true
end
-- Public module functions.
module(...)
dump = dumphints
on = dumphintson
off = dumphintsoff
start = dumphintson -- For -j command line option.
----------------------------------------------------------------------------
-- LuaJIT optimizer.
--
-- Copyright (C) 2005-2008 Mike Pall. All rights reserved.
-- Released under the MIT/X license. See luajit.h for full copyright notice.
----------------------------------------------------------------------------
-- This module contains a simple optimizer that generates some hints for
-- the compiler backend.
--
-- Compare: luajit -j dump -e 'return 1'
-- with: luajit -O -j dumphints -j dump -e 'return 1'
--
-- This module uses a very simplistic (but fast) abstract interpretation
-- algorithm. It mostly ignores control flow and/or basic block boundaries.
-- Thus the results of the analysis are really only predictions (e.g. about
-- monomorphic use of operators). The backend _must_ check all contracts
-- (e.g. verify the object type) and use a (polymorphic) fallback or
-- deoptimization in case a contract is broken.
--
-- Although simplistic, the generated hints are pretty accurate. Note that
-- some hints are really definitive and don't need to be checked (like
-- COMBINE or FOR_STEP_K).
--
-- TODO: Try MFP with an extended lattice. But it's unclear whether the
-- added complexity really pays off with the current backend.
------------------------------------------------------------------------------
-- Priority for compiler pipeline. Right in the middle before the backend.
local PRIORITY = 50
-- Default optimizer level, i.e. what you get with -O.
-- Caveat: this may change in the future when more optimizations are added.
local OPTLEVEL = 2
-- Heuristic limits for what the compiler should reasonably handle.
-- Functions outside these limits are unlikely to be run more than once.
-- Maybe a bit on the generous side. Check ljit.h for backend limits, too.
-- TODO: make it depend on the bytecode distribution, too.
local LIMITS = {
bytecodes = 4000,
stackslots = 150,
params = 20,
consts = 200,
subs = 30,
}
-- Cache some library functions and objects.
local jit = require("jit")
assert(jit.version_num == 10105, "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local type, rawget, next, pcall = type, rawget, next, pcall
local bytecode, const = jutil.bytecode, jutil.const
local hints, fhints = jutil.hints, jutil.fhints
local getmetatable = getmetatable
-- Turn compilation off for the whole module. LuaJIT would do that anyway.
jit.off(true, true)
-- Default optimizer level after loading. But -O runs setlevel(), too.
local optlevel = -1
-- Use iterative path marking to mark live instructions and branch targets.
local function marklive(func)
local live, work, workn, pc = {}, {}, 0, 1
repeat
repeat
local op, a, b, c, test = bytecode(func, pc)
live[pc] = true
pc = pc + 1
if op == "JMP" then
pc = pc + b
live[-pc] = true
elseif op == "FORLOOP" then
local mpc = -pc
live[mpc - b] = true
live[mpc] = true
elseif op == "RETURN" then
break
elseif test then
local fpc = pc + 1
-- No need for fallthrough target mark live[-fpc] in our analysis.
if not live[fpc] then -- Add fallthrough path to work list.
workn = workn + 1
work[workn] = fpc
end
elseif op == "CLOSURE" then
pc = pc + jutil.closurenup(func, b) -- Do not mark pseudo-ins live.
elseif op == "LOADBOOL" and c ~= 0 then
pc = pc + 1
live[-pc] = true
elseif op == "SETLIST" and c == 0 then
pc = pc + 1 -- Do not mark pseudo-ins live.
end
until live[pc]
if workn == 0 then return live end -- Return if work list is empty.
pc = work[workn] -- Else fetch next path to mark from work list.
workn = workn - 1
until false
end
-- Empty objects.
local function empty() end
-- Dummy function to set call hints. Replaced when jit.opt_inline is loaded.
local function callhint(st, slot, pc, base, narg, nres)
st[pc+hints.TYPE] = slot[base]
for i=base,base+nres-1 do slot[i] = nil end
end
-- Set TYPE hint, but only for numbers, strings or tables.
local function typehint(st, pc, o)
local tp = type(o)
if tp == "number" or tp == "string" or tp == "table" then
st[pc+hints.TYPE] = o
end
end
-- Set TYPE and TYPEKEY hints for table operations.
local function tablehint(st, slot, pc, t, kslot)
local tp = type(t)
if tp == "table" or tp == "userdata" then st[pc+hints.TYPE] = t end
if kslot >= 0 then -- Don't need this hint for constants.
local key = slot[kslot]
local tp = type(key)
if tp == "number" or tp == "string" then st[pc+hints.TYPEKEY] = key end
end
end
-- Try to lookup a value. Guess the value or at least the value type.
local function trylookup(st, t, k)
if k == nil then return nil end
if type(t) == "table" then
local v = rawget(t, k)
if v ~= nil then return v end
end
local mt = getmetatable(t)
if type(mt) == "table" then
-- One __index level is enough for our purposes.
local it = rawget(mt, "__index")
if type(it) == "table" then
local v = rawget(it, k)
if v ~= nil then return v end
end
end
local v = st.tableval[t] -- Resort to a generic guess.
if v == nil and type(t) == "table" then v = next(t) end -- Getting desperate.
return v
end
-- Check whether the previous instruction sets a const.
local function prevconst(st, slot, pc, reg)
if st.live[-pc] == nil then -- Current instruction must not be a target.
local op, ka, kb = bytecode(st.func, pc-1)
if ka == reg and (op == "LOADK" or op == "LOADBOOL" or
(op == "LOADNIL" and kb == reg)) then
return true, slot[reg]
end
end
end
-- Common handler for arithmetic and comparison opcodes.
local function arithop(st, slot, pc, a, b, c, op)
local sb, sc = slot[b], slot[c]
if sb == nil then sb = sc elseif sc == nil then sc = sb end
local tb, tc = type(sb), type(sc)
if tb == tc then
if tb == "number" then -- Improve the guess for numbers.
if op == "DIV" or sb % 1 ~= 0 or sc % 1 ~= 0 then
sb = 0.5 -- Probably a non-integral number.
else
sb = 1 -- Optimistic guess.
end
end
if sb ~= nil then st[pc+hints.TYPE] = sb end
else
st[pc+hints.TYPE] = false -- Marker for mixed types.
end
if op ~= "LT" and op ~= "LE" then
slot[a] = sb -- Assume coercion to 1st type if different.
end
end
-- Common handler for TEST and TESTSET.
local function testop(st, slot, pc, a, b, c)
-- Optimize the 'expr and k1 or k2' idiom.
local ok, k = prevconst(st, slot, pc, b)
if k and a == b then
st[pc+hints.COMBINE] = false -- Kill the TEST/TESTSET.
if c == 0 then st.live[pc+1] = nil end -- Kill the JMP.
end
slot[a] = slot[b]
end
-- Dispatch table for opcode handlers.
local handler = {
MOVE = function(st, slot, pc, a, b, c)
slot[a] = slot[b]
end,
LOADK = function(st, slot, pc, a, b, c)
slot[a] = const(st.func, b)
end,
LOADBOOL = function(st, slot, pc, a, b, c)
slot[a] = (b == 1)
end,
LOADNIL = function(st, slot, pc, a, b, c)
for i=a,b do slot[i] = nil end
end,
GETUPVAL = function(st, slot, pc, a, b, c)
slot[a] = jutil.upvalue(st.func, b)
end,
GETGLOBAL = function(st, slot, pc, a, b, c)
slot[a] = trylookup(st, st.stats.env, const(st.func, b))
end,
GETTABLE = function(st, slot, pc, a, b, c)
local t = slot[b]
tablehint(st, slot, pc, t, c)
slot[a] = trylookup(st, t, slot[c])
end,
SETGLOBAL = empty,
SETUPVAL = empty, -- TODO: shortcut -- but this is rare?
SETTABLE = function(st, slot, pc, a, b, c)
local t = slot[a]
tablehint(st, slot, pc, t, b)
if type(t) == "table" or type(t) == "userdata" then -- Must validate setkey.
local val = slot[c]
if val ~= nil then st.tableval[t] = val end
end
end,
NEWTABLE = function(st, slot, pc, a, b, c)
slot[a] = {} -- Need unique tables for indexing st.tableval.
end,
SELF = function(st, slot, pc, a, b, c)
local t = slot[b]
tablehint(st, slot, pc, t, c)
slot[a+1] = t
slot[a] = trylookup(st, t, slot[c])
end,
ADD = arithop, SUB = arithop, MUL = arithop, DIV = arithop,
MOD = arithop, POW = arithop, LT = arithop, LE = arithop,
UNM = function(st, slot, pc, a, b, c)
return arithop(st, slot, pc, a, b, b, "UNM")
end,
NOT = function(st, slot, pc, a, b, c)
slot[a] = true
end,
LEN = function(st, slot, pc, a, b, c)
typehint(st, pc, slot[b])
slot[a] = 1
end,
CONCAT = function(st, slot, pc, a, b, c)
local mixed
local sb = slot[b]
for i=b+1,c do
local si = slot[i]
if sb == nil then
sb = si
elseif si ~= nil and type(sb) ~= type(si) then
mixed = true
break
end
end
if sb == nil then
sb = ""
else
st[pc+hints.TYPE] = not mixed and sb or false
if type(sb) == "number" then sb = "" end
end
slot[a] = sb -- Assume coercion to 1st type (if different) or string.
end,
JMP = function(st, slot, pc, a, b, c)
if b >= 0 then -- Kill JMPs across dead code.
local tpc = pc + b
while not st.live[tpc] do tpc = tpc - 1 end
if tpc == pc then st[pc+hints.COMBINE] = false end
end
end,
EQ = function(st, slot, pc, a, b, c)
if b >= 0 and c >= 0 then typehint(st, pc, slot[b] or slot[c]) end
end,
TEST = function(st, slot, pc, a, b, c)
return testop(st, slot, pc, a, a, c)
end,
TESTSET = testop,
CALL = function(st, slot, pc, a, b, c)
callhint(st, slot, pc, a, b-1, c-1)
end,
TAILCALL = function(st, slot, pc, a, b, c)
callhint(st, slot, pc, a, b-1, -1)
end,
RETURN = function(st, slot, pc, a, b, c)
if b == 2 and prevconst(st, slot, pc, a) then
st[pc-1+hints.COMBINE] = true -- Set COMBINE hint for prev. instruction.
end
end,
FORLOOP = empty,
FORPREP = function(st, slot, pc, a, b, c)
local ok, step = prevconst(st, slot, pc, a+2)
if type(step) == "number" then
st[pc+hints.FOR_STEP_K] = step
end
local nstart, nstep = slot[a], slot[a+2]
local tnstart, tnstep = type(nstart), type(nstep)
local ntype = ((tnstart == "number" and nstart % 1 ~= 0) or
(tnstep == "number" and nstep % 1 ~= 0)) and 0.5 or 1
slot[a+3] = ntype
if tnstart == "number" and tnstep == "number" and
type(slot[a+1]) == "number" then
st[pc+hints.TYPE] = ntype
end
end,
-- TFORLOOP is at the end of the loop. Setting slots would be pointless.
-- Inlining is handled by the corresponding iterator constructor (CALL).
TFORLOOP = function(st, slot, pc, a, b, c)
st[pc+hints.TYPE] = slot[a]
end,
SETLIST = function(st, slot, pc, a, b, c)
-- TODO: if only (numeric) const: shortcut (+ nobarrier).
local t = slot[a]
-- Very imprecise. But better than nothing.
if type(t) == "table" then st.tableval[t] = slot[a+1] end
end,
CLOSE = empty,
CLOSURE = function(st, slot, pc, a, b, c)
slot[a] = empty
if st.noclose then
local nup = jutil.closurenup(st.func, b)
for i=pc+1,pc+nup do
local op = bytecode(st.func, i)
if op == "MOVE" then
st.noclose = false
return
end
end
end
end,
VARARG = function(st, slot, pc, a, b, c)
local params = st.stats.params
for i=1,b do slot[a+i-1] = st[params+i] end
end,
}
-- Generate some hints for the compiler backend.
local function optimize(st)
-- Deoptimization is simple: just don't generate any hints. :-)
if st.deopt then return end
local func = st.func
local stats = jutil.stats(func)
if not stats then return jutil.status.COMPILER_ERROR end -- Eh?
-- Check limits.
if stats.bytecodes > LIMITS.bytecodes or
stats.stackslots > LIMITS.stackslots or
stats.params > LIMITS.params or
stats.consts > LIMITS.consts or
stats.subs > LIMITS.subs then
return jutil.status.TOOLARGE
end
-- Mark live instructions (live[pc]) and branch targets (live[-pc]).
local live = marklive(func)
-- Handlers need access to some temporary state fields.
st.noclose = true
st.stats = stats
st.live = live
st.tableval = { [stats.env] = empty } -- Guess: unknown globals are functions.
-- Initialize slots with argument hints and constants.
local slot = {}
for i=1,stats.params do slot[i-1] = st[i] end
for i=-1,-256,-1 do -- No need to copy non-RK-able consts.
local k, ok = const(func, i)
if not ok then break end
slot[i] = k
end
-- Step through all live instructions, update slots and add hints.
for pc=1,stats.bytecodes do
if live[pc] then
local op, a, b, c, test = bytecode(func, pc)
handler[op](st, slot, pc, a, b, c, op)
else
st[pc+hints.COMBINE] = false -- Dead instruction hint.
end
end
-- Update function hints.
if st.noclose then st[fhints.NOCLOSE] = true end
-- Clear temporary state fields.
st.noclose = nil
st.stats = nil
st.live = nil
st.tableval = nil
end
-- Active flags.
local active, active_opt_inline
-- Handler for compiler pipeline.
local function h_opt(st)
if optlevel <= 0 then return end
local ok, err = pcall(optimize, st)
if not ok then
io.stderr:write("\nERROR: jit.opt disabled: ", err, "\n")
jit.attach(h_opt) -- Better turn ourselves off after a failure.
active = nil
else
if err then return err end
end
end
-- Load add-on module.
local function loadaddon(opt)
local name, val = string.match(opt, "^(.-)=(.*)$") -- Strip value.
if not name then name = opt end
name = "jit.opt_"..name
local ok, mod = pcall(require, name)
if not ok then
-- Return error if not installed, but propagate other errors.
if string.sub(mod, 1, 7) ~= "module " then error(mod, 0) end
return "optimizer add-on module "..name.." not found"
end
mod.start(val)
end
-- Attach optimizer and set optimizer level or load add-on module.
local function setlevel_(opt)
-- Easier to always attach the optimizer (even for -O0).
if not active then
jit.attach(h_opt, PRIORITY)
active = true
end
-- Parse -O<level> or -O<name[=value]>.
if opt == nil or opt == "" then
optlevel = OPTLEVEL
else
local level = tonumber(opt) -- Numeric level?
if level then
if level < 0 or level % 1 ~= 0 then
error("bad optimizer level", 0)
end
optlevel = level
else
if optlevel == -1 then optlevel = OPTLEVEL end
local err = loadaddon(opt)
if err then error(err, 0) end
end
end
-- Load add-on module for inlining functions for -O2 and above.
if not active_opt_inline and optlevel >= 2 then
loadaddon("inline") -- Be silent if not installed.
active_opt_inline = true -- Try this only once.
end
end
-- Public module functions.
module(...)
-- Callback to allow attaching a call hinter. Used by jit.opt_inline.
function attach_callhint(f)
callhint = f
end
function getlevel()
return optlevel
end
setlevel = setlevel_
start = setlevel_ -- For -O command line option.
----------------------------------------------------------------------------
-- LuaJIT optimizer add-on module for function inlining.
--
-- Copyright (C) 2005-2008 Mike Pall. All rights reserved.
-- Released under the MIT/X license. See luajit.h for full copyright notice.
----------------------------------------------------------------------------
-- This is a simple framework for C function signature maps.
-- It helps with type propagation and C function inlining.
--
-- This module is automatically loaded with -O2 and above.
-- By default most standard library functions are added.
--
-- TODO: generalize it, e.g. for back propagation (i.e. arg types).
-- TODO: extend it for Lua functions (but need to analyze them before use).
------------------------------------------------------------------------------
-- Cache some library functions and objects.
local jit = require("jit")
assert(jit.version_num == 10105, "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local type, rawget, next = type, rawget, next
local hints, fhints = jutil.hints, jutil.fhints
local sub, match, gsub = string.sub, string.match, string.gsub
-- Turn compilation off for the whole module. LuaJIT would do that anyway.
jit.off(true, true)
-- Prototypical objects used for type hints.
local TABLE = {}
local CFUNC = collectgarbage -- Pretty sure this is never inlined.
-- Map from C closures to signatures. Cannot use a weak table.
-- Closures must be kept alive because inlining checks against their addrs.
local map_sign = {}
-- For jit.dumphints: get printable name for TYPE hint: "#INLINE(foo.bar)".
local function getname_(f, idx)
local sign = map_sign[f]
if sign then
local libname, name = sign.libname, sign.name
if libname then
return libname.."."..name
else
return name
end
elseif idx == 0 then
return "recursive"
else
return "?"
end
end
-- Name, base table and running index for convenience functions.
-- CHECK: the library index and the order below must match with ljit_hints.h
local flibname, flib, fidx
local function fadd(name, results, args, handler)
local f = rawget(flib, name)
if f then
map_sign[f] = {
libname = flibname, name = name, idx = fidx,
results = results, args = args, handler = handler,
}
end
if fidx then fidx = fidx + 1 end
end
local function faddf(name, f, results, args, handler)
map_sign[f] = {
libname = flibname, name = name, idx = fidx,
results = results, args = args, handler = handler,
}
if fidx then fidx = fidx + 1 end
end
-- Signature handler: copy first argument to first result.
local function copyfirst(st, slot, pc, base, narg, nres)
slot[base] = slot[base+1]
end
-- Helper for iterators: check if the function is an iterator constructor.
--
-- 'for ivars in func(args) do body end'
--
-- ...load func+args...
-- CALL func <-- pc
-- JMP fwd ---+
-- back: | <--+
-- ...body... | |
-- fwd: <--+ |
-- TFORLOOP ivars | <-- tforpc
-- JMP back ---+
--
local function itercheck(st, slot, pc, base, idx)
if idx then
local bytecode, func = jutil.bytecode, st.func
local op, _, fwd = bytecode(func, pc+1)
if op == "JMP" then
local tforpc = pc+2+fwd
local op, tfbase, _, tfnres = bytecode(func, tforpc)
if op == "TFORLOOP" and tfbase == base and tfnres <= 2 then
local op, _, back = bytecode(func, tforpc+1)
if op == "JMP" and fwd+back == -2 then
-- Must set inlining hint for TFORLOOP instruction here.
st[tforpc+hints.INLINE] = idx -- Serves as iterator index, too.
return -- Inline it.
end
end
end
end
slot[base] = CFUNC -- Better make it different from pairs.
return true -- Better not inline it, if not used in a for statement.
end
-- Helper for pairs/next: guess result types for standard table iterator.
local function guessnext(st, slot, base, dest)
local t, k, v = slot[base+1]
if type(t) == "table" then
k, v = next(t)
if v == nil then v = st.tableval[t] end
end
slot[dest] = k or "" -- Strings are a good guess for the key type.
slot[dest+1] = v -- But better not guess any fixed value type.
end
-- Signatures for base library functions.
-- Note: Only add functions where result type hints or inlining makes sense.
flibname, flib, fidx = nil, _G, 65536*1
fadd("pairs", "..0", "T",
function(st, slot, pc, base, narg, nres, idx)
-- Table in slot[base+1] is kept (2nd result = 1st arg).
-- Fill result slots for the iterator here (TFORLOOP is at the end).
guessnext(st, slot, base, base+3)
return itercheck(st, slot, pc, base, idx)
end)
fadd("ipairs", "..I", "T",
function(st, slot, pc, base, narg, nres, idx)
-- Table in slot[base+1] is kept (2nd result = 1st arg).
-- Fill result slots for the iterator here (TFORLOOP is at the end).
local t = slot[base+1]
slot[base+3] = 1 -- Integer key.
local v
if type(t) == "table" then
v = rawget(t, 1)
if v == nil then v = st.tableval[t] end
end
slot[base+4] = v
return itercheck(st, slot, pc, base, idx)
end)
fidx = nil -- Pure result type signatures follow:
fadd("next", "..", "T.?",
function(st, slot, pc, base, narg, nres)
guessnext(st, slot, base, base)
end)
fadd("type", "S", ".")
fadd("getmetatable", "T", ".")
fadd("setmetatable", ".", "TT?", copyfirst)
fadd("rawequal", "B", "..")
fadd("rawget", ".", "T.",
function(st, slot, pc, base, narg, nres)
local t = slot[base+1]
slot[base] = type(t) == "table" and rawget(t, slot[base+2]) or ""
end)
fadd("rawset", ".", "T..", copyfirst)
fadd("assert", "*", "..*",
function(st, slot, pc, base, narg, nres)
for i=1,nres do slot[base+i-1] = i <= narg and slot[base+i] or nil end
end)
fadd("tonumber", "I", ".I?")
fadd("tostring", "S", ".")
fadd("require", "T", "S")
-- Signatures for coroutine library functions.
flibname, flib, fidx = "coroutine", coroutine, 65536*2
if flib then
fadd("yield", "*", ".*")
fadd("resume", "*", "R.*",
function(st, slot, pc, base, narg, nres)
slot[base] = true
for i=1,nres-1 do slot[base+i] = nil end -- No guess.
end)
fidx = nil -- Pure result type signatures follow:
fadd("wrap", "C", "F")
end
-- Signatures for string library functions.
flibname, flib, fidx = "string", string, 65536*3
if flib then
fadd("len", "I", "S")
fadd("sub", "S", "SII?")
fadd("char", "S", "I*")
fidx = nil -- Pure result type signatures follow:
fadd("byte", "I", "S",
function(st, slot, pc, base, narg, nres)
for i=0,nres-1 do slot[base+i] = 1 end -- Set all result hints.
end)
fadd("rep", "S", "SI")
fadd("reverse", "S", "S")
fadd("upper", "S", "S")
fadd("lower", "S", "S")
fadd("format", "S", "S.*")
fadd("find", "*", "SSI?.?",
function(st, slot, pc, base, narg, nres)
slot[base] = 1
slot[base+1] = 1
for i=2,nres-1 do slot[base+i] = "" end -- Hints for matches.
end)
fadd("match", "*", "SSI?",
function(st, slot, pc, base, narg, nres)
for i=0,nres-1 do slot[base+i] = "" end -- Hints for matches.
end)
fadd("gsub", "SI", "SSGI?")
fadd("gmatch", "C00", "SS",
function(st, slot, pc, base, narg, nres)
-- Fill result slots for gmatch_iter here (TFORLOOP is at the end).
for i=base+3,st.stats.stackslots-1 do slot[i] = "" end
end)
-- The gmatch iterator itself is never inlined. No point in adding it.
end
-- Signatures for table library functions.
flibname, flib, fidx = "table", table, 65536*4
if flib then
fadd("insert", "", "TI?.")
fadd("remove", ".", "T",
function(st, slot, pc, base, narg, nres)
if nres >= 1 then
local t = slot[base+1]
slot[base] = type(t) == "table" and rawget(t, 1) or ""
end
end)
fadd("getn", "I", "T")
fidx = nil -- Pure result type signatures follow:
fadd("concat", "S", "TS?I?I?")
end
-- Signatures for math library functions.
flibname, flib, fidx = "math", math, 65536*5
if flib then
-- 1 arg, 1 result.
fadd("log", "N", "N")
fadd("log10", "N", "N")
fadd("exp", "N", "N")
fadd("sinh", "N", "N")
fadd("cosh", "N", "N")
fadd("tanh", "N", "N")
fadd("asin", "N", "N")
fadd("acos", "N", "N")
fadd("atan", "N", "N")
fadd("sin", "N", "N")
fadd("cos", "N", "N")
fadd("tan", "N", "N")
fadd("ceil", "I", "N")
fadd("floor", "I", "N")
fadd("abs", ".", "N", copyfirst)
fadd("sqrt", "N", "N")
-- 2 args, 1 result.
-- math.fmod is aliased to math.mod for compatibility.
fadd("fmod", ".", "NN",
function(st, slot, pc, base, narg, nres)
slot[base] = slot[base+2] or 1 -- Copy integer or number hint.
end)
fadd("atan2", "N", "NN")
fidx = nil -- Pure result type signatures follow:
-- 1-n args, 1 result.
fadd("min", ".", "NN*", copyfirst) -- Really depends on all args.
fadd("max", ".", "NN*", copyfirst) -- Really depends on all args.
-- 1 arg, 1 result.
fadd("deg", "N", "N")
fadd("rad", "N", "N")
-- 1 arg, 2 results.
fadd("modf", "IN", "N")
fadd("frexp", "NI", "N")
-- 2 args, 1 result.
fadd("pow", "N", "NN")
fadd("ldexp", ".", "NI", copyfirst)
-- 1 arg, 0 results.
fadd("randomseed", "", "I")
-- 0-2 args, 1 result.
fadd("random", "N", "I?I?",
function(st, slot, pc, base, narg, nres)
if narg > 0 then slot[base] = 1 end
end)
end
-- Signatures for I/O library functions.
-- Not inlined anytime soon. Used for result types only.
flibname, flib, fidx = "io", io, nil
if flib then
fadd("lines", "C00S", "S?")
fadd("read", "S", "") -- Simplified (a lot).
-- Adding io methods doesn't work, because we don't deal with userdata (yet).
end
-- Type names to argument type shorthands.
-- TODO: make the matches more exact? Need to differentiate nil/unknown.
local map_argtype = {
["nil"] = "0", boolean = "b", number = "n", string = "s",
table = "t", ["function"] = "f", userdata = "u", thread = "r",
}
-- Complex argument match patterns to regexp fragments.
local map_argmatch = {
B = "[b0]", S = "[s0]", T = "[t0]", F = "[f0]", U = "[u0]", R = "[r0]",
N = "[n0]", I = "[n0]", -- Number/int args are the same for now.
G = "[stf0]", -- For string.gsub.
}
-- Result type shorthands to sample types.
local map_restype = {
-- ["0"] = nil,
B = true, S = "", T = {},
N = 0.5, I = 1,
L = function() end, C = collectgarbage, -- Pretty sure this is never inlined.
}
-- Create argument match regexp and cache it.
local function getargmatch(sign)
local argmatch = "^"..gsub(sign.args, ".", map_argmatch).."0*$"
sign.argmatch = argmatch
return argmatch
end
-- Set INLINE hints and result types for known C functions.
local function inlinehint(sign, st, slot, pc, base, narg, nres)
local idx = sign.idx
if idx then
if narg ~= -1 then
local argpat = ""
for i=1,narg do argpat = argpat..map_argtype[type(slot[base+i])] end
if not match(argpat, sign.argmatch or getargmatch(sign)) then
idx = nil
end
end
end
local results = sign.results
if results ~= "*" and nres ~= -1 then
if nres > #results then idx = nil end
for i=1,#results do
local c = sub(results, i, i)
if c ~= "." then slot[base+i-1] = map_restype[c] end
end
end
local handler = sign.handler
if handler and handler(st, slot, pc, base, narg, nres, idx) then idx = nil end
if idx then st[pc+hints.INLINE] = idx end
end
-- Set call hints and result types during forward propagation.
local function fwdcallhint(st, slot, pc, base, narg, nres)
local f = slot[base]
st[pc+hints.TYPE] = f
if type(f) == "function" then
local sign = map_sign[f]
if sign then
inlinehint(sign, st, slot, pc, base, narg, nres)
return
end
if f == st.func and not st.stats.isvararg and
(narg == -1 or narg == st.stats.params) then
st[pc+hints.INLINE] = 0 -- Recursive call.
end
end
-- Clear result types for unknown functions.
for i=base,base+nres-1 do slot[i] = nil end
end
-- Attach call hinter to optimizer.
local function start_()
local jopt = require "jit.opt"
jopt.attach_callhint(fwdcallhint)
-- Note that just loading the optimizer does not start it, yet.
end
-- Public module functions.
module(...)
-- TODO: Public API to add signatures. Alas, the API is still in flux.
getname = getname_
start = start_
----------------------------------------------------------------------------
-- LuaJIT compiler tracing module.
--
-- Copyright (C) 2005-2008 Mike Pall. All rights reserved.
-- Released under the MIT/X license. See luajit.h for full copyright notice.
----------------------------------------------------------------------------
-- Activate this module to trace the progress of the JIT compiler.
--
-- Try: luajit -j trace -e 'print "foo"'
-- luajit -j trace=foo.trace foo.lua
--
-- Default output is to stderr. To redirect output to a file,
-- pass a filename as an argument or set the environment variable
-- "LUAJIT_TRACEFILE".
-- Note: the file is overwritten each time you run luajit.
------------------------------------------------------------------------------
-- Priority for compiler pipeline. Must run after backend (negative)
-- and should be odd to catch compiler errors, too.
local PRIORITY = -99
-- Cache some library functions and objects.
local jit = require("jit")
assert(jit.version_num == 10105, "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local type, tostring, sub, format = type, tostring, string.sub, string.format
local getinfo, justats = debug.getinfo, jutil.stats
local stdout, stderr = io.stdout, io.stderr
-- Turn compilation off for the whole module. LuaJIT would do that anyway.
jit.off(true, true)
-- Active flag and output file handle.
local active, out
-- Generate range string from table: pc[-pc] [,...]
local function rangestring(t)
local s = ""
for i,range in ipairs(t) do
if i ~= 1 then s = s.."," end
local pc = range % 65536
range = (range - pc) / 65536
s = s..pc
if range ~= 0 then s = s..(-(pc+range)) end
end
return s
end
-- Trace handler for compiler pipeline.
local function h_trace(st, status)
local o = out or stderr
local func = st.func
if type(func) ~= "function" then return end
local info = getinfo(func, "S")
local src, line = info.source, info.linedefined or 0
if src then
if sub(src, 1, 1) == "@" or sub(src, 1, 2) == "=(" then
src = sub(src, 2)
else
src = "**"..string.gsub(sub(src, 1, 40), "%c", " ").."**"
end
else
src = "?"
end
local aux = st.deopt and " DEOPT="..rangestring(st.deopt) or ""
if status == nil then
local stats = justats(func)
if not stats then return end
o:write(format("[LuaJIT: OK %4d %6d %s:%d%s]\n",
stats.bytecodes, stats.mcodesize or -1, src, line, aux))
return
else
local stname = jit.util.status[status] or status
local pc, err = st.dasm_pc, st.dasm_err
if type(pc) == "number" and type(err) == "number" then
local op = jutil.bytecode(func, pc) or "END"
o:write(format("[LuaJIT: %s %s@%d %08x %s:%d%s]\n",
stname, op, pc, err, src, line, aux))
else
o:write(format("[LuaJIT: %s %s:%d%s]\n", stname, src, line, aux))
end
end
end
-- Detach trace handler from compiler pipeline.
local function traceoff()
if active then
active = false
jit.attach(h_trace)
if out and out ~= stdout then out:close() end
out = nil
end
end
-- Open the output file and attach trace handler to compiler pipeline.
local function traceon(filename)
if active then traceoff() end
local outfile = filename or os.getenv("LUAJIT_TRACEFILE")
out = outfile and (outfile == "-" and stdout or assert(io.open(outfile, "w")))
jit.attach(h_trace, PRIORITY)
active = true
end
-- Public module functions.
module(...)
on = traceon
off = traceoff
start = traceon -- For -j command line option.
newoption {
trigger = "lua",
value = "VM_Type",
description = "Virtual Machine to use for Lua, either the default one or a JIT",
allowed = {
{ "default", "Default Lua Virtual Machine" },
{ "jitx86", "LuaJIT x86" }
}
}
_OPTIONS.lua = _OPTIONS.lua or "default"
solution "TEngine"
configurations { "Debug", "Release" }
objdir "obj"
includedirs {
"src",
"src/dynasm",
"src/lua",
"src/luasocket",
"src/fov",
......@@ -24,8 +37,8 @@ configuration "Debug"
configuration "Release"
defines { "NDEBUG=1" }
flags { "Optimize" }
buildoptions { "-O2" }
flags { "Optimize", "NoFramePointer" }
buildoptions { "-O3" }
targetdir "bin/Release"
project "TEngine"
......@@ -33,7 +46,7 @@ project "TEngine"
language "C"
targetname "t-engine"
files { "src/*.c", }
links { "physfs", "lua", "fov", "luasocket", "luaprofiler", "lualanes" }
links { "physfs", "lua".._OPTIONS.lua, "fov", "luasocket", "luaprofiler", "lualanes" }
defines { "_DEFAULT_VIDEOMODE_FLAGS_='SDL_HWSURFACE|SDL_DOUBLEBUF'" }
defines { [[TENGINE_HOME_PATH='".t-engine"']] }
......@@ -85,12 +98,22 @@ project "physfs"
files { "src/physfs/platform/macosx.c", "src/physfs/platform/posix.c", }
includedirs { "/Library/Frameworks/SDL.framework/Headers" }
project "lua"
kind "StaticLib"
language "C"
targetname "lua"
files { "src/lua/*.c", }
if _OPTIONS.lua == "default" then
project "luadefault"
kind "StaticLib"
language "C"
targetname "lua"
files { "src/lua/*.c", }
elseif _OPTIONS.lua == "jitx86" then
project "luajitx86"
kind "StaticLib"
language "C"
targetname "lua"
files { "src/luajit/*.c", }
defines { "LUA_USE_POSIX" }
end
project "luasocket"
kind "StaticLib"
......
/*
** DynASM encoding engine prototypes.
** Copyright (C) 2005-2008 Mike Pall. All rights reserved.
** Released under the MIT/X license. See dynasm.lua for full copyright notice.
*/
#ifndef _DASM_PROTO_H
#define _DASM_PROTO_H
#include <stddef.h>
#include <stdarg.h>
#define DASM_VERSION 10104 /* 1.1.4 */
#ifndef Dst_DECL
#define Dst_DECL dasm_State *Dst
#endif
#ifndef Dst_GET
#define Dst_GET (Dst)
#endif
#ifndef DASM_FDEF
#define DASM_FDEF extern
#endif
/* Internal DynASM encoder state. */
typedef struct dasm_State dasm_State;
/* Action list type. */
typedef const unsigned char *dasm_ActList;
/* 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, dasm_ActList 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 */
/*
** DynASM x86 encoding engine.
** Copyright (C) 2005-2008 Mike Pall. All rights reserved.
** Released under the MIT/X license. See dynasm.lua for full copyright notice.
*/
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define DASM_ARCH "x86"
/* Action definitions. DASM_STOP must be 255. */
enum {
DASM_DISP = 235,
DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB,
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_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_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))
/* Per-section structure. */
typedef struct dasm_Section {
int *rbuf; /* Biased buffer pointer (negative section bias). */
int *buf; /* True buffer pointer. */
size_t bsize; /* Buffer size in bytes. */
int pos; /* Biased buffer position. */
int epos; /* End of biased buffer position - max single put. */
int ofs; /* Byte offset into section. */
} dasm_Section;
/* Core structure holding the DynASM encoding state. */
struct dasm_State {
size_t psize; /* Allocated size of this structure. */
dasm_ActList actionlist; /* Current actionlist pointer. */
int *lglabels; /* Local/global chain/pos ptrs. */
size_t lgsize;
int *pclabels; /* PC label chains/pos ptrs. */
size_t pcsize;
void **globals; /* Array of globals (bias -10). */
dasm_Section *section; /* Pointer to active section. */
size_t codesize; /* Total size of all code sections. */
int maxsection; /* 0 <= sectionidx < maxsection. */
int status; /* Status code. */
dasm_Section sections[1]; /* All sections. Alloc-extended. */
};
/* The size of the core structure depends on the max. number of sections. */
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
/* Initialize DynASM state. */
void dasm_init(Dst_DECL, int maxsection)
{
dasm_State *D;
size_t psz = 0;
int i;
Dst_REF = NULL;
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
D = Dst_REF;
D->psize = psz;
D->lglabels = NULL;
D->lgsize = 0;
D->pclabels = NULL;
D->pcsize = 0;
D->globals = NULL;
D->maxsection = maxsection;
for (i = 0; i < maxsection; i++) {
D->sections[i].buf = NULL; /* Need this for pass3. */
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
D->sections[i].bsize = 0;
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
}
}
/* Free DynASM state. */
void dasm_free(Dst_DECL)
{
dasm_State *D = Dst_REF;
int i;
for (i = 0; i < D->maxsection; i++)
if (D->sections[i].buf)
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
DASM_M_FREE(Dst, D, D->psize);
}
/* Setup global label array. Must be called before dasm_setup(). */
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
{
dasm_State *D = Dst_REF;
D->globals = gl - 10; /* Negative bias to compensate for locals. */
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
}
/* Grow PC label array. Can be called after dasm_setup(), too. */
void dasm_growpc(Dst_DECL, unsigned int maxpc)
{
dasm_State *D = Dst_REF;
size_t osz = D->pcsize;
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
}
/* Setup encoder. */
void dasm_setup(Dst_DECL, dasm_ActList actionlist)
{
dasm_State *D = Dst_REF;
int i;
D->actionlist = actionlist;
D->status = DASM_S_OK;
D->section = &D->sections[0];
memset((void *)D->lglabels, 0, D->lgsize);
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
for (i = 0; i < D->maxsection; i++) {
D->sections[i].pos = DASM_SEC2POS(i);
D->sections[i].ofs = 0;
}
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) { \
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
#define CKPL(kind, st) \
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
#else
#define CK(x, st) ((void)0)
#define CKPL(kind, st) ((void)0)
#endif
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
void dasm_put(Dst_DECL, int start, ...)
{
va_list ap;
dasm_State *D = Dst_REF;
dasm_ActList p = D->actionlist + start;
dasm_Section *sec = D->section;
int pos = sec->pos, ofs = sec->ofs, mrm = 4;
int *b;
if (pos >= sec->epos) {
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
sec->epos = sec->bsize/sizeof(int) - DASM_MAXSECPOS + DASM_POS2BIAS(pos);
}
b = sec->rbuf;
b[pos++] = start;
va_start(ap, start);
while (1) {
int action = *p++;
if (action < DASM_DISP) {
ofs++;
} else if (action <= DASM_REL_A) {
int n = va_arg(ap, int);
b[pos++] = n;
switch (action) {
case DASM_DISP:
if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; }
case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob;
case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */
case DASM_IMM_D: ofs += 4; break;
case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob;
case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break;
case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob;
case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break;
case DASM_SPACE: p++; ofs += n; break;
case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */
}
mrm = 4;
} else {
int *pl, n;
switch (action) {
case DASM_REL_LG:
case DASM_IMM_LG:
n = *p++; pl = D->lglabels + n;
if (n <= 246) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */
pl -= 246; n = *pl;
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
goto linkrel;
case DASM_REL_PC:
case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
putrel:
n = *pl;
if (n < 0) { /* Label exists. Get label pos and store it. */
b[pos] = -n;
} else {
linkrel:
b[pos] = n; /* Else link to rel chain, anchored at label. */
*pl = pos;
}
pos++;
ofs += 4; /* Maximum offset needed. */
if (action == DASM_REL_LG || action == DASM_REL_PC)
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel;
case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
putlabel:
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; }
*pl = -pos; /* Label exists now. */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_ALIGN:
ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_ESC: p++; ofs++; break;
case DASM_MARK: mrm = p[-2]; break;
case DASM_SECTION:
n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n];
case DASM_STOP: goto stop;
}
}
}
stop:
va_end(ap);
sec->pos = pos;
sec->ofs = ofs;
}
#undef CK
/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */
int dasm_link(Dst_DECL, size_t *szp)
{
dasm_State *D = Dst_REF;
int secnum;
int ofs = 0;
#ifdef DASM_CHECKS
*szp = 0;
if (D->status != DASM_S_OK) return D->status;
{
int pc;
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
}
#endif
{ /* Handle globals not defined in this translation unit. */
int idx;
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
int n = D->lglabels[idx];
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
}
}
/* Combine all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->rbuf;
int pos = DASM_SEC2POS(secnum);
int lastpos = sec->pos;
while (pos != lastpos) {
dasm_ActList p = D->actionlist + b[pos++];
while (1) {
int op, action = *p++;
switch (action) {
case DASM_REL_LG: p++; op = p[-3]; goto rel_pc;
case DASM_REL_PC: op = p[-2]; rel_pc: {
int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0);
if (shrink) { /* Shrinkable branch opcode? */
int lofs, lpos = b[pos];
if (lpos < 0) goto noshrink; /* Ext global? */
lofs = *DASM_POS2PTR(D, lpos);
if (lpos > pos) { /* Fwd label: add cumulative section offsets. */
int i;
for (i = secnum; i < DASM_POS2SEC(lpos); i++)
lofs += D->sections[i].ofs;
} else {
lofs -= ofs; /* Bkwd label: unfix offset. */
}
lofs -= b[pos+1]; /* Short branch ok? */
if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */
else { noshrink: shrink = 0; } /* No, cannot shrink op. */
}
b[pos+1] = shrink;
pos += 2;
break;
}
case DASM_SPACE: case DASM_IMM_LG: p++;
case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W:
case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB:
case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break;
case DASM_LABEL_LG: p++;
case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */
case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */
case DASM_ESC: p++;
case DASM_MARK: break;
case DASM_SECTION: case DASM_STOP: goto stop;
}
}
stop: (void)0;
}
ofs += sec->ofs; /* Next section starts right after current section. */
}
D->codesize = ofs; /* Total size of all code sections */
*szp = ofs;
return DASM_S_OK;
}
#define dasmb(x) *cp++ = (unsigned char)(x)
#ifndef DASM_ALIGNED_WRITES
#define dasmw(x) \
do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0)
#define dasmd(x) \
do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0)
#else
#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0)
#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0)
#endif
/* Pass 3: Encode sections. */
int dasm_encode(Dst_DECL, void *buffer)
{
dasm_State *D = Dst_REF;
unsigned char *base = (unsigned char *)buffer;
unsigned char *cp = base;
int secnum;
/* Encode all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->buf;
int *endb = sec->rbuf + sec->pos;
while (b != endb) {
dasm_ActList p = D->actionlist + *b++;
unsigned char *mark = NULL;
while (1) {
int action = *p++;
int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0;
switch (action) {
case DASM_DISP: if (!mark) mark = cp; {
unsigned char *mm = mark;
if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL;
if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7;
if (mrm != 5) { mm[-1] -= 0x80; break; } }
if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40;
}
case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break;
case DASM_IMM_DB: if (((n+128)&-256) == 0) {
db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb;
} else mark = NULL;
case DASM_IMM_D: wd: dasmd(n); break;
case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL;
case DASM_IMM_W: dasmw(n); break;
case DASM_REL_LG: p++; if (n >= 0) goto rel_pc;
b++; n = (int)D->globals[-n];
case DASM_REL_A: rel_a: n -= (int)(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 - ((cp-base) + 4-shrink);
if (shrink == 0) goto wd;
if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb;
goto wb;
}
case DASM_IMM_LG: p++; if (n < 0) { n = (int)D->globals[-n]; goto wd; }
case DASM_IMM_PC: {
int *pb = DASM_POS2PTR(D, n);
n = *pb < 0 ? pb[1] : (*pb + (ptrdiff_t)base);
goto wd;
}
case DASM_LABEL_LG: {
int idx = *p++;
if (idx >= 10)
D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n));
break;
}
case DASM_LABEL_PC: case DASM_SETLABEL: break;
case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; }
case DASM_ALIGN:
n = *p++;
while (((cp-base) & n)) *cp++ = 0x90; /* nop */
break;
case DASM_MARK: mark = cp; break;
case DASM_ESC: action = *p++;
default: *cp++ = action; break;
case DASM_SECTION: case DASM_STOP: goto stop;
}
}
stop: (void)0;
}
}
if (base + D->codesize != cp) /* Check for phase errors. */
return DASM_S_PHASE;
return DASM_S_OK;
}
/* Get PC label offset. */
int dasm_getpclabel(Dst_DECL, unsigned int pc)
{
dasm_State *D = Dst_REF;
if (pc*sizeof(int) < D->pcsize) {
int pos = D->pclabels[pc];
if (pos < 0) return *DASM_POS2PTR(D, -pos);
if (pos > 0) return -1; /* Undefined. */
}
return -2; /* Unused or out of range. */
}
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
int dasm_checkstep(Dst_DECL, int secmatch)
{
dasm_State *D = Dst_REF;
if (D->status == DASM_S_OK) {
int i;
for (i = 1; i <= 9; i++) {
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; }
D->lglabels[i] = 0;
}
}
if (D->status == DASM_S_OK && secmatch >= 0 &&
D->section != &D->sections[secmatch])
D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
return D->status;
}
#endif
This diff is collapsed.
This diff is collapsed.
# makefile for building Lua
# see ../INSTALL for installation instructions
# see ../Makefile and luaconf.h for further customization
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# Your platform. See PLATS for possible values.
PLAT= none
CC= gcc
CFLAGS= -O3 -fomit-frame-pointer -Wall $(MYCFLAGS) $(COCOCFLAGS) $(JITCFLAGS)
AR= ar rcu
RANLIB= ranlib
RM= rm -f
LIBS= -lm $(MYLIBS)
MYCFLAGS=
MYLDFLAGS=
MYLIBS=
# ++ Coco =========
# Default: autodetect gccasm/setjmp/ucontext/fibers context switch method.
COCOCFLAGS=
# Force use of setjmp (instead of gccasm).
#COCOCFLAGS= -DCOCO_USE_SETJMP
# Force use of ucontext (instead of gccasm or setjmp).
#COCOCFLAGS= -DCOCO_USE_UCONTEXT
# Uncomment this if you want to compile LuaJIT without Coco.
# This effectively disables yielding from JIT compiled functions.
#COCOCFLAGS= -DCOCO_DISABLE
# -- Coco =========
# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE =========
PLATS= linux bsd macosx solaris mingw cygwin posix generic linux_rl bsd_rl macosx_rl
# ++ Coco =========
COCO_O= lcoco.o
# -- Coco =========
# ++ LuaJIT =========
DASMDIR= ../dynasm
DASMFLAGS=
DASMDISTFLAGS= -LN
# This assumes you already have a copy of (plain) Lua 5.1 installed
# You can use luajit, too (built with the pre-processed headers from the dist)
DASM= lua $(DASMDIR)/dynasm.lua
JITCFLAGS= -I$(DASMDIR)
JIT_O= ljit_core.o ljit_mem.o ljit_dasm.o ljit_backend.o
JITLIB_O= ljitlib.o
ALL_DH = ljit_x86.h
# -- LuaJIT =========
LUA_A= liblua.a
CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \
lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \
lundump.o lvm.o lzio.o $(COCO_O) $(JIT_O)
LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \
lstrlib.o loadlib.o $(JITLIB_O) linit.o
# Standalone has been renamed to avoid conflicts during installation
LUA_T= luajit
LUA_O= lua.o
LUAC_T= luac
LUAC_O= luac.o print.o
ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O)
# Do not build luac by default
#ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
ALL_T= $(LUA_A) $(LUA_T)
ALL_A= $(LUA_A)
default: $(PLAT)
all: $(ALL_T)
o: $(ALL_O)
a: $(ALL_A)
$(LUA_A): $(CORE_O) $(LIB_O)
$(AR) $@ $?
$(RANLIB) $@
$(LUA_T): $(LUA_O) $(LUA_A)
$(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
$(LUAC_T): $(LUAC_O) $(LUA_A)
$(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
# ++ LuaJIT =========
ljit_x86.h: ljit_x86.dasc ljit_x86_inline.dash ljit_x86.dash
$(DASM) $(DASMFLAGS) -o $@ ljit_x86.dasc
distclean: clean
$(DASM) $(DASMDISTFLAGS) -o ljit_x86.h ljit_x86.dasc
cleaner: clean
$(RM) $(ALL_DH)
# -- LuaJIT =========
clean:
$(RM) $(ALL_T) $(ALL_O)
depend:
@$(CC) $(CFLAGS) -MM l*.c print.c
echo:
@echo "PLAT = $(PLAT)"
@echo "CC = $(CC)"
@echo "CFLAGS = $(CFLAGS)"
@echo "AR = $(AR)"
@echo "RANLIB = $(RANLIB)"
@echo "RM = $(RM)"
@echo "MYCFLAGS = $(MYCFLAGS)"
@echo "MYLDFLAGS = $(MYLDFLAGS)"
@echo "MYLIBS = $(MYLIBS)"
# convenience targets for popular platforms
none:
@echo "Please choose a platform:"
@echo " $(PLATS)"
bsd:
$(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E"
bsd_rl:
$(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -DLUA_USE_READLINE" MYLIBS="-Wl,-E -lreadline"
generic:
$(MAKE) all MYCFLAGS=
linux:
$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl"
linux_rl:
$(MAKE) all MYCFLAGS="-DLUA_USE_LINUX -DLUA_USE_READLINE" MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses"
# Mac OS X on Intel Macs only!
macosx:
$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX
# use this on Mac OS X 10.3
# $(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX
macosx_rl:
$(MAKE) all MYCFLAGS="-DLUA_USE_LINUX -DLUA_USE_READLINE" MYLIBS="-lreadline"
mingw:
$(MAKE) "LUA_A=lua51.dll" "LUA_T=luajit.exe" \
"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
"MYCFLAGS=-DLUA_BUILD_AS_DLL -maccumulate-outgoing-args" \
"MYLIBS=" "MYLDFLAGS=-s" luajit.exe
cygwin:
$(MAKE) "CC=gcc -mno-cygwin" mingw
posix:
$(MAKE) all MYCFLAGS=-DLUA_USE_POSIX
# Solaris x86 only!
solaris:
$(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl"
# list targets that do not create files (but not all makes understand .PHONY)
.PHONY: all $(PLATS) default o a clean depend echo none cleaner distclean
# DO NOT DELETE
lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \
lstate.h ltm.h lzio.h lmem.h lcoco.h ldo.h lfunc.h lgc.h lstring.h \
ltable.h lundump.h lvm.h
lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h
lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h lcoco.h
lcoco.o: lcoco.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \
lzio.h lmem.h lcoco.h ldo.h lvm.h lgc.h
lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h lcoco.h \
ldo.h lgc.h ltable.h
ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h
ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \
llex.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
lcoco.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h ljit.h
ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
lzio.h lmem.h lcoco.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h \
lstring.h ltable.h lundump.h lvm.h ljit.h
ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \
lzio.h lmem.h lcoco.h lundump.h
lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \
lstate.h ltm.h lzio.h lcoco.h ljit.h
lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
lzio.h lmem.h lcoco.h ldo.h lfunc.h lgc.h lstring.h ltable.h
linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h
liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h
ljit_backend.o: ljit_backend.c lua.h luaconf.h lobject.h llimits.h \
lstate.h ltm.h lzio.h lmem.h lcoco.h ldo.h lfunc.h lgc.h lstring.h \
ltable.h lvm.h lopcodes.h ldebug.h ljit.h ljit_hints.h ljit_dasm.h \
../dynasm/dasm_proto.h ljit_x86.h
ljit_core.o: ljit_core.c lua.h luaconf.h lobject.h llimits.h lstate.h \
ltm.h lzio.h lmem.h lcoco.h ldo.h lstring.h lgc.h ltable.h ldebug.h \
lopcodes.h ljit.h ljit_hints.h luajit.h
ljit_dasm.o: ljit_dasm.c lua.h luaconf.h ljit.h lobject.h llimits.h \
ljit_dasm.h ../dynasm/dasm_proto.h lmem.h ../dynasm/dasm_x86.h
ljit_mem.o: ljit_mem.c lua.h luaconf.h lmem.h llimits.h ldo.h lobject.h \
lstate.h ltm.h lzio.h lcoco.h ljit.h ljit_dasm.h ../dynasm/dasm_proto.h
ljitlib.o: ljitlib.c lua.h luaconf.h lauxlib.h luajit.h lualib.h \
lobject.h llimits.h lstate.h ltm.h lzio.h lmem.h lcoco.h lstring.h \
lgc.h ltable.h lfunc.h lopcodes.h ljit.h ljit_hints.h
llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \
lzio.h lmem.h lcoco.h llex.h lparser.h lstring.h lgc.h ltable.h
lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h
lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
ltm.h lzio.h lmem.h lcoco.h ldo.h
loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h luajit.h
lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \
ltm.h lzio.h lmem.h lcoco.h lstring.h lgc.h lvm.h
lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h
loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h
lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h lcoco.h \
ldo.h lfunc.h lstring.h lgc.h ltable.h
lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
ltm.h lzio.h lmem.h lcoco.h ldo.h lfunc.h lgc.h llex.h lstring.h \
ltable.h ljit.h
lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \
ltm.h lzio.h lcoco.h lstring.h lgc.h
lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
ltm.h lzio.h lmem.h lcoco.h ldo.h lgc.h ltable.h
ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \
lmem.h lcoco.h lstring.h lgc.h ltable.h
lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h luajit.h
luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \
lstate.h ltm.h lzio.h lmem.h lcoco.h lfunc.h lopcodes.h lstring.h lgc.h \
lundump.h
lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h lcoco.h ldo.h lfunc.h lstring.h lgc.h \
lundump.h
lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
lzio.h lmem.h lcoco.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h \
lvm.h
lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \
lzio.h lcoco.h
print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \
ltm.h lzio.h lmem.h lcoco.h lopcodes.h lundump.h
# (end of Makefile)
This diff is collapsed.
/*
** $Id: lapi.h,v 2.2.1.1 2007/12/27 13:02:25 roberto Exp $
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
#ifndef lapi_h
#define lapi_h
#include "lobject.h"
LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o);
#endif
This diff is collapsed.
/*
** $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"
#if defined(LUA_COMPAT_GETN)
LUALIB_API int (luaL_getn) (lua_State *L, int t);
LUALIB_API void (luaL_setn) (lua_State *L, int t, int n);
#else
#define luaL_getn(L,i) ((int)lua_objlen(L, i))
#define luaL_setn(L,i,j) ((void)0) /* no op! */
#endif
#if defined(LUA_COMPAT_OPENLIB)
#define luaI_openlib luaL_openlib
#endif
/* 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 (luaI_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[]);
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);
/*
** ===============================================================
** 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)))
/*
** {======================================================
** 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);
/* }====================================================== */
/* compatibility with ref system */
/* pre-defined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
(lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))
#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref))
#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref))
#define luaL_reg luaL_Reg
#endif
This diff is collapsed.
This diff is collapsed.
/*
** Lua/Coco glue.
** Copyright (C) 2004-2008 Mike Pall. See copyright notice in lcoco.c
*/
#ifndef lcoco_h
#define lcoco_h
#define LUACOCO_VERSION "Coco 1.1.5"
#define LUACOCO_VERSION_NUM 10105
/* Exported C API to add a C stack to a coroutine. */
LUA_API lua_State *lua_newcthread(lua_State *L, int cstacksize);
/* Internal support routines. */
LUAI_FUNC void luaCOCO_free(lua_State *L);
LUAI_FUNC int luaCOCO_resume(lua_State *L, int nargs);
LUAI_FUNC int luaCOCO_yield(lua_State *L);
LUAI_FUNC int luaCOCO_cstacksize(int cstacksize);
/* Forward declaration. */
typedef struct coco_State coco_State;
/* These are redefined below. */
#undef LUAI_EXTRASPACE
#undef luai_userstateopen
/* luai_userstateclose unused */
#undef luai_userstatethread
#undef luai_userstatefree
#undef luai_userstateresume
#undef luai_userstateyield
/* Use Windows Fibers (Win98+). */
#if defined(_WIN32)
/* Fibers allocate their own stack. The whole Coco state is in front of L. */
struct coco_State {
void *fib; /* Own fiber (if any). */
void *back; /* Fiber to switch back to. */
int nargs; /* Number of arguments to pass. */
int dummy_align;
};
#define L2COCO(L) (&((coco_State *)(L))[-1])
#define LHASCOCO(L) (L2COCO(L)->fib)
#define LUAI_EXTRASPACE sizeof(coco_State)
#define luai_userstateopen(L) L2COCO(L)->fib = NULL
#define luai_userstatethread(L,L1) L2COCO(L1)->fib = NULL
#define COCO_USE_FIBERS
#else /* !defined(_WIN32) */
/* The Coco state depends on the context switch method used. See lcoco.c. */
/* It's stored at the end of the stack. Only need a pointer in front of L. */
#define L2COCO(L) (((coco_State **)(L))[-1])
#define LHASCOCO(L) (L2COCO(L))
/* This wastes some space on 32 bit systems, but gets better alignment. */
#define LUAI_EXTRASPACE sizeof(LUAI_USER_ALIGNMENT_T)
#define luai_userstateopen(L) L2COCO(L) = NULL
#define luai_userstatethread(L,L1) L2COCO(L1) = NULL
#endif /* !defined(_WIN32) */
#define luai_userstatefree(L) if (LHASCOCO(L)) luaCOCO_free(L)
#define luai_userstateresume(L, nargs) \
if (LHASCOCO(L)) return luaCOCO_resume(L, nargs)
#define luai_userstateyield(L, nresults) \
do { if (LHASCOCO(L)) { \
L->base = L->top - (nresults); /* Protect stack slots below. */ \
return luaCOCO_yield(L); } } while (0)
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment