摘要函数参数格式及其对性能的影响?

时间:2013-09-09 09:58:20

标签: c++ performance abstraction calling-convention vm-implementation

我正在开发一个VM,我希望能够调用已编译的函数。但是,因为每个函数可能最终都有不同的签名,我的计划是将所有调用一般化为2种可能的场景 - 调用函数而不返回且没有参数,以及调用函数需要一个void *参数。

计划与thiscall类似地使用它 - 所有参数都在传递指针的位置正确对齐,并通过间接检索参数。不应该比从堆栈中读取它们慢,至少是IMO。

所以而不是:

int foo(int a, int b) { return a+b; }

我可以有类似的东西:

void foo2(void *p) {
   *(int*)p = *(int*)(p + 4) + *(int*)(p + 8);
}

所以我的问题是使用这种方法可能会出现什么问题?我可以立刻知道它是“在黑暗中”工作,因此正确计算偏移量至关重要。这也有点不方便,因为所有临时工都需要由用户提供。假设我的VM编译器将处理这两个问题,我最关心的是性能 - 我不想创建一个普通的函数,并且对于每个普通函数一个void *包装器 - 我想直接使用该约定所有函数,所以我不禁想知道编译器在编译代码中使用函数时编译函数有多好?是否会有任何其他可能的性能影响我忽略(排除__fastcall将使用一个寄存器和一个更少的间接)?

2 个答案:

答案 0 :(得分:0)

性能方面(和易用性)你可能最好用cdecl - 一切都进入堆栈。 C标准允许您使用任意参数

指定函数原型
typedef void (__cdecl * function_with_any_parameters)();

您必须确保将您要调用的所有函数定义为:

void __cdecl f(type1 arg1, type2 arg2, type3 arg3); // any amount of arguments

只需使用适量的参数调用它们:

f(arg1, arg2, arg3, arg4);

如果你希望通过单个指针,那么你会有额外的开销:一个指针。最简单的方法是将所有函数定义为接受指向匿名结构的指针:

void f(struct {type1 a; type2 b;} * args);

然后,您可以使用指向相应结构的指针调用该函数,以避免任何错位。

struct {type1 a; type2 b;} args = {arg1, arg2};
f(&args);

您正在有效地实施cdecl

答案 1 :(得分:0)

在运行一些基准测试后,我会说编译器在优化类似的指针函数方面做得非常好。 void *函数与add函数和常规+运算符一样快。

似乎这个约定对于提供必要的调用抽象非常有用,而不会损害优化和整体性能。唯一的牺牲是安全,根据应用背景,这可能是也可能不是主要关注点。