我正在耕种TCL源代码,并在tclExecute.c中的宏NEXT_INST_F和NEXT_INST_V上感到困惑。具体来说就是宏的const fib = n => {
const alpha = 5**0.5
const beta = alpha / 2;
return (1 / alpha) * ((0.5 + beta) ** n - (0.5 - beta) ** n);
}
console.log(fib(10));
参数。
最初,我认为cleanup
表示从堆栈中消耗/弹出的插槽的净数量,例如当弹出3个对象并推入1个对象时,清理为2。
但是我看到cleanup
的{{1}}设置为1,难道不是因为弹出一个对象并推入1个对象而将其设置为零吗?
我迷失了NEXT_INST_F和NEXT_INST_V的代码,跳转太多了。
希望您可以为我澄清INST_LOAD_STK
的语义。
答案 0 :(得分:0)
NEXT_INST_F
和NEXT_INST_V
宏(在Tcl的字节码引擎的实现中)清除操作数堆栈的状态,并在转到下一条指令之前推送操作的结果。两者之间的唯一实际区别是,当要清理的堆栈位置的数目为常数时(从较小的范围:0、1和2开始,这是绝大多数情况),一个被设计为高效的。 ,另一种效率较低,但可以处理可变数量的位置进行清理,也可以处理范围较小的位置。因此,NEXT_INST_F
基本上是NEXT_INST_V
的优化版本。
在tclExecute.c中声明宏的地方有这样的说法:
/*
* The new macro for ending an instruction; note that a reasonable C-optimiser
* will resolve all branches at compile time. (result) is always a constant;
* the macro NEXT_INST_F handles constant (nCleanup), NEXT_INST_V is resolved
* at runtime for variable (nCleanup).
*
* ARGUMENTS:
* pcAdjustment: how much to increment pc
* nCleanup: how many objects to remove from the stack
* resultHandling: 0 indicates no object should be pushed on the stack;
* otherwise, push objResultPtr. If (result < 0), objResultPtr already
* has the correct reference count.
*
* We use the new compile-time assertions to check that nCleanup is constant
* and within range.
*/
但是,指令也可以直接操纵堆栈。这使事情变得非常复杂。 多数不会,但这与全部不同。如果您将这种特殊的代码负载视为一大堆特殊情况,那您就不会错了。
INST_LOAD_STK
(如果正在读取一些Tcl代码的反汇编,也称为loadStk
)是一项操作,该操作将从堆栈中弹出未解析的变量名称,并从该名称的变量中读取读取的值。 (否则将引发错误。)由于我们正在弹出(并减少引用计数)变量名值,然后推入并递增,因此完全可以期望弹出一个值并从objResultPtr
中推入另一个值。从变量读取的另一个值的引用计数。
读取和写入变量的代码是字节码引擎中最复杂的代码之一。 goto
远远超过对您的健康有益的物质。