aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>1997-09-16 16:25:59 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>1997-09-16 16:25:59 -0300
commit6990da0057008adf934d88125ae9cf5162964117 (patch)
tree551873be0e3921c9c93b7c32d75a72a688bd26b1
parentd985dc0629c2a10371b345d1ce3e4404bb011ad9 (diff)
downloadlua-6990da0057008adf934d88125ae9cf5162964117.tar.gz
lua-6990da0057008adf934d88125ae9cf5162964117.tar.bz2
lua-6990da0057008adf934d88125ae9cf5162964117.zip
Lua virtual machine
-rw-r--r--lvm.c655
-rw-r--r--lvm.h29
2 files changed, 684 insertions, 0 deletions
diff --git a/lvm.c b/lvm.c
new file mode 100644
index 00000000..8993056b
--- /dev/null
+++ b/lvm.c
@@ -0,0 +1,655 @@
1/*
2** $Id: $
3** Lua virtual machine
4** See Copyright Notice in lua.h
5*/
6
7
8#include <stdio.h>
9#include <string.h>
10
11#include "lauxlib.h"
12#include "ldo.h"
13#include "lfunc.h"
14#include "lgc.h"
15#include "lglobal.h"
16#include "lmem.h"
17#include "lopcodes.h"
18#include "lstring.h"
19#include "ltable.h"
20#include "ltm.h"
21#include "luadebug.h"
22#include "lvm.h"
23
24
25#define get_word(w,pc) {w=*pc+(*(pc+1)<<8); pc+=2;}
26
27
28/* Extra stack to run a function: LUA_T_LINE(1), TM calls(2), ... */
29#define EXTRA_STACK 4
30
31
32
33static TaggedString *strconc (char *l, char *r)
34{
35 size_t nl = strlen(l);
36 char *buffer = luaM_buffer(nl+strlen(r)+1);
37 strcpy(buffer, l);
38 strcpy(buffer+nl, r);
39 return luaS_new(buffer);
40}
41
42
43int luaV_tonumber (TObject *obj)
44{
45 double t;
46 char c;
47 if (ttype(obj) != LUA_T_STRING)
48 return 1;
49 else if (sscanf(svalue(obj), "%lf %c",&t, &c) == 1) {
50 nvalue(obj) = (real)t;
51 ttype(obj) = LUA_T_NUMBER;
52 return 0;
53 }
54 else
55 return 2;
56}
57
58
59int luaV_tostring (TObject *obj)
60{
61 if (ttype(obj) != LUA_T_NUMBER)
62 return 1;
63 else {
64 char s[60];
65 real f = nvalue(obj);
66 int i;
67 if ((real)(-MAX_INT) <= f && f <= (real)MAX_INT && (real)(i=(int)f) == f)
68 sprintf (s, "%d", i);
69 else
70 sprintf (s, "%g", (double)nvalue(obj));
71 tsvalue(obj) = luaS_new(s);
72 ttype(obj) = LUA_T_STRING;
73 return 0;
74 }
75}
76
77
78void luaV_closure (void)
79{
80 int nelems = (luaD_stack.top-1)->value.tf->nupvalues;
81 Closure *c = luaF_newclosure(nelems);
82 c->consts[0] = *(luaD_stack.top-1);
83 memcpy(&c->consts[1], luaD_stack.top-(nelems+1), nelems*sizeof(TObject));
84 luaD_stack.top -= nelems;
85 ttype(luaD_stack.top-1) = LUA_T_FUNCTION;
86 (luaD_stack.top-1)->value.cl = c;
87}
88
89
90/*
91** Function to index a table.
92** Receives the table at top-2 and the index at top-1.
93*/
94void luaV_gettable (void)
95{
96 TObject *im;
97 if (ttype(luaD_stack.top-2) != LUA_T_ARRAY) /* not a table, get "gettable" method */
98 im = luaT_getimbyObj(luaD_stack.top-2, IM_GETTABLE);
99 else { /* object is a table... */
100 int tg = (luaD_stack.top-2)->value.a->htag;
101 im = luaT_getim(tg, IM_GETTABLE);
102 if (ttype(im) == LUA_T_NIL) { /* and does not have a "gettable" method */
103 TObject *h = luaH_get(avalue(luaD_stack.top-2), luaD_stack.top-1);
104 if (h != NULL && ttype(h) != LUA_T_NIL) {
105 --luaD_stack.top;
106 *(luaD_stack.top-1) = *h;
107 }
108 else if (ttype(im=luaT_getim(tg, IM_INDEX)) != LUA_T_NIL)
109 luaD_callTM(im, 2, 1);
110 else {
111 --luaD_stack.top;
112 ttype(luaD_stack.top-1) = LUA_T_NIL;
113 }
114 return;
115 }
116 /* else it has a "gettable" method, go through to next command */
117 }
118 /* object is not a table, or it has a "gettable" method */
119 if (ttype(im) != LUA_T_NIL)
120 luaD_callTM(im, 2, 1);
121 else
122 lua_error("indexed expression not a table");
123}
124
125
126/*
127** Function to store indexed based on values at the luaD_stack.top
128** mode = 0: raw store (without internal methods)
129** mode = 1: normal store (with internal methods)
130** mode = 2: "deep luaD_stack.stack" store (with internal methods)
131*/
132void luaV_settable (TObject *t, int mode)
133{
134 TObject *im = (mode == 0) ? NULL : luaT_getimbyObj(t, IM_SETTABLE);
135 if (ttype(t) == LUA_T_ARRAY && (im == NULL || ttype(im) == LUA_T_NIL)) {
136 TObject *h = luaH_set(avalue(t), t+1);
137 *h = *(luaD_stack.top-1);
138 luaD_stack.top -= (mode == 2) ? 1 : 3;
139 }
140 else { /* object is not a table, and/or has a specific "settable" method */
141 if (im && ttype(im) != LUA_T_NIL) {
142 if (mode == 2) {
143 *(luaD_stack.top+1) = *(luaD_stack.top-1);
144 *(luaD_stack.top) = *(t+1);
145 *(luaD_stack.top-1) = *t;
146 luaD_stack.top += 2; /* WARNING: caller must assure stack space */
147 }
148 luaD_callTM(im, 3, 0);
149 }
150 else
151 lua_error("indexed expression not a table");
152 }
153}
154
155
156void luaV_getglobal (Word n)
157{
158 /* WARNING: caller must assure stack space */
159 TObject *value = &luaG_global[n].object;
160 TObject *im = luaT_getimbyObj(value, IM_GETGLOBAL);
161 if (ttype(im) == LUA_T_NIL) { /* default behavior */
162 *luaD_stack.top = *value;
163 luaD_stack.top++;
164 }
165 else {
166 ttype(luaD_stack.top) = LUA_T_STRING;
167 tsvalue(luaD_stack.top) = luaG_global[n].varname;
168 luaD_stack.top++;
169 *luaD_stack.top = *value;
170 luaD_stack.top++;
171 luaD_callTM(im, 2, 1);
172 }
173}
174
175
176void luaV_setglobal (Word n)
177{
178 TObject *oldvalue = &luaG_global[n].object;
179 TObject *im = luaT_getimbyObj(oldvalue, IM_SETGLOBAL);
180 if (ttype(im) == LUA_T_NIL) /* default behavior */
181 s_object(n) = *(--luaD_stack.top);
182 else {
183 /* WARNING: caller must assure stack space */
184 TObject newvalue = *(luaD_stack.top-1);
185 ttype(luaD_stack.top-1) = LUA_T_STRING;
186 tsvalue(luaD_stack.top-1) = luaG_global[n].varname;
187 *luaD_stack.top = *oldvalue;
188 luaD_stack.top++;
189 *luaD_stack.top = newvalue;
190 luaD_stack.top++;
191 luaD_callTM(im, 3, 0);
192 }
193}
194
195
196static void call_binTM (IMS event, char *msg)
197{
198 TObject *im = luaT_getimbyObj(luaD_stack.top-2, event);/* try first operand */
199 if (ttype(im) == LUA_T_NIL) {
200 im = luaT_getimbyObj(luaD_stack.top-1, event); /* try second operand */
201 if (ttype(im) == LUA_T_NIL) {
202 im = luaT_getim(0, event); /* try a 'global' i.m. */
203 if (ttype(im) == LUA_T_NIL)
204 lua_error(msg);
205 }
206 }
207 lua_pushstring(luaT_eventname[event]);
208 luaD_callTM(im, 3, 1);
209}
210
211
212static void call_arith (IMS event)
213{
214 call_binTM(event, "unexpected type at arithmetic operation");
215}
216
217
218static void comparison (lua_Type ttype_less, lua_Type ttype_equal,
219 lua_Type ttype_great, IMS op)
220{
221 TObject *l = luaD_stack.top-2;
222 TObject *r = luaD_stack.top-1;
223 int result;
224 if (ttype(l) == LUA_T_NUMBER && ttype(r) == LUA_T_NUMBER)
225 result = (nvalue(l) < nvalue(r)) ? -1 : (nvalue(l) == nvalue(r)) ? 0 : 1;
226 else if (ttype(l) == LUA_T_STRING && ttype(r) == LUA_T_STRING)
227 result = strcoll(svalue(l), svalue(r));
228 else {
229 call_binTM(op, "unexpected type at comparison");
230 return;
231 }
232 luaD_stack.top--;
233 nvalue(luaD_stack.top-1) = 1;
234 ttype(luaD_stack.top-1) = (result < 0) ? ttype_less :
235 (result == 0) ? ttype_equal : ttype_great;
236}
237
238
239void luaV_pack (StkId firstel, int nvararg, TObject *tab)
240{
241 TObject *firstelem = luaD_stack.stack+firstel;
242 int i;
243 if (nvararg < 0) nvararg = 0;
244 avalue(tab) = luaH_new(nvararg+1); /* +1 for field 'n' */
245 ttype(tab) = LUA_T_ARRAY;
246 for (i=0; i<nvararg; i++) {
247 TObject index;
248 ttype(&index) = LUA_T_NUMBER;
249 nvalue(&index) = i+1;
250 *(luaH_set(avalue(tab), &index)) = *(firstelem+i);
251 }
252 /* store counter in field "n" */ {
253 TObject index, extra;
254 ttype(&index) = LUA_T_STRING;
255 tsvalue(&index) = luaS_new("n");
256 ttype(&extra) = LUA_T_NUMBER;
257 nvalue(&extra) = nvararg;
258 *(luaH_set(avalue(tab), &index)) = extra;
259 }
260}
261
262
263static void adjust_varargs (StkId first_extra_arg)
264{
265 TObject arg;
266 luaV_pack(first_extra_arg,
267 (luaD_stack.top-luaD_stack.stack)-first_extra_arg, &arg);
268 luaD_adjusttop(first_extra_arg);
269 *luaD_stack.top = arg;
270 luaD_stack.top++;
271}
272
273
274
275/*
276** Execute the given opcode, until a RET. Parameters are between
277** [luaD_stack.stack+base,luaD_stack.top). Returns n such that the the results are between
278** [luaD_stack.stack+n,luaD_stack.top).
279*/
280StkId luaV_execute (Closure *cl, StkId base)
281{
282 TProtoFunc *func = cl->consts[0].value.tf;
283 Byte *pc = func->code;
284 if (lua_callhook)
285 luaD_callHook(base, LUA_T_MARK, 0);
286 luaD_checkstack((*pc++)+EXTRA_STACK);
287 while (1) {
288 OpCode opcode;
289 switch (opcode = (OpCode)*pc++) {
290
291 case PUSHNIL:
292 ttype(luaD_stack.top) = LUA_T_NIL;
293 luaD_stack.top++;
294 break;
295
296 case PUSHNILS: {
297 int n = *pc++;
298 while (n--)
299 ttype(luaD_stack.top++) = LUA_T_NIL;
300 break;
301 }
302
303 case PUSH0: case PUSH1: case PUSH2:
304 ttype(luaD_stack.top) = LUA_T_NUMBER;
305 nvalue(luaD_stack.top) = opcode-PUSH0;
306 luaD_stack.top++;
307 break;
308
309 case PUSHBYTE:
310 ttype(luaD_stack.top) = LUA_T_NUMBER;
311 nvalue(luaD_stack.top) = *pc++;
312 luaD_stack.top++;
313 break;
314
315 case PUSHWORD: {
316 Word w;
317 get_word(w,pc);
318 ttype(luaD_stack.top) = LUA_T_NUMBER;
319 nvalue(luaD_stack.top) = w;
320 luaD_stack.top++;
321 break;
322 }
323
324 case PUSHLOCAL0: case PUSHLOCAL1: case PUSHLOCAL2:
325 case PUSHLOCAL3: case PUSHLOCAL4: case PUSHLOCAL5:
326 case PUSHLOCAL6: case PUSHLOCAL7: case PUSHLOCAL8:
327 case PUSHLOCAL9:
328 *luaD_stack.top = *((luaD_stack.stack+base) + (int)(opcode-PUSHLOCAL0));
329 luaD_stack.top++;
330 break;
331
332 case PUSHLOCAL:
333 *luaD_stack.top = *((luaD_stack.stack+base) + (*pc++));
334 luaD_stack.top++;
335 break;
336
337 case PUSHGLOBAL: {
338 Word w;
339 get_word(w,pc);
340 luaV_getglobal(w);
341 break;
342 }
343
344 case PUSHTABLE:
345 luaV_gettable();
346 break;
347
348 case PUSHSELF: {
349 TObject receiver = *(luaD_stack.top-1);
350 Word w;
351 get_word(w,pc);
352 *luaD_stack.top = func->consts[w];
353 luaD_stack.top++;
354 luaV_gettable();
355 *luaD_stack.top = receiver;
356 luaD_stack.top++;
357 break;
358 }
359
360 case PUSHCONSTANTB: {
361 *luaD_stack.top = func->consts[*pc++];
362 luaD_stack.top++;
363 break;
364 }
365
366 case PUSHCONSTANT: {
367 Word w;
368 get_word(w,pc);
369 *luaD_stack.top = func->consts[w];
370 luaD_stack.top++;
371 break;
372 }
373
374 case PUSHUPVALUE0:
375 case PUSHUPVALUE: {
376 int i = (opcode == PUSHUPVALUE0) ? 0 : *pc++;
377 *luaD_stack.top = cl->consts[i+1];
378 luaD_stack.top++;
379 break;
380 }
381
382 case SETLOCAL0: case SETLOCAL1: case SETLOCAL2:
383 case SETLOCAL3: case SETLOCAL4: case SETLOCAL5:
384 case SETLOCAL6: case SETLOCAL7: case SETLOCAL8:
385 case SETLOCAL9:
386 *((luaD_stack.stack+base) + (int)(opcode-SETLOCAL0)) =
387 *(--luaD_stack.top);
388 break;
389
390 case SETLOCAL:
391 *((luaD_stack.stack+base) + (*pc++)) = *(--luaD_stack.top); break;
392
393 case SETGLOBAL: {
394 Word w;
395 get_word(w,pc);
396 luaV_setglobal(w);
397 break;
398 }
399
400 case SETTABLE0:
401 luaV_settable(luaD_stack.top-3, 1);
402 break;
403
404 case SETTABLE: {
405 int n = *pc++;
406 luaV_settable(luaD_stack.top-3-n, 2);
407 break;
408 }
409
410 case SETLIST0:
411 case SETLIST: {
412 int m, n;
413 TObject *arr;
414 if (opcode == SETLIST0) m = 0;
415 else m = *(pc++) * LFIELDS_PER_FLUSH;
416 n = *(pc++);
417 arr = luaD_stack.top-n-1;
418 while (n) {
419 ttype(luaD_stack.top) = LUA_T_NUMBER; nvalue(luaD_stack.top) = n+m;
420 *(luaH_set (avalue(arr), luaD_stack.top)) = *(luaD_stack.top-1);
421 luaD_stack.top--;
422 n--;
423 }
424 break;
425 }
426
427 case SETMAP: {
428 int n = *(pc++);
429 TObject *arr = luaD_stack.top-(2*n)-1;
430 while (n--) {
431 *(luaH_set (avalue(arr), luaD_stack.top-2)) = *(luaD_stack.top-1);
432 luaD_stack.top-=2;
433 }
434 break;
435 }
436
437 case POPS:
438 luaD_stack.top -= *(pc++);
439 break;
440
441 case ARGS:
442 luaD_adjusttop(base + *(pc++));
443 break;
444
445 case VARARGS:
446 luaC_checkGC();
447 adjust_varargs(base + *(pc++));
448 break;
449
450 case CREATEARRAY: {
451 Word size;
452 luaC_checkGC();
453 get_word(size,pc);
454 avalue(luaD_stack.top) = luaH_new(size);
455 ttype(luaD_stack.top) = LUA_T_ARRAY;
456 luaD_stack.top++;
457 break;
458 }
459
460 case EQOP: case NEQOP: {
461 int res = luaO_equalObj(luaD_stack.top-2, luaD_stack.top-1);
462 --luaD_stack.top;
463 if (opcode == NEQOP) res = !res;
464 ttype(luaD_stack.top-1) = res ? LUA_T_NUMBER : LUA_T_NIL;
465 nvalue(luaD_stack.top-1) = 1;
466 break;
467 }
468
469 case LTOP:
470 comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT);
471 break;
472
473 case LEOP:
474 comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE);
475 break;
476
477 case GTOP:
478 comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT);
479 break;
480
481 case GEOP:
482 comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE);
483 break;
484
485 case ADDOP: {
486 TObject *l = luaD_stack.top-2;
487 TObject *r = luaD_stack.top-1;
488 if (tonumber(r) || tonumber(l))
489 call_arith(IM_ADD);
490 else {
491 nvalue(l) += nvalue(r);
492 --luaD_stack.top;
493 }
494 break;
495 }
496
497 case SUBOP: {
498 TObject *l = luaD_stack.top-2;
499 TObject *r = luaD_stack.top-1;
500 if (tonumber(r) || tonumber(l))
501 call_arith(IM_SUB);
502 else {
503 nvalue(l) -= nvalue(r);
504 --luaD_stack.top;
505 }
506 break;
507 }
508
509 case MULTOP: {
510 TObject *l = luaD_stack.top-2;
511 TObject *r = luaD_stack.top-1;
512 if (tonumber(r) || tonumber(l))
513 call_arith(IM_MUL);
514 else {
515 nvalue(l) *= nvalue(r);
516 --luaD_stack.top;
517 }
518 break;
519 }
520
521 case DIVOP: {
522 TObject *l = luaD_stack.top-2;
523 TObject *r = luaD_stack.top-1;
524 if (tonumber(r) || tonumber(l))
525 call_arith(IM_DIV);
526 else {
527 nvalue(l) /= nvalue(r);
528 --luaD_stack.top;
529 }
530 break;
531 }
532
533 case POWOP:
534 call_arith(IM_POW);
535 break;
536
537 case CONCOP: {
538 TObject *l = luaD_stack.top-2;
539 TObject *r = luaD_stack.top-1;
540 if (tostring(l) || tostring(r))
541 call_binTM(IM_CONCAT, "unexpected type for concatenation");
542 else {
543 tsvalue(l) = strconc(svalue(l), svalue(r));
544 --luaD_stack.top;
545 }
546 luaC_checkGC();
547 break;
548 }
549
550 case MINUSOP:
551 if (tonumber(luaD_stack.top-1)) {
552 ttype(luaD_stack.top) = LUA_T_NIL;
553 luaD_stack.top++;
554 call_arith(IM_UNM);
555 }
556 else
557 nvalue(luaD_stack.top-1) = - nvalue(luaD_stack.top-1);
558 break;
559
560 case NOTOP:
561 ttype(luaD_stack.top-1) =
562 (ttype(luaD_stack.top-1) == LUA_T_NIL) ? LUA_T_NUMBER : LUA_T_NIL;
563 nvalue(luaD_stack.top-1) = 1;
564 break;
565
566 case ONTJMP: {
567 Word w;
568 get_word(w,pc);
569 if (ttype(luaD_stack.top-1) != LUA_T_NIL) pc += w;
570 else luaD_stack.top--;
571 }
572 break;
573
574 case ONFJMP: {
575 Word w;
576 get_word(w,pc);
577 if (ttype(luaD_stack.top-1) == LUA_T_NIL) pc += w;
578 else luaD_stack.top--;
579 break;
580 }
581
582 case JMP: {
583 Word w;
584 get_word(w,pc);
585 pc += w;
586 break;
587 }
588
589 case UPJMP: {
590 Word w;
591 get_word(w,pc);
592 pc -= w;
593 break;
594 }
595
596 case IFFJMP: {
597 Word w;
598 get_word(w,pc);
599 luaD_stack.top--;
600 if (ttype(luaD_stack.top) == LUA_T_NIL) pc += w;
601 break;
602 }
603
604 case IFFUPJMP: {
605 Word w;
606 get_word(w,pc);
607 luaD_stack.top--;
608 if (ttype(luaD_stack.top) == LUA_T_NIL) pc -= w;
609 break;
610 }
611
612 case CLOSURE:
613 luaV_closure();
614 luaC_checkGC();
615 break;
616
617 case CALLFUNC: {
618 int nParams = *pc++;
619 int nResults = *pc++;
620 StkId newBase = (luaD_stack.top-luaD_stack.stack)-nParams;
621 luaD_call(newBase, nResults);
622 break;
623 }
624
625 case ENDCODE:
626 luaD_stack.top = luaD_stack.stack + base;
627 /* goes through */
628 case RETCODE:
629 if (lua_callhook)
630 luaD_callHook(base, LUA_T_MARK, 1);
631 return (base + ((opcode==RETCODE) ? *pc : 0));
632
633 case SETLINE: {
634 Word line;
635 get_word(line,pc);
636 if ((luaD_stack.stack+base-1)->ttype != LUA_T_LINE) {
637 /* open space for LINE value */
638 luaD_openstack((luaD_stack.top-luaD_stack.stack)-base);
639 base++;
640 (luaD_stack.stack+base-1)->ttype = LUA_T_LINE;
641 }
642 (luaD_stack.stack+base-1)->value.i = line;
643 if (lua_linehook)
644 luaD_lineHook(line);
645 break;
646 }
647
648#ifdef DEBUG
649 default:
650 lua_error("internal error - opcode doesn't match");
651#endif
652 }
653 }
654}
655
diff --git a/lvm.h b/lvm.h
new file mode 100644
index 00000000..9a180e3e
--- /dev/null
+++ b/lvm.h
@@ -0,0 +1,29 @@
1/*
2** $Id: $
3** Lua virtual machine
4** See Copyright Notice in lua.h
5*/
6
7#ifndef lvm_h
8#define lvm_h
9
10
11#include "ldo.h"
12#include "lobject.h"
13
14
15#define tonumber(o) ((ttype(o) != LUA_T_NUMBER) && (luaV_tonumber(o) != 0))
16#define tostring(o) ((ttype(o) != LUA_T_STRING) && (luaV_tostring(o) != 0))
17
18
19void luaV_pack (StkId firstel, int nvararg, TObject *tab);
20int luaV_tonumber (TObject *obj);
21int luaV_tostring (TObject *obj);
22void luaV_gettable (void);
23void luaV_settable (TObject *t, int mode);
24void luaV_getglobal (Word n);
25void luaV_setglobal (Word n);
26StkId luaV_execute (Closure *func, StkId base);
27void luaV_closure (void);
28
29#endif