Memory Wasm热重新加载实验:消除假设,以及如何指定数据部分的位置?

Memory Wasm热重新加载实验:消除假设,以及如何指定数据部分的位置?,memory,linker,webassembly,hot-reload,Memory,Linker,Webassembly,Hot Reload,首先,为了避免让这看起来像一个XYZ问题,我想给出一些上下文(注意,我没有使用Emscripten): 我想看看我是否可以实现一个以C++为基础编写的WASM程序的热重新加载形式,它是在Web上托管的。为了做到这一点,我希望有一段我称之为“世界状态”的记忆(对于看过《手工英雄》的人来说,这将是熟悉的): 典型地,对于具有平台层的完全C++程序,您将在平台侧分配该结构,并通过代码的可加载/DLL/DyLIB部分中的函数指针向该内存提供指针。可重新加载的代码将所有内容都放入这个持久内存中,因此如果代

首先,为了避免让这看起来像一个XYZ问题,我想给出一些上下文(注意,我没有使用Emscripten):

<>我想看看我是否可以实现一个以C++为基础编写的WASM程序的热重新加载形式,它是在Web上托管的。为了做到这一点,我希望有一段我称之为“世界状态”的记忆(对于看过《手工英雄》的人来说,这将是熟悉的):

典型地,对于具有平台层的完全C++程序,您将在平台侧分配该结构,并通过代码的可加载/DLL/DyLIB部分中的函数指针向该内存提供指针。可重新加载的代码将所有内容都放入这个持久内存中,因此如果代码需要重新编译和重新加载,那么所有状态都将继续存在,因为内存是在程序中未重新加载的部分分配的。据我所知,这在Wasm是不可能的。 首先,我必须使用WebAssembly.Memory的假设正确吗--或者我可以在js中分配一个uint8array,并将其用于持久状态,与程序内存分离吗?如果是这样的话,速度会慢吗

因此,只要我不使用像WASI这样的动态分配器,而是使用我可以控制的推式分配器,这就行了。(我这样认为是因为,假设我使用malloc获取内存地址并重新加载——malloc的内部状态将重新加载,并认为所有堆内存在不可用时都是可用的,因此将来的分配可能会比以前的分配更有效。) 重新加载后,我可以首先将结构复制到js端的临时缓冲区中,重新加载,从Wasm获取结构的内存位置(我将要求它存在),然后将保存的内存从js复制回原来的位置

但是,如果我使用指针,这会出现问题,因为如果我更改程序(即点)
\uu data\u end
可能会更改,这将偏移所有地址!我检查了这里的链接器标志,看看我能控制什么。我可以指定堆栈位于数据段之前,但堆仍然位于数据段之后,这会导致相同的问题。我还可以指定全局数据的位置,但我认为这不是数据段,因此可变大小的数据段仍然可以偏移我的所有地址。 这是一个很好的页面,可以帮助我们可视化Wasm内存:

有人会想到如何实现我想要的吗?我能想到的唯一选项包括以某种方式使用Wasm内存之外的内存(可能较慢或不可能),只使用堆栈内存而不使用指针(不现实,除非我可以在重新编译后自动重新计算所有指针偏移量,这将是痛苦和容易出现错误的),或者找到一种方法使数据段位于堆栈和堆之后的固定地址,这样可以保证如果数据段需要增长,堆栈和堆段不会得到偏移。如果可能的话,另一个选择是固定数据段的最大大小。当涉及到这样的内存操作时,Wasm规范/文档并不是很好,所以我也希望能澄清一下可能的情况。最后,也许我可以使用两个Wasm模块(但这种间接寻址不是很慢吗)?我可能遗漏了一些与内存布局相关的重要信息

如果你需要更多的细节,请告诉我。正如我提到的,我以前在C中做过类似的事情,这是一种常见的快速迭代游戏开发技术。基本上,我想在Wasm中重现它

编辑:显然,您可以直接从另一个模块调用Wasm函数。首先,您是如何做到这一点的,其次,访问另一个模块的内存的性能特征是什么


EDIT2:如果支持的话,可能是某种形式的动态链接

WebAssembly模块在三个不同的位置保存变量状态:

  • 线性存储器
  • 与执行堆栈关联的局部变量
  • 全局变量
其中,主机环境只能访问全局变量和线性内存,并且可能是可序列化的,以便在热重新加载模块时缓存它们。当然,没有办法直接访问和存储当前调用堆栈


如果我想实现这一点,我会在WebAssembly中创建自己的状态机,将其存储在线性内存中的已知位置。

WebAssembly模块在三个不同的位置保存变量状态:

  • 线性存储器
  • 与执行堆栈关联的局部变量
  • 全局变量
其中,主机环境只能访问全局变量和线性内存,并且可能是可序列化的,以便在热重新加载模块时缓存它们。当然,没有办法直接访问和存储当前调用堆栈


如果我想实现这一点,我会在WebAssembly中创建自己的状态机,将其存储在线性内存中的已知位置。

Wasm被组织成模块,模块定义了四种相关的实体:函数、内存、表和全局。代码在函数中,而其他三个表示模块的状态

现在,有趣的是,这四种实体类型都可以导入和导出。此外,它们都可以在模块外部创建,例如通过JSAPI创建

因此,模拟代码交换的一种方法是设置模块,以便在外部创建所有三个状态并将其导入模块。这样,您可以在外部保持它们的活动状态,并在可用时将它们传递给升级的模块。(您还需要确保升级后的模块不会以覆盖先前存在状态的方式使用数据/元素段或启动函数。)

当然,这只有在升级之间模块状态的形状没有改变时才有效。例如,没有新的全局变量,没有新的全局变量
struct State {
// put everything here
} state;