@@ -130,6 +130,35 @@ class Flow {
130130 }
131131};
132132
133+ struct FuncData {
134+ // Name of the function in the module.
135+ Name name;
136+
137+ // The interpreter instance we are in. This is only used for equality
138+ // comparisons, as two functions are equal iff they have the same name and are
139+ // in the same instance (in particular, we do *not* compare the |call| field
140+ // below, which is an execution detail).
141+ void * self;
142+
143+ // A way to execute this function. We use this when it is called.
144+ using Call = std::function<Flow(Literals)>;
145+ std::optional<Call> call;
146+
147+ FuncData (Name name,
148+ void * self = nullptr ,
149+ std::optional<Call> call = std::nullopt )
150+ : name(name), self(self), call(call) {}
151+
152+ bool operator ==(const FuncData& other) const {
153+ return name == other.name && self == other.self ;
154+ }
155+
156+ Flow doCall (Literals arguments) {
157+ assert (call);
158+ return (*call)(arguments);
159+ }
160+ };
161+
133162// Suspend/resume support.
134163//
135164// As we operate directly on our structured IR, we do not have a program counter
@@ -277,6 +306,16 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
277306 Execute,
278307 };
279308
309+ Literal makeFuncData (Name name, HeapType type) {
310+ // Identify the interpreter, but do not provide a way to actually call the
311+ // function.
312+ auto allocation = std::make_shared<FuncData>(name, this );
313+ #if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer)
314+ __lsan_ignore_object (allocation.get ());
315+ #endif
316+ return Literal (allocation, type);
317+ }
318+
280319protected:
281320 RelaxedBehavior relaxedBehavior = RelaxedBehavior::NonConstant;
282321
@@ -1801,7 +1840,7 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
18011840 return Literal (int32_t (value.isNull ()));
18021841 }
18031842 Flow visitRefFunc (RefFunc* curr) {
1804- return Literal::makeFunc (curr->func , curr->type .getHeapType ());
1843+ return self ()-> makeFuncData (curr->func , curr->type .getHeapType ());
18051844 }
18061845 Flow visitRefEq (RefEq* curr) {
18071846 Flow flow = visit (curr->left );
@@ -3545,7 +3584,7 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
35453584 if (curr->isReturn ) {
35463585 // Return calls are represented by their arguments followed by a reference
35473586 // to the function to be called.
3548- arguments.push_back (Literal::makeFunc (target, funcType));
3587+ arguments.push_back (self ()-> makeFuncData (target, funcType));
35493588 return Flow (RETURN_CALL_FLOW, std::move (arguments));
35503589 }
35513590
@@ -3651,7 +3690,7 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
36513690 std::cout << self ()->indent () << " (calling ref " << targetRef.getFunc ()
36523691 << " )\n " ;
36533692#endif
3654- Flow ret = callFunction ( targetRef.getFunc (), arguments);
3693+ Flow ret = targetRef.getFuncData ()-> doCall ( arguments);
36553694#if WASM_INTERPRETER_DEBUG
36563695 std::cout << self ()->indent () << " (returned to " << scope->function ->name
36573696 << " )\n " ;
@@ -5057,6 +5096,19 @@ class ModuleRunner : public ModuleRunnerBase<ModuleRunner> {
50575096 ExternalInterface* externalInterface,
50585097 std::map<Name, std::shared_ptr<ModuleRunner>> linkedInstances = {})
50595098 : ModuleRunnerBase(wasm, externalInterface, linkedInstances) {}
5099+
5100+ Literal makeFuncData (Name name, HeapType type) {
5101+ // As the super's |makeFuncData|, but here we also provide a way to
5102+ // actually call the function.
5103+ auto allocation =
5104+ std::make_shared<FuncData>(name, this , [this , name](Literals arguments) {
5105+ return callFunction (name, arguments);
5106+ });
5107+ #if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer)
5108+ __lsan_ignore_object (allocation.get ());
5109+ #endif
5110+ return Literal (allocation, type);
5111+ }
50605112};
50615113
50625114} // namespace wasm
0 commit comments