Wasm Hot Reloading Experiment: предположения о разоблачении, и как указать, где находится раздел данных? - PullRequest
1 голос
/ 14 января 2020

Во-первых, чтобы не показалось, что это проблема XYZ, я хотел бы дать некоторый контекст (заметьте, я не использую Emscripten):

Я пытаюсь выяснить, могу ли я реализовать форму горячая перезагрузка для программ Wasm, написанных на C ++, размещенных в сети. Для этого я хочу иметь раздел памяти, который я называю своим «состоянием мира» (всем, кто смотрел Handmade Hero (https://handmadehero.org/), это будет знакомо):

struct State {
// put everything here
} state;

Обычно для полной программы на C ++ с уровнем платформы вы размещаете эту структуру на стороне платформы и передаете указатель на эту память через указатель на функцию в части кода reloadable / dll / dylib. Перезагружаемый код помещает ВСЕ в эту постоянную память, поэтому, если код необходимо перекомпилировать и перезагрузить, все состояние будет продолжать существовать, поскольку память была выделена в той части программы, которая не была перезагружена. Насколько я могу судить, в Wasm это невозможно. Во-первых, верно ли мое предположение, что я должен использовать WebAssembly.Memory? - или я могу выделить массив uint8 в js и использовать его для моего постоянного состояния отдельно от памяти программы? Если так, это медленнее?

Так что это будет работать до тех пор, пока я не использую динамический c распределитель, такой как WASI, и вместо этого использую pu sh, которым я могу управлять. (Я думаю, это потому, что, предположим, я использую mallo c для получения адресов памяти и перезагрузки - внутреннее состояние mallo c перезагрузится и будет думать, что вся кучная память доступна, когда она недоступна, поэтому будущие выделения могут затормозить предыдущие .) После перезагрузки я могу сначала скопировать структуру во временный буфер на стороне js, перезагрузить, получить расположение памяти структуры из Wasm (я буду требовать, чтобы она существовала), и скопировать сохраненную память из * 1038. * обратно в положение.

Однако, если я использую указатели, это развалится, потому что, если я изменю программу (что является точкой), __data_end может измениться, что сместит все адреса! Я проверил флаги компоновщика здесь https://lld.llvm.org/WebAssembly.html, чтобы увидеть, что я мог контролировать Я могу указать, что стек идет перед сегментом данных, но куча все равно идет после этого, что приводит к той же проблеме. Я также могу указать, где расположены глобальные данные, но я считаю, что это не сегмент данных, поэтому сегмент данных переменного размера все еще может компенсировать все мои адреса. Вот хорошая страница, которая может помочь нам визуализировать память Wasm: https://dassur.ma/things/c-to-webassembly/

У кого-нибудь есть мысли о том, как достичь того, чего я хочу? Единственные варианты, которые я могу придумать, включают использование памяти вне памяти Wasm (возможно, медленнее или невозможной), использование только стековой памяти и без указателей (нереально c, если только я не могу автоматически пересчитать все смещения указателя после перекомпиляции, что будет болезненный и подверженный ошибкам), или поиск способа заставить сегмент данных следовать за стеком и кучей по фиксированному адресу, что гарантировало бы, что сегменты стека и кучи не будут смещены, если сегмент данных должен расти. Другим вариантом, если это возможно, было бы установить максимальный размер сегмента данных. Спецификация / документация Wasm не очень хороши, когда дело доходит до манипуляций с памятью, поэтому я был бы признателен за разъяснение того, что возможно. Наконец, может быть, я мог бы использовать два модуля Wasm (но разве такого рода косвенность не будет медленной)? Возможно, мне не хватает чего-то важного, связанного с разметкой памяти.

Пожалуйста, дайте мне знать, если вам нужно больше деталей. Как я уже упоминал, я делал что-то подобное в C, и это обычная техника быстрой итерации для разработчиков игр. В основном я пытаюсь воссоздать его в Wasm.

EDIT: Очевидно, вы можете вызывать функции Wasm из другого модуля напрямую. Во-первых, как вы это сделаете, а во-вторых, какими будут характеристики производительности для доступа к памяти другого модуля?

EDIT2: Может быть, какая-то форма динамического c связывания, если это поддерживается? https://webassembly.org/docs/dynamic-linking/

Ответы [ 2 ]

0 голосов
/ 15 января 2020

Wasm организован в модули, и модули определяют четыре соответствующих вида сущностей: функции, память, таблицы, глобальные переменные. Код находится в функциях, в то время как остальные три представляют состояние модуля.

Теперь интересно то, что все четыре вида этих сущностей можно импортировать и экспортировать. Более того, все они могут быть созданы внешним образом для модуля, например, с помощью API JS.

Следовательно, способ эмуляции обмена кодом состоит в том, чтобы настроить ваш модуль так, чтобы все три элемента состояния были создан снаружи и импортирован в модуль. Таким образом, вы можете сохранить их внешне и передать их обновленному модулю, когда он станет доступен. (Вам также необходимо убедиться, что обновленный модуль не использует сегменты данных / элементов или запускает функции таким образом, что прокладывает путь по сравнению с существовавшим ранее состоянием.)

Конечно, это работает, только если форма модуля состояние не меняется между обновлениями. Например, нет новых глобальных переменных, нет новой компоновки данных в памяти, иначе новый код не сможет понять старое состояние. То, что на самом деле является трудной частью проблемы, но не зависит от особенностей Wasm.

0 голосов
/ 14 января 2020

Модули WebAssembly хранят состояние переменных в трех разных местах:

  • Линейная память
  • Локальные переменные, связанные со стеком выполнения
  • Глобальные переменные

Из них только глобальные переменные и линейная память доступны для хост-среды и потенциально сериализуемы для их кэширования при горячей перезагрузке модуля. Конечно, нет никакого способа напрямую получить доступ и сохранить текущий стек вызовов.

Если бы я хотел этого добиться, я бы создал свой собственный конечный автомат в WebAssembly, храня его в известном месте в линейном режиме. память.

...