Во-первых, чтобы это не выглядело как проблема XYZ, я хотел бы дать некоторый контекст (обратите внимание, что я не использую Emscripten):
Я пытаюсь понять, смогу ли я реализовать некую форму горячей перезагрузки для программ Wasm, написанных на C ++, размещенных в Интернете. Для этого мне нужен раздел памяти, который я называю своим «мировым состоянием» (для всех, кто смотрел Handmadehero.org/" rel="nofollow noreferrer"> https://handmadehero.org/), это будет вам знакомо):
struct State {
// put everything here
} state;
Обычно для полной программы C ++ со слоем платформы вы выделяете эту структуру на стороне платформы и передаете указатель на эту память через указатель функции в перезагружаемой части кода / dll / dylib. Перезагружаемый код помещает ВСЕ в эту постоянную память, поэтому, если код необходимо перекомпилировать и перезагрузить, все состояние будет продолжать существовать, поскольку память была выделена в той части программы, которая не была перезагружена. Насколько я могу судить, в Wasm это невозможно. Во-первых, верно ли мое предположение, что я должен использовать WebAssembly.Memory? - или я могу выделить uint8array в js и использовать его для своего постоянного состояния отдельно от программной памяти? Если да, то это медленнее?
Так что это будет работать до тех пор, пока я не использую динамический распределитель, такой как WASI, а вместо этого использую распределитель push, которым я могу управлять. (Я думаю, это потому, что, предположим, я использую malloc для получения адресов памяти и перезагрузки - внутреннее состояние malloc будет перезагружено и будет думать, что вся память кучи доступна, когда ее нет, поэтому будущие выделения могут затмить предыдущие.) После перезагрузки я могу сначала скопируйте структуру во временный буфер на стороне js, перезагрузите, получите местоположение структуры в памяти из Wasm (мне потребуется, чтобы она существовала) и скопируйте сохраненную память из js обратно в позицию.
Однако это развалится, если я использую указатели, потому что, если я изменю программу (в этом суть) __data_end
может измениться, что приведет к смещению всех адресов! Я проверил флаги компоновщика здесь https://lld.llvm.org/WebAssembly.html, чтобы посмотреть, что я могу контролировать. Я могу указать, что стек идет перед сегментом данных, но куча все равно будет после этого, что приводит к той же проблеме. Я также могу указать, где расположены глобальные данные, но я считаю, что это не тот сегмент данных, поэтому сегмент данных переменного размера может по-прежнему компенсировать все мои адреса. Вот хорошая страница, которая может помочь нам визуализировать память Wasm: https://dassur.ma/things/c-to-webassembly/
Есть ли у кого-нибудь мысли о том, как добиться того, чего я хочу? Единственные варианты, о которых я могу думать, включают использование памяти вне памяти Wasm (возможно, более медленное или невозможное), с использованием только стековой памяти и без указателей (нереально, если я не могу автоматически пересчитать все смещения указателей после перекомпиляции, что было бы болезненно и ошибочно -prone) или найти способ сделать так, чтобы сегмент данных шел после стека и кучи по фиксированному адресу, что тогда гарантировало бы, что сегменты стека и кучи не будут смещены, если сегмент данных должен расти. Другой вариант, если это возможно, - исправить максимальный размер сегмента данных. Спецификация / документация Wasm не очень хороша, когда дело доходит до подобного рода манипуляций с памятью, поэтому я также был бы признателен за некоторые пояснения относительно того, что возможно. Наконец, может быть, я мог бы использовать два модуля Wasm (но разве такое косвенное обращение не будет медленным)? Возможно, мне не хватает чего-то важного, связанного с разметкой памяти.
Пожалуйста, дайте мне знать, если вам понадобится дополнительная информация. Как я уже упоминал, я уже делал что-то подобное на C, и это обычная техника быстрой итерационной разработки игр. В основном я пытаюсь воссоздать это в Wasm.
РЕДАКТИРОВАТЬ: По-видимому, вы можете напрямую вызывать функции Wasm из другого модуля. Во-первых, как вы это делаете, а во-вторых, каковы будут характеристики производительности для доступа к памяти другого модуля?
EDIT2: Может быть, какая-то форма динамического связывания, если она поддерживается? https://webassembly.org/docs/dynamic-linking/