diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/LuaJIT-1.1.7/jit/opt_inline.lua | 397 |
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. | ||
18 | local jit = require("jit") | ||
19 | assert(jit.version_num == 10107, "LuaJIT core/library version mismatch") | ||
20 | local jutil = require("jit.util") | ||
21 | local type, rawget, next = type, rawget, next | ||
22 | local hints, fhints = jutil.hints, jutil.fhints | ||
23 | local sub, match, gsub = string.sub, string.match, string.gsub | ||
24 | |||
25 | -- Turn compilation off for the whole module. LuaJIT would do that anyway. | ||
26 | jit.off(true, true) | ||
27 | |||
28 | -- Prototypical objects used for type hints. | ||
29 | local TABLE = {} | ||
30 | local 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. | ||
35 | local map_sign = {} | ||
36 | |||
37 | -- For jit.dumphints: get printable name for TYPE hint: "#INLINE(foo.bar)". | ||
38 | local 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 | ||
52 | end | ||
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 | ||
56 | local flibname, flib, fidx | ||
57 | |||
58 | local 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 | ||
67 | end | ||
68 | |||
69 | local 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 | ||
75 | end | ||
76 | |||
77 | |||
78 | -- Signature handler: copy first argument to first result. | ||
79 | local function copyfirst(st, slot, pc, base, narg, nres) | ||
80 | slot[base] = slot[base+1] | ||
81 | end | ||
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 | -- | ||
96 | local 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. | ||
115 | end | ||
116 | |||
117 | -- Helper for pairs/next: guess result types for standard table iterator. | ||
118 | local 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. | ||
126 | end | ||
127 | |||
128 | |||
129 | -- Signatures for base library functions. | ||
130 | -- Note: Only add functions where result type hints or inlining makes sense. | ||
131 | flibname, flib, fidx = nil, _G, 65536*1 | ||
132 | fadd("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 | |||
140 | fadd("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 | |||
155 | fidx = nil -- Pure result type signatures follow: | ||
156 | fadd("next", "..", "T.?", | ||
157 | function(st, slot, pc, base, narg, nres) | ||
158 | guessnext(st, slot, base, base) | ||
159 | end) | ||
160 | fadd("type", "S", ".") | ||
161 | fadd("getmetatable", "T", ".") | ||
162 | fadd("setmetatable", ".", "TT?", copyfirst) | ||
163 | fadd("rawequal", "B", "..") | ||
164 | fadd("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) | ||
169 | fadd("rawset", ".", "T..", copyfirst) | ||
170 | fadd("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) | ||
174 | fadd("tonumber", "I", ".I?") | ||
175 | fadd("tostring", "S", ".") | ||
176 | fadd("require", "T", "S") | ||
177 | |||
178 | -- Signatures for coroutine library functions. | ||
179 | flibname, flib, fidx = "coroutine", coroutine, 65536*2 | ||
180 | if 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") | ||
190 | end | ||
191 | |||
192 | -- Signatures for string library functions. | ||
193 | flibname, flib, fidx = "string", string, 65536*3 | ||
194 | if 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. | ||
227 | end | ||
228 | |||
229 | -- Signatures for table library functions. | ||
230 | flibname, flib, fidx = "table", table, 65536*4 | ||
231 | if 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?") | ||
244 | end | ||
245 | |||
246 | -- Signatures for math library functions. | ||
247 | flibname, flib, fidx = "math", math, 65536*5 | ||
248 | if 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) | ||
294 | end | ||
295 | |||
296 | -- Signatures for I/O library functions. | ||
297 | -- Not inlined anytime soon. Used for result types only. | ||
298 | flibname, flib, fidx = "io", io, nil | ||
299 | if 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). | ||
303 | end | ||
304 | |||
305 | |||
306 | -- Type names to argument type shorthands. | ||
307 | -- TODO: make the matches more exact? Need to differentiate nil/unknown. | ||
308 | local 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. | ||
314 | local 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. | ||
321 | local 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. | ||
329 | local function getargmatch(sign) | ||
330 | local argmatch = "^"..gsub(sign.args, ".", map_argmatch).."0*$" | ||
331 | sign.argmatch = argmatch | ||
332 | return argmatch | ||
333 | end | ||
334 | |||
335 | -- Set INLINE hints and result types for known C functions. | ||
336 | local 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 | ||
361 | end | ||
362 | |||
363 | -- Set call hints and result types during forward propagation. | ||
364 | local 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 | ||
380 | end | ||
381 | |||
382 | |||
383 | -- Attach call hinter to optimizer. | ||
384 | local 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. | ||
388 | end | ||
389 | |||
390 | |||
391 | -- Public module functions. | ||
392 | module(...) | ||
393 | |||
394 | -- TODO: Public API to add signatures. Alas, the API is still in flux. | ||
395 | getname = getname_ | ||
396 | start = start_ | ||
397 | |||