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