]> git.lizzy.rs Git - metalua.git/blob - metalua/compiler/bytecode/lcode.lua
Merge branch 'master' of ssh://git.eclipse.org/gitroot/koneki/org.eclipse.koneki...
[metalua.git] / metalua / compiler / bytecode / lcode.lua
1 -------------------------------------------------------------------------------
2 -- Copyright (c) 2005-2013 Kein-Hong Man, Fabien Fleutot and others.
3 --
4 -- All rights reserved.
5 --
6 -- This program and the accompanying materials are made available
7 -- under the terms of the Eclipse Public License v1.0 which
8 -- accompanies this distribution, and is available at
9 -- http://www.eclipse.org/legal/epl-v10.html
10 --
11 -- This program and the accompanying materials are also made available
12 -- under the terms of the MIT public license which accompanies this
13 -- distribution, and is available at http://www.lua.org/license.html
14 --
15 -- Contributors:
16 --     Kein-Hong Man  - Initial implementation for Lua 5.0, part of Yueliang
17 --     Fabien Fleutot - Port to Lua 5.1, integration with Metalua
18 --
19 -------------------------------------------------------------------------------
20
21 --[[--------------------------------------------------------------------
22
23   $Id$
24
25   lcode.lua
26   Lua 5 code generator in Lua
27   This file is part of Yueliang.
28
29   Copyright (c) 2005 Kein-Hong Man <khman@users.sf.net>
30   The COPYRIGHT file describes the conditions
31   under which this software may be distributed.
32
33   See the ChangeLog for more information.
34
35 ------------------------------------------------------------------------
36
37   [FF] Slightly modified, mainly to produce Lua 5.1 bytecode.
38
39 ----------------------------------------------------------------------]]
40
41 --[[--------------------------------------------------------------------
42 -- Notes:
43 -- * one function manipulate a pointer argument with a simple data type
44 --   (can't be emulated by a table, ambiguous), now returns that value:
45 --   luaK:concat(fs, l1, l2)
46 -- * some function parameters changed to boolean, additional code
47 --   translates boolean back to 1/0 for instruction fields
48 -- * Added:
49 --   luaK:ttisnumber(o) (from lobject.h)
50 --   luaK:nvalue(o) (from lobject.h)
51 --   luaK:setnilvalue(o) (from lobject.h)
52 --   luaK:setsvalue(o) (from lobject.h)
53 --   luaK:setnvalue(o) (from lobject.h)
54 --   luaK:sethvalue(o) (from lobject.h)
55 ----------------------------------------------------------------------]]
56
57 local luaP = require 'metalua.compiler.bytecode.lopcodes'
58
59 local function debugf() end
60
61 local luaK = { }
62
63 luaK.MAXSTACK    = 250        -- (llimits.h, used in lcode.lua)
64 luaK.LUA_MULTRET = -1         -- (lua.h)
65
66 ------------------------------------------------------------------------
67 -- Marks the end of a patch list. It is an invalid value both as an absolute
68 -- address, and as a list link (would link an element to itself).
69 ------------------------------------------------------------------------
70 luaK.NO_JUMP = -1
71
72 --FF 5.1
73 function luaK:isnumeral(e)
74    return e.k=="VKNUM" and e.t==self.NO_JUMP and e.t==self.NO_JUMP
75 end
76
77 ------------------------------------------------------------------------
78 -- emulation of TObject macros (these are from lobject.h)
79 -- * TObject is a table since lcode passes references around
80 -- * tt member field removed, using Lua's type() instead
81 ------------------------------------------------------------------------
82 function luaK:ttisnumber(o)
83   if o then return type(o.value) == "number" else return false end
84 end
85 function luaK:nvalue(o) return o.value end
86 function luaK:setnilvalue(o) o.value = nil end
87 function luaK:setsvalue(o, s) o.value = s end
88 luaK.setnvalue = luaK.setsvalue
89 luaK.sethvalue = luaK.setsvalue
90
91 ------------------------------------------------------------------------
92 -- returns the instruction object for given e (expdesc)
93 ------------------------------------------------------------------------
94 function luaK:getcode(fs, e)
95   return fs.f.code[e.info]
96 end
97
98 ------------------------------------------------------------------------
99 -- codes an instruction with a signed Bx (sBx) field
100 ------------------------------------------------------------------------
101 function luaK:codeAsBx(fs, o, A, sBx)
102   return self:codeABx(fs, o, A, sBx + luaP.MAXARG_sBx)
103 end
104
105 ------------------------------------------------------------------------
106 --
107 ------------------------------------------------------------------------
108 function luaK:hasjumps(e)
109   return e.t ~= e.f
110 end
111
112 ------------------------------------------------------------------------
113 -- FF updated 5.1
114 ------------------------------------------------------------------------
115 function luaK:_nil(fs, from, n)
116    if fs.pc > fs.lasttarget then  -- no jumps to current position?
117       if fs.pc == 0 then return end --function start, positions are already clean
118       local previous = fs.f.code[fs.pc - 1]
119       if luaP:GET_OPCODE(previous) == "OP_LOADNIL" then
120          local pfrom = luaP:GETARG_A(previous)
121          local pto = luaP:GETARG_B(previous)
122          if pfrom <= from and from <= pto + 1 then  -- can connect both?
123             if from + n - 1 > pto then
124                luaP:SETARG_B(previous, from + n - 1)
125             end
126             return
127          end
128       end
129    end
130    self:codeABC(fs, "OP_LOADNIL", from, from + n - 1, 0)  -- else no optimization
131 end
132
133 ------------------------------------------------------------------------
134 --
135 ------------------------------------------------------------------------
136 function luaK:jump(fs)
137   local jpc = fs.jpc  -- save list of jumps to here
138   fs.jpc = self.NO_JUMP
139   local j = self:codeAsBx(fs, "OP_JMP", 0, self.NO_JUMP)
140   return self:concat(fs, j, jpc)  -- keep them on hold
141 end
142
143 --FF 5.1
144 function luaK:ret (fs, first, nret)
145    luaK:codeABC (fs, "OP_RETURN", first, nret+1, 0)
146 end
147
148
149 ------------------------------------------------------------------------
150 --
151 ------------------------------------------------------------------------
152 function luaK:condjump(fs, op, A, B, C)
153   self:codeABC(fs, op, A, B, C)
154   return self:jump(fs)
155 end
156
157 ------------------------------------------------------------------------
158 --
159 ------------------------------------------------------------------------
160 function luaK:fixjump(fs, pc, dest)
161   local jmp = fs.f.code[pc]
162   local offset = dest - (pc + 1)
163   assert(dest ~= self.NO_JUMP)
164   if math.abs(offset) > luaP.MAXARG_sBx then
165     error("control structure too long")
166   end
167   luaP:SETARG_sBx(jmp, offset)
168 end
169
170 ------------------------------------------------------------------------
171 -- returns current 'pc' and marks it as a jump target (to avoid wrong
172 -- optimizations with consecutive instructions not in the same basic block).
173 ------------------------------------------------------------------------
174 function luaK:getlabel(fs)
175   fs.lasttarget = fs.pc
176   return fs.pc
177 end
178
179 ------------------------------------------------------------------------
180 --
181 ------------------------------------------------------------------------
182 function luaK:getjump(fs, pc)
183   local offset = luaP:GETARG_sBx(fs.f.code[pc])
184   if offset == self.NO_JUMP then  -- point to itself represents end of list
185     return self.NO_JUMP  -- end of list
186   else
187     return (pc + 1) + offset  -- turn offset into absolute position
188   end
189 end
190
191 ------------------------------------------------------------------------
192 --
193 ------------------------------------------------------------------------
194 function luaK:getjumpcontrol(fs, pc)
195   local pi = fs.f.code[pc]
196   local ppi = fs.f.code[pc - 1]
197   if pc >= 1 and luaP:testOpMode(luaP:GET_OPCODE(ppi), "OpModeT") then
198     return ppi
199   else
200     return pi
201   end
202 end
203
204 ------------------------------------------------------------------------
205 -- check whether list has any jump that do not produce a value
206 -- (or produce an inverted value)
207 ------------------------------------------------------------------------
208 --FF updated 5.1
209 function luaK:need_value(fs, list, cond)
210   while list ~= self.NO_JUMP do
211     local i = self:getjumpcontrol(fs, list)
212     if luaP:GET_OPCODE(i) ~= "OP_TESTSET" or
213        luaP:GETARG_A(i) ~= luaP.NO_REG or
214        luaP:GETARG_C(i) ~= cond then
215       return true
216     end
217     list = self:getjump(fs, list)
218   end
219   return false  -- not found
220 end
221
222 ------------------------------------------------------------------------
223 --
224 ------------------------------------------------------------------------
225 --FF updated 5.1
226 function luaK:patchtestreg(fs, node, reg)
227    assert(reg) -- pour assurer, vu que j'ai ajoute un parametre p/r a 5.0
228    local i = self:getjumpcontrol(fs, node)
229    if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then 
230       return false end -- cannot patch other instructions
231    if reg ~= luaP.NO_REG and reg ~= luaP:GETARG_B(i) then
232       luaP:SETARG_A(i, reg)
233    else 
234       -- no register to put value or register already has the value
235       luaP:SET_OPCODE(i, "OP_TEST")
236       luaP:SETARG_A(i, luaP:GETARG_B(i))
237       luaP:SETARG_B(i, 0)
238       luaP:SETARG_C(i, luaP:GETARG_C(i))
239    end
240    return true
241 end
242
243 --FF added 5.1
244 function luaK:removevalues (fs, list)
245    while list ~= self.NO_JUMP do
246       self:patchtestreg (fs, list, luaP.NO_REG)
247       list = self:getjump (fs, list)
248    end
249 end
250
251 ------------------------------------------------------------------------
252 -- FF updated 5.1
253 ------------------------------------------------------------------------
254 function luaK:patchlistaux(fs, list, vtarget, reg, dtarget)
255    while list ~= self.NO_JUMP do
256       local _next = self:getjump(fs, list)
257       if self:patchtestreg (fs, list, reg) then
258          self:fixjump(fs, list, vtarget)
259       else
260          self:fixjump (fs, list, dtarget)
261       end
262       list = _next
263    end
264 end
265
266 ------------------------------------------------------------------------
267 --
268 ------------------------------------------------------------------------
269 function luaK:dischargejpc(fs)
270   self:patchlistaux(fs, fs.jpc, fs.pc, luaP.NO_REG, fs.pc)
271   fs.jpc = self.NO_JUMP
272 end
273
274 ------------------------------------------------------------------------
275 --
276 ------------------------------------------------------------------------
277 function luaK:patchlist(fs, list, target)
278   if target == fs.pc then
279     self:patchtohere(fs, list)
280   else
281     assert(target < fs.pc)
282     self:patchlistaux(fs, list, target, luaP.NO_REG, target)
283   end
284 end
285
286 ------------------------------------------------------------------------
287 --
288 ------------------------------------------------------------------------
289 function luaK:patchtohere(fs, list)
290   self:getlabel(fs)
291   fs.jpc = self:concat(fs, fs.jpc, list)
292 end
293
294 ------------------------------------------------------------------------
295 -- * l1 was a pointer, now l1 is returned and callee assigns the value
296 ------------------------------------------------------------------------
297 function luaK:concat(fs, l1, l2)
298   if l2 == self.NO_JUMP then return l1  -- unchanged
299   elseif l1 == self.NO_JUMP then
300     return l2  -- changed
301   else
302     local list = l1
303     local _next = self:getjump(fs, list)
304     while _next ~= self.NO_JUMP do  -- find last element
305       list = _next
306       _next = self:getjump(fs, list)
307     end
308     self:fixjump(fs, list, l2)
309   end
310   return l1  -- unchanged
311 end
312
313 ------------------------------------------------------------------------
314 --
315 ------------------------------------------------------------------------
316 function luaK:checkstack(fs, n)
317   local newstack = fs.freereg + n
318   if newstack > fs.f.maxstacksize then
319     if newstack >= luaK.MAXSTACK then
320       error("function or expression too complex")
321     end
322     fs.f.maxstacksize = newstack
323   end
324 end
325
326 ------------------------------------------------------------------------
327 --
328 ------------------------------------------------------------------------
329 function luaK:reserveregs(fs, n)
330   self:checkstack(fs, n)
331   fs.freereg = fs.freereg + n
332 end
333
334 ------------------------------------------------------------------------
335 --
336 ------------------------------------------------------------------------
337 function luaK:freereg(fs, reg)
338   if not luaP:ISK (reg) and reg >= fs.nactvar then
339     fs.freereg = fs.freereg - 1
340     assert(reg == fs.freereg, 
341            string.format("reg=%i, fs.freereg=%i", reg, fs.freereg))
342   end
343 end
344
345 ------------------------------------------------------------------------
346 --
347 ------------------------------------------------------------------------
348 function luaK:freeexp(fs, e)
349   if e.k == "VNONRELOC" then
350     self:freereg(fs, e.info)
351   end
352 end
353
354 ------------------------------------------------------------------------
355 -- k is a constant, v is... what?
356 -- fs.h is a hash value --> index in f.k
357 ------------------------------------------------------------------------
358 -- * luaH_get, luaH_set deleted; direct table access used instead
359 -- * luaO_rawequalObj deleted in first assert
360 -- * setobj2n deleted in assignment of v to f.k table
361 ------------------------------------------------------------------------
362 --FF radically updated, not completely understood
363 function luaK:addk(fs, k, v)
364    local idx = fs.h[k.value]
365    local f = fs.f
366 --   local oldsize = f.sizek
367    if self:ttisnumber (idx) then
368       --TODO this assert currently FAILS
369       --assert(fs.f.k[self:nvalue(idx)] == v)
370       return self:nvalue(idx)
371    else  -- constant not found; create a new entry
372       do
373          local t = type (v.value)
374          assert(t=="nil" or t=="string" or t=="number" or t=="boolean")
375       end
376       --debugf("[const: k[%i] = %s ]", fs.nk, tostringv(v.value))
377       fs.f.k[fs.nk] = v
378       fs.h[k.value] = { }
379       self:setnvalue(fs.h[k.value], fs.nk)
380       local nk = fs.nk
381       fs.nk = fs.nk+1
382       return nk
383    end
384 end
385
386 ------------------------------------------------------------------------
387 --
388 ------------------------------------------------------------------------
389 function luaK:stringK(fs, s)
390    assert (type(s)=="string")
391    local o = {}  -- TObject
392    self:setsvalue(o, s)
393    return self:addk(fs, o, o)
394 end
395
396 ------------------------------------------------------------------------
397 --
398 ------------------------------------------------------------------------
399 function luaK:numberK(fs, r)
400    assert (type(r)=="number")
401   local o = {}  -- TObject
402   self:setnvalue(o, r)
403   return self:addk(fs, o, o)
404 end
405
406 ------------------------------------------------------------------------
407 --
408 ------------------------------------------------------------------------
409 function luaK:boolK(fs, r)
410    assert (type(r)=="boolean")
411    local o = {}  -- TObject
412    self:setnvalue(o, r)
413    return self:addk(fs, o, o)
414 end
415
416 ------------------------------------------------------------------------
417 --
418 ------------------------------------------------------------------------
419 function luaK:nilK(fs)
420   local k, v = {}, {}  -- TObject
421   self:setnilvalue(v)
422   self:sethvalue(k, fs.h)  -- cannot use nil as key; instead use table itself
423   return self:addk(fs, k, v)
424 end
425
426
427 --FF 5.1
428 function luaK:setreturns (fs, e, nresults)
429    if e.k == "VCALL" then  -- expression is an open function call?
430       luaP:SETARG_C(self:getcode(fs, e), nresults + 1)
431    elseif e.k == "VVARARG" then
432       luaP:SETARG_B (self:getcode (fs, e), nresults + 1)
433       luaP:SETARG_A (self:getcode (fs, e), fs.freereg)
434       self:reserveregs (fs, 1)
435    end
436 end
437
438 --FF 5.1
439 function luaK:setmultret (fs, e)
440    self:setreturns (fs, e, self.LUA_MULTRET)
441 end
442
443 --FF 5.1
444 function luaK:setoneret (fs, e)
445    if e.k == "VCALL" then  -- expression is an open function call?
446       e.k = "VNONRELOC"
447       e.info = luaP:GETARG_A(self:getcode(fs, e))
448    elseif e.k == "VVARARG" then
449       luaP:SETARG_B (self:getcode (fs, e), 2)
450       e.k = "VRELOCABLE"
451    end
452 end
453
454
455 ------------------------------------------------------------------------
456 --FF deprecated in 5.1
457 ------------------------------------------------------------------------
458 function luaK:setcallreturns(fs, e, nresults)
459    assert (false, "setcallreturns deprecated")
460    --print "SCR:"
461    --printv(e)
462    --printv(self:getcode(fs, e))
463    if e.k == "VCALL" then  -- expression is an open function call?
464       luaP:SETARG_C(self:getcode(fs, e), nresults + 1)
465       if nresults == 1 then  -- 'regular' expression?
466          e.k = "VNONRELOC"
467          e.info = luaP:GETARG_A(self:getcode(fs, e))
468       end
469    elseif e.k == "VVARARG" then
470       --printf("Handle vararg return on expr %s, whose code is %s", 
471       --       tostringv(e), tostringv(self:getcode(fs, e)))
472       if nresults == 1 then
473          luaP:SETARG_B (self:getcode (fs, e), 2)
474          e.k = "VRELOCABLE"
475 --FIXME: why no SETARG_A???
476       else
477          luaP:SETARG_B (self:getcode (fs, e), nresults + 1)
478          luaP:SETARG_A (self:getcode (fs, e), fs.freereg)
479          self:reserveregs (fs, 1)
480       --printf("Now code is %s", tostringv(self:getcode(fs, e)))
481       end
482    end
483 end
484
485 ------------------------------------------------------------------------
486 -- Ajoute le code pour effectuer l'extraction de la locvar/upval/globvar
487 -- /idx, sachant
488 ------------------------------------------------------------------------
489 function luaK:dischargevars(fs, e)
490 --printf("\ndischargevars\n")
491   local k = e.k
492   if k == "VLOCAL" then
493     e.k = "VNONRELOC"
494   elseif k == "VUPVAL" then
495     e.info = self:codeABC(fs, "OP_GETUPVAL", 0, e.info, 0)
496     e.k = "VRELOCABLE"
497   elseif k == "VGLOBAL" then
498     e.info = self:codeABx(fs, "OP_GETGLOBAL", 0, e.info)
499     e.k = "VRELOCABLE"
500   elseif k == "VINDEXED" then
501     self:freereg(fs, e.aux)
502     self:freereg(fs, e.info)
503     e.info = self:codeABC(fs, "OP_GETTABLE", 0, e.info, e.aux)
504     e.k = "VRELOCABLE"
505   elseif k == "VCALL" or k == "VVARARG" then
506     self:setoneret(fs, e)
507   else
508     -- there is one value available (somewhere)
509   end
510 --printf("\n/dischargevars\n")
511 end
512
513 ------------------------------------------------------------------------
514 --
515 ------------------------------------------------------------------------
516 function luaK:code_label(fs, A, b, jump)
517   self:getlabel(fs)  -- those instructions may be jump targets
518   return self:codeABC(fs, "OP_LOADBOOL", A, b, jump)
519 end
520
521 ------------------------------------------------------------------------
522 -- FF updated 5.1
523 ------------------------------------------------------------------------
524 function luaK:discharge2reg(fs, e, reg)
525    self:dischargevars(fs, e)
526    local k = e.k
527    if k == "VNIL" then
528       self:_nil(fs, reg, 1)
529    elseif k == "VFALSE" or k == "VTRUE" then
530       self:codeABC(fs, "OP_LOADBOOL", reg, (e.k == "VTRUE") and 1 or 0, 0)
531    elseif k == "VKNUM" then
532       self:codeABx (fs, "OP_LOADK", reg, self:numberK(fs, e.nval))
533    elseif k == "VK" then
534       self:codeABx(fs, "OP_LOADK", reg, e.info)
535    elseif k == "VRELOCABLE" then
536       local pc = self:getcode(fs, e)
537       luaP:SETARG_A(pc, reg)
538    elseif k == "VNONRELOC" then
539       if reg ~= e.info then
540          self:codeABC(fs, "OP_MOVE", reg, e.info, 0)
541       end
542    else
543       assert(e.k == "VVOID" or e.k == "VJMP")
544       return  -- nothing to do...
545    end
546    e.info = reg
547    e.k = "VNONRELOC"
548 end
549
550 ------------------------------------------------------------------------
551 --
552 ------------------------------------------------------------------------
553 function luaK:discharge2anyreg(fs, e)
554   if e.k ~= "VNONRELOC" then
555     self:reserveregs(fs, 1)
556     self:discharge2reg(fs, e, fs.freereg - 1)
557   end
558 end
559
560 ------------------------------------------------------------------------
561 --
562 ------------------------------------------------------------------------
563 function luaK:exp2reg(fs, e, reg)
564   self:discharge2reg(fs, e, reg)
565   if e.k == "VJMP" then
566     e.t = self:concat(fs, e.t, e.info)  -- put this jump in 't' list
567   end
568   if self:hasjumps(e) then
569     local final  -- position after whole expression
570     local p_f = self.NO_JUMP  -- position of an eventual LOAD false
571     local p_t = self.NO_JUMP  -- position of an eventual LOAD true
572     if self:need_value(fs, e.t, 1) or self:need_value(fs, e.f, 0) then
573       local fj = self.NO_JUMP  -- first jump (over LOAD ops.)
574       if e.k ~= "VJMP" then fj = self:jump(fs) end
575       p_f = self:code_label(fs, reg, 0, 1)
576       p_t = self:code_label(fs, reg, 1, 0)
577       self:patchtohere(fs, fj)
578     end
579     final = self:getlabel(fs)
580     self:patchlistaux(fs, e.f, final, reg, p_f)
581     self:patchlistaux(fs, e.t, final, reg, p_t)
582   end
583   e.f, e.t = self.NO_JUMP, self.NO_JUMP
584   e.info = reg
585   e.k = "VNONRELOC"
586 end
587
588 ------------------------------------------------------------------------
589 --
590 ------------------------------------------------------------------------
591 function luaK:exp2nextreg(fs, e)
592   self:dischargevars(fs, e)
593   --[FF] Allready in place (added for expr.Stat)
594   if e.k == "VNONRELOC" and e.info == fs.freereg then 
595      --printf("Expression already in next reg %i: %s", fs.freereg, tostringv(e))
596      return end
597   self:freeexp(fs, e)
598   self:reserveregs(fs, 1)
599   self:exp2reg(fs, e, fs.freereg - 1)
600 end
601
602 ------------------------------------------------------------------------
603 --
604 ------------------------------------------------------------------------
605 function luaK:exp2anyreg(fs, e)
606    --printf("exp2anyregs(e=%s)", tostringv(e))
607    self:dischargevars(fs, e)
608    if e.k == "VNONRELOC" then
609       if not self:hasjumps(e) then  -- exp is already in a register
610          return e.info
611       end
612       if e.info >= fs.nactvar then  -- reg. is not a local?
613          self:exp2reg(fs, e, e.info)  -- put value on it
614          return e.info
615       end
616    end
617    self:exp2nextreg(fs, e)  -- default
618    return e.info
619 end
620
621 ------------------------------------------------------------------------
622 --
623 ------------------------------------------------------------------------
624 function luaK:exp2val(fs, e)
625   if self:hasjumps(e) then
626     self:exp2anyreg(fs, e)
627   else
628     self:dischargevars(fs, e)
629   end
630 end
631
632 ------------------------------------------------------------------------
633 -- FF updated 5.1
634 ------------------------------------------------------------------------
635 function luaK:exp2RK(fs, e)
636    self:exp2val(fs, e)
637    local k = e.k
638    if k=="VNIL" or k=="VTRUE" or k=="VFALSE" or k=="VKNUM" then
639       if fs.nk <= luaP.MAXINDEXRK then
640          if     k=="VNIL"  then e.info = self:nilK(fs)
641          elseif k=="VKNUM" then e.info = self:numberK (fs, e.nval)
642          else                   e.info = self:boolK(fs, e.k=="VTRUE") end
643          e.k = "VK"
644          return luaP:RKASK(e.info)
645       end
646    elseif k == "VK" then
647       if e.info <= luaP.MAXINDEXRK then  -- constant fit in argC?
648          return luaP:RKASK (e.info)
649       end
650    end
651    -- not a constant in the right range: put it in a register
652    return self:exp2anyreg(fs, e)
653 end
654
655 ------------------------------------------------------------------------
656 --
657 ------------------------------------------------------------------------
658 function luaK:storevar(fs, var, exp)
659    --print("STOREVAR")
660    --printf("var=%s", tostringv(var))
661    --printf("exp=%s", tostringv(exp))
662
663    local k = var.k
664    if k == "VLOCAL" then
665       self:freeexp(fs, exp)
666       self:exp2reg(fs, exp, var.info)
667       return
668    elseif k == "VUPVAL" then
669       local e = self:exp2anyreg(fs, exp)
670       self:codeABC(fs, "OP_SETUPVAL", e, var.info, 0)
671    elseif k == "VGLOBAL" then
672       --printf("store global, exp=%s", tostringv(exp))
673       local e = self:exp2anyreg(fs, exp)
674       self:codeABx(fs, "OP_SETGLOBAL", e, var.info)
675    elseif k == "VINDEXED" then
676       local e = self:exp2RK(fs, exp)
677       self:codeABC(fs, "OP_SETTABLE", var.info, var.aux, e)
678    else
679       assert(0)  -- invalid var kind to store
680    end
681    self:freeexp(fs, exp)
682    --print("/STOREVAR")
683 end
684
685 ------------------------------------------------------------------------
686 --
687 ------------------------------------------------------------------------
688 function luaK:_self(fs, e, key)
689   self:exp2anyreg(fs, e)
690   self:freeexp(fs, e)
691   local func = fs.freereg
692   self:reserveregs(fs, 2)
693   self:codeABC(fs, "OP_SELF", func, e.info, self:exp2RK(fs, key))
694   self:freeexp(fs, key)
695   e.info = func
696   e.k = "VNONRELOC"
697 end
698
699 ------------------------------------------------------------------------
700 -- FF updated 5.1
701 ------------------------------------------------------------------------
702 function luaK:invertjump(fs, e)
703    --printf("invertjump on jump instruction #%i", e.info)
704    --printv(self:getcode(fs, e))
705    local pc = self:getjumpcontrol(fs, e.info)
706    assert(luaP:testOpMode(luaP:GET_OPCODE(pc), "OpModeT") and
707              luaP:GET_OPCODE(pc) ~= "OP_TESTSET" and
708              luaP:GET_OPCODE(pc) ~= "OP_TEST")
709    --printf("Before invert:")
710    --printv(pc)
711    luaP:SETARG_A(pc, (luaP:GETARG_A(pc) == 0) and 1 or 0)
712    --printf("After invert:")
713    --printv(pc)
714 end
715
716 ------------------------------------------------------------------------
717 --
718 ------------------------------------------------------------------------
719 function luaK:jumponcond(fs, e, cond)
720   if e.k == "VRELOCABLE" then
721     local ie = self:getcode(fs, e)
722     if luaP:GET_OPCODE(ie) == "OP_NOT" then
723       fs.pc = fs.pc - 1  -- remove previous OP_NOT
724       return self:condjump(fs, "OP_TEST", luaP:GETARG_B(ie), 0,
725                            cond and 0 or 1)
726     end
727     -- else go through
728   end
729   self:discharge2anyreg(fs, e)
730   self:freeexp(fs, e)
731   return self:condjump(fs, "OP_TESTSET", luaP.NO_REG, e.info, cond and 1 or 0)
732 end
733
734 ------------------------------------------------------------------------
735 --
736 ------------------------------------------------------------------------
737 function luaK:goiftrue(fs, e)
738   local pc  -- pc of last jump
739   self:dischargevars(fs, e)
740   local k = e.k
741   if k == "VK" or k == "VTRUE" or k == "VKNUM" then
742     pc = self.NO_JUMP  -- always true; do nothing
743   elseif k == "VFALSE" then
744     pc = self:jump(fs)  -- always jump
745   elseif k == "VJMP" then
746     self:invertjump(fs, e)
747     pc = e.info
748   else
749     pc = self:jumponcond(fs, e, false)
750  end
751   e.f = self:concat(fs, e.f, pc)  -- insert last jump in 'f' list
752   self:patchtohere(fs, e.t)
753   e.t = self.NO_JUMP
754 end
755
756 ------------------------------------------------------------------------
757 --
758 ------------------------------------------------------------------------
759 function luaK:goiffalse(fs, e)
760   local pc  -- pc of last jump
761   self:dischargevars(fs, e)
762   local k = e.k
763   if k == "VNIL" or k == "VFALSE"then
764     pc = self.NO_JUMP  -- always false; do nothing
765   elseif k == "VTRUE" then
766     pc = self:jump(fs)  -- always jump
767   elseif k == "VJMP" then
768     pc = e.info
769   else
770     pc = self:jumponcond(fs, e, true)
771   end
772   e.t = self:concat(fs, e.t, pc)  -- insert last jump in 't' list
773   self:patchtohere(fs, e.f)
774   e.f = self.NO_JUMP
775 end
776
777 ------------------------------------------------------------------------
778 --
779 ------------------------------------------------------------------------
780 function luaK:codenot(fs, e)
781   self:dischargevars(fs, e)
782   local k = e.k
783   if k == "VNIL" or k == "VFALSE" then
784     e.k = "VTRUE"
785   elseif k == "VK" or k == "VKNUM" or k == "VTRUE" then
786     e.k = "VFALSE"
787   elseif k == "VJMP" then
788     self:invertjump(fs, e)
789   elseif k == "VRELOCABLE" or k == "VNONRELOC" then
790     self:discharge2anyreg(fs, e)
791     self:freeexp(fs, e)
792     e.info = self:codeABC(fs, "OP_NOT", 0, e.info, 0)
793     e.k = "VRELOCABLE"
794   else
795     assert(0)  -- cannot happen
796   end
797   -- interchange true and false lists
798   e.f, e.t = e.t, e.f
799   self:removevalues(fs, e.f)
800   self:removevalues(fs, e.t)
801 end
802
803 ------------------------------------------------------------------------
804 --
805 ------------------------------------------------------------------------
806 function luaK:indexed(fs, t, k)
807   t.aux = self:exp2RK(fs, k)
808   t.k = "VINDEXED"
809 end
810
811 --FF 5.1
812 function luaK:constfolding (op, e1, e2)
813    if not self:isnumeral(e1) or not self:isnumeral(e2) then return false end
814    local v1, v2, e, r = e1.nval, e2 and e2.nval, nil
815    if     op == "OP_ADD" then r = v1+v2
816    elseif op == "OP_SUB" then r = v1-v2
817    elseif op == "OP_MUL" then r = v1*v2
818    elseif op == "OP_DIV" then if v2==0 then return false end r = v1/v2
819    elseif op == "OP_MOD" then if v2==0 then return false end r = v1%v2
820    elseif op == "OP_POW" then r = v1^v2
821    elseif op == "OP_UNM" then r = -v1
822    elseif op == "OP_LEN" then return false
823    else   assert (false, "Unknown numeric value") end
824    e1.nval = r
825    return true
826 end
827
828 --FF 5.1
829 function luaK:codearith (fs, op, e1, e2)
830    if self:constfolding (op, e1, e2) then return else
831       local o1 = self:exp2RK (fs, e1)
832       local o2 = 0
833       if op ~= "OP_UNM" and op ~= "OP_LEN" then 
834          o2 = self:exp2RK (fs, e2) end
835       self:freeexp(fs, e2)
836       self:freeexp(fs, e1)
837       e1.info = self:codeABC (fs, op, 0, o1, o2)
838       e1.k = "VRELOCABLE"
839    end
840 end
841
842 --FF 5.1
843 function luaK:codecomp (fs, op, cond, e1, e2)
844    assert (type (cond) == "boolean")
845    local o1 = self:exp2RK (fs, e1)
846    local o2 = self:exp2RK (fs, e2)
847    self:freeexp (fs, e2)
848    self:freeexp (fs, e1)
849    if not cond and op ~= "OP_EQ" then 
850       local temp = o1; o1=o2; o2=temp cond = true end
851    e1.info = self:condjump (fs, op, cond and 1 or 0, o1, o2)
852    e1.k = "VJMP"
853 end
854
855 ------------------------------------------------------------------------
856 --
857 ------------------------------------------------------------------------
858 function luaK:prefix (fs, op, e)
859    local e2 = { t = self.NO_JUMP; f = self.NO_JUMP;
860                 k = "VKNUM"; nval = 0 }
861    if op == "unm" then
862       if e.k == "VK" then
863          self:exp2anyreg (fs, e) end
864       self:codearith (fs, "OP_UNM", e, e2)
865    elseif op == "not" then
866       self:codenot (fs, e)
867    elseif op == "len" then
868       self:exp2anyreg (fs, e)
869       self:codearith (fs, "OP_LEN", e, e2)
870    else
871       assert (false, "Unknown unary operator")
872    end
873 end
874
875 ------------------------------------------------------------------------
876 --
877 ------------------------------------------------------------------------
878 function luaK:infix (fs, op, v)
879   if op == "and" then
880     self:goiftrue(fs, v)
881   elseif op == "or" then
882     self:goiffalse(fs, v)
883   elseif op == "concat" then
884     self:exp2nextreg(fs, v)  -- operand must be on the 'stack'
885  else
886     if not self:isnumeral (v) then self:exp2RK(fs, v) end
887   end
888 end
889
890 ------------------------------------------------------------------------
891 --
892 -- grep "ORDER OPR" if you change these enums
893 ------------------------------------------------------------------------
894 luaK.arith_opc = {  -- done as a table lookup instead of a calc
895    add = "OP_ADD",
896    sub = "OP_SUB",
897    mul = "OP_MUL",
898    mod = "OP_MOD",
899    div = "OP_DIV",
900    pow = "OP_POW",
901    len = "OP_LEN",
902    ["not"] = "OP_NOT"
903 }
904 luaK.test_opc = {  -- was ops[] in the codebinop function
905   eq = {opc="OP_EQ", cond=true},
906   lt = {opc="OP_LT", cond=true},
907   le = {opc="OP_LE", cond=true},
908
909   -- Pseudo-ops, with no metatable equivalent:
910   ne = {opc="OP_EQ", cond=false},
911   gt = {opc="OP_LT", cond=false},
912   ge = {opc="OP_LE", cond=false}
913 }
914
915 ------------------------------------------------------------------------
916 --
917 ------------------------------------------------------------------------
918 function luaK:posfix(fs, op, e1, e2)
919    if op == "and" then
920       assert(e1.t == self.NO_JUMP)  -- list must be closed
921       self:dischargevars(fs, e2)
922       e2.f = self:concat(fs, e2.f, e1.f)
923       for k,v in pairs(e2) do e1[k]=v end -- *e1 = *e2
924    elseif op == "or" then
925       assert(e1.f == self.NO_JUMP)  -- list must be closed
926       self:dischargevars(fs, e2)
927       e2.t = self:concat(fs, e2.t, e1.t)
928       for k,v in pairs(e2) do e1[k]=v end -- *e1 = *e2
929    elseif op == "concat" then
930       self:exp2val(fs, e2)
931       if e2.k == "VRELOCABLE"
932          and luaP:GET_OPCODE(self:getcode(fs, e2)) == "OP_CONCAT" then
933          assert(e1.info == luaP:GETARG_B(self:getcode(fs, e2)) - 1)
934          self:freeexp(fs, e1)
935          luaP:SETARG_B(self:getcode(fs, e2), e1.info)
936          e1.k = "VRELOCABLE"; e1.info = e2.info
937       else
938          self:exp2nextreg(fs, e2)
939          self:codearith (fs, "OP_CONCAT", e1, e2)
940       end
941    else
942       local opc = self.arith_opc[op]
943       if opc then self:codearith (fs, opc, e1, e2) else
944          opc = self.test_opc[op] or error ("Unknown operator "..op)
945          self:codecomp (fs, opc.opc, opc.cond, e1, e2)
946       end
947    end
948 end
949
950 ------------------------------------------------------------------------
951 --
952 ------------------------------------------------------------------------
953 function luaK:fixline(fs, line)
954    --assert (line)
955    if not line then
956      --print(debug.traceback "fixline (line == nil)")
957    end
958    fs.f.lineinfo[fs.pc - 1] = line or 0
959 end
960
961 ------------------------------------------------------------------------
962 --
963 ------------------------------------------------------------------------
964 function luaK:code(fs, i, line)
965   if not line then 
966     line = 0
967     --print(debug.traceback "line == nil")
968   end
969   local f = fs.f
970
971   do -- print it
972     local params = { }
973     for _,x in ipairs{"A","B","Bx", "sBx", "C"} do
974       if i[x] then table.insert (params, string.format ("%s=%i", x, i[x])) end
975     end
976     debugf ("[code:\t%s\t%s]", luaP.opnames[i.OP], table.concat (params, ", "))
977   end
978
979   self:dischargejpc(fs)  -- 'pc' will change
980
981   f.code[fs.pc] = i
982   f.lineinfo[fs.pc] = line
983
984   if line == 0 then
985     f.lineinfo[fs.pc] = fs.lastline
986     if fs.lastline == 0 then
987       --print(debug.traceback())
988     end    
989   end
990
991   if f.lineinfo[fs.pc] == 0 then
992     f.lineinfo[fs.pc] = 42
993   end
994
995   local pc = fs.pc
996   fs.pc = fs.pc + 1
997   return pc
998 end
999
1000 ------------------------------------------------------------------------
1001 -- 
1002 ------------------------------------------------------------------------
1003 function luaK:codeABC(fs, o, a, b, c)
1004   assert(luaP:getOpMode(o) == "iABC", o.." is not an ABC operation")
1005   --assert getbmode(o) ~= opargn or b == 0
1006   --assert getcmode(o) ~= opargn or c == 0
1007   --FF
1008   --return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.ls.lastline)
1009   return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.lastline)
1010 end
1011
1012 ------------------------------------------------------------------------
1013 --
1014 ------------------------------------------------------------------------
1015 function luaK:codeABx(fs, o, a, bc)
1016   assert(luaP:getOpMode(o) == "iABx" or luaP:getOpMode(o) == "iAsBx")
1017   --assert getcmode(o) == opargn
1018   --FF
1019   --return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.ls.lastline)
1020   return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.lastline)
1021 end
1022
1023 ------------------------------------------------------------------------
1024 --
1025 ------------------------------------------------------------------------
1026 function luaK:setlist (fs, base, nelems, tostore)
1027    local c = math.floor ((nelems-1) / luaP.LFIELDS_PER_FLUSH + 1)
1028    local b = tostore == self.LUA_MULTRET and 0 or tostore
1029    assert (tostore ~= 0)
1030    if c <= luaP.MAXARG_C then self:codeABC (fs, "OP_SETLIST", base, b, c)
1031    else
1032       self:codeABC (fs, "OP_SETLIST", base, b, 0)
1033       self:code (fs, c, fs.lastline)--FIXME
1034    end
1035    fs.freereg = base + 1
1036 end
1037
1038 return luaK