LCOV - code coverage report
Current view: top level - core/wasm/exports - SPWasm.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 184 308 59.7 %
Date: 2024-05-12 00:16:13 Functions: 30 43 69.8 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "SPWasm.h"
      24             : 
      25             : #include "SPWasm-core.cc"
      26             : #include "SPWasm-filesystem.cc"
      27             : #include "SPWasm-data.cc"
      28             : 
      29             : namespace stappler::wasm {
      30             : 
      31             : static std::mutex s_loadMutex;
      32             : static Runtime *s_instance = nullptr;
      33             : 
      34             : struct Runtime::Data {
      35             :         bool enabled = false;
      36             : };
      37             : 
      38      112225 : static void *runtime_malloc(size_t size) {
      39      112225 :         return ::malloc(size);
      40             : }
      41             : 
      42       89275 : static void runtime_free(void *ptr) {
      43       89275 :         ::free(ptr);
      44       89275 : }
      45             : 
      46           0 : static void *runtime_realloc(void *ptr, size_t size) {
      47           0 :         return ::realloc(ptr, size);
      48             : }
      49             : 
      50         950 : static void StapplerWasmDebugPrint(wasm_exec_env_t exec_env, uint32_t ptr, uint32_t size) {
      51         950 :         auto mod = wasm_runtime_get_module_inst(exec_env);
      52         950 :         auto sptr = (const char *)wasm_runtime_addr_app_to_native(mod, ptr);
      53             : 
      54         950 :         log::debug("wasm::Runtime", StringView(sptr, size));
      55         950 : }
      56             : 
      57             : static NativeSymbol stapper_wasm_symbols[] = {
      58             :         NativeSymbol{"debug-print", (void *)&StapplerWasmDebugPrint, "(ii)", NULL},
      59             : };
      60             : 
      61             : static NativeModule s_wasmModule("stappler:wasm/wasm", stapper_wasm_symbols, sizeof(stapper_wasm_symbols) / sizeof(NativeSymbol));
      62             : 
      63          25 : Runtime *Runtime::getInstance() {
      64          25 :         std::unique_lock lock(s_loadMutex);
      65          25 :         if (!s_instance) {
      66          25 :                 s_instance = new Runtime;
      67             :         }
      68          25 :         return s_instance;
      69          25 : }
      70             : 
      71           0 : Runtime::~Runtime() {
      72           0 :         if (_data->enabled) {
      73           0 :                 wasm_runtime_destroy();
      74           0 :                 _data->enabled = false;
      75             :         }
      76           0 :         if (_data) {
      77           0 :                 delete _data;
      78           0 :                 _data = nullptr;
      79             :         }
      80           0 : }
      81             : 
      82             : struct RuntimeNativeStorage {
      83         275 :         static RuntimeNativeStorage *getInstance() {
      84         275 :                 static RuntimeNativeStorage s_instance;
      85         275 :                 return &s_instance;
      86             :         }
      87             : 
      88             :         Set<NativeModule *> s_nativeModules;
      89             : };
      90             : 
      91             : 
      92          25 : Runtime::Runtime() {
      93          25 :         _data = new Data;
      94             : 
      95             :         RuntimeInitArgs init_args;
      96          25 :         memset(&init_args, 0, sizeof(RuntimeInitArgs));
      97             : 
      98          25 :         init_args.mem_alloc_type = Alloc_With_Allocator;
      99          25 :         init_args.mem_alloc_option.allocator.malloc_func = (void *)&runtime_malloc;
     100          25 :         init_args.mem_alloc_option.allocator.realloc_func = (void *)&runtime_realloc;
     101          25 :         init_args.mem_alloc_option.allocator.free_func = (void *)&runtime_free;
     102             :         // init_args.mem_alloc_option.allocator.user_data = this;
     103             : 
     104          25 :         init_args.n_native_symbols = 0;
     105          25 :         init_args.native_module_name = "env";
     106          25 :         init_args.native_symbols = nullptr;
     107             : 
     108             : #ifdef WASM_DEBUG
     109             :         strcpy(init_args.ip_addr, "127.0.0.1");
     110             :         init_args.instance_port = 0;
     111             : #endif
     112             : 
     113             :         /* initialize runtime environment */
     114          25 :         if (wasm_runtime_full_init(&init_args)) {
     115          25 :                 _data->enabled = true;
     116             : 
     117         150 :                 for (auto &it : RuntimeNativeStorage::getInstance()->s_nativeModules) {
     118         125 :                         wasm_runtime_register_natives(it->name.data(), it->symbols, it->symbolsCount);
     119             :                 }
     120             :         }
     121          25 : }
     122             : 
     123         125 : NativeModule::NativeModule(StringView n, NativeSymbol *s, size_t count)
     124         125 : : name(n.str<Interface>()), symbols(s), symbolsCount(count) {
     125         125 :         RuntimeNativeStorage::getInstance()->s_nativeModules.emplace(this);
     126         125 : }
     127             : 
     128         125 : NativeModule::~NativeModule() {
     129         125 :         RuntimeNativeStorage::getInstance()->s_nativeModules.erase(this);
     130         125 : }
     131             : 
     132          50 : Module::~Module() {
     133          25 :         if (_module) {
     134          25 :                 wasm_runtime_unload(_module);
     135          25 :                 _module = nullptr;
     136             :         }
     137          50 : }
     138             : 
     139           0 : bool Module::init(StringView name, BytesView data) {
     140           0 :         char errorBuf[128] = { 0 };
     141             : 
     142           0 :         _runtime = Runtime::getInstance();
     143             : 
     144           0 :         _data = data.bytes<Interface>();
     145             : 
     146           0 :         auto mod = wasm_runtime_load(const_cast<uint8_t *>(_data.data()), static_cast<uint32_t>(_data.size()), errorBuf, sizeof(errorBuf));
     147           0 :         if (!mod) {
     148           0 :                 log::error("wasm::Module", "Fail to load module: ", errorBuf);
     149           0 :                 return false;
     150             :         }
     151             : 
     152           0 :         _name = name.str<Interface>();
     153           0 :         _module = mod;
     154             : 
     155           0 :         if (!wasm_runtime_register_module(_name.data(), _module, errorBuf, sizeof(errorBuf))) {
     156           0 :                 log::error("wasm::Module", "Fail to register module '", name, "': ", errorBuf);
     157           0 :                 return false;
     158             :         }
     159             : 
     160           0 :         return true;
     161             : }
     162             : 
     163           0 : bool Module::init(StringView name, Bytes &&data) {
     164           0 :         char errorBuf[128] = { 0 };
     165             : 
     166           0 :         _runtime = Runtime::getInstance();
     167             : 
     168           0 :         _data = move(data);
     169             : 
     170           0 :         auto mod = wasm_runtime_load(const_cast<uint8_t *>(_data.data()), static_cast<uint32_t>(_data.size()), errorBuf, sizeof(errorBuf));
     171           0 :         if (!mod) {
     172           0 :                 log::error("wasm::Module", "Fail to load module: ", errorBuf);
     173           0 :                 return false;
     174             :         }
     175             : 
     176           0 :         _name = name.str<Interface>();
     177           0 :         _module = mod;
     178             : 
     179           0 :         if (!wasm_runtime_register_module(_name.data(), _module, errorBuf, sizeof(errorBuf))) {
     180           0 :                 log::error("wasm::Module", "Fail to register module '", name, "': ", errorBuf);
     181           0 :                 return false;
     182             :         }
     183             : 
     184           0 :         return true;
     185             : }
     186             : 
     187          25 : bool Module::init(StringView name, FilePath path) {
     188          25 :         char errorBuf[128] = { 0 };
     189          25 :         _data = filesystem::readIntoMemory<Interface>(path.get());
     190             : 
     191          25 :         if (_data.empty()) {
     192           0 :                 log::error("wasm::Module", "Fail to open file: ", path.get());
     193           0 :                 return false;
     194             :         }
     195             : 
     196          25 :         _runtime = Runtime::getInstance();
     197             : 
     198          25 :         auto mod = wasm_runtime_load(const_cast<uint8_t *>(_data.data()), static_cast<uint32_t>(_data.size()), errorBuf, sizeof(errorBuf));
     199          25 :         if (!mod) {
     200           0 :                 log::error("wasm::Module", "Fail to load module '", path.get(), "': ", errorBuf);
     201           0 :                 return false;
     202             :         }
     203             : 
     204          25 :         _name = name.str<Interface>();
     205          25 :         _module = mod;
     206             : 
     207          25 :         if (!wasm_runtime_register_module(_name.data(), _module, errorBuf, sizeof(errorBuf))) {
     208           0 :                 log::error("wasm::Module", "Fail to register module '", path.get(), "': ", errorBuf);
     209           0 :                 return false;
     210             :         }
     211             : 
     212          25 :         return true;
     213             : }
     214             : 
     215          50 : ModuleInstance::~ModuleInstance() {
     216          25 :         if (_inst) {
     217         100 :                 for (auto &it : _handles) {
     218          75 :                         if (it.destructor) {
     219          25 :                                 it.destructor();
     220             :                         }
     221          75 :                         it.destructor = nullptr;
     222             :                 }
     223             : 
     224          25 :                 _handles.clear();
     225          25 :                 _objects.clear();
     226             : 
     227          25 :                 auto senv = wasm_runtime_get_exec_env_singleton(_inst);
     228          25 :                 if (senv && _finalize) {
     229          25 :                         wasm_runtime_call_wasm(senv, _finalize, 0, nullptr);
     230          25 :                         _finalize = nullptr;
     231             :                 }
     232          25 :                 wasm_runtime_deinstantiate(_inst);
     233          25 :                 _inst = nullptr;
     234             :         }
     235          50 : }
     236             : 
     237          25 : bool ModuleInstance::init(Module *mod, uint32_t stackSize, uint32_t heapSize) {
     238          25 :         char errorBuf[128] = { 0 };
     239          25 :         auto inst = wasm_runtime_instantiate(mod->getModule(), stackSize, heapSize, errorBuf, sizeof(errorBuf));
     240             :         /* instantiate the module */
     241          25 :         if (!inst) {
     242           0 :                 log::error("wasm::Module", "Fail to instantiate module '", mod->getName(), "': ", errorBuf);
     243           0 :                 return false;
     244             :         }
     245             : 
     246          25 :         _inst = inst;
     247          25 :         _module = mod;
     248             : 
     249          25 :         auto senv = wasm_runtime_get_exec_env_singleton(_inst);
     250          25 :         auto env = Rc<ExecEnv>::create(this, senv);
     251             : 
     252          25 :         auto realloc = Rc<ExecFunction>::create(this, "realloc");
     253          25 :         if (realloc && realloc->getNumArgs() == 2 && realloc->getNumResults() == 1) {
     254          25 :                 _realloc = realloc->getFunc();
     255             :         }
     256             : 
     257          25 :         _selfHandle = addHandle(this, [] { });
     258             : 
     259             :         // search for _start
     260          25 :         auto initialize = Rc<ExecFunction>::create(this, "_initialize");
     261             :         // search for _initialize
     262          25 :         if (initialize) {
     263          25 :                 if (initialize->getName() != "_initialize") {
     264             :                         // component-named _initialize, try stappler_initialize first
     265           0 :                         auto stapplerInitialize = Rc<ExecFunction>::create(this, "initialize");
     266           0 :                         if (stapplerInitialize) {
     267           0 :                                 stapplerInitialize->call(env);
     268             :                         } else {
     269           0 :                                 initialize->call(env);
     270             :                         }
     271           0 :                 }
     272             :         } else {
     273           0 :                 auto start = Rc<ExecFunction>::create(this, "_start");
     274           0 :                 if (start) {
     275             :                         // assume WASI command module
     276           0 :                         return true;
     277             :                 }
     278           0 :         }
     279             : 
     280          25 :         auto fin = Rc<ExecFunction>::create(this, "_finalize");
     281          25 :         if (fin && fin->getNumArgs() == 0 && fin->getNumResults() == 0) {
     282          25 :                 _finalize = fin->getFunc();
     283             :         }
     284             : 
     285          25 :         _handles.reserve(16);
     286             : 
     287          25 :         return true;
     288          25 : }
     289             : 
     290         375 : void *ModuleInstance::appToNative(uint32_t offset) const {
     291         375 :         return wasm_runtime_addr_app_to_native(_inst, offset);
     292             : }
     293             : 
     294           0 : uint32_t ModuleInstance::nativeToApp(void *ptr) const {
     295           0 :         return wasm_runtime_addr_native_to_app(_inst, ptr);
     296             : }
     297             : 
     298         450 : uint32_t ModuleInstance::allocate(uint32_t size, void **ptr) {
     299         450 :         return wasm_runtime_module_malloc(_inst, size, ptr);
     300             : }
     301             : 
     302           0 : uint32_t ModuleInstance::reallocate(uint32_t offset, uint32_t size, void **ptr) {
     303           0 :         if (_realloc) {
     304             :                 uint32_t args[] = {
     305             :                         offset, size
     306           0 :                 };
     307             : 
     308           0 :                 auto senv = wasm_runtime_get_exec_env_singleton(_inst);
     309             : 
     310           0 :                 if (wasm_runtime_call_wasm(senv, _realloc, 2, args)) {
     311           0 :                         if (ptr) {
     312           0 :                                 *ptr = appToNative(args[0]);
     313             :                         }
     314           0 :                         return args[0];
     315             :                 }
     316             :         }
     317             : 
     318           0 :         wasm_runtime_module_free(_inst, offset);
     319           0 :         return wasm_runtime_module_malloc(_inst, size, ptr);
     320             : }
     321             : 
     322         150 : void ModuleInstance::free(uint32_t ptr) {
     323         150 :         wasm_runtime_module_free(_inst, ptr);
     324         150 : }
     325             : 
     326          25 : Rc<ExecFunction> ModuleInstance::lookup(StringView name) {
     327          50 :         return Rc<ExecFunction>::create(this, name);
     328             : }
     329             : 
     330           0 : uint32_t ModuleInstance::getHandle(void *obj) const {
     331           0 :         auto it = _objects.find(obj);
     332           0 :         if (it != _objects.end()) {
     333           0 :                 return it->second;
     334             :         }
     335           0 :         return InvalidHandle;
     336             : }
     337             : 
     338          75 : void ModuleInstance::removeHandle(uint32_t idx) {
     339          75 :         if (idx >= _handles.size()) {
     340           0 :                 return;
     341             :         }
     342             : 
     343          75 :         auto &slot = _handles.at(idx);
     344          75 :         if (slot.object) {
     345          75 :                 _objects.erase(slot.object);
     346          75 :                 if (slot.destructor) {
     347          50 :                         slot.destructor();
     348          50 :                         slot.destructor = nullptr;
     349             :                 }
     350          75 :                 slot.nextIndex = _freeHandleSlot;
     351          75 :                 slot.object = nullptr;
     352             : 
     353          75 :                 _freeHandleSlot = slot.index;
     354             :         }
     355             : }
     356             : 
     357          25 : void ModuleInstance::removeObject(void *obj) {
     358          25 :         auto it = _objects.find(obj);
     359          25 :         if (it != _objects.end()) {
     360          25 :                 removeHandle(it->second);
     361             :         }
     362          25 : }
     363             : 
     364         100 : uint32_t ModuleInstance::addHandleObject(void *obj, std::type_index &&idx, Function<void()> &&cb) {
     365         100 :         if (!obj) {
     366           0 :                 return InvalidHandle;
     367             :         }
     368             : 
     369         100 :         HandleSlot *slot = nullptr;
     370         100 :         if (_freeHandleSlot != InvalidHandle) {
     371          25 :                 slot = &_handles.at(_freeHandleSlot);
     372          25 :                 _freeHandleSlot = slot->nextIndex;
     373          25 :                 slot->nextIndex = InvalidHandle;
     374             :         } else {
     375          75 :                 slot = &_handles.emplace_back(HandleSlot());
     376          75 :                 slot->index = _handles.size() - 1;
     377             :         }
     378             : 
     379         100 :         slot->object = obj;
     380         100 :         slot->type = move(idx);
     381         100 :         slot->destructor = move(cb);
     382             : 
     383         100 :         _objects.emplace(obj, slot->index);
     384         100 :         return slot->index;
     385             : }
     386             : 
     387           0 : uint32_t ModuleInstance::getHandleObject(void *obj, const std::type_index &type) const {
     388           0 :         auto it = _objects.find(obj);
     389           0 :         if (it != _objects.end()) {
     390           0 :                 uint32_t idx = it->second;
     391           0 :                 if (_handles[idx].type == type) {
     392           0 :                         return idx;
     393             :                 }
     394             :         }
     395           0 :         return InvalidHandle;
     396             : }
     397             : 
     398         275 : void *ModuleInstance::getObjectHandle(uint32_t idx, const std::type_index &type) const {
     399         275 :         if (idx >= _handles.size()) {
     400           0 :                 return nullptr;
     401             :         }
     402             : 
     403         275 :         auto &slot = _handles.at(idx);
     404         275 :         if (slot.type == type) {
     405         275 :                 return slot.object;
     406             :         }
     407             : 
     408           0 :         return nullptr;
     409             : }
     410             : 
     411         525 : ExecEnv *ExecEnv::get(wasm_exec_env_t env) {
     412         525 :         return reinterpret_cast<ExecEnv *>(wasm_runtime_get_user_data(env));
     413             : }
     414             : 
     415         100 : ExecEnv::~ExecEnv() {
     416          50 :         if (_env) {
     417          50 :                 if (_isSingleton) {
     418          25 :                         wasm_runtime_set_user_data(_env, nullptr);
     419             :                 } else {
     420          25 :                         wasm_runtime_destroy_exec_env(_env);
     421             :                 }
     422          50 :                 _env = nullptr;
     423             :         }
     424         100 : }
     425             : 
     426          25 : bool ExecEnv::init(ModuleInstance *inst, uint32_t stackSize) {
     427          25 :         auto env = wasm_runtime_create_exec_env(inst->getInstance(), stackSize);
     428             :         /* create an execution env */
     429          25 :         if (!env) {
     430           0 :                 log::error("wasm::Module", "Fail to create exec env for '", inst->getModule()->getName(), "' instance");
     431           0 :                 return false;
     432             :         }
     433             : 
     434          25 :         _env = env;
     435          25 :         _instance = inst;
     436             : 
     437          25 :         wasm_runtime_set_user_data(_env, this);
     438             : 
     439             : #ifdef WASM_DEBUG
     440             :         auto debugEnv = ::getenv("WASM_DEBUG");
     441             :         if (debugEnv) {
     442             :                 auto port = wasm_runtime_start_debug_instance(env);
     443             :                 log::info("wasm::Runtime", "start debug server with port ", port, "; Wait for debugger connection...");
     444             :         }
     445             : #endif
     446             : 
     447          25 :         return true;
     448             : }
     449             : 
     450          25 : bool ExecEnv::init(ModuleInstance *inst, wasm_exec_env_t env) {
     451          25 :         if (wasm_runtime_get_user_data(env)) {
     452           0 :                 log::warn("wasm::Module", "Userdata is not empty for '", inst->getModule()->getName(), "' instance env, it will be lost");
     453             :         }
     454             : 
     455          25 :         _env = env;
     456          25 :         _instance = inst;
     457          25 :         _isSingleton = true;
     458             : 
     459          25 :         wasm_runtime_set_user_data(_env, this);
     460             : 
     461          25 :         return true;
     462             : }
     463             : 
     464           0 : uint32_t ExecEnv::nativeToApp(void *ptr) const {
     465           0 :         return _instance->nativeToApp(ptr);
     466             : }
     467             : 
     468           0 : bool ExecEnv::callIndirect(uint32_t fn, uint32_t argc, uint32_t argv[]) {
     469           0 :         return wasm_runtime_call_indirect(_env, fn, argc, argv);
     470             : }
     471             : 
     472         100 : bool ExecFunction::init(ModuleInstance *inst, StringView name) {
     473             :         // search not prefixed version first
     474         100 :         _name = name.str<Interface>();
     475             : 
     476         100 :         auto fn = wasm_runtime_lookup_function(inst->getInstance(), _name.data(), NULL);
     477         100 :         if (!fn) {
     478          25 :                 _name = toString(inst->getModule()->getName(), "#", name);
     479             :                 // search module-prefixed
     480          25 :                 fn = wasm_runtime_lookup_function(inst->getInstance(), _name.data(), NULL);
     481             :         }
     482             : 
     483         100 :         if (!fn) {
     484           0 :                 log::warn("wasm::ExecFunction", "Fail to lookup function '", name, "' in module '", inst->getModule()->getName(), "'");
     485           0 :                 return false;
     486             :         }
     487             : 
     488         100 :         _func = fn;
     489         100 :         _inst = inst;
     490         100 :         _nArgs = wasm_func_get_param_count(_func, _inst->getInstance());
     491         100 :         _nResults = wasm_func_get_result_count(_func, _inst->getInstance());
     492             : 
     493         100 :         if (_nArgs > StaticArgumentsLimit) {
     494           0 :                 log::warn("wasm::ExecFunction", "Too many arguments for '", _name, "' in module '", inst->getModule()->getName(), "'");
     495             :         } else {
     496         100 :                 wasm_func_get_param_types(_func, _inst->getInstance(), _argTypesStatic);
     497             :         }
     498             : 
     499         100 :         if (_nResults > StaticResultsLimit) {
     500           0 :                 log::warn("wasm::ExecFunction", "Too many results for '", _name, "' in module '", inst->getModule()->getName(), "'");
     501             :         } else {
     502         100 :                 wasm_func_get_result_types(_func, _inst->getInstance(), _resultTypesStatic);
     503             :         }
     504             : 
     505         100 :         return true;
     506             : }
     507             : 
     508           0 : Vector<wasm_valkind_t> ExecFunction::getArgsFull() const {
     509           0 :         Vector<wasm_valkind_t> ret; ret.resize(_nArgs);
     510           0 :         wasm_func_get_param_types(_func, _inst->getInstance(), ret.data());
     511           0 :         return ret;
     512           0 : }
     513             : 
     514           0 : Vector<wasm_valkind_t> ExecFunction::getResultsFull() const {
     515           0 :         Vector<wasm_valkind_t> ret; ret.resize(_nResults);
     516           0 :         wasm_func_get_result_types(_func, _inst->getInstance(), ret.data());
     517           0 :         return ret;
     518           0 : }
     519             : 
     520           0 : bool ExecFunction::call(ExecEnv *env, SpanView<wasm_val_t> args, VectorAdapter<wasm_val_t> *results) const {
     521           0 :         if (args.size() != _nArgs) {
     522           0 :                 log::warn("wasm::ExecFunction", "Wrong number of arguments for '", _name, "' from module '", _inst->getModule()->getName(), "'");
     523             :         }
     524             : 
     525           0 :         bool ret = false;
     526           0 :         if (results) {
     527           0 :                 results->resize(_nResults);
     528           0 :                 ret = wasm_runtime_call_wasm_a(env->getEnv(), _func, _nResults, results->begin(), args.size(), const_cast<wasm_val_t *>(args.data()));
     529             :         } else {
     530           0 :                 if (_nResults) {
     531           0 :                         log::warn("wasm::ExecFunction", "Results buffer was not provided for call of '", _name, "' from module '", _inst->getModule()->getName(), "'");
     532             :                 }
     533           0 :                 ret = wasm_runtime_call_wasm_a(env->getEnv(), _func, 0, nullptr, args.size(), const_cast<wasm_val_t *>(args.data()));
     534             :         }
     535             : 
     536           0 :         if (!ret) {
     537           0 :                 auto ex = wasm_runtime_get_exception(_inst->getInstance());
     538           0 :                 if (ex) {
     539           0 :                         log::error("wasm::ExecFunction", "Exception when call '", _name, "' from module '", _inst->getModule()->getName(), "': ", ex);
     540             :                 }
     541             :         }
     542             : 
     543           0 :         return false;
     544             : }
     545             : 
     546          25 : wasm_val_t ExecFunction::call1(ExecEnv *env, SpanView<wasm_val_t> args) const {
     547          25 :         if (args.size() != _nArgs) {
     548           0 :                 log::warn("wasm::ExecFunction", "Wrong number of arguments for '", _name, "' from module '", _inst->getModule()->getName(), "'");
     549             :         }
     550             : 
     551             :         wasm_val_t ret;
     552          25 :         ret.kind = WASM_ANYREF;
     553          25 :         ret.of.foreign = 0;
     554             : 
     555          25 :         if (_nResults != 1) {
     556           0 :                 log::warn("wasm::ExecFunction", "Function '", _name, "' from module '", _inst->getModule()->getName(), "' called as single-argument function");
     557             :         }
     558          25 :         auto success = wasm_runtime_call_wasm_a(env->getEnv(), _func, 1, &ret, args.size(), const_cast<wasm_val_t *>(args.data()));
     559          25 :         if (!success) {
     560           0 :                 auto ex = wasm_runtime_get_exception(_inst->getInstance());
     561           0 :                 if (ex) {
     562           0 :                         log::error("wasm::ExecFunction", "Exception when call '", _name, "' from module '", _inst->getModule()->getName(), "': ", ex);
     563             :                 }
     564             :         }
     565          25 :         return ret;
     566             : }
     567             : 
     568             : }

Generated by: LCOV version 1.14