blob: c3691f681d1233715a06efd7599baa0dc37ce4e4 [file]
#ifdef WITH_RIVE_SCRIPTING_WASM
#include "rive/wasm/wamr_state_transplant.hpp"
// The one TU reading wamr instance internals; runtime builds compile it
// empty and use the header's inline stub.
#ifdef RIVE_WASM_TIER_LADDER
#include "aot_runtime.h"
#include "wasm_runtime.h"
#include <cstring>
#include <vector>
namespace rive
{
namespace
{
struct GlobalRef
{
uint8_t type = 0;
uint32_t offset = 0;
};
static size_t globalSize(uint8_t type)
{
switch (type)
{
case VALUE_TYPE_I32:
case VALUE_TYPE_F32:
return 4;
case VALUE_TYPE_I64:
case VALUE_TYPE_F64:
return 8;
#if WASM_ENABLE_SIMD != 0 || WASM_ENABLE_SIMDE != 0
case VALUE_TYPE_V128:
return 16;
#endif
default:
return 0;
}
}
// The two representations agree on the wasm's global index space but not on
// data offsets: the interp loader assigns natural-size offsets at load, the
// aot compiler assigns its own at compile. Enumerate through each side's own
// metadata.
static bool collectGlobals(WASMModuleInstance* inst,
std::vector<GlobalRef>& out,
std::string& error)
{
if (inst->module_type == Wasm_Module_Bytecode)
{
WASMModuleInstanceExtra* extra = (WASMModuleInstanceExtra*)inst->e;
for (uint32_t i = 0; i < extra->global_count; i++)
{
out.push_back(
{extra->globals[i].type, extra->globals[i].data_offset});
}
return true;
}
if (inst->module_type == Wasm_Module_AoT)
{
AOTModule* module = (AOTModule*)((AOTModuleInstance*)inst)->module;
for (uint32_t i = 0; i < module->import_global_count; i++)
{
out.push_back({module->import_globals[i].type.val_type,
module->import_globals[i].data_offset});
}
for (uint32_t i = 0; i < module->global_count; i++)
{
out.push_back({module->globals[i].type.val_type,
module->globals[i].data_offset});
}
return true;
}
error = "unknown module representation";
return false;
}
} // namespace
bool wamrTransplantState(wasm_module_inst_t source,
wasm_module_inst_t destination,
std::string& error)
{
WASMModuleInstance* src = (WASMModuleInstance*)source;
WASMModuleInstance* dst = (WASMModuleInstance*)destination;
// Memories: grow the fresh instance up to the source's live size, then
// copy bytes.
if (src->memory_count != dst->memory_count)
{
error = "memory count mismatch";
return false;
}
for (uint32_t i = 0; i < src->memory_count; i++)
{
WASMMemoryInstance* srcMem = src->memories[i];
WASMMemoryInstance* dstMem = dst->memories[i];
if (srcMem->cur_page_count > dstMem->cur_page_count)
{
if (!wasm_runtime_enlarge_memory(destination,
srcMem->cur_page_count -
dstMem->cur_page_count))
{
error = "destination memory grow failed";
return false;
}
// Growth may reallocate the instance's memory table entry.
dstMem = dst->memories[i];
}
if (dstMem->memory_data_size < srcMem->memory_data_size)
{
error = "destination memory smaller than source after grow";
return false;
}
memcpy(dstMem->memory_data,
srcMem->memory_data,
srcMem->memory_data_size);
}
// Globals: per-global typed copy through each side's own offsets.
std::vector<GlobalRef> srcGlobals;
std::vector<GlobalRef> dstGlobals;
if (!collectGlobals(src, srcGlobals, error) ||
!collectGlobals(dst, dstGlobals, error))
{
return false;
}
if (srcGlobals.size() != dstGlobals.size())
{
error = "global count mismatch";
return false;
}
for (size_t i = 0; i < srcGlobals.size(); i++)
{
if (srcGlobals[i].type != dstGlobals[i].type)
{
error = "global type mismatch";
return false;
}
size_t size = globalSize(srcGlobals[i].type);
if (size == 0)
{
error = "unsupported global type";
return false;
}
memcpy(dst->global_data + dstGlobals[i].offset,
src->global_data + srcGlobals[i].offset,
size);
}
// Tables: entries are function indexes in both representations (non-GC
// builds), so index copy is representation-neutral.
if (src->table_count != dst->table_count)
{
error = "table count mismatch";
return false;
}
for (uint32_t i = 0; i < src->table_count; i++)
{
WASMTableInstance* srcTable = src->tables[i];
WASMTableInstance* dstTable = dst->tables[i];
if (dstTable->cur_size < srcTable->cur_size)
{
error = "destination table smaller than source";
return false;
}
memcpy(dstTable->elems,
srcTable->elems,
sizeof(table_elem_type_t) * srcTable->cur_size);
}
return true;
}
} // namespace rive
#endif // RIVE_WASM_TIER_LADDER
#endif // WITH_RIVE_SCRIPTING_WASM