Skip to content

Commit b355442

Browse files
committed
4.1字节码 更新
1 parent fb4ab9e commit b355442

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

04.1-Bytecode.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,4 +366,39 @@ private:
366366

367367
你看到那些”保留“和”取回“了吗?每个“保留”对应于一个push,每个“取回”对应于一个pop。这意味着我们可以轻易将其转换为字节码。例如,第一行获取巫师的当前生命值:
368368

369-
LITERAL 0 GET_HEALTH
369+
LITERAL 0
370+
GET_HEALTH
371+
372+
这段字节码将巫师的生命值入栈。如果我们重复这样的操作,最终会得到一段能计算出原表达式的字节码。为了让你体会指令是怎样组合的,我已经帮你做好了。
373+
374+
为了演示堆栈如何随时间变化,权且将巫师的初始状态设置为45点生命、7点敏捷和11点智力。跟在每个指令后面的是执行后的堆栈状态,以及这个指令作用的注释:
375+
376+
LITERAL 0 [0] # Wi zard i ndex
377+
LITERAL 0 [0, 0] # Wi zard i ndex
378+
GET_HEALTH [0, 45] # getHealth()
379+
LITERAL 0 [0, 45, 0] # Wi zard i ndex
380+
GET_AGILITY [0, 45, 7] # getAgi li ty()
381+
LITERAL 0 [0, 45, 7, 0] # Wi zard i ndex
382+
GET_WISDOM [0, 45, 7, 11] # getWi sdom()
383+
ADD [0, 45, 18] # Add agi li ty and wi sdom
384+
LITERAL 2 [0, 45, 18, 2] # Di vi sor
385+
DIVIDE [0, 45, 9] # Average agi li ty and wi sdom
386+
ADD [0, 54] # Add average to current health
387+
SET_HEALTH [] # Set health to result
388+
389+
如果你一步一步看完这个堆栈,你就会发现数据像魔法一样在它内部流动。我们在一开始入栈巫师的索引0,然后做了很多不同的操作,直到最后栈低设置巫师生命值时用到它。
390+
391+
> 也许我这里对“魔法”的定义有点宽。
392+
393+
###一个虚拟机
394+
395+
我可以继续前进,添加更多各种各样的指令,但这是个停下来的好地方。像它现在这样,我们有了一个不错的小虚拟机,好让我们能使用简单又可压缩的数据根式来定义相对可扩展的指令。虽然“字节码”和“虚拟机”听起来有点吓人,但你会发现它们往往简单到一个堆栈、一个循环或是一个switch语句。
396+
397+
还记得我们最初目标是让字节码得到很好的沙箱化?现在你看过虚拟机的整个实现过程,很明显我们已经做到了。字节码没法深入引擎的各个部分做有恶意的事情,因为我们只定义了少量访问引擎局部的指令。
398+
399+
我们通过控制堆栈尺寸来限制它的可用内存,我们要当心以免内存溢出。我们甚至可以限制它的执行时间。在指令循环中,我们可以记录已经执行了多久,在它超出某个时间限制时,将它取消掉。
400+
401+
> 限制执行时间在我们的例子中并非必要,因为我们没有任何循环指令。我们可以通过限制字节码的总尺寸来限制执行时间。这也意味着字节码并非图灵完备。
402+
403+
只剩下一个问题了:真正去创建字节码。眼下我们将一段伪代码编译成了字节码。除非你真的很闲,否则这在实践中根本行不通。
404+

0 commit comments

Comments
 (0)