Hi, I'm working on optimization of indirect calls [https://bugzilla.mozilla.org/show_bug.cgi?id=1639153] and happy to leave some comments about call_tags:
- let's talk about performance:
calls are efficient (just an additional push, pop, and bitwise equality check compared to a typed function call, which has been evaluated to produce no measurable overhead)
Well, right now it works as you described, with a few low-level details. So, we don't need call_tags here.
modules can restrict how their functions can be called indirectly (e.g. ensure no other module can indirectly call a particular function)
Yes, this is useful, there is an motivational example for C++ -> wasm:
class Base {
public:
virtual int foo() { return 1; }
};
class Derived : public Base {
public:
int foo() override { return 2; }
};
int Bar(Base* base) {
return base->foo();
}
The Bar
function will be compiled to call_indirect
and wasm engine can't optimize it because call_indirect
target can be from different instance or from js [https://godbolt.org/z/41M9rc8jK]. We can optimize this case via call-tags
or we can use private tables and do the same stuff via existing mechanism.
When an engine (let it be SpiderMonkey) populates the table with pointers it can deduce what this table is.
If the table has been created in the current module and it hasn't been exported than we can fill the table with raw pointers to the specified functions.
We don't need to switch instances in that case too and so, call_indirect
for this case can be as effective as simple call
+ signature check.
Since we can declare any number of tables we can restrict how our functions will be called via call_indirect
.
Could you clarify benefits of call-tags vs tables for this case? @RossTate
call_indirect $table $functype is simply the special case call_with_tag (call_tag.canon $functype) (table.get $table)
table.get $table
is really expensive one because we should create JS wrapper for that function as we don't now how we will use that reference - does it flow out to JS or stay in wasm realm?
BTW,
Looking at a function's definition alone, it's not apparent if a function can be indirectly called via call_indirect. One has to do some analysis to check if a reference to that function is made. And once a function reference has been made, it can be very difficult to ensure even something as simple as the function is only accessed by its own module.
In any case we need to track what function is referenced because we need to create some JS wrappers for that function, so this information is already available.