]> git.lizzy.rs Git - metalua.git/blob - src/compiler/lcode.lua
c4af6846ab75663e5f8b8d4835a8d3ba470af3be
[metalua.git] / src / compiler / lcode.lua
1 ----------------------------------------------------------------------
2 --
3 -- WARNING! You're entering a hackish area, proceed at your own risks!
4 --
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
8 -- in it.
9 --
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
13 -- on.
14 --
15 -- End of warning.
16 --
17 ----------------------------------------------------------------------
18
19 --[[--------------------------------------------------------------------
20
21   $Id$
22
23   lcode.lua
24   Lua 5 code generator in Lua
25   This file is part of Yueliang.
26
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.
30
31   See the ChangeLog for more information.
32
33 ------------------------------------------------------------------------
34
35   [FF] Slightly modified, mainly to produce Lua 5.1 bytecode.
36
37 ----------------------------------------------------------------------]]
38
39 --[[--------------------------------------------------------------------
40 -- Notes:
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
46 -- * Added:
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 ----------------------------------------------------------------------]]
54
55 module("bytecode", package.seeall)
56
57 local function debugf() end
58
59 luaK = {}
60
61 luaK.MAXSTACK    = 250        -- (llimits.h, used in lcode.lua)
62 luaK.LUA_MULTRET = -1         -- (lua.h)
63
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 ------------------------------------------------------------------------
68 luaK.NO_JUMP = -1
69
70 --FF 5.1
71 function luaK:isnumeral(e)
72    return e.k=="VKNUM" and e.t==self.NO_JUMP and e.t==self.NO_JUMP
73 end
74
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
82 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
88
89 ------------------------------------------------------------------------
90 -- returns the instruction object for given e (expdesc)
91 ------------------------------------------------------------------------
92 function luaK:getcode(fs, e)
93   return fs.f.code[e.info]
94 end
95
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)
101 end
102
103 ------------------------------------------------------------------------
104 --
105 ------------------------------------------------------------------------
106 function luaK:hasjumps(e)
107   return e.t ~= e.f
108 end
109
110 ------------------------------------------------------------------------
111 -- FF updated 5.1
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)
123             end
124             return
125          end
126       end
127    end
128    self:codeABC(fs, "OP_LOADNIL", from, from + n - 1, 0)  -- else no optimization
129 end
130
131 ------------------------------------------------------------------------
132 --
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
139 end
140
141 --FF 5.1
142 function luaK:ret (fs, first, nret)
143    luaK:codeABC (fs, "OP_RETURN", first, nret+1, 0)
144 end
145
146
147 ------------------------------------------------------------------------
148 --
149 ------------------------------------------------------------------------
150 function luaK:condjump(fs, op, A, B, C)
151   self:codeABC(fs, op, A, B, C)
152   return self:jump(fs)
153 end
154
155 ------------------------------------------------------------------------
156 --
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")
164   end
165   luaP:SETARG_sBx(jmp, offset)
166 end
167
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
174   return fs.pc
175 end
176
177 ------------------------------------------------------------------------
178 --
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
184   else
185     return (pc + 1) + offset  -- turn offset into absolute position
186   end
187 end
188
189 ------------------------------------------------------------------------
190 --
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
196     return ppi
197   else
198     return pi
199   end
200 end
201
202 ------------------------------------------------------------------------
203 -- check whether list has any jump that do not produce a value
204 -- (or produce an inverted value)
205 ------------------------------------------------------------------------
206 --FF updated 5.1
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
213       return true
214     end
215     list = self:getjump(fs, list)
216   end
217   return false  -- not found
218 end
219
220 ------------------------------------------------------------------------
221 --
222 ------------------------------------------------------------------------
223 --FF updated 5.1
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)
231    else 
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))
235       luaP:SETARG_B(i, 0)
236       luaP:SETARG_C(i, luaP:GETARG_C(i))
237    end
238    return true
239 end
240
241 --FF added 5.1
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)
246    end
247 end
248
249 ------------------------------------------------------------------------
250 -- FF updated 5.1
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)
257       else
258          self:fixjump (fs, list, dtarget)
259       end
260       list = _next
261    end
262 end
263
264 ------------------------------------------------------------------------
265 --
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
270 end
271
272 ------------------------------------------------------------------------
273 --
274 ------------------------------------------------------------------------
275 function luaK:patchlist(fs, list, target)
276   if target == fs.pc then
277     self:patchtohere(fs, list)
278   else
279     assert(target < fs.pc)
280     self:patchlistaux(fs, list, target, luaP.NO_REG, target)
281   end
282 end
283
284 ------------------------------------------------------------------------
285 --
286 ------------------------------------------------------------------------
287 function luaK:patchtohere(fs, list)
288   self:getlabel(fs)
289   fs.jpc = self:concat(fs, fs.jpc, list)
290 end
291
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
298     return l2  -- changed
299   else
300     local list = l1
301     local _next = self:getjump(fs, list)
302     while _next ~= self.NO_JUMP do  -- find last element
303       list = _next
304       _next = self:getjump(fs, list)
305     end
306     self:fixjump(fs, list, l2)
307   end
308   return l1  -- unchanged
309 end
310
311 ------------------------------------------------------------------------
312 --
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")
319     end
320     fs.f.maxstacksize = newstack
321   end
322 end
323
324 ------------------------------------------------------------------------
325 --
326 ------------------------------------------------------------------------
327 function luaK:reserveregs(fs, n)
328   self:checkstack(fs, n)
329   fs.freereg = fs.freereg + n
330 end
331
332 ------------------------------------------------------------------------
333 --
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))
340   end
341 end
342
343 ------------------------------------------------------------------------
344 --
345 ------------------------------------------------------------------------
346 function luaK:freeexp(fs, e)
347   if e.k == "VNONRELOC" then
348     self:freereg(fs, e.info)
349   end
350 end
351
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]
363    local f = fs.f
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
370       do
371          local t = type (v.value)
372          assert(t=="nil" or t=="string" or t=="number" or t=="boolean")
373       end
374       --debugf("[const: k[%i] = %s ]", fs.nk, tostringv(v.value))
375       fs.f.k[fs.nk] = v
376       fs.h[k.value] = { }
377       self:setnvalue(fs.h[k.value], fs.nk)
378       local nk = fs.nk
379       fs.nk = fs.nk+1
380       return nk
381    end
382 end
383
384 ------------------------------------------------------------------------
385 --
386 ------------------------------------------------------------------------
387 function luaK:stringK(fs, s)
388    assert (type(s)=="string")
389    local o = {}  -- TObject
390    self:setsvalue(o, s)
391    return self:addk(fs, o, o)
392 end
393
394 ------------------------------------------------------------------------
395 --
396 ------------------------------------------------------------------------
397 function luaK:numberK(fs, r)
398    assert (type(r)=="number")
399   local o = {}  -- TObject
400   self:setnvalue(o, r)
401   return self:addk(fs, o, o)
402 end
403
404 ------------------------------------------------------------------------
405 --
406 ------------------------------------------------------------------------
407 function luaK:boolK(fs, r)
408    assert (type(r)=="boolean")
409    local o = {}  -- TObject
410    self:setnvalue(o, r)
411    return self:addk(fs, o, o)
412 end
413
414 ------------------------------------------------------------------------
415 --
416 ------------------------------------------------------------------------
417 function luaK:nilK(fs)
418   local k, v = {}, {}  -- TObject
419   self:setnilvalue(v)
420   self:sethvalue(k, fs.h)  -- cannot use nil as key; instead use table itself
421   return self:addk(fs, k, v)
422 end
423
424
425 --FF 5.1
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)
433    end
434 end
435
436 --FF 5.1
437 function luaK:setmultret (fs, e)
438    self:setreturns (fs, e, self.LUA_MULTRET)
439 end
440
441 --FF 5.1
442 function luaK:setoneret (fs, e)
443    if e.k == "VCALL" then  -- expression is an open function call?
444       e.k = "VNONRELOC"
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)
448       e.k = "VRELOCABLE"
449    end
450 end
451
452
453 ------------------------------------------------------------------------
454 --FF deprecated in 5.1
455 ------------------------------------------------------------------------
456 function luaK:setcallreturns(fs, e, nresults)
457    assert (false, "setcallreturns deprecated")
458    --print "SCR:"
459    --printv(e)
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?
464          e.k = "VNONRELOC"
465          e.info = luaP:GETARG_A(self:getcode(fs, e))
466       end
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)
472          e.k = "VRELOCABLE"
473 --FIXME: why no SETARG_A???
474       else
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)))
479       end
480    end
481 end
482
483 ------------------------------------------------------------------------
484 -- Ajoute le code pour effectuer l'extraction de la locvar/upval/globvar
485 -- /idx, sachant
486 ------------------------------------------------------------------------
487 function luaK:dischargevars(fs, e)
488 --printf("\ndischargevars\n")
489   local k = e.k
490   if k == "VLOCAL" then
491     e.k = "VNONRELOC"
492   elseif k == "VUPVAL" then
493     e.info = self:codeABC(fs, "OP_GETUPVAL", 0, e.info, 0)
494     e.k = "VRELOCABLE"
495   elseif k == "VGLOBAL" then
496     e.info = self:codeABx(fs, "OP_GETGLOBAL", 0, e.info)
497     e.k = "VRELOCABLE"
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)
502     e.k = "VRELOCABLE"
503   elseif k == "VCALL" or k == "VVARARG" then
504     self:setoneret(fs, e)
505   else
506     -- there is one value available (somewhere)
507   end
508 --printf("\n/dischargevars\n")
509 end
510
511 ------------------------------------------------------------------------
512 --
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)
517 end
518
519 ------------------------------------------------------------------------
520 -- FF updated 5.1
521 ------------------------------------------------------------------------
522 function luaK:discharge2reg(fs, e, reg)
523    self:dischargevars(fs, e)
524    local k = e.k
525    if k == "VNIL" then
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)
539       end
540    else
541       assert(e.k == "VVOID" or e.k == "VJMP")
542       return  -- nothing to do...
543    end
544    e.info = reg
545    e.k = "VNONRELOC"
546 end
547
548 ------------------------------------------------------------------------
549 --
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)
555   end
556 end
557
558 ------------------------------------------------------------------------
559 --
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
565   end
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)
576     end
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)
580   end
581   e.f, e.t = self.NO_JUMP, self.NO_JUMP
582   e.info = reg
583   e.k = "VNONRELOC"
584 end
585
586 ------------------------------------------------------------------------
587 --
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))
594      return end
595   self:freeexp(fs, e)
596   self:reserveregs(fs, 1)
597   self:exp2reg(fs, e, fs.freereg - 1)
598 end
599
600 ------------------------------------------------------------------------
601 --
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
608          return e.info
609       end
610       if e.info >= fs.nactvar then  -- reg. is not a local?
611          self:exp2reg(fs, e, e.info)  -- put value on it
612          return e.info
613       end
614    end
615    self:exp2nextreg(fs, e)  -- default
616    return e.info
617 end
618
619 ------------------------------------------------------------------------
620 --
621 ------------------------------------------------------------------------
622 function luaK:exp2val(fs, e)
623   if self:hasjumps(e) then
624     self:exp2anyreg(fs, e)
625   else
626     self:dischargevars(fs, e)
627   end
628 end
629
630 ------------------------------------------------------------------------
631 -- FF updated 5.1
632 ------------------------------------------------------------------------
633 function luaK:exp2RK(fs, e)
634    self:exp2val(fs, e)
635    local k = e.k
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
641          e.k = "VK"
642          return luaP:RKASK(e.info)
643       end
644    elseif k == "VK" then
645       if e.info <= luaP.MAXINDEXRK then  -- constant fit in argC?
646          return luaP:RKASK (e.info)
647       end
648    end
649    -- not a constant in the right range: put it in a register
650    return self:exp2anyreg(fs, e)
651 end
652
653 ------------------------------------------------------------------------
654 --
655 ------------------------------------------------------------------------
656 function luaK:storevar(fs, var, exp)
657    --print("STOREVAR")
658    --printf("var=%s", tostringv(var))
659    --printf("exp=%s", tostringv(exp))
660
661    local k = var.k
662    if k == "VLOCAL" then
663       self:freeexp(fs, exp)
664       self:exp2reg(fs, exp, var.info)
665       return
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)
676    else
677       assert(0)  -- invalid var kind to store
678    end
679    self:freeexp(fs, exp)
680    --print("/STOREVAR")
681 end
682
683 ------------------------------------------------------------------------
684 --
685 ------------------------------------------------------------------------
686 function luaK:_self(fs, e, key)
687   self:exp2anyreg(fs, e)
688   self:freeexp(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)
693   e.info = func
694   e.k = "VNONRELOC"
695 end
696
697 ------------------------------------------------------------------------
698 -- FF updated 5.1
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:")
708    --printv(pc)
709    luaP:SETARG_A(pc, (luaP:GETARG_A(pc) == 0) and 1 or 0)
710    --printf("After invert:")
711    --printv(pc)
712 end
713
714 ------------------------------------------------------------------------
715 --
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,
723                            cond and 0 or 1)
724     end
725     -- else go through
726   end
727   self:discharge2anyreg(fs, e)
728   self:freeexp(fs, e)
729   return self:condjump(fs, "OP_TESTSET", luaP.NO_REG, e.info, cond and 1 or 0)
730 end
731
732 ------------------------------------------------------------------------
733 --
734 ------------------------------------------------------------------------
735 function luaK:goiftrue(fs, e)
736   local pc  -- pc of last jump
737   self:dischargevars(fs, e)
738   local k = e.k
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)
745     pc = e.info
746   else
747     pc = self:jumponcond(fs, e, false)
748  end
749   e.f = self:concat(fs, e.f, pc)  -- insert last jump in 'f' list
750   self:patchtohere(fs, e.t)
751   e.t = self.NO_JUMP
752 end
753
754 ------------------------------------------------------------------------
755 --
756 ------------------------------------------------------------------------
757 function luaK:goiffalse(fs, e)
758   local pc  -- pc of last jump
759   self:dischargevars(fs, e)
760   local k = e.k
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
766     pc = e.info
767   else
768     pc = self:jumponcond(fs, e, true)
769   end
770   e.t = self:concat(fs, e.t, pc)  -- insert last jump in 't' list
771   self:patchtohere(fs, e.f)
772   e.f = self.NO_JUMP
773 end
774
775 ------------------------------------------------------------------------
776 --
777 ------------------------------------------------------------------------
778 function luaK:codenot(fs, e)
779   self:dischargevars(fs, e)
780   local k = e.k
781   if k == "VNIL" or k == "VFALSE" then
782     e.k = "VTRUE"
783   elseif k == "VK" or k == "VKNUM" or k == "VTRUE" then
784     e.k = "VFALSE"
785   elseif k == "VJMP" then
786     self:invertjump(fs, e)
787   elseif k == "VRELOCABLE" or k == "VNONRELOC" then
788     self:discharge2anyreg(fs, e)
789     self:freeexp(fs, e)
790     e.info = self:codeABC(fs, "OP_NOT", 0, e.info, 0)
791     e.k = "VRELOCABLE"
792   else
793     assert(0)  -- cannot happen
794   end
795   -- interchange true and false lists
796   e.f, e.t = e.t, e.f
797   self:removevalues(fs, e.f)
798   self:removevalues(fs, e.t)
799 end
800
801 ------------------------------------------------------------------------
802 --
803 ------------------------------------------------------------------------
804 function luaK:indexed(fs, t, k)
805   t.aux = self:exp2RK(fs, k)
806   t.k = "VINDEXED"
807 end
808
809 --FF 5.1
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
822    e1.nval = r
823    return true
824 end
825
826 --FF 5.1
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)
830       local o2 = 0
831       if op ~= "OP_UNM" and op ~= "OP_LEN" then 
832          o2 = self:exp2RK (fs, e2) end
833       self:freeexp(fs, e2)
834       self:freeexp(fs, e1)
835       e1.info = self:codeABC (fs, op, 0, o1, o2)
836       e1.k = "VRELOCABLE"
837    end
838 end
839
840 --FF 5.1
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)
850    e1.k = "VJMP"
851 end
852
853 ------------------------------------------------------------------------
854 --
855 ------------------------------------------------------------------------
856 function luaK:prefix (fs, op, e)
857    local e2 = { t = self.NO_JUMP; f = self.NO_JUMP;
858                 k = "VKNUM"; nval = 0 }
859    if op == "unm" then
860       if e.k == "VK" then
861          self:exp2anyreg (fs, e) end
862       self:codearith (fs, "OP_UNM", e, e2)
863    elseif op == "not" then
864       self:codenot (fs, e)
865    elseif op == "len" then
866       self:exp2anyreg (fs, e)
867       self:codearith (fs, "OP_LEN", e, e2)
868    else
869       assert (false, "Unknown unary operator")
870    end
871 end
872
873 ------------------------------------------------------------------------
874 --
875 ------------------------------------------------------------------------
876 function luaK:infix (fs, op, v)
877   if op == "and" then
878     self:goiftrue(fs, 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'
883  else
884     if not self:isnumeral (v) then self:exp2RK(fs, v) end
885   end
886 end
887
888 ------------------------------------------------------------------------
889 --
890 -- grep "ORDER OPR" if you change these enums
891 ------------------------------------------------------------------------
892 luaK.arith_opc = {  -- done as a table lookup instead of a calc
893    add = "OP_ADD",
894    sub = "OP_SUB",
895    mul = "OP_MUL",
896    mod = "OP_MOD",
897    div = "OP_DIV",
898    pow = "OP_POW",
899    len = "OP_LEN",
900    ["not"] = "OP_NOT"
901 }
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},
906
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}
911 }
912
913 ------------------------------------------------------------------------
914 --
915 ------------------------------------------------------------------------
916 function luaK:posfix(fs, op, e1, e2)
917    if op == "and" then
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
928       self:exp2val(fs, e2)
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)
932          self:freeexp(fs, e1)
933          luaP:SETARG_B(self:getcode(fs, e2), e1.info)
934          e1.k = "VRELOCABLE"; e1.info = e2.info
935       else
936          self:exp2nextreg(fs, e2)
937          self:codearith (fs, "OP_CONCAT", e1, e2)
938       end
939    else
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)
944       end
945    end
946 end
947
948 ------------------------------------------------------------------------
949 --
950 ------------------------------------------------------------------------
951 function luaK:fixline(fs, line)
952    --assert (line)
953    if not line then
954      --print(debug.traceback "fixline (line == nil)")
955    end
956    fs.f.lineinfo[fs.pc - 1] = line or 0
957 end
958
959 ------------------------------------------------------------------------
960 --
961 ------------------------------------------------------------------------
962 function luaK:code(fs, i, line)
963   if not line then 
964     line = 0
965     --print(debug.traceback "line == nil")
966   end
967   local f = fs.f
968
969   do -- print it
970     local params = { }
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
973     end
974     debugf ("[code:\t%s\t%s]", luaP.opnames[i.OP], table.concat (params, ", "))
975   end
976
977   self:dischargejpc(fs)  -- 'pc' will change
978
979   f.code[fs.pc] = i
980   f.lineinfo[fs.pc] = line
981
982   if line == 0 then
983     f.lineinfo[fs.pc] = fs.lastline
984     if fs.lastline == 0 then
985       --print(debug.traceback())
986     end    
987   end
988
989   if f.lineinfo[fs.pc] == 0 then
990     f.lineinfo[fs.pc] = 42
991   end
992
993   local pc = fs.pc
994   fs.pc = fs.pc + 1
995   return pc
996 end
997
998 ------------------------------------------------------------------------
999 -- 
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
1005   --FF
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)
1008 end
1009
1010 ------------------------------------------------------------------------
1011 --
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
1016   --FF
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)
1019 end
1020
1021 ------------------------------------------------------------------------
1022 --
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)
1029    else
1030       self:codeABC (fs, "OP_SETLIST", base, b, 0)
1031       self:code (fs, c, fs.lastline)--FIXME
1032    end
1033    fs.freereg = base + 1
1034 end