aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/LuaJIT-1.1.7/jit/opt_inline.lua
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/LuaJIT-1.1.7/jit/opt_inline.lua397
1 files changed, 397 insertions, 0 deletions
diff --git a/libraries/LuaJIT-1.1.7/jit/opt_inline.lua b/libraries/LuaJIT-1.1.7/jit/opt_inline.lua
new file mode 100644
index 0000000..cc19bf4
--- /dev/null
+++ b/libraries/LuaJIT-1.1.7/jit/opt_inline.lua
@@ -0,0 +1,397 @@
1----------------------------------------------------------------------------
2-- LuaJIT optimizer add-on module for function inlining.
3--
4-- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
5-- Released under the MIT/X license. See luajit.h for full copyright notice.
6----------------------------------------------------------------------------
7-- This is a simple framework for C function signature maps.
8-- It helps with type propagation and C function inlining.
9--
10-- This module is automatically loaded with -O2 and above.
11-- By default most standard library functions are added.
12--
13-- TODO: generalize it, e.g. for back propagation (i.e. arg types).
14-- TODO: extend it for Lua functions (but need to analyze them before use).
15------------------------------------------------------------------------------
16
17-- Cache some library functions and objects.
18local jit = require("jit")
19assert(jit.version_num == 10107, "LuaJIT core/library version mismatch")
20local jutil = require("jit.util")
21local type, rawget, next = type, rawget, next
22local hints, fhints = jutil.hints, jutil.fhints
23local sub, match, gsub = string.sub, string.match, string.gsub
24
25-- Turn compilation off for the whole module. LuaJIT would do that anyway.
26jit.off(true, true)
27
28-- Prototypical objects used for type hints.
29local TABLE = {}
30local CFUNC = collectgarbage -- Pretty sure this is never inlined.
31
32
33-- Map from C closures to signatures. Cannot use a weak table.
34-- Closures must be kept alive because inlining checks against their addrs.
35local map_sign = {}
36
37-- For jit.dumphints: get printable name for TYPE hint: "#INLINE(foo.bar)".
38local function getname_(f, idx)
39 local sign = map_sign[f]
40 if sign then
41 local libname, name = sign.libname, sign.name
42 if libname then
43 return libname.."."..name
44 else
45 return name
46 end
47 elseif idx == 0 then
48 return "recursive"
49 else
50 return "?"
51 end
52end
53
54-- Name, base table and running index for convenience functions.
55-- CHECK: the library index and the order below must match with ljit_hints.h
56local flibname, flib, fidx
57
58local function fadd(name, results, args, handler)
59 local f = rawget(flib, name)
60 if f then
61 map_sign[f] = {
62 libname = flibname, name = name, idx = fidx,
63 results = results, args = args, handler = handler,
64 }
65 end
66 if fidx then fidx = fidx + 1 end
67end
68
69local function faddf(name, f, results, args, handler)
70 map_sign[f] = {
71 libname = flibname, name = name, idx = fidx,
72 results = results, args = args, handler = handler,
73 }
74 if fidx then fidx = fidx + 1 end
75end
76
77
78-- Signature handler: copy first argument to first result.
79local function copyfirst(st, slot, pc, base, narg, nres)
80 slot[base] = slot[base+1]
81end
82
83-- Helper for iterators: check if the function is an iterator constructor.
84--
85-- 'for ivars in func(args) do body end'
86--
87-- ...load func+args...
88-- CALL func <-- pc
89-- JMP fwd ---+
90-- back: | <--+
91-- ...body... | |
92-- fwd: <--+ |
93-- TFORLOOP ivars | <-- tforpc
94-- JMP back ---+
95--
96local function itercheck(st, slot, pc, base, idx)
97 if idx then
98 local bytecode, func = jutil.bytecode, st.func
99 local op, _, fwd = bytecode(func, pc+1)
100 if op == "JMP" then
101 local tforpc = pc+2+fwd
102 local op, tfbase, _, tfnres = bytecode(func, tforpc)
103 if op == "TFORLOOP" and tfbase == base and tfnres <= 2 then
104 local op, _, back = bytecode(func, tforpc+1)
105 if op == "JMP" and fwd+back == -2 then
106 -- Must set inlining hint for TFORLOOP instruction here.
107 st[tforpc+hints.INLINE] = idx -- Serves as iterator index, too.
108 return -- Inline it.
109 end
110 end
111 end
112 end
113 slot[base] = CFUNC -- Better make it different from pairs.
114 return true -- Better not inline it, if not used in a for statement.
115end
116
117-- Helper for pairs/next: guess result types for standard table iterator.
118local function guessnext(st, slot, base, dest)
119 local t, k, v = slot[base+1]
120 if type(t) == "table" then
121 k, v = next(t)
122 if v == nil then v = st.tableval[t] end
123 end
124 slot[dest] = k or "" -- Strings are a good guess for the key type.
125 slot[dest+1] = v -- But better not guess any fixed value type.
126end
127
128
129-- Signatures for base library functions.
130-- Note: Only add functions where result type hints or inlining makes sense.
131flibname, flib, fidx = nil, _G, 65536*1
132fadd("pairs", "..0", "T",
133 function(st, slot, pc, base, narg, nres, idx)
134 -- Table in slot[base+1] is kept (2nd result = 1st arg).
135 -- Fill result slots for the iterator here (TFORLOOP is at the end).
136 guessnext(st, slot, base, base+3)
137 return itercheck(st, slot, pc, base, idx)
138 end)
139
140fadd("ipairs", "..I", "T",
141 function(st, slot, pc, base, narg, nres, idx)
142 -- Table in slot[base+1] is kept (2nd result = 1st arg).
143 -- Fill result slots for the iterator here (TFORLOOP is at the end).
144 local t = slot[base+1]
145 slot[base+3] = 1 -- Integer key.
146 local v
147 if type(t) == "table" then
148 v = rawget(t, 1)
149 if v == nil then v = st.tableval[t] end
150 end
151 slot[base+4] = v
152 return itercheck(st, slot, pc, base, idx)
153 end)
154
155fidx = nil -- Pure result type signatures follow:
156fadd("next", "..", "T.?",
157 function(st, slot, pc, base, narg, nres)
158 guessnext(st, slot, base, base)
159 end)
160fadd("type", "S", ".")
161fadd("getmetatable", "T", ".")
162fadd("setmetatable", ".", "TT?", copyfirst)
163fadd("rawequal", "B", "..")
164fadd("rawget", ".", "T.",
165 function(st, slot, pc, base, narg, nres)
166 local t = slot[base+1]
167 slot[base] = type(t) == "table" and rawget(t, slot[base+2]) or ""
168 end)
169fadd("rawset", ".", "T..", copyfirst)
170fadd("assert", "*", "..*",
171 function(st, slot, pc, base, narg, nres)
172 for i=1,nres do slot[base+i-1] = i <= narg and slot[base+i] or nil end
173 end)
174fadd("tonumber", "I", ".I?")
175fadd("tostring", "S", ".")
176fadd("require", "T", "S")
177
178-- Signatures for coroutine library functions.
179flibname, flib, fidx = "coroutine", coroutine, 65536*2
180if flib then
181 fadd("yield", "*", ".*")
182 fadd("resume", "*", "R.*",
183 function(st, slot, pc, base, narg, nres)
184 slot[base] = true
185 for i=1,nres-1 do slot[base+i] = nil end -- No guess.
186 end)
187
188 fidx = nil -- Pure result type signatures follow:
189 fadd("wrap", "C", "F")
190end
191
192-- Signatures for string library functions.
193flibname, flib, fidx = "string", string, 65536*3
194if flib then
195 fadd("len", "I", "S")
196 fadd("sub", "S", "SII?")
197 fadd("char", "S", "I*")
198
199 fidx = nil -- Pure result type signatures follow:
200 fadd("byte", "I", "S",
201 function(st, slot, pc, base, narg, nres)
202 for i=0,nres-1 do slot[base+i] = 1 end -- Set all result hints.
203 end)
204 fadd("rep", "S", "SI")
205 fadd("reverse", "S", "S")
206 fadd("upper", "S", "S")
207 fadd("lower", "S", "S")
208
209 fadd("format", "S", "S.*")
210 fadd("find", "*", "SSI?.?",
211 function(st, slot, pc, base, narg, nres)
212 slot[base] = 1
213 slot[base+1] = 1
214 for i=2,nres-1 do slot[base+i] = "" end -- Hints for matches.
215 end)
216 fadd("match", "*", "SSI?",
217 function(st, slot, pc, base, narg, nres)
218 for i=0,nres-1 do slot[base+i] = "" end -- Hints for matches.
219 end)
220 fadd("gsub", "SI", "SSGI?")
221 fadd("gmatch", "C00", "SS",
222 function(st, slot, pc, base, narg, nres)
223 -- Fill result slots for gmatch_iter here (TFORLOOP is at the end).
224 for i=base+3,st.stats.stackslots-1 do slot[i] = "" end
225 end)
226 -- The gmatch iterator itself is never inlined. No point in adding it.
227end
228
229-- Signatures for table library functions.
230flibname, flib, fidx = "table", table, 65536*4
231if flib then
232 fadd("insert", "", "TI?.")
233 fadd("remove", ".", "T",
234 function(st, slot, pc, base, narg, nres)
235 if nres >= 1 then
236 local t = slot[base+1]
237 slot[base] = type(t) == "table" and rawget(t, 1) or ""
238 end
239 end)
240 fadd("getn", "I", "T")
241
242 fidx = nil -- Pure result type signatures follow:
243 fadd("concat", "S", "TS?I?I?")
244end
245
246-- Signatures for math library functions.
247flibname, flib, fidx = "math", math, 65536*5
248if flib then
249 -- 1 arg, 1 result.
250 fadd("log", "N", "N")
251 fadd("log10", "N", "N")
252 fadd("exp", "N", "N")
253 fadd("sinh", "N", "N")
254 fadd("cosh", "N", "N")
255 fadd("tanh", "N", "N")
256 fadd("asin", "N", "N")
257 fadd("acos", "N", "N")
258 fadd("atan", "N", "N")
259 fadd("sin", "N", "N")
260 fadd("cos", "N", "N")
261 fadd("tan", "N", "N")
262 fadd("ceil", "I", "N")
263 fadd("floor", "I", "N")
264 fadd("abs", ".", "N", copyfirst)
265 fadd("sqrt", "N", "N")
266 -- 2 args, 1 result.
267 -- math.fmod is aliased to math.mod for compatibility.
268 fadd("fmod", ".", "NN",
269 function(st, slot, pc, base, narg, nres)
270 slot[base] = slot[base+2] or 1 -- Copy integer or number hint.
271 end)
272 fadd("atan2", "N", "NN")
273
274 fidx = nil -- Pure result type signatures follow:
275 -- 1-n args, 1 result.
276 fadd("min", ".", "NN*", copyfirst) -- Really depends on all args.
277 fadd("max", ".", "NN*", copyfirst) -- Really depends on all args.
278 -- 1 arg, 1 result.
279 fadd("deg", "N", "N")
280 fadd("rad", "N", "N")
281 -- 1 arg, 2 results.
282 fadd("modf", "IN", "N")
283 fadd("frexp", "NI", "N")
284 -- 2 args, 1 result.
285 fadd("pow", "N", "NN")
286 fadd("ldexp", ".", "NI", copyfirst)
287 -- 1 arg, 0 results.
288 fadd("randomseed", "", "I")
289 -- 0-2 args, 1 result.
290 fadd("random", "N", "I?I?",
291 function(st, slot, pc, base, narg, nres)
292 if narg > 0 then slot[base] = 1 end
293 end)
294end
295
296-- Signatures for I/O library functions.
297-- Not inlined anytime soon. Used for result types only.
298flibname, flib, fidx = "io", io, nil
299if flib then
300 fadd("lines", "C00S", "S?")
301 fadd("read", "S", "") -- Simplified (a lot).
302 -- Adding io methods doesn't work, because we don't deal with userdata (yet).
303end
304
305
306-- Type names to argument type shorthands.
307-- TODO: make the matches more exact? Need to differentiate nil/unknown.
308local map_argtype = {
309 ["nil"] = "0", boolean = "b", number = "n", string = "s",
310 table = "t", ["function"] = "f", userdata = "u", thread = "r",
311}
312
313-- Complex argument match patterns to regexp fragments.
314local map_argmatch = {
315 B = "[b0]", S = "[s0]", T = "[t0]", F = "[f0]", U = "[u0]", R = "[r0]",
316 N = "[n0]", I = "[n0]", -- Number/int args are the same for now.
317 G = "[stf0]", -- For string.gsub.
318}
319
320-- Result type shorthands to sample types.
321local map_restype = {
322 -- ["0"] = nil,
323 B = true, S = "", T = {},
324 N = 0.5, I = 1,
325 L = function() end, C = collectgarbage, -- Pretty sure this is never inlined.
326}
327
328-- Create argument match regexp and cache it.
329local function getargmatch(sign)
330 local argmatch = "^"..gsub(sign.args, ".", map_argmatch).."0*$"
331 sign.argmatch = argmatch
332 return argmatch
333end
334
335-- Set INLINE hints and result types for known C functions.
336local function inlinehint(sign, st, slot, pc, base, narg, nres)
337 local idx = sign.idx
338 if idx then
339 if narg ~= -1 then
340 local argpat = ""
341 for i=1,narg do argpat = argpat..map_argtype[type(slot[base+i])] end
342 if not match(argpat, sign.argmatch or getargmatch(sign)) then
343 idx = nil
344 end
345 end
346 end
347
348 local results = sign.results
349 if results ~= "*" and nres ~= -1 then
350 if nres > #results then idx = nil end
351 for i=1,#results do
352 local c = sub(results, i, i)
353 if c ~= "." then slot[base+i-1] = map_restype[c] end
354 end
355 end
356
357 local handler = sign.handler
358 if handler and handler(st, slot, pc, base, narg, nres, idx) then idx = nil end
359
360 if idx then st[pc+hints.INLINE] = idx end
361end
362
363-- Set call hints and result types during forward propagation.
364local function fwdcallhint(st, slot, pc, base, narg, nres)
365 local f = slot[base]
366 st[pc+hints.TYPE] = f
367 if type(f) == "function" then
368 local sign = map_sign[f]
369 if sign then
370 inlinehint(sign, st, slot, pc, base, narg, nres)
371 return
372 end
373 if f == st.func and not st.stats.isvararg and
374 (narg == -1 or narg == st.stats.params) then
375 st[pc+hints.INLINE] = 0 -- Recursive call.
376 end
377 end
378 -- Clear result types for unknown functions.
379 for i=base,base+nres-1 do slot[i] = nil end
380end
381
382
383-- Attach call hinter to optimizer.
384local function start_()
385 local jopt = require "jit.opt"
386 jopt.attach_callhint(fwdcallhint)
387 -- Note that just loading the optimizer does not start it, yet.
388end
389
390
391-- Public module functions.
392module(...)
393
394-- TODO: Public API to add signatures. Alas, the API is still in flux.
395getname = getname_
396start = start_
397