lua源码注释-lvm.c

github链接 lua515子域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
/*
** $Id: lvm.c,v 2.63.1.5 2011/08/17 20:43:11 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define lvm_c
#define LUA_CORE

#include "lua.h"

#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
#include "lvm.h"



/* limit for table tag-method chains (to avoid loops) */
#define MAXTAGLOOP 100

/* number,string-->number */
const TValue *luaV_tonumber (const TValue *obj, TValue *n) {
lua_Number num;
if (ttisnumber(obj)) return obj;
if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
setnvalue(n, num);
return n;
}
else
return NULL;
}

/* number->string */
int luaV_tostring (lua_State *L, StkId obj) {
if (!ttisnumber(obj))
return 0;
else {
char s[LUAI_MAXNUMBER2STR];
lua_Number n = nvalue(obj);
lua_number2str(s, n);
setsvalue2s(L, obj, luaS_new(L, s));
return 1;
}
}

/* 判断调试MASK是否设置,以及相关条件是否已满足,满足则进入钩子函数 */
static void traceexec (lua_State *L, const Instruction *pc) {
lu_byte mask = L->hookmask;
const Instruction *oldpc = L->savedpc;
L->savedpc = pc;
if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { /* 执行了指定数量的pc,调用指定的钩子函数 */
resethookcount(L);
luaD_callhook(L, LUA_HOOKCOUNT, -1);
}
if (mask & LUA_MASKLINE) { /* LUA_MASKLINE不是说执行到了某一行,具体的意思看下面的代码 */
Proto *p = ci_func(L->ci)->l.p;
int npc = pcRel(pc, p);
int newline = getline(p, npc);
/* call linehook when enter a new function, when jump back (loop),
or when enter a new line */
if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p)))
luaD_callhook(L, LUA_HOOKLINE, newline);
}
}

/* 调用元方法,将结果返回给res */
static void callTMres (lua_State *L, StkId res, const TValue *f,
const TValue *p1, const TValue *p2) {
ptrdiff_t result = savestack(L, res);
setobj2s(L, L->top, f); /* push function */
setobj2s(L, L->top+1, p1); /* 1st argument */
setobj2s(L, L->top+2, p2); /* 2nd argument */
luaD_checkstack(L, 3);
L->top += 3;
luaD_call(L, L->top - 3, 1);
res = restorestack(L, result);
L->top--;
setobjs2s(L, res, L->top);
}



static void callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) {
setobj2s(L, L->top, f); /* push function */
setobj2s(L, L->top+1, p1); /* 1st argument */
setobj2s(L, L->top+2, p2); /* 2nd argument */
setobj2s(L, L->top+3, p3); /* 3th argument */
luaD_checkstack(L, 4);
L->top += 4;
luaD_call(L, L->top - 4, 0);
}


void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
int loop;
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t)) { /* `t' is a table? */
Table *h = hvalue(t);
const TValue *res = luaH_get(h, key); /* do a primitive get */
if (!ttisnil(res) || /* result is no nil? */
(tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
setobj2s(L, val, res);
return;
}
/* else will try the tag method */
}
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
luaG_typeerror(L, t, "index");
if (ttisfunction(tm)) {
callTMres(L, val, tm, t, key);
return;
}
t = tm; /* else repeat with `tm' */
}
luaG_runerror(L, "loop in gettable");
}


void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
int loop;
TValue temp;
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t)) { /* `t' is a table? */
Table *h = hvalue(t);
TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
if (!ttisnil(oldval) || /* result is no nil? */
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
setobj2t(L, oldval, val);
h->flags = 0; /* 更新flags:假设所有的tm都存在 */
luaC_barriert(L, h, val);
return;
}
/* else will try the tag method */
}
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
luaG_typeerror(L, t, "index");
if (ttisfunction(tm)) {
callTM(L, tm, t, key, val);
return;
}
/* else repeat with `tm' */
setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */
t = &temp;
}
luaG_runerror(L, "loop in settable");
}

/* 同上callTM,针对tblA+tblB这种两个操作数的,尝试调用特定元方法 */
static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2,
StkId res, TMS event) {
const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
if (ttisnil(tm))
tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
if (ttisnil(tm)) return 0;
callTMres(L, res, tm, p1, p2);
return 1;
}

/* only for userdata */
static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2,
TMS event) {
const TValue *tm1 = fasttm(L, mt1, event);
const TValue *tm2;
if (tm1 == NULL) return NULL; /* no metamethod */
if (mt1 == mt2) return tm1; /* same metatables => same metamethods */
tm2 = fasttm(L, mt2, event);
if (tm2 == NULL) return NULL; /* no metamethod */
if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */
return tm1;
return NULL;
}

/* 元方法:比较操作 */
static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) {
const TValue *tm1 = luaT_gettmbyobj(L, p1, event);
const TValue *tm2;
if (ttisnil(tm1)) return -1; /* no metamethod? */
tm2 = luaT_gettmbyobj(L, p2, event);
if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */
return -1;
callTMres(L, L->top, tm1, p1, p2);
return !l_isfalse(L->top);
}


static int l_strcmp (const TString *ls, const TString *rs) {
const char *l = getstr(ls);
size_t ll = ls->tsv.len;
const char *r = getstr(rs);
size_t lr = rs->tsv.len;
for (;;) {
int temp = strcoll(l, r); /* 依环境变量 LC_COLLATE 所指定的文字排列次序来比较 s1 和 s2 字符串 */
if (temp != 0) return temp;
else { /* strings are equal up to a `\0' */
size_t len = strlen(l); /* index of first `\0' in both strings */
if (len == lr) /* r is finished? */
return (len == ll) ? 0 : 1;
else if (len == ll) /* l is finished? */
return -1; /* l is smaller than r (because r is not finished) */
/* both strings longer than `len'; go on comparing (after the `\0') */
len++;
l += len; ll -= len; r += len; lr -= len;
}
}
}

/* 比较指令 */
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int res;
if (ttype(l) != ttype(r))
return luaG_ordererror(L, l, r);
else if (ttisnumber(l))
return luai_numlt(nvalue(l), nvalue(r));
else if (ttisstring(l))
return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
return res;
return luaG_ordererror(L, l, r);
}


static int lessequal (lua_State *L, const TValue *l, const TValue *r) {
int res;
if (ttype(l) != ttype(r))
return luaG_ordererror(L, l, r);
else if (ttisnumber(l))
return luai_numle(nvalue(l), nvalue(r));
else if (ttisstring(l))
return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */
return res;
else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */
return !res;
return luaG_ordererror(L, l, r);
}


int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
const TValue *tm;
lua_assert(ttype(t1) == ttype(t2));
switch (ttype(t1)) {
case LUA_TNIL: return 1;
case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2));
case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
case LUA_TUSERDATA: {
if (uvalue(t1) == uvalue(t2)) return 1;
tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable,
TM_EQ);
break; /* will try TM */
}
case LUA_TTABLE: {
if (hvalue(t1) == hvalue(t2)) return 1;
tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
}
default: return gcvalue(t1) == gcvalue(t2);
}
if (tm == NULL) return 0; /* no TM? */
callTMres(L, L->top, tm, t1, t2); /* call TM */
return !l_isfalse(L->top);
}

/* 从last开始,一共链接total个slot */
void luaV_concat (lua_State *L, int total, int last) {
do {
StkId top = L->base + last + 1;
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
luaG_concaterror(L, top-2, top-1);
} else if (tsvalue(top-1)->len == 0) /* second op is empty? */
(void)tostring(L, top - 2); /* result is first op (as string) */
else {
/* at least two string values; get as many as possible */
size_t tl = tsvalue(top-1)->len;
char *buffer;
int i;
/* collect total length */
for (n = 1; n < total && tostring(L, top-n-1); n++) {
size_t l = tsvalue(top-n-1)->len;
if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
tl += l;
}
buffer = luaZ_openspace(L, &G(L)->buff, tl);
tl = 0;
for (i=n; i>0; i--) { /* concat all strings */
size_t l = tsvalue(top-i)->len;
memcpy(buffer+tl, svalue(top-i), l);
tl += l;
}
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
}
total -= n-1; /* got `n' strings to create 1 new */
last -= n-1;
} while (total > 1); /* repeat until only 1 result left */
}


static void Arith (lua_State *L, StkId ra, const TValue *rb,
const TValue *rc, TMS op) {
TValue tempb, tempc;
const TValue *b, *c;
if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
(c = luaV_tonumber(rc, &tempc)) != NULL) {
lua_Number nb = nvalue(b), nc = nvalue(c);
switch (op) {
case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break;
case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break;
case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
default: lua_assert(0); break;
}
}
else if (!call_binTM(L, rb, rc, ra, op))
luaG_aritherror(L, rb, rc);
}



/*
** some macros for common tasks in `luaV_execute'
*/

#define runtime_check(L, c) { if (!(c)) break; }

/* 提取指令中A,B,C的值 */
#define RA(i) (base+GETARG_A(i))
/* to be used after possible stack reallocation */
#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i))


#define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);}

/* x可能触发新的frame,这里保存和恢复“部分现场”配合下面的execute一起看
** pc:为何要存档呢?这是一个局部变量,且是相对frame有效,若切换execute则pc作为上一个execute的局部变量保存起来了,
** 所以为啥要保存这个变量呢?
** base: {x}可能修改stack,造成base记录的本frame的base失效,故而这里要刷新base
*/
#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; }

/* 这个宏有意思哈 */
#define arith_op(op,tm) { \
TValue *rb = RKB(i); \
TValue *rc = RKC(i); \
if (ttisnumber(rb) && ttisnumber(rc)) { \
lua_Number nb = nvalue(rb), nc = nvalue(rc); \
setnvalue(ra, op(nb, nc)); \
} \
else \
Protect(Arith(L, ra, rb, rc, tm)); \
}


/*
** KEYCODE
** nexeccalls:Lua连续调用的层次
**
** eg: c(0)->Lua(1)->Lua(2)->c()->Lua(1)->Lua(2)->Lua(3)->c(0)->Lua(1)
** 某次Lua调用结束,--nexeccalls,如果nexeccalls==0,表示当前lua调用链结束了,需要跳出luaV_execute函数
** 大于0表示本Lua调用结束后,上一层必然还是Lua函数,需要进入reentry点
*/
void luaV_execute (lua_State *L, int nexeccalls) {
LClosure *cl;
StkId base;
TValue *k;
const Instruction *pc;

reentry: /* entry point for new (callInfo,frame) */
lua_assert(isLua(L->ci)); /* C函数frame的执行不在这里,亲! */

/* KEYCODE vm执行的关键参数:base,top,pc,savedpc, closure,k, L->ci,
** 后续因为call和return等切换调用栈时,必须正确处理上述参数
**
** !!!!!!!! L->top没有在这里更新,这点要有印象,resason:类似funA(funB())一个函数(frame)运行完毕时的某些状态eg:L->top
** 对上下文的frame可能有影响,所以这里没有更新L->top,而是让有关业务(return,call...)自行处理
*/

pc = L->savedpc;
cl = &clvalue(L->ci->func)->l;
base = L->base;
k = cl->p->k; /* locvars 仅在编译阶段/调试库中有效,虚拟机运行阶段无效(已编码到pc中) */

/* main loop of interpreter */
for (;;) {
const Instruction i = *pc++; /* 等效:*(pc++) */
StkId ra;
/* 运行钩子逻辑 */
if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
(--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
traceexec(L, pc);
if (L->status == LUA_YIELD) { /* did hook yield? */
L->savedpc = pc - 1;
return;
}
base = L->base;
}
/* warning!! several(某些) calls may realloc the stack and invalidate `ra' */
ra = RA(i);
lua_assert(base == L->base && L->base == L->ci->base);
lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);

/* luaG_checkopenop的用途对照上面L->top的注释看就明白了 */
lua_assert(L->top == L->ci->top || luaG_checkopenop(i));
switch (GET_OPCODE(i)) {
case OP_MOVE: {
setobjs2s(L, ra, RB(i));
continue;
}
case OP_LOADK: {
setobj2s(L, ra, KBx(i));
continue;
}
case OP_LOADBOOL: {
setbvalue(ra, GETARG_B(i));
if (GETARG_C(i)) pc++; /* skip next instruction (if C) */
continue;
}
case OP_LOADNIL: {
TValue *rb = RB(i);
do {
setnilvalue(rb--);
} while (rb >= ra);
continue;
}
case OP_GETUPVAL: {
int b = GETARG_B(i);
setobj2s(L, ra, cl->upvals[b]->v);
continue;
}
case OP_GETGLOBAL: {
TValue g;
TValue *rb = KBx(i);
sethvalue(L, &g, cl->env);
lua_assert(ttisstring(rb)); /* 全局变量名类型必须是TString */
Protect(luaV_gettable(L, &g, rb, ra));
continue;
}
case OP_GETTABLE: {
Protect(luaV_gettable(L, RB(i), RKC(i), ra));
continue;
}
case OP_SETGLOBAL: {
TValue g;
sethvalue(L, &g, cl->env);
lua_assert(ttisstring(KBx(i)));
Protect(luaV_settable(L, &g, KBx(i), ra));
continue;
}
case OP_SETUPVAL: {
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_barrier(L, uv, ra);
continue;
}
case OP_SETTABLE: {
Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
continue;
}
case OP_NEWTABLE: {
int b = GETARG_B(i);
int c = GETARG_C(i);
sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
Protect(luaC_checkGC(L));
continue;
}
case OP_SELF: {
StkId rb = RB(i); /* 拿到self.sub中的self指代的表 */
setobjs2s(L, ra+1, rb); /* 将上述表self存起来 */
Protect(luaV_gettable(L, rb, RKC(i), ra)); /* 计算self.sub的值 */
continue;
}
case OP_ADD: {
arith_op(luai_numadd, TM_ADD);
continue;
}
case OP_SUB: {
arith_op(luai_numsub, TM_SUB);
continue;
}
case OP_MUL: {
arith_op(luai_nummul, TM_MUL);
continue;
}
case OP_DIV: {
arith_op(luai_numdiv, TM_DIV);
continue;
}
case OP_MOD: {
arith_op(luai_nummod, TM_MOD);
continue;
}
case OP_POW: {
arith_op(luai_numpow, TM_POW);
continue;
}
case OP_UNM: {
TValue *rb = RB(i);
if (ttisnumber(rb)) {
lua_Number nb = nvalue(rb);
setnvalue(ra, luai_numunm(nb));
}
else {
Protect(Arith(L, ra, rb, rb, TM_UNM));
}
continue;
}
case OP_NOT: {
int res = l_isfalse(RB(i)); /* next assignment may change this value */
setbvalue(ra, res);
continue;
}
case OP_LEN: {
const TValue *rb = RB(i);
switch (ttype(rb)) {
case LUA_TTABLE: {
setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
break;
}
case LUA_TSTRING: {
setnvalue(ra, cast_num(tsvalue(rb)->len));
break;
}
default: { /* try metamethod */
Protect(
if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
luaG_typeerror(L, rb, "get length of");
)
}
}
continue;
}
case OP_CONCAT: {
int b = GETARG_B(i);
int c = GETARG_C(i);
/* */
Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L));
setobjs2s(L, RA(i), base+b);
continue;
}
case OP_JMP: {
dojump(L, pc, GETARG_sBx(i));
continue;
}
/* KEYCODE 重点,难点,代表性的指令
** if ((RK(B) == RK(C)) ~= A) then pc++
** OP_EQ后面紧跟着是跳转指令,这里猜测,跳转的值Bx应该短1,因为后面又进行了pc++
*/
case OP_EQ: {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
Protect(
if (equalobj(L, rb, rc) == GETARG_A(i))
dojump(L, pc, GETARG_sBx(*pc));
)
pc++;
continue;
}
case OP_LT: {
Protect(
if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
dojump(L, pc, GETARG_sBx(*pc));
)
pc++;
continue;
}
case OP_LE: {
Protect(
if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
dojump(L, pc, GETARG_sBx(*pc));
)
pc++;
continue;
}
case OP_TEST: {
if (l_isfalse(ra) != GETARG_C(i))
dojump(L, pc, GETARG_sBx(*pc));
pc++;
continue;
}
case OP_TESTSET: {
TValue *rb = RB(i);
if (l_isfalse(rb) != GETARG_C(i)) {
setobjs2s(L, ra, rb);
dojump(L, pc, GETARG_sBx(*pc));
}
pc++;
continue;
}
case OP_CALL: { /* R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
int b = GETARG_B(i); /* 传入参数个数, B:0:... 1:0个,2:1个,3:2个依次类推 */
int nresults = GETARG_C(i) - 1; /* 期待的返回值个数 C:0(...), 1:(期待返回0个),2:(期待返回1个) */

/* 注解99: 当传入的参数数量明确时,设置L->top告知被调用函数确切的传入参数数量,
** 不明确时,OP_VARARG(fun(...))/ RETURN.B(funA(funB())等指令中已确定了top的位置,这里不能也不用再更改设置(否则L->top!=实际传入的参数位置)
**
** L->top都是指向了最后一个参数的"位置",也是告知被调用函数,我已经准备好了你要的参数且top指针已指到相应的位置了
*/
if (b != 0)
L->top = ra+b; /* else previous instruction set top */

L->savedpc = pc; /* 记下原本接下来要执行的下一条指令,等待new'frame运行结束后,继续运行本frame */
switch (luaD_precall(L, ra, nresults)) {
case PCRLUA: {
nexeccalls++;
/* 若子函数(frame)是Lua,这里continue才真正开始执行子函数(frame)的opcode */
goto reentry; /* restart luaV_execute over new Lua function */
}
case PCRC: {
/* it was a C function (`precall' called it); adjust results */

/* 注解100: C调用结束时luaD_poscall已经将所有的返回值填充到RA开头的addr上,L->top指向最后一个返回值
** 期待返回值个数确定时eg:local a,b = fun(),luaD_poscall函数自动赋值了a,b,L->top已经完成了使命
** 故而这里将其复原。
** 期待返回个数不确定时eg:local t = {fun()}或funA(funB()),这种情况下L->top指向的最后一个返回值地址,
** 将被下一条指令setlist(B=0)或callA(B=0)用于计算传入参数的个数,所以不能复原(下一条指令要用到)
*/
if (nresults >= 0)
L->top = L->ci->top;

base = L->base; /* 调用过程中stack可能变化而移动,故而重新获取最新的(L->ci->base==L->base)的base,下同 */
/* 子函数(frame)为c,luaD_precall的返回意味着子函数(frame)已运行完毕,相关参数也调整完毕
** 这里接着运行母函数(frame)的紧跟着OP_CALL后面的下一条指令 */
continue;
}
default: {
return; /* yield,交出lua的执行权 */
}
}
}
case OP_TAILCALL: {
/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
int b = GETARG_B(i);
if (b != 0) {
L->top = ra+b; /* else previous instruction set top */
} else {
/* return fun(...) 前面的OP_VARARG指令设置好了L->top */
}
L->savedpc = pc;
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); /* 尾调用的定义中:必须返回其调用返回的所有值,所以这里C必须为0 */
switch (luaD_precall(L, ra, LUA_MULTRET)) {
case PCRLUA: { /* 画图,代码不难,看懂它们 */
/* tail call: put new frame in place of previous one */
CallInfo *ci = L->ci - 1; /* previous frame */
int aux;
StkId func = ci->func;
StkId pfunc = (ci+1)->func; /* previous function index */
if (L->openupval) luaF_close(L, ci->base);
L->base = ci->base = ci->func + ((ci+1)->base - pfunc);

/* !!!!移动后func指向的地址不变,但值改变了(由母函数变成了被尾调用的子函数) */
for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */
setobjs2s(L, func+aux, pfunc+aux);

ci->top = L->top = func+aux; /* correct top */
lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize);
ci->savedpc = L->savedpc; /* 这里也要更新 */
ci->tailcalls++; /* one more call lost */
L->ci--; /* remove new frame */
goto reentry;
}
case PCRC: { /* it was a C function (`precall' called it) */
base = L->base; /* restore base */
continue;
}
default: {
return; /* yield */
}
}
}
case OP_RETURN: {
/* return R(A), ... ,R(A+B-2) */
int b = GETARG_B(i); /* 0:返回所有值,1:返回0个值,2:返回1个值 ... */
if (b != 0) /* b==0其它的指令argvar等已处理好top,eg:(return ...)或者return(a, fun()) */
L->top = ra+b-1; /* 以便确定返回值的确切个数 */
if (L->openupval) luaF_close(L, base);
L->savedpc = pc;
b = luaD_poscall(L, ra); /* 将子函数的返回值移到指定地方,并适配母函数的result要求 */

/* lua调用结束,返回值已经按照移动到指定的位置(本fun的addr),且L->top指向了最后一个返回值的位置(可以用来计算返回值的个数)
这里直接return,将CPU交换到母C函数 */
if (--nexeccalls == 0) /* was previous function running `here'? Lua层面的调用结束了,结束lua的execute的执行,返回到C */
return; /* no: return */
else { /* yes: continue its execution */
if (b) /* 同上注解100,请往上翻阅 */
L->top = L->ci->top; /* */
lua_assert(isLua(L->ci)); /* return后,lua连续调用链还没结束,那么上一层必然是个lua函数 */
lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); /* 上一个指令必然是call */
goto reentry; /* 切回到母lua的execute的frame */
}
}
case OP_FORLOOP: { /* 先看 OP_FORPREP 指令 */
lua_Number step = nvalue(ra+2);
lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
lua_Number limit = nvalue(ra+1);
if (luai_numlt(0, step) ? luai_numle(idx, limit)
: luai_numle(limit, idx)) {
dojump(L, pc, GETARG_sBx(i)); /* jump back */
setnvalue(ra, idx); /* update internal index... */
setnvalue(ra+3, idx); /* ...and external index 这个idx才是暴露给for循环里面的i(for i = 0; 10; 1) */
}
continue;
}
case OP_FORPREP: {
const TValue *init = ra;
const TValue *plimit = ra+1;
const TValue *pstep = ra+2;
L->savedpc = pc; /* next steps may throw errors */
if (!tonumber(init, ra))
luaG_runerror(L, LUA_QL("for") " initial value must be a number");
else if (!tonumber(plimit, ra+1))
luaG_runerror(L, LUA_QL("for") " limit must be a number");
else if (!tonumber(pstep, ra+2))
luaG_runerror(L, LUA_QL("for") " step must be a number");
setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); /* 这里提前-=step */
dojump(L, pc, GETARG_sBx(i)); /* 跳到cond判断那里 */
continue;
}
case OP_TFORLOOP: {
/* 编译模块保证了ra+3是个有意义的参数
** next函数会吃掉传入的参数,所以这里CP了一份
*/
/* 结合 http://shankusu.me/lua/ANo-FrillsIntroductiontoLua51VMInstructions/ 文档来看,更容易理解 */
StkId cb = ra + 3; /* call base */
setobjs2s(L, cb+2, ra+2);
setobjs2s(L, cb+1, ra+1);
setobjs2s(L, cb, ra);
L->top = cb+3; /* func. + 2 args (state and index) */
Protect(luaD_call(L, cb, GETARG_C(i)));
L->top = L->ci->top;
cb = RA(i) + 3; /* previous call may change the stack */
if (!ttisnil(cb)) { /* continue loop? */
setobjs2s(L, cb-1, cb); /* save control variable */
dojump(L, pc, GETARG_sBx(*pc)); /* jump back */
}
pc++;
continue;
}
case OP_SETLIST: { /* local t = {...} 本指令之前可能会有一条vararg或local t2={fun(...)}产生的OP_CALL,所以结合vararg来理解本block的代码 */
/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
int n = GETARG_B(i);
int c = GETARG_C(i);
int last;
Table *h;
if (n == 0) {
n = cast_int(L->top - ra) - 1; /* 计算确切的参数个数 */
L->top = L->ci->top; /* OP_VARARG指令L->top已经指向了{...}不定参数的最后一个slot的位置以便求n,这里将其复原 */
}
if (c == 0) c = cast_int(*pc++); /* 这行代码最好有个印象 */
runtime_check(L, ttistable(ra)); /* 编译模块出错了 */
h = hvalue(ra);
last = ((c-1)*LFIELDS_PER_FLUSH) + n; /* 计算当前能确定的数组下标的最大值 */
if (last > h->sizearray) /* needs more space? 数组区域大小不够,需扩展*/
luaH_resizearray(L, h, last); /* pre-alloc it at once */
for (; n > 0; n--) {
TValue *val = ra+n;
setobj2t(L, luaH_setnum(L, h, last--), val);
luaC_barriert(L, h, val);
}
continue;
}
case OP_CLOSE: {
/* close all variables in the stack up to (>=) R(A) 编译模块如何确定参数A?*/
luaF_close(L, ra);
continue;
}
case OP_CLOSURE: {
/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
Proto *p;
Closure *ncl;
int nup, j;
p = cl->p->p[GETARG_Bx(i)]; /* 找到对应的proto */
nup = p->nups;
ncl = luaF_newLclosure(L, nup, cl->env);
ncl->l.p = p;
/* 下面的block尚未完全看懂 */
for (j=0; j<nup; j++, pc++) {
if (GET_OPCODE(*pc) == OP_GETUPVAL)
ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)];
else {
lua_assert(GET_OPCODE(*pc) == OP_MOVE);
ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
}
}
setclvalue(L, ra, ncl);
Protect(luaC_checkGC(L));
continue;
}
case OP_VARARG: {
/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
int b = GETARG_B(i) - 1;
int j;
CallInfo *ci = L->ci;
int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; /* 本次函数调用传入的不定参数的个数eg: funA(a,b, ...) funA */
if (b == LUA_MULTRET) {
Protect(luaD_checkstack(L, n));
ra = RA(i); /* previous call may change the stack */
b = n; /* 出现在 local tbl = {...} 或者 funA(...) 需要拷贝所有的不定参数的地方 */

/* 为可能即将到来的C/lua函数调用做准备,(L->top-func可知即将发生的函数调用实际上有多少个传入参数)
**
** local tbl={...} OP_SETLIST指令也用到了L->top,故而可以推断出,这里L->top标记了实际上...携带的参数个数
** 以便其它指令能准确的执行(主要是获取..参数个数),这里将实际传入的参数个数通过L->top计算好,避免其它指令再去计算一遍
** 其它指令用完L->top后需将其复原
*/
L->top = ra + n;
}
/* 将不定参数赋值给指定的对象???
** local a, b = ...
** 不定参数数量不足则补nil
*/
for (j = 0; j < b; j++) {
if (j < n) { /* 本函数的不定参数的个数还能满足ra+j代表的dst寄存器 */
setobjs2s(L, ra + j, ci->base - n + j);
}
else {
setnilvalue(ra + j); /* local a, b = ... 本函数实际上只收到了一个不定参数,那么不足的部分(b)就要补nil值了 */
}
}
continue;
}
}
}
}
-------------本文结束 感谢阅读-------------