-
Notifications
You must be signed in to change notification settings - Fork 1
/
lua-notes.html
420 lines (413 loc) · 29.3 KB
/
lua-notes.html
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
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.13.1: http://docutils.sourceforge.net/" />
<title>Lua 源码阅读笔记</title>
<link rel="stylesheet" href="style.css" type="text/css" />
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<div class="document" id="lua">
<div id="top"></div>
<h1 class="title">Lua 源码阅读笔记</h1>
<style>
.document h2:before { content:""; }
.document h2:after { content:" :"; }
.document h2 { font-weight: bold; }
</style><div class="contents topic" id="id1">
<p class="topic-title first">目录</p>
<ul class="simple">
<li><a class="reference internal" href="#be-prepared" id="id5">Be Prepared</a></li>
<li><a class="reference internal" href="#lapi-c" id="id6">lapi.c</a><ul>
<li><a class="reference internal" href="#index2addr" id="id7">index2addr</a></li>
</ul>
</li>
<li><a class="reference internal" href="#lobject-h" id="id8">lobject.h</a><ul>
<li><a class="reference internal" href="#tvalue" id="id9">TValue</a></li>
<li><a class="reference internal" href="#value" id="id10">Value</a></li>
<li><a class="reference internal" href="#pseudo-index" id="id11">Pseudo Index</a></li>
<li><a class="reference internal" href="#commonheader" id="id12">CommonHeader</a></li>
</ul>
</li>
<li><a class="reference internal" href="#lstate-h" id="id13">lstate.h</a><ul>
<li><a class="reference internal" href="#gcobject" id="id14">GCObject</a></li>
<li><a class="reference internal" href="#callinfo" id="id15">CallInfo</a></li>
<li><a class="reference internal" href="#lua-state" id="id16">lua_State</a></li>
</ul>
</li>
<li><a class="reference internal" href="#lvm-c" id="id17">lvm.c</a><ul>
<li><a class="reference internal" href="#luav-execute" id="id18">luaV_execute</a></li>
</ul>
</li>
</ul>
</div>
<hr class="docutils" />
<p>某天在 reddit 上面看到 LuaJIT 作者推荐的 Lua源码阅读顺序 :</p>
<blockquote>
<ol class="arabic simple">
<li>lmathlib.c, lstrlib.c: get familiar with the external C API. Don't bother with the pattern matcher though. Just the easy functions.</li>
<li>lapi.c: Check how the API is implemented internally. Only skim this to get a feeling for the code. Cross-reference to lua.h and luaconf.h as needed.</li>
<li>lobject.h: tagged values and object representation. skim through this first. you'll want to keep a window with this file open all the time.</li>
<li>lstate.h: state objects. ditto.</li>
<li>lopcodes.h: bytecode instruction format and opcode definitions. easy.</li>
<li>lvm.c: scroll down to luaV_execute, the main interpreter loop. see how all of the instructions are implemented. skip the details for now. reread later.</li>
<li>ldo.c: calls, stacks, exceptions, coroutines. tough read.</li>
<li>lstring.c: string interning. cute, huh?</li>
<li>ltable.c: hash tables and arrays. tricky code.</li>
<li>ltm.c: metamethod handling, reread all of lvm.c now.</li>
<li>You may want to reread lapi.c now.</li>
<li>ldebug.c: surprise waiting for you. abstract interpretation is used to find object names for tracebacks. does bytecode verification, too.</li>
<li>lparser.c, lcode.c: recursive descent parser, targetting a register-based VM. start from chunk() and work your way through. read the expression parser and the code generator parts last.</li>
<li>lgc.c: incremental garbage collector. take your time.</li>
<li>Read all the other files as you see references to them. Don't let your stack get too deep though.</li>
</ol>
</blockquote>
<p>感觉很有道理,所以……就按他说的来吧~</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p>唔,插一句…… GNU Global 真是神器!</p>
<p class="last">再插一句,其实他漏掉了第零步:Lua 文档</p>
</div>
<div class="section" id="be-prepared">
<h1><a class="toc-backref" href="#id5">Be Prepared</a></h1>
<ul class="simple">
<li>去看看 <a class="reference external" href="http://www.lua.org/manual/5.2/manual.html">Lua Manual</a></li>
<li>去 <a class="reference external" href="http://lua-users.org/wiki/LuaSource">Lua Wiki</a> 看看 Lua 代码的组织方式和代码风格</li>
<li>打开 <a class="reference external" href="http://www.lua.org/source/5.2/">Lua Source</a> 对着看</li>
</ul>
<p>Lua 代码风格:</p>
<pre class="literal-block">
luaA_ - lapi.c
luaB_ - lbaselib.c
luaC_ - lgc.c
luaD_ - ldo.c
luaE_ - lstate.c
luaF_ - lfunc.c
luaG_ - ldebug.c
luaH_ - ltable.c
luaI_ - lauxlib.c
luaK_ - lcode.c
luaL_ - lauxlib.c/h, linit.c (public functions)
luaM_ - lmem.c
luaO_ - lobject.c
luaP_ - lopcodes.c
luaS_ - lstring.c
luaT_ - ltm.c
luaU_ - lundump.c
luaV_ - lvm.c
luaX_ - llex.c
luaY_ - lparser.c
luaZ_ - lzio.c
lua_ - lapi.c/h + luaconf.h, debug.c
luai_ - luaconf.h
luaopen_ - luaconf.h + libraries (lbaselib.c, ldblib.c, liolib.c, lmathlib.c,
loadlib.c, loslib.c, lstrlib.c, ltablib.c)
</pre>
</div>
<div class="section" id="lapi-c">
<h1><a class="toc-backref" href="#id6">lapi.c</a></h1>
<p>在 <cite>lapi.c</cite> 中,最重要的函数可以说是 <tt class="docutils literal">index2addr</tt> 了吧:</p>
<div class="section" id="index2addr">
<h2><a class="toc-backref" href="#id7">index2addr</a></h2>
<pre class="code c literal-block">
<span class="k">static</span> <span class="n">TValue</span> <span class="o">*</span><span class="nf">index2addr</span> <span class="p">(</span><span class="n">lua_State</span> <span class="o">*</span><span class="n">L</span><span class="p">,</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> <span class="p">{</span>
<span class="n">CallInfo</span> <span class="o">*</span><span class="n">ci</span> <span class="o">=</span> <span class="n">L</span><span class="o">-></span><span class="n">ci</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">idx</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="n">TValue</span> <span class="o">*</span><span class="n">o</span> <span class="o">=</span> <span class="n">ci</span><span class="o">-></span><span class="n">func</span> <span class="o">+</span> <span class="n">idx</span><span class="p">;</span>
<span class="n">api_check</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="n">idx</span> <span class="o"><=</span> <span class="n">ci</span><span class="o">-></span><span class="n">top</span> <span class="o">-</span> <span class="p">(</span><span class="n">ci</span><span class="o">-></span><span class="n">func</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="s">"unacceptable index"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">o</span> <span class="o">>=</span> <span class="n">L</span><span class="o">-></span><span class="n">top</span><span class="p">)</span> <span class="k">return</span> <span class="n">NONVALIDVALUE</span><span class="p">;</span>
<span class="k">else</span> <span class="k">return</span> <span class="n">o</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">idx</span> <span class="o">></span> <span class="n">LUA_REGISTRYINDEX</span><span class="p">)</span> <span class="p">{</span>
<span class="n">api_check</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="n">idx</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">&&</span> <span class="o">-</span><span class="n">idx</span> <span class="o"><=</span> <span class="n">L</span><span class="o">-></span><span class="n">top</span> <span class="o">-</span> <span class="p">(</span><span class="n">ci</span><span class="o">-></span><span class="n">func</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="s">"invalid index"</span><span class="p">);</span>
<span class="k">return</span> <span class="n">L</span><span class="o">-></span><span class="n">top</span> <span class="o">+</span> <span class="n">idx</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">idx</span> <span class="o">==</span> <span class="n">LUA_REGISTRYINDEX</span><span class="p">)</span>
<span class="k">return</span> <span class="o">&</span><span class="n">G</span><span class="p">(</span><span class="n">L</span><span class="p">)</span><span class="o">-></span><span class="n">l_registry</span><span class="p">;</span>
<span class="k">else</span> <span class="p">{</span> <span class="cm">/* upvalues */</span>
<span class="n">idx</span> <span class="o">=</span> <span class="n">LUA_REGISTRYINDEX</span> <span class="o">-</span> <span class="n">idx</span><span class="p">;</span>
<span class="n">api_check</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="n">idx</span> <span class="o"><=</span> <span class="n">MAXUPVAL</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"upvalue index too large"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ttislcf</span><span class="p">(</span><span class="n">ci</span><span class="o">-></span><span class="n">func</span><span class="p">))</span> <span class="cm">/* light C function? */</span>
<span class="k">return</span> <span class="n">NONVALIDVALUE</span><span class="p">;</span> <span class="cm">/* it has no upvalues */</span>
<span class="k">else</span> <span class="p">{</span>
<span class="n">CClosure</span> <span class="o">*</span><span class="n">func</span> <span class="o">=</span> <span class="n">clCvalue</span><span class="p">(</span><span class="n">ci</span><span class="o">-></span><span class="n">func</span><span class="p">);</span>
<span class="k">return</span> <span class="p">(</span><span class="n">idx</span> <span class="o"><=</span> <span class="n">func</span><span class="o">-></span><span class="n">nupvalues</span><span class="p">)</span> <span class="o">?</span> <span class="o">&</span><span class="n">func</span><span class="o">-></span><span class="n">upvalue</span><span class="p">[</span><span class="n">idx</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">:</span> <span class="n">NONVALIDVALUE</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre>
<p>几乎所有其他的函数都是建立在它的功能之上的 —— 回忆 Lua 文档,
很多的 Lua API 函数都会接受一个 index 参数,用来指定参数在栈上的位置,比如 <tt class="docutils literal">lua_settop</tt>, <tt class="docutils literal">lua_remove</tt>, <tt class="docutils literal">lua_insert</tt>,
<tt class="docutils literal">lua_replace</tt> 等等,而这个 <a class="reference internal" href="#index2addr">index2addr</a> 函数的作用就是通过给定的 index 参数取出对应的 <a class="reference internal" href="#tvalue">TValue</a> 类型的对象指针</p>
<p>关于 Registry 的应用可以回忆 <a class="reference external" href="http://www.lua.org/manual/5.2/manual.html#4.5">Lua 文档上对于 Registry 的介绍</a> 。</p>
<p>而结合 <a class="reference internal" href="#pseudo-index">Pseudo Index</a> 可以看出该函数的逻辑如下:</p>
<table border="1" class="docutils">
<colgroup>
<col width="46%" />
<col width="54%" />
</colgroup>
<tbody valign="top">
<tr><td>当 index > 0 时</td>
<td>在当前 function 的栈空间找对应的 TValue</td>
</tr>
<tr><td>当 LUA_REGISTRYINDEX < index <= 0 时</td>
<td>在当前 function 的栈空间逆向找对应的 TValue</td>
</tr>
<tr><td>当 index == LUA_REGISTRYINDEX 时</td>
<td>返回 registry</td>
</tr>
<tr><td>否则( index < LUA_REGISTRYINDEX 时 )</td>
<td>查找 upvalue</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="section" id="lobject-h">
<h1><a class="toc-backref" href="#id8">lobject.h</a></h1>
<div class="section" id="tvalue">
<h2><a class="toc-backref" href="#id9">TValue</a></h2>
<pre class="code c literal-block">
<span class="k">typedef</span> <span class="k">struct</span> <span class="n">lua_TValue</span> <span class="n">TValue</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">lua_TValue</span> <span class="p">{</span>
<span class="n">TValuefields</span><span class="p">;</span>
<span class="p">};</span>
<span class="cp">#define TValuefields Value value_; int tt_</span>
</pre>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">#define LUA_NANTRICK 之后, TValuefields 会有不同的定义,不过基本原理不便,此处暂且假定
<strong>没有使用 LUA_NANTRICK</strong></p>
</div>
<p><cite>value_</cite> 项用于保存数据, <cite>tt_</cite> 项用于保存数据类型;
可选的数据类型有:</p>
<pre class="code c literal-block" id="id3">
<span class="cp">#define LUA_TNONE (-1)
</span>
<span class="cp">#define LUA_TNIL 0
#define LUA_TBOOLEAN 1
#define LUA_TLIGHTUSERDATA 2
#define LUA_TNUMBER 3
#define LUA_TSTRING 4
#define LUA_TTABLE 5
#define LUA_TFUNCTION 6
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8</span>
</pre>
<p>BTW 其中 function 类型又有三种区分:</p>
<ul class="simple">
<li>lua function</li>
<li>light C function</li>
<li>C function</li>
</ul>
<p>其中 light C function 与 C function 的区别在于前者只是一个 C 函数指针,
而后者可以有自己的 upvalue,即可以构成一个 closure。</p>
<p>string 类型有两种区分:</p>
<ul class="simple">
<li>short string</li>
<li>long string</li>
</ul>
<p>这两者的区别则在于前者会计算 hash 值,保证相同的短字符串全局唯一;
而为了避免 <a class="reference external" href="http://lua-users.org/wiki/HashDos">hash dos</a> ,长字符串并不计算 hash 值</p>
<pre class="code c literal-block">
<span class="cm">/* Variant tags for functions */</span>
<span class="cp">#define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) </span><span class="cm">/* Lua closure */</span><span class="cp">
#define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) </span><span class="cm">/* light C function */</span><span class="cp">
#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) </span><span class="cm">/* C closure */</span><span class="cp">
</span>
<span class="cm">/*
** LUA_TSTRING variants */</span>
<span class="cp">#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) </span><span class="cm">/* short strings */</span><span class="cp">
#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) </span><span class="cm">/* long strings */</span>
</pre>
</div>
<div class="section" id="value">
<h2><a class="toc-backref" href="#id10">Value</a></h2>
<pre class="code c literal-block">
<span class="k">union</span> <span class="n">Value</span> <span class="p">{</span>
<span class="n">GCObject</span> <span class="o">*</span><span class="n">gc</span><span class="p">;</span> <span class="cm">/* collectable objects */</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span> <span class="cm">/* light userdata */</span>
<span class="kt">int</span> <span class="n">b</span><span class="p">;</span> <span class="cm">/* booleans */</span>
<span class="n">lua_CFunction</span> <span class="n">f</span><span class="p">;</span> <span class="cm">/* light C functions */</span>
<span class="n">numfield</span> <span class="cm">/* numbers */</span>
<span class="p">};</span>
<span class="k">typedef</span> <span class="k">union</span> <span class="n">GCObject</span> <span class="n">GCObject</span><span class="p">;</span>
</pre>
<p>可以看出除了按值引用的数据( light userdata, boolean, light C function, number ),
其他( string, table, function, userdata, thread )都是以 <a class="reference internal" href="#gcobject">GCObject</a> 指针形式保存,
以便用于垃圾回收</p>
</div>
<div class="section" id="pseudo-index">
<h2><a class="toc-backref" href="#id11">Pseudo Index</a></h2>
<pre class="code c literal-block">
<span class="cp">#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000)
</span>
<span class="cp">#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))</span>
</pre>
</div>
<div class="section" id="commonheader">
<h2><a class="toc-backref" href="#id12">CommonHeader</a></h2>
<pre class="code c literal-block">
<span class="cm">/*
** Common Header for all collectable objects (in macro form, to be
** included in other objects)
*/</span>
<span class="cp">#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked</span>
</pre>
<p>CommonHeader 是 Lua 用于垃圾回收的结构,其中 <a class="reference internal" href="#gcobject">GCObject</a> * next 指向下一个可回收对象,
构成了一个单向链表,tt <a class="reference internal" href="#tvalue">依旧是</a> 用于保存数据类型,而 marked 则是用于标记垃圾回收的状态</p>
</div>
</div>
<div class="section" id="lstate-h">
<h1><a class="toc-backref" href="#id13">lstate.h</a></h1>
<div class="section" id="gcobject">
<h2><a class="toc-backref" href="#id14">GCObject</a></h2>
<pre class="code c literal-block">
<span class="k">union</span> <span class="n">GCObject</span> <span class="p">{</span>
<span class="n">GCheader</span> <span class="n">gch</span><span class="p">;</span> <span class="cm">/* common header */</span>
<span class="k">union</span> <span class="n">TString</span> <span class="n">ts</span><span class="p">;</span>
<span class="k">union</span> <span class="n">Udata</span> <span class="n">u</span><span class="p">;</span>
<span class="k">union</span> <span class="n">Closure</span> <span class="n">cl</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">Table</span> <span class="n">h</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">Proto</span> <span class="n">p</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">UpVal</span> <span class="n">uv</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">lua_State</span> <span class="n">th</span><span class="p">;</span> <span class="cm">/* thread */</span>
<span class="p">};</span>
</pre>
</div>
<div class="section" id="callinfo">
<h2><a class="toc-backref" href="#id15">CallInfo</a></h2>
<pre class="code c literal-block">
<span class="cm">/*
** information about a call
*/</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="n">CallInfo</span> <span class="p">{</span>
<span class="n">StkId</span> <span class="n">func</span><span class="p">;</span> <span class="cm">/* function index in the stack */</span>
<span class="n">StkId</span> <span class="n">top</span><span class="p">;</span> <span class="cm">/* top for this function */</span>
<span class="k">struct</span> <span class="n">CallInfo</span> <span class="o">*</span><span class="n">previous</span><span class="p">,</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> <span class="cm">/* dynamic call link */</span>
<span class="kt">short</span> <span class="n">nresults</span><span class="p">;</span> <span class="cm">/* expected number of results from this function */</span>
<span class="n">lu_byte</span> <span class="n">callstatus</span><span class="p">;</span>
<span class="kt">ptrdiff_t</span> <span class="n">extra</span><span class="p">;</span>
<span class="k">union</span> <span class="p">{</span>
<span class="k">struct</span> <span class="p">{</span> <span class="cm">/* only for Lua functions */</span>
<span class="n">StkId</span> <span class="n">base</span><span class="p">;</span> <span class="cm">/* base for this function */</span>
<span class="k">const</span> <span class="n">Instruction</span> <span class="o">*</span><span class="n">savedpc</span><span class="p">;</span>
<span class="p">}</span> <span class="n">l</span><span class="p">;</span>
<span class="k">struct</span> <span class="p">{</span> <span class="cm">/* only for C functions */</span>
<span class="kt">int</span> <span class="n">ctx</span><span class="p">;</span> <span class="cm">/* context info. in case of yields */</span>
<span class="n">lua_CFunction</span> <span class="n">k</span><span class="p">;</span> <span class="cm">/* continuation in case of yields */</span>
<span class="kt">ptrdiff_t</span> <span class="n">old_errfunc</span><span class="p">;</span>
<span class="n">lu_byte</span> <span class="n">old_allowhook</span><span class="p">;</span>
<span class="n">lu_byte</span> <span class="n">status</span><span class="p">;</span>
<span class="p">}</span> <span class="n">c</span><span class="p">;</span>
<span class="p">}</span> <span class="n">u</span><span class="p">;</span>
<span class="p">}</span> <span class="n">CallInfo</span><span class="p">;</span>
<span class="cm">/*
** Bits in CallInfo status
*/</span>
<span class="cp">#define CIST_LUA (1<<0) </span><span class="cm">/* call is running a Lua function */</span><span class="cp">
#define CIST_HOOKED (1<<1) </span><span class="cm">/* call is running a debug hook */</span><span class="cp">
#define CIST_REENTRY (1<<2) </span><span class="cm">/* call is running on same invocation of
luaV_execute of previous call */</span><span class="cp">
#define CIST_YIELDED (1<<3) </span><span class="cm">/* call reentered after suspension */</span><span class="cp">
#define CIST_YPCALL (1<<4) </span><span class="cm">/* call is a yieldable protected call */</span><span class="cp">
#define CIST_STAT (1<<5) </span><span class="cm">/* call has an error status (pcall) */</span><span class="cp">
#define CIST_TAIL (1<<6) </span><span class="cm">/* call was tail called */</span><span class="cp">
#define CIST_HOOKYIELD (1<<7) </span><span class="cm">/* last hook called yielded */</span>
</pre>
</div>
<div class="section" id="lua-state">
<h2><a class="toc-backref" href="#id16">lua_State</a></h2>
<p>这是每个 Lua 函数都会接受的表示当前状态的结构,最主要的成员包括运行栈 stack,
栈用于表示函数调用、传递参数及返回值</p>
<pre class="code c literal-block">
<span class="cm">/*
** `per thread' state
*/</span>
<span class="k">struct</span> <span class="n">lua_State</span> <span class="p">{</span>
<span class="n">CommonHeader</span><span class="p">;</span>
<span class="n">lu_byte</span> <span class="n">status</span><span class="p">;</span>
<span class="n">StkId</span> <span class="n">top</span><span class="p">;</span> <span class="cm">/* first free slot in the stack */</span>
<span class="n">global_State</span> <span class="o">*</span><span class="n">l_G</span><span class="p">;</span>
<span class="n">CallInfo</span> <span class="o">*</span><span class="n">ci</span><span class="p">;</span> <span class="cm">/* call info for current function */</span>
<span class="k">const</span> <span class="n">Instruction</span> <span class="o">*</span><span class="n">oldpc</span><span class="p">;</span> <span class="cm">/* last pc traced */</span>
<span class="n">StkId</span> <span class="n">stack_last</span><span class="p">;</span> <span class="cm">/* last free slot in the stack */</span>
<span class="n">StkId</span> <span class="n">stack</span><span class="p">;</span> <span class="cm">/* stack base */</span>
<span class="kt">int</span> <span class="n">stacksize</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">nny</span><span class="p">;</span> <span class="cm">/* number of non-yieldable calls in stack */</span>
<span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">nCcalls</span><span class="p">;</span> <span class="cm">/* number of nested C calls */</span>
<span class="n">lu_byte</span> <span class="n">hookmask</span><span class="p">;</span>
<span class="n">lu_byte</span> <span class="n">allowhook</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">basehookcount</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">hookcount</span><span class="p">;</span>
<span class="n">lua_Hook</span> <span class="n">hook</span><span class="p">;</span>
<span class="n">GCObject</span> <span class="o">*</span><span class="n">openupval</span><span class="p">;</span> <span class="cm">/* list of open upvalues in this stack */</span>
<span class="n">GCObject</span> <span class="o">*</span><span class="n">gclist</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">lua_longjmp</span> <span class="o">*</span><span class="n">errorJmp</span><span class="p">;</span> <span class="cm">/* current error recover point */</span>
<span class="kt">ptrdiff_t</span> <span class="n">errfunc</span><span class="p">;</span> <span class="cm">/* current error handling function (stack index) */</span>
<span class="n">CallInfo</span> <span class="n">base_ci</span><span class="p">;</span> <span class="cm">/* CallInfo for first level (C calling Lua) */</span>
<span class="p">};</span>
</pre>
</div>
</div>
<div class="section" id="lvm-c">
<h1><a class="toc-backref" href="#id17">lvm.c</a></h1>
<p>首先 <tt class="docutils literal">Instruction</tt> 的定义是 <tt class="docutils literal">uint32</tt></p>
<p>留意一下 lvm.h 这一段很重要的注释</p>
<pre class="code c literal-block">
<span class="cm">/*===========================================================================
We assume that instructions are unsigned numbers.
All instructions have an opcode in the first 6 bits.
Instructions can have the following fields:
`A' : 8 bits
`B' : 9 bits
`C' : 9 bits
'Ax' : 26 bits ('A', 'B', and 'C' together)
`Bx' : 18 bits (`B' and `C' together)
`sBx' : signed Bx
A signed argument is represented in excess K; that is, the number
value is the unsigned value minus K. K is exactly the maximum value
for that argument (so that -max is represented by 0, and +max is
represented by 2*max), which is half the maximum for the corresponding
unsigned argument.
===========================================================================*/</span>
</pre>
<p>我们可以发现体积最大的操作数 <tt class="docutils literal">Ax</tt> 加上 6bit 指令正好有 32 位 —— 不难猜出虚拟机的指令组织方式</p>
<div class="section" id="luav-execute">
<h2><a class="toc-backref" href="#id18">luaV_execute</a></h2>
<p>虚拟机本体</p>
<p>随便取一个指令的解析来看看:</p>
<pre class="code c literal-block">
<span class="n">vmcase</span><span class="p">(</span><span class="n">OP_MOVE</span><span class="p">,</span>
<span class="n">setobjs2s</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="n">ra</span><span class="p">,</span> <span class="n">RB</span><span class="p">(</span><span class="n">i</span><span class="p">));</span>
<span class="p">)</span>
</pre>
<p><tt class="docutils literal">ra</tt> 是用 <tt class="docutils literal">RA(</tt> <a class="reference internal" href="#callinfo">CallInfo</a>.u.l.savedpc <tt class="docutils literal">)</tt> 取出的,而 <tt class="docutils literal">RA</tt> 所做的事情是取出指令(此处即 <tt class="docutils literal">savedpc</tt> )中的第 7-14 位的数值,然后加上 base 地址,获得一个 TValue 的指针</p>
<p><tt class="docutils literal">RB</tt> 做的也是类似的事情,所以这句话就是说遇到 <tt class="docutils literal">OP_MOVE</tt> 指令的时候对紧接在后面的 <tt class="docutils literal">A</tt>, <tt class="docutils literal">B</tt> 两个操作数执行 <tt class="docutils literal">setobjs2s</tt> 操作</p>
<blockquote>
PS. <tt class="docutils literal">newframe</tt> 标签看上去真是个万般无奈的解啊</blockquote>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">to be continued ...</p>
</div>
</div>
</div>
<div id="bottomnav"><a id="gohome" href="/">cd ~</a> | <a id="gotop" href="#top">goto top;</a></div>
<footer>
Contact/Comment: <a href="https://github.com/find/find.github.com/issues">issue on github</a>
or
mail to address in <a href="/about.html#public-key">my pub key</a>
<br/>
Copyright © <a href="http://www.yuguo.me/">If</a>.
</footer>
</div>
<div class="footer">
<hr class="footer" />
<a class="reference external" href="src/lua-notes.rst">View document source</a>.
</div>
</body>
</html>