如何在字节码解释器中实现动态类型?

时间:2015-07-23 08:58:04

标签: interpreter dynamic-typing

我正在为一个dinamically类型的语言创建一个字节码解释器。例如,这个表达式:

2 + 3

将创建以下类似于程序集的输出(稍后编译为字节码):

iconst reg1, 2 ; Put integer 2 to register 1
iconst reg2, 3 ; Put integer 3 to register 2
iadd reg3, reg1, reg2 ; Add the 2 as integers from reg1 and 2 and put it into reg3

另一个例子是:

1 + 3.2

输出:

iconst reg1, 1
itof reg2, reg1 ; Convert integer to float and put it into reg2
fconst reg3, reg2
fadd reg4, reg2, reg3

所以每种类型都有它自己的运算符(fadd,iadd,也许悲伤......)。这意味着我需要知道编译类型的类型。在我有一个函数调用之前,这不是问题:

function foo(x, y):
    return x + y

foo()可以用整数,浮点数,甚至是混合调用。所以我无法在编译时为它生成正确的字节码。什么是最好的,所以它不会真正影响速度。使用所使用的参数类型生成函数是一个好策略吗?所以,如果这被调用:

foo(2, 3.2)

它会产生类似foo @ int,float()的东西。或者在运行时解决它是否更好?我能否在不影响性能的情况下做到这一点?怎么样? lua是怎么做到的?

对不起,如果这是重复的,也许我需要处理我的谷歌搜索技巧。

1 个答案:

答案 0 :(得分:2)

我可以想到几种方法来解决这个问题:

1 - 跟踪foo(x,y)的调用方式,并记录不同的函数签名。这可能会变得复杂,因为foo(x,y)可能会从bar(a,b)调用,而bar(a,b)可能会从baz(c,d)调用,依此类推。

解析完整个程序后,构建AST并遍历它以记录调用foo(x,y)的所有唯一签名,生成调用它的不同方式的代码。

你可能有:

foo(int, int)
foo(float, int)

这告诉您,您需要两个独特的foo(x,y)函数。

2 - 将操作码集更改为具有通用的add,sub,mul等操作码。然后,通用操作码必须在运行时确定其操作数的类型并适当地执行。这会慢一点,因为操作码现在必须检查操作数的类型,并根据它进行分支。

3 - 正如您所推测的那样,在实际调用函数之前,不要生成函数代码。这会慢一点,但仅限于所述函数的第一次调用。与(1)中一样,您仍然需要支持多个独特的功能签名,因此仍需要一些簿记。

我希望这有帮助!