1 ----------------------------------------------------------------------
3 -- WARNING! You're entering a hackish area, proceed at your own risks!
5 -- This code results from the borrowing, then ruthless abuse, of
6 -- Yueliang's implementation of Lua 5.0 compiler. I claim
7 -- responsibility for all of the ugly, dirty stuff that you might spot
10 -- Eventually, this code will be rewritten, either in Lua or more
11 -- probably in C. Meanwhile, if you're interested into digging
12 -- metalua's sources, this is not the best part to invest your time
17 ----------------------------------------------------------------------
19 --[[--------------------------------------------------------------------
24 Lua 5 code generator in Lua
25 This file is part of Yueliang.
27 Copyright (c) 2005 Kein-Hong Man <khman@users.sf.net>
28 The COPYRIGHT file describes the conditions
29 under which this software may be distributed.
31 See the ChangeLog for more information.
33 ------------------------------------------------------------------------
35 [FF] Slightly modified, mainly to produce Lua 5.1 bytecode.
37 ----------------------------------------------------------------------]]
39 --[[--------------------------------------------------------------------
41 -- * one function manipulate a pointer argument with a simple data type
42 -- (can't be emulated by a table, ambiguous), now returns that value:
43 -- luaK:concat(fs, l1, l2)
44 -- * some function parameters changed to boolean, additional code
45 -- translates boolean back to 1/0 for instruction fields
47 -- luaK:ttisnumber(o) (from lobject.h)
48 -- luaK:nvalue(o) (from lobject.h)
49 -- luaK:setnilvalue(o) (from lobject.h)
50 -- luaK:setsvalue(o) (from lobject.h)
51 -- luaK:setnvalue(o) (from lobject.h)
52 -- luaK:sethvalue(o) (from lobject.h)
53 ----------------------------------------------------------------------]]
55 module("bytecode", package
.seeall
)
57 local function debugf() end
61 luaK
.MAXSTACK
= 250 -- (llimits.h, used in lcode.lua)
62 luaK
.LUA_MULTRET
= -1 -- (lua.h)
64 ------------------------------------------------------------------------
65 -- Marks the end of a patch list. It is an invalid value both as an absolute
66 -- address, and as a list link (would link an element to itself).
67 ------------------------------------------------------------------------
71 function luaK
:isnumeral(e
)
72 return e
.k
=="VKNUM" and e
.t
==self
.NO_JUMP
and e
.t
==self
.NO_JUMP
75 ------------------------------------------------------------------------
76 -- emulation of TObject macros (these are from lobject.h)
77 -- * TObject is a table since lcode passes references around
78 -- * tt member field removed, using Lua's type() instead
79 ------------------------------------------------------------------------
80 function luaK
:ttisnumber(o
)
81 if o
then return type(o
.value
) == "number" else return false end
83 function luaK
:nvalue(o
) return o
.value
end
84 function luaK
:setnilvalue(o
) o
.value
= nil end
85 function luaK
:setsvalue(o
, s
) o
.value
= s
end
86 luaK
.setnvalue
= luaK
.setsvalue
87 luaK
.sethvalue
= luaK
.setsvalue
89 ------------------------------------------------------------------------
90 -- returns the instruction object for given e (expdesc)
91 ------------------------------------------------------------------------
92 function luaK
:getcode(fs
, e
)
93 return fs
.f
.code
[e
.info
]
96 ------------------------------------------------------------------------
97 -- codes an instruction with a signed Bx (sBx) field
98 ------------------------------------------------------------------------
99 function luaK
:codeAsBx(fs
, o
, A
, sBx
)
100 return self
:codeABx(fs
, o
, A
, sBx
+ luaP
.MAXARG_sBx
)
103 ------------------------------------------------------------------------
105 ------------------------------------------------------------------------
106 function luaK
:hasjumps(e
)
110 ------------------------------------------------------------------------
112 ------------------------------------------------------------------------
113 function luaK
:_nil(fs
, from
, n
)
114 if fs
.pc
> fs
.lasttarget
then -- no jumps to current position?
115 if fs
.pc
== 0 then return end --function start, positions are already clean
116 local previous
= fs
.f
.code
[fs
.pc
- 1]
117 if luaP
:GET_OPCODE(previous
) == "OP_LOADNIL" then
118 local pfrom
= luaP
:GETARG_A(previous
)
119 local pto
= luaP
:GETARG_B(previous
)
120 if pfrom
<= from
and from
<= pto
+ 1 then -- can connect both?
121 if from
+ n
- 1 > pto
then
122 luaP
:SETARG_B(previous
, from
+ n
- 1)
128 self
:codeABC(fs
, "OP_LOADNIL", from
, from
+ n
- 1, 0) -- else no optimization
131 ------------------------------------------------------------------------
133 ------------------------------------------------------------------------
134 function luaK
:jump(fs
)
135 local jpc
= fs
.jpc
-- save list of jumps to here
136 fs
.jpc
= self
.NO_JUMP
137 local j
= self
:codeAsBx(fs
, "OP_JMP", 0, self
.NO_JUMP
)
138 return self
:concat(fs
, j
, jpc
) -- keep them on hold
142 function luaK
:ret (fs
, first
, nret
)
143 luaK
:codeABC (fs
, "OP_RETURN", first
, nret
+1, 0)
147 ------------------------------------------------------------------------
149 ------------------------------------------------------------------------
150 function luaK
:condjump(fs
, op
, A
, B
, C
)
151 self
:codeABC(fs
, op
, A
, B
, C
)
155 ------------------------------------------------------------------------
157 ------------------------------------------------------------------------
158 function luaK
:fixjump(fs
, pc
, dest
)
159 local jmp
= fs
.f
.code
[pc
]
160 local offset
= dest
- (pc
+ 1)
161 assert(dest
~= self
.NO_JUMP
)
162 if math
.abs(offset
) > luaP
.MAXARG_sBx
then
163 luaX
:syntaxerror(fs
.ls
, "control structure too long")
165 luaP
:SETARG_sBx(jmp
, offset
)
168 ------------------------------------------------------------------------
169 -- returns current 'pc' and marks it as a jump target (to avoid wrong
170 -- optimizations with consecutive instructions not in the same basic block).
171 ------------------------------------------------------------------------
172 function luaK
:getlabel(fs
)
173 fs
.lasttarget
= fs
.pc
177 ------------------------------------------------------------------------
179 ------------------------------------------------------------------------
180 function luaK
:getjump(fs
, pc
)
181 local offset
= luaP
:GETARG_sBx(fs
.f
.code
[pc
])
182 if offset
== self
.NO_JUMP
then -- point to itself represents end of list
183 return self
.NO_JUMP
-- end of list
185 return (pc
+ 1) + offset
-- turn offset into absolute position
189 ------------------------------------------------------------------------
191 ------------------------------------------------------------------------
192 function luaK
:getjumpcontrol(fs
, pc
)
193 local pi
= fs
.f
.code
[pc
]
194 local ppi
= fs
.f
.code
[pc
- 1]
195 if pc
>= 1 and luaP
:testOpMode(luaP
:GET_OPCODE(ppi
), "OpModeT") then
202 ------------------------------------------------------------------------
203 -- check whether list has any jump that do not produce a value
204 -- (or produce an inverted value)
205 ------------------------------------------------------------------------
207 function luaK
:need_value(fs
, list
, cond
)
208 while list
~= self
.NO_JUMP
do
209 local i
= self
:getjumpcontrol(fs
, list
)
210 if luaP
:GET_OPCODE(i
) ~= "OP_TESTSET" or
211 luaP
:GETARG_A(i
) ~= luaP
.NO_REG
or
212 luaP
:GETARG_C(i
) ~= cond
then
215 list
= self
:getjump(fs
, list
)
217 return false -- not found
220 ------------------------------------------------------------------------
222 ------------------------------------------------------------------------
224 function luaK
:patchtestreg(fs
, node
, reg
)
225 assert(reg
) -- pour assurer, vu que j'ai ajoute un parametre p/r a 5.0
226 local i
= self
:getjumpcontrol(fs
, node
)
227 if luaP
:GET_OPCODE(i
) ~= "OP_TESTSET" then
228 return false end -- cannot patch other instructions
229 if reg
~= luaP
.NO_REG
and reg
~= luaP
:GETARG_B(i
) then
230 luaP
:SETARG_A(i
, reg
)
232 -- no register to put value or register already has the value
233 luaP
:SET_OPCODE(i
, "OP_TEST")
234 luaP
:SETARG_A(i
, luaP
:GETARG_B(i
))
236 luaP
:SETARG_C(i
, luaP
:GETARG_C(i
))
242 function luaK
:removevalues (fs
, list
)
243 while list
~= self
.NO_JUMP
do
244 self
:patchtestreg (fs
, list
, luaP
.NO_REG
)
245 list
= self
:getjump (fs
, list
)
249 ------------------------------------------------------------------------
251 ------------------------------------------------------------------------
252 function luaK
:patchlistaux(fs
, list
, vtarget
, reg
, dtarget
)
253 while list
~= self
.NO_JUMP
do
254 local _next
= self
:getjump(fs
, list
)
255 if self
:patchtestreg (fs
, list
, reg
) then
256 self
:fixjump(fs
, list
, vtarget
)
258 self
:fixjump (fs
, list
, dtarget
)
264 ------------------------------------------------------------------------
266 ------------------------------------------------------------------------
267 function luaK
:dischargejpc(fs
)
268 self
:patchlistaux(fs
, fs
.jpc
, fs
.pc
, luaP
.NO_REG
, fs
.pc
)
269 fs
.jpc
= self
.NO_JUMP
272 ------------------------------------------------------------------------
274 ------------------------------------------------------------------------
275 function luaK
:patchlist(fs
, list
, target
)
276 if target
== fs
.pc
then
277 self
:patchtohere(fs
, list
)
279 assert(target
< fs
.pc
)
280 self
:patchlistaux(fs
, list
, target
, luaP
.NO_REG
, target
)
284 ------------------------------------------------------------------------
286 ------------------------------------------------------------------------
287 function luaK
:patchtohere(fs
, list
)
289 fs
.jpc
= self
:concat(fs
, fs
.jpc
, list
)
292 ------------------------------------------------------------------------
293 -- * l1 was a pointer, now l1 is returned and callee assigns the value
294 ------------------------------------------------------------------------
295 function luaK
:concat(fs
, l1
, l2
)
296 if l2
== self
.NO_JUMP
then return l1
-- unchanged
297 elseif l1
== self
.NO_JUMP
then
301 local _next
= self
:getjump(fs
, list
)
302 while _next
~= self
.NO_JUMP
do -- find last element
304 _next
= self
:getjump(fs
, list
)
306 self
:fixjump(fs
, list
, l2
)
308 return l1
-- unchanged
311 ------------------------------------------------------------------------
313 ------------------------------------------------------------------------
314 function luaK
:checkstack(fs
, n
)
315 local newstack
= fs
.freereg
+ n
316 if newstack
> fs
.f
.maxstacksize
then
317 if newstack
>= luaK
.MAXSTACK
then
318 luaX
:syntaxerror(fs
.ls
, "function or expression too complex")
320 fs
.f
.maxstacksize
= newstack
324 ------------------------------------------------------------------------
326 ------------------------------------------------------------------------
327 function luaK
:reserveregs(fs
, n
)
328 self
:checkstack(fs
, n
)
329 fs
.freereg
= fs
.freereg
+ n
332 ------------------------------------------------------------------------
334 ------------------------------------------------------------------------
335 function luaK
:freereg(fs
, reg
)
336 if not luaP
:ISK (reg
) and reg
>= fs
.nactvar
then
337 fs
.freereg
= fs
.freereg
- 1
338 assert(reg
== fs
.freereg
,
339 string.format("reg=%i, fs.freereg=%i", reg
, fs
.freereg
))
343 ------------------------------------------------------------------------
345 ------------------------------------------------------------------------
346 function luaK
:freeexp(fs
, e
)
347 if e
.k
== "VNONRELOC" then
348 self
:freereg(fs
, e
.info
)
352 ------------------------------------------------------------------------
353 -- k is a constant, v is... what?
354 -- fs.h is a hash value --> index in f.k
355 ------------------------------------------------------------------------
356 -- * luaH_get, luaH_set deleted; direct table access used instead
357 -- * luaO_rawequalObj deleted in first assert
358 -- * setobj2n deleted in assignment of v to f.k table
359 ------------------------------------------------------------------------
360 --FF radically updated, not completely understood
361 function luaK
:addk(fs
, k
, v
)
362 local idx
= fs
.h
[k
.value
]
364 -- local oldsize = f.sizek
365 if self
:ttisnumber (idx
) then
366 --TODO this assert currently FAILS
367 --assert(fs.f.k[self:nvalue(idx)] == v)
368 return self
:nvalue(idx
)
369 else -- constant not found; create a new entry
371 local t
= type (v
.value
)
372 assert(t
=="nil" or t
=="string" or t
=="number" or t
=="boolean")
374 --debugf("[const: k[%i] = %s ]", fs.nk, tostringv(v.value))
377 self
:setnvalue(fs
.h
[k
.value
], fs
.nk
)
384 ------------------------------------------------------------------------
386 ------------------------------------------------------------------------
387 function luaK
:stringK(fs
, s
)
388 assert (type(s
)=="string")
389 local o
= {} -- TObject
391 return self
:addk(fs
, o
, o
)
394 ------------------------------------------------------------------------
396 ------------------------------------------------------------------------
397 function luaK
:numberK(fs
, r
)
398 assert (type(r
)=="number")
399 local o
= {} -- TObject
401 return self
:addk(fs
, o
, o
)
404 ------------------------------------------------------------------------
406 ------------------------------------------------------------------------
407 function luaK
:boolK(fs
, r
)
408 assert (type(r
)=="boolean")
409 local o
= {} -- TObject
411 return self
:addk(fs
, o
, o
)
414 ------------------------------------------------------------------------
416 ------------------------------------------------------------------------
417 function luaK
:nilK(fs
)
418 local k
, v
= {}, {} -- TObject
420 self
:sethvalue(k
, fs
.h
) -- cannot use nil as key; instead use table itself
421 return self
:addk(fs
, k
, v
)
426 function luaK
:setreturns (fs
, e
, nresults
)
427 if e
.k
== "VCALL" then -- expression is an open function call?
428 luaP
:SETARG_C(self
:getcode(fs
, e
), nresults
+ 1)
429 elseif e
.k
== "VVARARG" then
430 luaP
:SETARG_B (self
:getcode (fs
, e
), nresults
+ 1)
431 luaP
:SETARG_A (self
:getcode (fs
, e
), fs
.freereg
)
432 self
:reserveregs (fs
, 1)
437 function luaK
:setmultret (fs
, e
)
438 self
:setreturns (fs
, e
, self
.LUA_MULTRET
)
442 function luaK
:setoneret (fs
, e
)
443 if e
.k
== "VCALL" then -- expression is an open function call?
445 e
.info
= luaP
:GETARG_A(self
:getcode(fs
, e
))
446 elseif e
.k
== "VVARARG" then
447 luaP
:SETARG_B (self
:getcode (fs
, e
), 2)
453 ------------------------------------------------------------------------
454 --FF deprecated in 5.1
455 ------------------------------------------------------------------------
456 function luaK
:setcallreturns(fs
, e
, nresults
)
457 assert (false, "setcallreturns deprecated")
460 --printv(self:getcode(fs, e))
461 if e
.k
== "VCALL" then -- expression is an open function call?
462 luaP
:SETARG_C(self
:getcode(fs
, e
), nresults
+ 1)
463 if nresults
== 1 then -- 'regular' expression?
465 e
.info
= luaP
:GETARG_A(self
:getcode(fs
, e
))
467 elseif e
.k
== "VVARARG" then
468 --printf("Handle vararg return on expr %s, whose code is %s",
469 -- tostringv(e), tostringv(self:getcode(fs, e)))
470 if nresults
== 1 then
471 luaP
:SETARG_B (self
:getcode (fs
, e
), 2)
473 --FIXME: why no SETARG_A???
475 luaP
:SETARG_B (self
:getcode (fs
, e
), nresults
+ 1)
476 luaP
:SETARG_A (self
:getcode (fs
, e
), fs
.freereg
)
477 self
:reserveregs (fs
, 1)
478 --printf("Now code is %s", tostringv(self:getcode(fs, e)))
483 ------------------------------------------------------------------------
484 -- Ajoute le code pour effectuer l'extraction de la locvar/upval/globvar
486 ------------------------------------------------------------------------
487 function luaK
:dischargevars(fs
, e
)
488 --printf("\ndischargevars\n")
490 if k
== "VLOCAL" then
492 elseif k
== "VUPVAL" then
493 e
.info
= self
:codeABC(fs
, "OP_GETUPVAL", 0, e
.info
, 0)
495 elseif k
== "VGLOBAL" then
496 e
.info
= self
:codeABx(fs
, "OP_GETGLOBAL", 0, e
.info
)
498 elseif k
== "VINDEXED" then
499 self
:freereg(fs
, e
.aux
)
500 self
:freereg(fs
, e
.info
)
501 e
.info
= self
:codeABC(fs
, "OP_GETTABLE", 0, e
.info
, e
.aux
)
503 elseif k
== "VCALL" or k
== "VVARARG" then
504 self
:setoneret(fs
, e
)
506 -- there is one value available (somewhere)
508 --printf("\n/dischargevars\n")
511 ------------------------------------------------------------------------
513 ------------------------------------------------------------------------
514 function luaK
:code_label(fs
, A
, b
, jump
)
515 self
:getlabel(fs
) -- those instructions may be jump targets
516 return self
:codeABC(fs
, "OP_LOADBOOL", A
, b
, jump
)
519 ------------------------------------------------------------------------
521 ------------------------------------------------------------------------
522 function luaK
:discharge2reg(fs
, e
, reg
)
523 self
:dischargevars(fs
, e
)
526 self
:_nil(fs
, reg
, 1)
527 elseif k
== "VFALSE" or k
== "VTRUE" then
528 self
:codeABC(fs
, "OP_LOADBOOL", reg
, (e
.k
== "VTRUE") and 1 or 0, 0)
529 elseif k
== "VKNUM" then
530 self
:codeABx (fs
, "OP_LOADK", reg
, self
:numberK(fs
, e
.nval
))
531 elseif k
== "VK" then
532 self
:codeABx(fs
, "OP_LOADK", reg
, e
.info
)
533 elseif k
== "VRELOCABLE" then
534 local pc
= self
:getcode(fs
, e
)
535 luaP
:SETARG_A(pc
, reg
)
536 elseif k
== "VNONRELOC" then
537 if reg
~= e
.info
then
538 self
:codeABC(fs
, "OP_MOVE", reg
, e
.info
, 0)
541 assert(e
.k
== "VVOID" or e
.k
== "VJMP")
542 return -- nothing to do...
548 ------------------------------------------------------------------------
550 ------------------------------------------------------------------------
551 function luaK
:discharge2anyreg(fs
, e
)
552 if e
.k
~= "VNONRELOC" then
553 self
:reserveregs(fs
, 1)
554 self
:discharge2reg(fs
, e
, fs
.freereg
- 1)
558 ------------------------------------------------------------------------
560 ------------------------------------------------------------------------
561 function luaK
:exp2reg(fs
, e
, reg
)
562 self
:discharge2reg(fs
, e
, reg
)
563 if e
.k
== "VJMP" then
564 e
.t
= self
:concat(fs
, e
.t
, e
.info
) -- put this jump in 't' list
566 if self
:hasjumps(e
) then
567 local final
-- position after whole expression
568 local p_f
= self
.NO_JUMP
-- position of an eventual LOAD false
569 local p_t
= self
.NO_JUMP
-- position of an eventual LOAD true
570 if self
:need_value(fs
, e
.t
, 1) or self
:need_value(fs
, e
.f
, 0) then
571 local fj
= self
.NO_JUMP
-- first jump (over LOAD ops.)
572 if e
.k
~= "VJMP" then fj
= self
:jump(fs
) end
573 p_f
= self
:code_label(fs
, reg
, 0, 1)
574 p_t
= self
:code_label(fs
, reg
, 1, 0)
575 self
:patchtohere(fs
, fj
)
577 final
= self
:getlabel(fs
)
578 self
:patchlistaux(fs
, e
.f
, final
, reg
, p_f
)
579 self
:patchlistaux(fs
, e
.t
, final
, reg
, p_t
)
581 e
.f
, e
.t
= self
.NO_JUMP
, self
.NO_JUMP
586 ------------------------------------------------------------------------
588 ------------------------------------------------------------------------
589 function luaK
:exp2nextreg(fs
, e
)
590 self
:dischargevars(fs
, e
)
591 --[FF] Allready in place (added for expr.Stat)
592 if e
.k
== "VNONRELOC" and e
.info
== fs
.freereg
then
593 --printf("Expression already in next reg %i: %s", fs.freereg, tostringv(e))
596 self
:reserveregs(fs
, 1)
597 self
:exp2reg(fs
, e
, fs
.freereg
- 1)
600 ------------------------------------------------------------------------
602 ------------------------------------------------------------------------
603 function luaK
:exp2anyreg(fs
, e
)
604 --printf("exp2anyregs(e=%s)", tostringv(e))
605 self
:dischargevars(fs
, e
)
606 if e
.k
== "VNONRELOC" then
607 if not self
:hasjumps(e
) then -- exp is already in a register
610 if e
.info
>= fs
.nactvar
then -- reg. is not a local?
611 self
:exp2reg(fs
, e
, e
.info
) -- put value on it
615 self
:exp2nextreg(fs
, e
) -- default
619 ------------------------------------------------------------------------
621 ------------------------------------------------------------------------
622 function luaK
:exp2val(fs
, e
)
623 if self
:hasjumps(e
) then
624 self
:exp2anyreg(fs
, e
)
626 self
:dischargevars(fs
, e
)
630 ------------------------------------------------------------------------
632 ------------------------------------------------------------------------
633 function luaK
:exp2RK(fs
, e
)
636 if k
=="VNIL" or k
=="VTRUE" or k
=="VFALSE" or k
=="VKNUM" then
637 if fs
.nk
<= luaP
.MAXINDEXRK
then
638 if k
=="VNIL" then e
.info
= self
:nilK(fs
)
639 elseif k
=="VKNUM" then e
.info
= self
:numberK (fs
, e
.nval
)
640 else e
.info
= self
:boolK(fs
, e
.k
=="VTRUE") end
642 return luaP
:RKASK(e
.info
)
644 elseif k
== "VK" then
645 if e
.info
<= luaP
.MAXINDEXRK
then -- constant fit in argC?
646 return luaP
:RKASK (e
.info
)
649 -- not a constant in the right range: put it in a register
650 return self
:exp2anyreg(fs
, e
)
653 ------------------------------------------------------------------------
655 ------------------------------------------------------------------------
656 function luaK
:storevar(fs
, var
, exp)
658 --printf("var=%s", tostringv(var))
659 --printf("exp=%s", tostringv(exp))
662 if k
== "VLOCAL" then
663 self
:freeexp(fs
, exp)
664 self
:exp2reg(fs
, exp, var
.info
)
666 elseif k
== "VUPVAL" then
667 local e
= self
:exp2anyreg(fs
, exp)
668 self
:codeABC(fs
, "OP_SETUPVAL", e
, var
.info
, 0)
669 elseif k
== "VGLOBAL" then
670 --printf("store global, exp=%s", tostringv(exp))
671 local e
= self
:exp2anyreg(fs
, exp)
672 self
:codeABx(fs
, "OP_SETGLOBAL", e
, var
.info
)
673 elseif k
== "VINDEXED" then
674 local e
= self
:exp2RK(fs
, exp)
675 self
:codeABC(fs
, "OP_SETTABLE", var
.info
, var
.aux
, e
)
677 assert(0) -- invalid var kind to store
679 self
:freeexp(fs
, exp)
683 ------------------------------------------------------------------------
685 ------------------------------------------------------------------------
686 function luaK
:_self(fs
, e
, key
)
687 self
:exp2anyreg(fs
, e
)
689 local func
= fs
.freereg
690 self
:reserveregs(fs
, 2)
691 self
:codeABC(fs
, "OP_SELF", func
, e
.info
, self
:exp2RK(fs
, key
))
692 self
:freeexp(fs
, key
)
697 ------------------------------------------------------------------------
699 ------------------------------------------------------------------------
700 function luaK
:invertjump(fs
, e
)
701 --printf("invertjump on jump instruction #%i", e.info)
702 --printv(self:getcode(fs, e))
703 local pc
= self
:getjumpcontrol(fs
, e
.info
)
704 assert(luaP
:testOpMode(luaP
:GET_OPCODE(pc
), "OpModeT") and
705 luaP
:GET_OPCODE(pc
) ~= "OP_TESTSET" and
706 luaP
:GET_OPCODE(pc
) ~= "OP_TEST")
707 --printf("Before invert:")
709 luaP
:SETARG_A(pc
, (luaP
:GETARG_A(pc
) == 0) and 1 or 0)
710 --printf("After invert:")
714 ------------------------------------------------------------------------
716 ------------------------------------------------------------------------
717 function luaK
:jumponcond(fs
, e
, cond
)
718 if e
.k
== "VRELOCABLE" then
719 local ie
= self
:getcode(fs
, e
)
720 if luaP
:GET_OPCODE(ie
) == "OP_NOT" then
721 fs
.pc
= fs
.pc
- 1 -- remove previous OP_NOT
722 return self
:condjump(fs
, "OP_TEST", luaP
:GETARG_B(ie
), 0,
727 self
:discharge2anyreg(fs
, e
)
729 return self
:condjump(fs
, "OP_TESTSET", luaP
.NO_REG
, e
.info
, cond
and 1 or 0)
732 ------------------------------------------------------------------------
734 ------------------------------------------------------------------------
735 function luaK
:goiftrue(fs
, e
)
736 local pc
-- pc of last jump
737 self
:dischargevars(fs
, e
)
739 if k
== "VK" or k
== "VTRUE" or k
== "VKNUM" then
740 pc
= self
.NO_JUMP
-- always true; do nothing
741 elseif k
== "VFALSE" then
742 pc
= self
:jump(fs
) -- always jump
743 elseif k
== "VJMP" then
744 self
:invertjump(fs
, e
)
747 pc
= self
:jumponcond(fs
, e
, false)
749 e
.f
= self
:concat(fs
, e
.f
, pc
) -- insert last jump in 'f' list
750 self
:patchtohere(fs
, e
.t
)
754 ------------------------------------------------------------------------
756 ------------------------------------------------------------------------
757 function luaK
:goiffalse(fs
, e
)
758 local pc
-- pc of last jump
759 self
:dischargevars(fs
, e
)
761 if k
== "VNIL" or k
== "VFALSE"then
762 pc
= self
.NO_JUMP
-- always false; do nothing
763 elseif k
== "VTRUE" then
764 pc
= self
:jump(fs
) -- always jump
765 elseif k
== "VJMP" then
768 pc
= self
:jumponcond(fs
, e
, true)
770 e
.t
= self
:concat(fs
, e
.t
, pc
) -- insert last jump in 't' list
771 self
:patchtohere(fs
, e
.f
)
775 ------------------------------------------------------------------------
777 ------------------------------------------------------------------------
778 function luaK
:codenot(fs
, e
)
779 self
:dischargevars(fs
, e
)
781 if k
== "VNIL" or k
== "VFALSE" then
783 elseif k
== "VK" or k
== "VKNUM" or k
== "VTRUE" then
785 elseif k
== "VJMP" then
786 self
:invertjump(fs
, e
)
787 elseif k
== "VRELOCABLE" or k
== "VNONRELOC" then
788 self
:discharge2anyreg(fs
, e
)
790 e
.info
= self
:codeABC(fs
, "OP_NOT", 0, e
.info
, 0)
793 assert(0) -- cannot happen
795 -- interchange true and false lists
797 self
:removevalues(fs
, e
.f
)
798 self
:removevalues(fs
, e
.t
)
801 ------------------------------------------------------------------------
803 ------------------------------------------------------------------------
804 function luaK
:indexed(fs
, t
, k
)
805 t
.aux
= self
:exp2RK(fs
, k
)
810 function luaK
:constfolding (op
, e1
, e2
)
811 if not self
:isnumeral(e1
) or not self
:isnumeral(e2
) then return false end
812 local v1
, v2
, e
, r
= e1
.nval
, e2
and e2
.nval
, nil
813 if op
== "OP_ADD" then r
= v1
+v2
814 elseif op
== "OP_SUB" then r
= v1
-v2
815 elseif op
== "OP_MUL" then r
= v1
*v2
816 elseif op
== "OP_DIV" then if v2
==0 then return false end r
= v1
/v2
817 elseif op
== "OP_MOD" then if v2
==0 then return false end r
= v1
%v2
818 elseif op
== "OP_POW" then r
= v1^v2
819 elseif op
== "OP_UNM" then r
= -v1
820 elseif op
== "OP_LEN" then return false
821 else assert (false, "Unknown numeric value") end
827 function luaK
:codearith (fs
, op
, e1
, e2
)
828 if self
:constfolding (op
, e1
, e2
) then return else
829 local o1
= self
:exp2RK (fs
, e1
)
831 if op
~= "OP_UNM" and op
~= "OP_LEN" then
832 o2
= self
:exp2RK (fs
, e2
) end
835 e1
.info
= self
:codeABC (fs
, op
, 0, o1
, o2
)
841 function luaK
:codecomp (fs
, op
, cond
, e1
, e2
)
842 assert (type (cond
) == "boolean")
843 local o1
= self
:exp2RK (fs
, e1
)
844 local o2
= self
:exp2RK (fs
, e2
)
845 self
:freeexp (fs
, e2
)
846 self
:freeexp (fs
, e1
)
847 if not cond
and op
~= "OP_EQ" then
848 local temp
= o1
; o1
=o2
; o2
=temp cond
= true end
849 e1
.info
= self
:condjump (fs
, op
, cond
and 1 or 0, o1
, o2
)
853 ------------------------------------------------------------------------
855 ------------------------------------------------------------------------
856 function luaK
:prefix (fs
, op
, e
)
857 local e2
= { t
= self
.NO_JUMP
; f
= self
.NO_JUMP
;
858 k
= "VKNUM"; nval
= 0 }
861 self
:exp2anyreg (fs
, e
) end
862 self
:codearith (fs
, "OP_UNM", e
, e2
)
863 elseif op
== "not" then
865 elseif op
== "len" then
866 self
:exp2anyreg (fs
, e
)
867 self
:codearith (fs
, "OP_LEN", e
, e2
)
869 assert (false, "Unknown unary operator")
873 ------------------------------------------------------------------------
875 ------------------------------------------------------------------------
876 function luaK
:infix (fs
, op
, v
)
879 elseif op
== "or" then
880 self
:goiffalse(fs
, v
)
881 elseif op
== "concat" then
882 self
:exp2nextreg(fs
, v
) -- operand must be on the 'stack'
884 if not self
:isnumeral (v
) then self
:exp2RK(fs
, v
) end
888 ------------------------------------------------------------------------
890 -- grep "ORDER OPR" if you change these enums
891 ------------------------------------------------------------------------
892 luaK
.arith_opc
= { -- done as a table lookup instead of a calc
902 luaK
.test_opc
= { -- was ops[] in the codebinop function
903 eq
= {opc
="OP_EQ", cond
=true},
904 lt
= {opc
="OP_LT", cond
=true},
905 le
= {opc
="OP_LE", cond
=true},
907 -- Pseudo-ops, with no metatable equivalent:
908 ne
= {opc
="OP_EQ", cond
=false},
909 gt
= {opc
="OP_LT", cond
=false},
910 ge
= {opc
="OP_LE", cond
=false}
913 ------------------------------------------------------------------------
915 ------------------------------------------------------------------------
916 function luaK
:posfix(fs
, op
, e1
, e2
)
918 assert(e1
.t
== self
.NO_JUMP
) -- list must be closed
919 self
:dischargevars(fs
, e2
)
920 e2
.f
= self
:concat(fs
, e2
.f
, e1
.f
)
921 for k
,v
in pairs(e2
) do e1
[k
]=v
end -- *e1 = *e2
922 elseif op
== "or" then
923 assert(e1
.f
== self
.NO_JUMP
) -- list must be closed
924 self
:dischargevars(fs
, e2
)
925 e2
.t
= self
:concat(fs
, e2
.t
, e1
.t
)
926 for k
,v
in pairs(e2
) do e1
[k
]=v
end -- *e1 = *e2
927 elseif op
== "concat" then
929 if e2
.k
== "VRELOCABLE"
930 and luaP
:GET_OPCODE(self
:getcode(fs
, e2
)) == "OP_CONCAT" then
931 assert(e1
.info
== luaP
:GETARG_B(self
:getcode(fs
, e2
)) - 1)
933 luaP
:SETARG_B(self
:getcode(fs
, e2
), e1
.info
)
934 e1
.k
= "VRELOCABLE"; e1
.info
= e2
.info
936 self
:exp2nextreg(fs
, e2
)
937 self
:codearith (fs
, "OP_CONCAT", e1
, e2
)
940 local opc
= self
.arith_opc
[op
]
941 if opc
then self
:codearith (fs
, opc
, e1
, e2
) else
942 opc
= self
.test_opc
[op
] or error ("Unknown operator "..op
)
943 self
:codecomp (fs
, opc
.opc
, opc
.cond
, e1
, e2
)
948 ------------------------------------------------------------------------
950 ------------------------------------------------------------------------
951 function luaK
:fixline(fs
, line
)
954 --print(debug.traceback "fixline (line == nil)")
956 fs
.f
.lineinfo
[fs
.pc
- 1] = line
or 0
959 ------------------------------------------------------------------------
961 ------------------------------------------------------------------------
962 function luaK
:code(fs
, i
, line
)
965 --print(debug.traceback "line == nil")
971 for _
,x
in ipairs
{"A","B","Bx", "sBx", "C"} do
972 if i
[x
] then table.insert (params
, string.format ("%s=%i", x
, i
[x
])) end
974 debugf ("[code:\t%s\t%s]", luaP
.opnames
[i
.OP
], table.concat (params
, ", "))
977 self
:dischargejpc(fs
) -- 'pc' will change
980 f
.lineinfo
[fs
.pc
] = line
983 f
.lineinfo
[fs
.pc
] = fs
.lastline
984 if fs
.lastline
== 0 then
985 --print(debug.traceback())
989 if f
.lineinfo
[fs
.pc
] == 0 then
990 f
.lineinfo
[fs
.pc
] = 42
998 ------------------------------------------------------------------------
1000 ------------------------------------------------------------------------
1001 function luaK
:codeABC(fs
, o
, a
, b
, c
)
1002 assert(luaP
:getOpMode(o
) == "iABC", o
.." is not an ABC operation")
1003 --assert getbmode(o) ~= opargn or b == 0
1004 --assert getcmode(o) ~= opargn or c == 0
1006 --return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.ls.lastline)
1007 return self
:code(fs
, luaP
:CREATE_ABC(o
, a
, b
, c
), fs
.lastline
)
1010 ------------------------------------------------------------------------
1012 ------------------------------------------------------------------------
1013 function luaK
:codeABx(fs
, o
, a
, bc
)
1014 assert(luaP
:getOpMode(o
) == "iABx" or luaP
:getOpMode(o
) == "iAsBx")
1015 --assert getcmode(o) == opargn
1017 --return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.ls.lastline)
1018 return self
:code(fs
, luaP
:CREATE_ABx(o
, a
, bc
), fs
.lastline
)
1021 ------------------------------------------------------------------------
1023 ------------------------------------------------------------------------
1024 function luaK
:setlist (fs
, base
, nelems
, tostore
)
1025 local c
= math
.floor ((nelems
-1) / luaP
.LFIELDS_PER_FLUSH
+ 1)
1026 local b
= tostore
== self
.LUA_MULTRET
and 0 or tostore
1027 assert (tostore
~= 0)
1028 if c
<= luaP
.MAXARG_C
then self
:codeABC (fs
, "OP_SETLIST", base
, b
, c
)
1030 self
:codeABC (fs
, "OP_SETLIST", base
, b
, 0)
1031 self
:code (fs
, c
, fs
.lastline
)--FIXME
1033 fs
.freereg
= base
+ 1