Целевые показатели webassembly: изменение целевых функций по умолчанию, о которых вам необходимо знать

Целевые показатели 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 обычно выглядит как:

  1. Новое предложение Webassembly создается в новом репозитории, например, Webassembly/Foo.
  2. В конечном итоге Rust/LLVM реализует предложение под-Ctarget-feature=+foo
  3. В конечном итоге предложение вверх по течению объединяется в спецификацию, а Webassembly/Foo становится архивным хранилищем
  4. 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 "RustABI не стабилен на веб -ассемэмбилете, как в случае всех целей ржавчины, и с течением времени может быть изменена. В настоящее время нет справочной документации для чего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, ссылочные типы, многоцветную и т. Д.


Алекс Крайтон от имениКоманда компилятора

Также опубликованоздесь

ФотоЭнгин АкюртнаНеспособный


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE