
Целевые показатели webassembly: изменение целевых функций по умолчанию, о которых вам необходимо знать
12 июля 2025 г.Компилятор Rust недавно обновился до использования LLVM 19, и это изменение сопровождает некоторые обновления на набор целевых функций по умолчанию, включенные для целей Webassembly компилятора Rust. Beta Rust Today, которая станет Rust 1,82 в 2024-10-17, отражает все эти изменения и может использоваться для тестирования.
Webassembly - это развивающийся стандарт, в котором расширения добавляются с течением времени черезПроцесс предложенийПолем Предложения Webassembly достигают зрелости, объединились в саму спецификацию, получают реализацию в двигателях и оставались такими в течение довольно долгого времени, прежде чем продюсерские инструменты (например, LLVM)По умолчанию включите эти достаточно зрелостиПолем В LLVM 19 это произошло спредложения по многозначным и справочным типамДля целевых функций LLVM/Rustmultivalue
иreference-types
Полем Теперь они включены по умолчанию в LLVM и транзисивно означает, что он также включен по умолчанию и для ржавчины.
Целевые значения для rustулучшенные документациюо предложениях Webassembly и их соответствующих целевых функциях. Этот пост рассмотрит эти изменения и углубляется в то, что меняется в LLVM.
Предложения Webassembly и целевые функции компилятора
Предложения Webassembly - это формальное средство, с помощью которого сам стандарт Webassembly развивается с течением времени. Большинству предложений нуждается в интеграции инструментов в той или иной форме, например, новые флаги в LLVM или компилятор ржавчины. А-Ctarget-feature=...
Механизм используется для реализации этого сегодня. Это сигнал для LLVM и компилятор Rust, который предложения Webassembly включены или отключены.
Существует свободная связь между именем предложения (часто название репозитория GitHub предложения) и названием функции LLVM/Rust. Например, естьМногозначное предложениеноmultivalue
особенность.
Жизненный цикл реализации функции в Rust/LLVM обычно выглядит как:
- Новое предложение Webassembly создается в новом репозитории, например, Webassembly/Foo.
- В конечном итоге Rust/LLVM реализует предложение под
-Ctarget-feature=+foo
- В конечном итоге предложение вверх по течению объединяется в спецификацию, а Webassembly/Foo становится архивным хранилищем
- Rust/LLVM включить
-Ctarget-feature=+foo
Функция по умолчанию, но обычно сохраняет возможность отключить ее.
Аreference-types
иmultivalue
Целевые функции в Rust находятся на шаге (4) здесь сейчас, и этот пост объясняет последствия этого.
Включение типов ссылок по умолчанию
АПредложение о ссылочных типах на Webassemblyпредставил несколько новых концепций в Webassembly, в частностиexternref
Тип, который является определенным хост-ресурсом GC, к которому Webassembly не может получить доступ, но может передать. Rust не имеет поддержки для webassemblyexternref
Тип и LLVM 19 не меняет этого. Модули webassembly, произведенные из Rust, будут продолжать не использоватьexternref
Тип и не имеют возможности сделать это.
Это может быть включено в будущем (например, гипотетическийcore::arch::wasm32::Externref
Тип или аналогичный), но, скорее всего, это, вероятно, будет выполнено только на основе выбора и не повлияет на ранее существующий код по умолчанию.
Однако в предложение о справочных типах была также включена возможность иметь несколько таблиц Webassembly в одном модуле. В оригинальной версии спецификации Webassembly была разрешена только одна таблица, и это ограничение было расслаблено с предложением о эталонных типах. Таблицы Webassembly используются LLVM и Rust для реализации непрямых вызовов функций. Например, указатели функций в WebAssembly на самом деле являются табличными индексами, а непрямые вызовы функций - это веб -ассемембаностьcall_indirect
Инструкция с этим индексом таблицы.
С предложением о эталонных типах бинарное кодированиеcall_indirect
Инструкции были обновлены. Перед предложением эталонного типаcall_indirect
был закодирован с фиксированным нулевым байтом в его инструкции (должно быть ровно 0x00). Этот фиксированный нулевой байт был расслаблен до 32-битногоЛебЧтобы указать, какая таблицаcall_indirect
Инструкция использовалась.
Для тех, кто незнакомЛебявляется способом кодирования много-байтовых целых чисел в меньшем количестве байтов для меньших целых чисел. Например, 32-разрядное целое число 0 может быть закодировано как0x00
сЛебПолемЛебS гибкие, чтобы дополнительно разрешать «перекрытые» кодировки, чтобы целое число 0 дополнительно кодировалось как0x80 0x00
Полем
Поддержка LLVM отдельной компиляции исходного кода в двоичный вакансию WebAssembly означает, что, когда испускается объектный файл, он не знает окончательного индекса таблицы, которая будет использоваться в последнем двоичном файле. Перед ссылочными типами была только один вариант, таблица 0, поэтому0x00
всегда использовался при кодированииcall_indirect
инструкции.
Однако после эталонных типов LLVM излучит более длительноеЛебформы0x80 0x80 0x80 0x80 0x00
который является максимальной длиной 32-битнойЛебПолем ЭтотЛебзатем заполняется линкером с перемещением в фактический индекс таблицы, который используется конечным модулем.
При объединении всего это означает, что с LLVM 19, который имеетreference-types
Функция, включенная по умолчанию, любой модуль webassembly с непрямым вызовом функции (который почти всегда имеет место для кода Rust), будет создавать двоичный файл webassembly, который не может быть декодирован двигателями и инструментами, которые не поддерживают предложение ссылочных типов.
Ожидается, что это изменение окажет низкое влияние из-за возраста предложения контрольных типов и широты реализации в двигателях. Однако, учитывая множество двигателей Webassembly, рекомендуется, чтобы любые пользователи Webassembly проверили бета -версию Rust 1.82 и посмотрели, работает ли производимый модуль по их выбору.
LLVM, Rust и несколько таблиц
Один интересный момент, который стоит упомянуть, заключается в том, что, несмотря на предложение о эталонных типах, позволяющее нескольким таблицам в модулях Webassembly, это на самом деле не используется в настоящее время ни LLVM, ни ржавчиной. Излучаемые модули webassembly все еще будут иметь не более одной таблицы функций. Это означает, что более длительное 5-байтовое кодирование индекса 0 как0x80 0x80 0x80 0x80 0x00
На самом деле не требуется в настоящее время.
LLD, LLVM Linker для Webassembly, хочет обработать всеЛебПеремещения аналогичным образом, что в настоящее время заставляет это 5-байтовое кодирование нуля. Например, когда функция вызывает другую функциюcall
инструкция кодирует индекс целевой функции как 5-байтЛебкоторый заполняется линкером. В целом существует более чем одна функция, поэтому 5-байтовая кодирование позволяет кодировать все возможные функциональные индексы.
В будущем LLVM может начать использовать несколько таблиц. Например, LLVM может иметь режим в будущем, где появится тип таблицы на функцию вместо одной гетерогенной таблицы. Это может позволить двигателям внедрятьcall_indirect
более эффективно. Это не реализовано в это время, однако.
Для пользователей, которым нужен модуль webassembly минимального размера (например, если вы находитесь в веб-контексте и отправляете байты через проволоку), рекомендуется использовать инструмент оптимизации, такой какwasm-opt
Чтобы сократить размер выхода LLVM. Еще до этого изменения с эталонными типами рекомендуется сделать это какwasm-opt
Обычно может оптимизировать вывод по умолчанию LLVM еще дальше. При оптимизации модуля черезwasm-opt
Эти 5-байтовые кодировки индекса 0 сжаты до одного байта.
По умолчанию по умолчанию по умолчанию
Вторая функция, включенная по умолчанию в LLVM 19, являетсяmultivalue
Полем АМногозначное предложение о WebassemblyПозволяет, например, иметь более одного возвращаемого значения. Инструкции Webassembly также разрешено иметь более одного возврата. Это предложение является одним из первых, кто превратился в спецификацию Webassembly после исходного MVP и в течение некоторого времени внедрилось во многих двигателях.
Однако последствия включения этой функции по умолчанию в LLVM более незначительны для ржавчины, чем включениеreference-types
функция по умолчанию. LLVM по умолчанию C ABI для кода WebAssembly не меняется, даже когдаmultivalue
включено. Кроме того, ржавчинаextern "C"
ABI для WebAssembly также не меняется и продолжает соответствовать LLVM (или стремится,Различия в LLVMсчитаются ошибками для исправления). Несмотря на это, хотя изменение имеет возможность все еще повлиять на пользователей ржавчины.
Ржавчина в течение некоторого времени поддерживалаextern "wasm"
ABI на ночи, который был экспериментальным средством выявления способности определения функции в ржавчине, которая возвращала несколько значений (например, использовал предложение с несколькими значениями). Из -за инфраструктурных изменений и рефакторных в самом LLVM эта особенность ржавчины имеетбыл удалени больше не поддерживается ночью вообще. В результате больше нет никакого возможного метода написания функции в Rust, которая возвращает несколько значений на уровне типа функции WebAssembly.
Таким образом, ожидается, что это изменение не повлияет на код ржавчины в дикой природе, если вы не использовали ночную функциюextern "wasm"
В этом случае вы будете вынуждены отказаться от поддержки и использоватьextern "C"
вместо. Поддержка функций Webassembly Multi-Return в Rust-более широкая тема, чем этот пост может охватить, но в настоящее время это область, которая созрела для вклада от соответствующих мотивированных участников.
В стороне: стабильность ABI и Webassembly
На теме Абиса иmultivalue
Особенность, возможно, стоит также немного, что означает ABIS для Webassembly. Текущее определениеextern "C"
Abi для webassembly задокументирована вРепозиторий инструментовИ это то, что Clang реализует и для C -кода.
LLVM реализует достаточную поддержку для снижения в Webassembly, а также для поддержки всего этого. Аextern "Rust
ABI не стабилен на веб -ассемэмбилете, как в случае всех целей ржавчины, и с течением времени может быть изменена. В настоящее время нет справочной документации для чегоextern "Rust"
находится на веб -ассемберри.
Аextern "C"
ABI, то, что C код использует по умолчанию, трудно изменить, потому что для разных версий компилятора часто требуется стабильность. Например, можно ожидать, что код Webassembly, составленный с LLVM 18, будет работать с кодом, скомпилированным LLVM 20. Это означает, что изменение ABI - это сложная задача, которая требует полей версий, явных маркеров и т. Д., Чтобы помочь предотвратить несоответствия.
Аextern "Rust"
Аби, однако, может измениться со временем. Отличным примером этого может быть то, что когдаmultivalue
функция включенаextern "Rust"
ABI может быть пересмотрен, чтобы использовать многочисленные значения, которые затем поддержит Webassembly. Это позволило бы гораздо более эффективной доходности значений, превышающих 64-битные. Реализация этого потребует поддержки в LLVM, хотя в настоящее время нет.
Все это означает, что на самом деле используют несколько возвратов в функциях или функцию Webassembly, чтоmultivalue
позволяет, все еще находится на горизонте и не реализован. Сначала LLVM должен будет реализовать полную поддержку понижения для создания функций Webassembly с несколькими возвратами, а затемextern "Rust"
может быть изменен, чтобы использовать это при полной поддержке. В будущем, пока не стал будущий код C, может измениться, но это займет довольно много времени из-за ее истории о перекрестной версии.
Включение будущих предложений в Webassembly
Это не первый раз, когда предложение Webassembly переходило от неверного по умолчанию в LLVM, а также не будет последним. Например, LLVM уже позволяетПодвеска предложенияПо умолчанию, какого MVP Webassembly не имела. Ожидается, что в не слишком устойчивом будущемНезамие-FP-intПредложение, вероятно, будет включено по умолчанию. Эти изменения в настоящее время не внесены с учетом строгих критериев (например, двигатели N должны реализовать это в течение M лет), и может произойти поломка.
Если вы используете двигатель Webassembly, который не поддерживает модули, испускаемые Rust 1.82 Beta и LLVM 19, то ваши варианты:
- Попробуйте посмотреть, есть ли для его обновления какие -либо обновления. Вы можете использовать более старую версию, которая не поддерживала функцию, но более новая версия поддерживает эту функцию.
- Откройте проблему, чтобы повысить осведомленность о том, что изменение вызывает поломку. Это может быть сделано либо на репозитории вашего двигателя, репозитории Rust или WebassemblyИнструментальные конвенциирепозиторий. Рекомендуется сначала поиск, чтобы подтвердить, что еще нет открытой проблемы.
- Перекомпилируйте свой код с отключенными функциями, подробнее об этом в следующем разделе.
Общее предположение, лежащее в основе включения новых функций по умолчанию, заключается в том, что это относительно беспрепятственная операция для конечных пользователей, при этом приносят выгоду для всех (например, без перебоя в FP-инттаж, сделает конверсии с плавающей в интюд более оптимальными). Если обновления в конечном итоге вызывает хлопоты, лучше всего пометить это на раннем этапе, так что планы развертывания могут быть скорректированы при необходимости.
Отключение предложений по умолчанию по умолчанию
По разным причинам вы можете быть мотивированы отключить функции по умолчанию Webassembly: например, ваш двигатель трудно обновлять или не поддерживает новую функцию. Отключение функций по умолчанию, к сожалению, является не самой простой задачей. Примечательно недостаточно для использования-Ctarget-features=-sign-ext
Чтобы отключить функцию только для компиляции вашего собственного проекта, потому что стандартная библиотека ржавчины, отправленная в предварительно скомпилированной форме, все еще составлена с включенной функцией.
Чтобы отключить предложение по умолчанию по умолчанию, требуется, чтобы вы использовали грузы-Zbuild-std
особенность. Например:
$ export RUSTFLAGS=-Ctarget-cpu=mvp
$ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unknown
Это перекомпилирует стандартную библиотеку Rust в дополнение к вашему собственному коду с помощью «MVP -процессора», который является заполнителем LLVM для всех предложений Webassembly отключена. Это отключит подпись-EXT, ссылочные типы, многоцветную и т. Д.
Алекс Крайтон от имени
Также опубликованоздесь
ФотоЭнгин АкюртнаНеспособный
Оригинал